diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..1c757d6d4e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# System, cache and editor files +**/__pycache__ +**/.DS_Store + +.editorconfig +.idea +.git +.github +.gitignore +.pytest_cache +.pre-commit-config.yaml +.readthedocs.yml +.coverage +Procfile +README.md + +# Never bake in environment variables +.env +.env* +google_credentials.json +# See: https://github.com/google-github-actions/auth/issues/123 +gha-creds-*.json +gcp-creds-*.json + +.devcontainer/.zsh_history +share/docker diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index e890cdf6ed..0d6d3f2201 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -21,6 +21,7 @@ env: C_COMPILER: gcc-12 GCOV_EXE: gcov-12 CMAKE_BUILD_PARALLEL_LEVEL: 8 + CTEST_PARALLEL_LEVEL: 2 jobs: @@ -35,20 +36,21 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@v4 with: submodules: recursive - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' - name: Set up MATLAB - uses: matlab-actions/setup-matlab@v1 + uses: matlab-actions/setup-matlab@v2 + with: + products: Simulink - 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev - name: Setup workspace @@ -77,7 +79,7 @@ jobs: run: | cmake --build . --target all - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-all-debug-${{ github.sha }} @@ -89,7 +91,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies @@ -124,18 +126,17 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@v4 with: submodules: recursive - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev - name: Setup workspace @@ -160,7 +161,7 @@ jobs: run: | cmake --build . --target regression_test_module_drivers - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-drivers-release-${{ github.sha }} @@ -170,20 +171,21 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@v4 with: submodules: recursive - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' - name: Set up MATLAB - uses: matlab-actions/setup-matlab@v1 + uses: matlab-actions/setup-matlab@v2 + with: + products: Simulink - 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev # gcovr @@ -215,7 +217,7 @@ jobs: working-directory: ${{runner.workspace}}/openfast/build run: cmake --build . --target openfast_postlib - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-postlib-release-${{ github.sha }} @@ -226,19 +228,18 @@ jobs: needs: build-postlib-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-postlib-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -253,7 +254,7 @@ jobs: run: | cmake --build . --target openfastlib openfast_cpp_driver openfastcpp aerodyn_inflow_c_binding moordyn_c_binding ifw_c_binding hydrodyn_c_binding regression_test_controllers - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-interfaces-release-${{ github.sha }} @@ -264,19 +265,18 @@ jobs: needs: build-postlib-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-postlib-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -291,7 +291,7 @@ jobs: run: | cmake --build . --target openfast - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} @@ -302,19 +302,18 @@ jobs: needs: build-postlib-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-postlib-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -329,7 +328,7 @@ jobs: run: | cmake --build . --target FAST.Farm - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-fastfarm-release-${{ github.sha }} @@ -339,22 +338,21 @@ jobs: ### BUILD AND TEST JOBS build-test-uadriver-debug: - # UA driver requires -DUA_OUTS, cannot be compiled with other + # UA driver used to require -DUA_OUTS runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@v4 with: submodules: recursive - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev - name: Setup workspace @@ -374,7 +372,6 @@ jobs: -DVARIABLE_TRACKING=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ - -DCMAKE_Fortran_FLAGS="-DUA_OUTS=ON" \ ${GITHUB_WORKSPACE} - name: Build all working-directory: ${{runner.workspace}}/openfast/build @@ -388,7 +385,7 @@ jobs: ctest -VV -R "^ua_" - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-uadriver @@ -404,19 +401,18 @@ jobs: needs: build-drivers-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-drivers-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -449,7 +445,7 @@ jobs: - name: Run SubDyn tests uses: ./.github/actions/tests-module-subdyn - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-module-drivers @@ -462,19 +458,18 @@ jobs: needs: build-all-debug steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-all-debug-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -509,7 +504,7 @@ jobs: - name: Run VersionInfo tests uses: ./.github/actions/tests-module-version - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-modules-debug @@ -523,19 +518,18 @@ jobs: needs: build-interfaces-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-interfaces-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" vtk + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -552,7 +546,7 @@ jobs: run: | ctest -VV -L "cpp|python|fastlib" - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-interfaces @@ -571,19 +565,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -604,7 +597,7 @@ jobs: -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 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF @@ -624,7 +617,7 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} @@ -633,7 +626,9 @@ jobs: 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 + uses: matlab-actions/setup-matlab@v2 + with: + products: Simulink - name: Build FAST_SFunc working-directory: ${{runner.workspace}}/openfast/build run: | @@ -642,7 +637,7 @@ jobs: ${GITHUB_WORKSPACE} cmake --build . --target FAST_SFunc - name: Run MATLAB tests and generate artifacts - uses: matlab-actions/run-tests@v1 + uses: matlab-actions/run-tests@v2 with: source-folder: ${{runner.workspace}}/openfast/build/glue-codes/simulink; ${{runner.workspace}}/openfast/glue-codes/simulink/examples test-results-junit: test-results/results.xml @@ -654,12 +649,12 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' @@ -683,7 +678,7 @@ jobs: run: | ctest -VV -L aeromap -LE "cpp|linear|python" -R 5MW_Land_AeroMap - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_Land_AeroMap @@ -703,19 +698,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -733,7 +727,7 @@ jobs: run: | ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC4Semi_WSt_WavesWN - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_OC4Semi_WSt_WavesWN @@ -753,19 +747,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -783,7 +776,7 @@ jobs: run: | ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC3Mnpl_DLL_WTurb_WavesIrr - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_OC3Mnpl_DLL_WTurb_WavesIrr @@ -803,19 +796,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -833,7 +825,7 @@ jobs: run: | ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth @@ -853,19 +845,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -883,7 +874,7 @@ jobs: run: | ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC3Trpd_DLL_WSt_WavesReg - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_OC3Trpd_DLL_WSt_WavesReg @@ -903,19 +894,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -933,7 +923,7 @@ jobs: run: | ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_Land_BD_DLL_WTurb - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-5MW_Land_BD_DLL_WTurb @@ -953,19 +943,18 @@ jobs: needs: build-openfast-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -980,9 +969,9 @@ jobs: - name: Run OpenFAST linearization tests working-directory: ${{runner.workspace}}/openfast/build run: | - ctest -VV -j4 -L linear + ctest -VV -L linear - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-OF-linearization @@ -1002,19 +991,18 @@ jobs: needs: build-fastfarm-release steps: - name: Cache the workspace - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{runner.workspace}} key: build-fastfarm-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 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" + pip install -r requirements.txt sudo apt-get update -y sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libnetcdf-dev libopenmpi-dev libyaml-cpp-dev @@ -1034,7 +1022,7 @@ jobs: set OMP_NUM_THREADS=2 ctest -VV -L fastfarm --verbose - name: Failing test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: rtest-FF diff --git a/.github/workflows/build-docker-image-automatic.yml b/.github/workflows/build-docker-image-automatic.yml new file mode 100644 index 0000000000..01b80fcac2 --- /dev/null +++ b/.github/workflows/build-docker-image-automatic.yml @@ -0,0 +1,59 @@ +# This workflow builds an OpenFAST docker image for the linux/amd64 and linux/aarch64 architectures on merge into +# `main` from a release candidate branch. The image is tagged both with "latest" and the version extracted from the +# release candidate branch's name (e.g. "rc-3.5.3") before being pushed to the `nrel/openfast` repository. The build +# cache is stored in GitHub actions. +name: build-docker-image-automatic + +on: + release: + types: + - released + +jobs: + build-and-push: + runs-on: ubuntu-latest + timeout-minutes: 300 + env: + DOCKERFILE_PATH: share/docker/Dockerfile + DOCKERHUB_REPOSITORY: nrel/openfast + GH_REGISTRY: ghcr.io/OpenFAST/openfast + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Commenting out until we get the NREL DockerHub credentials + # - name: Log in to DockerHub + # uses: docker/login-action@v3 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.GH_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract tag from release candidate branch name + id: extract-tag + run: echo "openfast-tag=$(expr substr "${{ github.head_ref }}" 4 100)" >> $GITHUB_OUTPUT + + - name: Build and push to registry + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ env.DOCKERFILE_PATH }} + platforms: linux/amd64,linux/aarch64 + tags: | + ${{ env.GH_REGISTRY }}:${{ steps.extract-tag.outputs.openfast-tag }},${{ env.DOCKERHUB_REPOSITORY }}:latest +# ${{ env.DOCKERHUB_REPOSITORY }}:${{ steps.extract-tag.outputs.openfast-tag }},${{ env.DOCKERHUB_REPOSITORY }}:latest + push: true + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/build-docker-image-manual.yml b/.github/workflows/build-docker-image-manual.yml new file mode 100644 index 0000000000..608bd02307 --- /dev/null +++ b/.github/workflows/build-docker-image-manual.yml @@ -0,0 +1,72 @@ +# This manually-triggered workflow builds OpenFAST docker images for the linux/amd64 and linux/aarch64 architectures for +# the specified git ref (this can be a branch, tag, or commit hash). The image is tagged with the given tag and pushed +# to the `nrel/openfast` repository. The build cache is stored in GitHub actions. +name: build-docker-image-manual + +on: + workflow_dispatch: + inputs: + tag: + description: 'Tag for Docker image (excluding the "v" prefix e.g. 3.5.3)' + required: true + ref: + description: 'Branch, tag, or commit SHA to build from' + required: true + default: main + +jobs: + build-and-push: + runs-on: ubuntu-latest + timeout-minutes: 300 + env: + DOCKERFILE_PATH: share/docker/Dockerfile + DOCKERFILE_PERMALINK: https://raw.githubusercontent.com/OpenFAST/openfast/main/share/docker/Dockerfile + DOCKERHUB_REPOSITORY: nrel/openfast + GH_REGISTRY: ghcr.io/OpenFAST/openfast + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Commenting out until we get the NREL DockerHub credentials + # - name: Log in to DockerHub + # uses: docker/login-action@v3 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.GH_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # The updated Dockerfile is only available in the repository at the tag v3.5.3 and above. To build versions of + # OpenFAST that are below this version, the updated Dockerfile from that tag of the repository has to be acquired + # before building. For versions >= v3.5.3, the Dockerfile is already there so this step does nothing. + - name: Get Dockerfile for versions < 3.5.3 + run: | + if [ ! -f ${{ env.DOCKERFILE_PATH }} ]; \ + then wget -O ${{ env.DOCKERFILE_PATH }} ${{ env.DOCKERFILE_PERMALINK }}; \ + fi + + - name: Build and push to registry + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ env.DOCKERFILE_PATH }} + platforms: linux/amd64,linux/aarch64 + tags: | + ${{ env.GH_REGISTRY }}:${{ github.event.inputs.tag }} +# ${{ env.DOCKERHUB_REPOSITORY }}:${{ github.event.inputs.tag }} + push: true + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/test-build-docker-image.yml b/.github/workflows/test-build-docker-image.yml new file mode 100644 index 0000000000..1bd4d7b96b --- /dev/null +++ b/.github/workflows/test-build-docker-image.yml @@ -0,0 +1,38 @@ +# This workflow tests building an OpenFAST docker image for the linux/amd64 architecture on push to a release candidate +# branch. The build cache is stored in GitHub actions. +name: test-build-docker-image + +on: + pull_request: + branches: + - main + +jobs: + test-build: + if: startsWith(github.head_ref, 'rc-') + runs-on: ubuntu-latest + timeout-minutes: 300 + env: + DOCKERFILE_PATH: share/docker/Dockerfile + DOCKERHUB_REPOSITORY: nrel/openfast + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract tag from release candidate branch name + id: extract-tag + run: echo "openfast-tag=$(expr substr "${{ github.head_ref }}" 4 100)" >> $GITHUB_OUTPUT + + - name: Test building docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ env.DOCKERFILE_PATH }} + platforms: linux/amd64 + tags: ${{ env.DOCKERHUB_REPOSITORY }}:${{ steps.extract-tag.outputs.openfast-tag }} + push: false + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 0b6dd4368e..8004a8eb5d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,8 @@ vs-build/ .atom .fortls .devcontainer +.idea + # backup files *.asv ~$*.xlsx @@ -54,4 +56,3 @@ vs-build/ #Simulink cache files varcache *.slxc - diff --git a/CMakeLists.txt b/CMakeLists.txt index 3727f6f3de..2989bfe576 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,12 @@ include(${CMAKE_SOURCE_DIR}/cmake/set_rpath.cmake) #------------------------------------------------------------------------------- if (OPENMP OR BUILD_FASTFARM OR BUILD_OPENFAST_CPP_API) - FIND_PACKAGE(OpenMP REQUIRED) + if (OPENMP) + FIND_PACKAGE(OpenMP REQUIRED) + else() + # Optional for FF or the CPP interface + FIND_PACKAGE(OpenMP) + endif() if (OpenMP_Fortran_FOUND) set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") link_libraries("${OpenMP_Fortran_LIBRARIES}") @@ -204,6 +209,7 @@ set(OPENFAST_MODULES icefloe wakedynamics awae + lindyn map turbsim supercontroller diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index 6828ce34bf..2ece7d48db 100644 Binary files a/docs/OtherSupporting/OutListParameters.xlsx and b/docs/OtherSupporting/OutListParameters.xlsx differ diff --git a/docs/changelogs/v3.5.3.md b/docs/changelogs/v3.5.3.md new file mode 100644 index 0000000000..1dc519fcee --- /dev/null +++ b/docs/changelogs/v3.5.3.md @@ -0,0 +1,133 @@ +**Feature or improvement description** +Pull request to merge `rc-3.5.3` into `main` and create a tagged release for v3.5.3. + +See the milestone and project pages for additional information + + https://github.com/OpenFAST/openfast/milestone/13 + +Test results, if applicable +See GitHub Actions + +### Release checklist: +- [ ] Update the documentation version in docs/conf.py +- [ ] Update the versions in docs/source/user/api_change.rst +- [ ] Verify readthedocs builds correctly +- [ ] Create a tag in OpenFAST +- [ ] Create a merge commit in r-test and add a corresponding annotated tag +- [ ] Compile executables for Windows builds + - [ ] AeroDyn_Driver_x64.exe + - [ ] AeroDyn_Driver_x64_OpenMP.exe + - [ ] AeroDyn_Inflow_C_Binding_x64.dll + - [ ] AeroDyn_Inflow_C_Binding_x64_OpenMP.dll + - [ ] BeamDyn_Driver_x64.exe + - [ ] DISCON.dll (x64) + - [ ] DISCON_ITIBarge.dll (x64) + - [ ] DISCON_OC3Hywind.dll (x64) + - [ ] DISCON_SC.dll (x64) + - [ ] FAST.Farm_x64.exe + - [ ] FAST.Farm_x64_OMP.exe + - [ ] FAST_SFunc.mexw64 + - [ ] HydroDynDriver_x64.exe + - [ ] HydroDyn_C_Binding_x64.dll + - [ ] IfW_C_Binding_x64.dll + - [ ] InflowWind_Driver_x64.exe + - [ ] InflowWind_Driver_x64_OpenMP.exe + - [ ] MoorDyn_Driver_x64.exe + - [ ] MoorDyn_C_Binding_x64.dll + - [ ] OpenFAST-Simulink_x64.dll + - [ ] openfast_x64.exe + +# Changelog + +## Overview + +This release includes a long awaited set of bug fixes for linearization with BeamDyn. Anyone needing to linearize with BeamDyn should not use any version of OpenFAST prior to this release. + +Other notable improvements include corrections to turbine indexing when coupled to external codes such as AMR-Wind, new linearization regression tests, and new docker images (thanks to first time contributor @cortadocodes at the @Octue organization). + + +## General + +### Build systems + +#2116 VSbuild: always build Registry as release x64 (@andrew-platt) +#2120 #2125 CMake: openmp optional for FF and CPP if not explicitly requested (@andrew-platt and @deslaughter) +#2128 VSbuild: set VS version to VS 2017 (@andrew-platt) +#2138 Remove linking of implicit Fortran libraries. (@jrood-nrel) + + +### Docker builds + +#2124 Update dockerfile and facilitate nrel/openfast Docker Hub registry, with documentation (@cortadocodes, first time contributor) +#2139 Add final dockerfile updates (@cortadocodes) +#2141 GH actions to push docker image to Github container registry (@mayankchetan, first time contributor) + + +### GH actions + +#2041 Upgrade to setup-python@v4 and cache@v4 for GH actions (@andrew-platt) +#2129 Fix cache failure in Github Actions caused by setup-python (@deslaughter) + +### Documentation + +#2130 Fix cache failure in Github Actions caused by setup-python (@andrew-platt) +#2144 Edit to readthedocs.io -- Adding Internal Reference Hyperlink for appendixD.rst (@reilandsberger, first time contributor) +#2145 Docs/update for 3.5.3 release (@andrew-platt) + + +## Solvers + +### OpenFAST + +#2060 Fix BD + AD linearization indexing (negative damping results) (@deslaugher and @andrew-platt) + + +## Module changes + +### Multiple + +#2118 Fix use of uninitialized variables in FAST.Farm and increase stack size in Visual Studio (@deslaughter and @andrew-platt) + + +### BeamDyn + +#2063 Fix bug in BD linearization resulting from reference rotation change (@deslaughter) +#2085 Bug: BeamDyn Initial Strain and Linearization (@deslaughter) + + +### MoorDyn + +#2049 Backport of bathymetry bugfixes in #2013 and #2016 (@RyanDavies19) + + +### OpenFAST library + +#2097 Consistent use of turbine indexing when coupled to c/c++ (@andrew-platt and @deslaughter) + + +### ServoDyn + +#2079 Handling of Paths for SrvD UserSubs Input Files (@rdamiani) +#2134 Bugfix seg fault if blade StC used while writing summary file (@andrew-platt) + + +### TurbSim + +#2102 TurbSim: increase filename to 1024 characters (@andrew-platt) + + +## Regression tests + +#2038 Add linearization regression tests (@andrew-platt) +#2055 Lin tests: increase out precision, error printing full filename, add SD linearization test (@andrew-platt) + + + +## Input file changes + +No input files change with this release, as this only includes minor bugfixes. + +Full list of changes: https://openfast.readthedocs.io/en/main/source/user/api_change.html + +Full input file sets: https://github.com/OpenFAST/r-test/tree/v3.5.3 (example input files from the regression testing) + diff --git a/docs/conf.py b/docs/conf.py index 0f2d012146..c0432bfcaf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -72,6 +72,7 @@ def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): 'source/user/aerodyn-aeroacoustics/references.bib', 'source/user/aerodyn-olaf/bibliography.bib', 'source/user/aerodyn/bibliography.bib', + 'source/user/elastodyn/bibliography.bib', 'source/user/beamdyn/references.bib', 'source/user/extptfm/bibliography.bib', 'source/user/fast.farm/bibliography.bib', @@ -137,7 +138,7 @@ def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): # The short X.Y version. version = u'3.5' # The full version, including alpha/beta/rc tags. -release = u'v3.5.2' +release = u'v3.5.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst index 9da66481dc..85c33ac203 100644 --- a/docs/source/install/index.rst +++ b/docs/source/install/index.rst @@ -11,8 +11,8 @@ maintained paths for obtaining an OpenFAST executable. Most users of OpenFAST will not require modifying or compiling the source code. **For the simplest installation of OpenFAST without changing the source -code,** refer to the table in the :ref:`download_binaries` section and read -the corresponding documentation for specific instructions. +code,** refer to the table in the :ref:`download_binaries` or :ref:`use_docker` +sections and read the corresponding documentation for specific instructions. For instructions on compiling, see :ref:`compile_from_source`. .. _download_binaries: @@ -154,6 +154,60 @@ containing the executables, and running a simple test command: cd C:\your\path\Desktop\openfast_binaries\ openfast_x64.exe /h + +.. _use_docker: + +Running OpenFAST with docker +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OpenFAST is avilable to be run on docker starting with version 3.5.3. Three approaches are shared below. + +Using a docker image from Docker hub +------------------------------------ +Multiple versions of OpenFAST are also available as docker images from our `docker registry `_. +To pull and run one with files from your local machine available, run: + +.. code-block:: shell + + docker run --rm -it --volume=/path/to/files:/files nrel/openfast:latest openfast /files/main.fst + +This command deletes the container (but not the image) when the analysis is finished and leaves the outputs in the same +local directory as the input files. + +You can also run commands interactively inside the container with: + +.. code-block:: shell + + docker run --rm -it --volume=/path/to/files:/files nrel/openfast:latest /bin/bash + +To pull a specific release, substitute the version number in place of `latest` in the above commands (i.e. `nrel/openfast:3.5.3`). + + +Using a docker image from GitHub container registry +--------------------------------------------------- +In addition to images hosted on Docker hub, we also host docker images on our +`GitHub container registry `_. +The commands for pulling an image from the GitHub container repository are +similar to those for pulling and running from Docker hub. + +To pull and run with local files: + +.. code-block:: shell + + docker run --rm -it --volume=/path/to/files:/files ghcr.io/OpenFAST/openfast:latest openfast /files/main.fst + +For running the container interactively: + +.. code-block:: shell + + docker run --rm -it --volume=/path/to/files:/files ghcr.io/OpenFAST/openfast:latest /bin/bash + + +Build your own images +--------------------- +You can also build your own custom images using our `Dockerfile` or base your images on ours. See +`here `_ for more information on this. + + .. _compile_from_source: Compile from source diff --git a/docs/source/testing/regression_test.rst b/docs/source/testing/regression_test.rst index 9262e6bdc1..870fe8143d 100644 --- a/docs/source/testing/regression_test.rst +++ b/docs/source/testing/regression_test.rst @@ -64,12 +64,14 @@ reported as failed. The failure criteria is outlined below. Dependencies ------------ -The following packages are required for regression testing: +The following packages are required for regression testing (see also the +``requirements.txt`` file in the root directory for the python modules): -- Python 3.7+ -- Numpy - CMake and CTest (Optional) -- Bokeh 2.4+ (Optional) +- Python >=3.7,<=3.11 +- numpy +- vtk +- bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3 (Optional) .. _python_driver: diff --git a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat deleted file mode 100644 index 902354a4db..0000000000 --- a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat +++ /dev/null @@ -1,11 +0,0 @@ -Example Time-Series Input File for UnsteadyAero Driver - - -This file has 8 header lines followed by three columns of data: - - -Time Angle of Attack VRel omega -(s) (deg) (m/s) (rad/s) -0.0 0 10 0 -0.01 0 10 0 -0.02 0 10 0 diff --git a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.dvr b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.dvr deleted file mode 100644 index 290e7e2245..0000000000 --- a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.dvr +++ /dev/null @@ -1,28 +0,0 @@ -UnsteadyAero Driver file for Unit NACA. k = 0.077 -------------------------------------------------------------------------------- -FALSE Echo - Echo the input file data (flag) ----------------------- ENVIRONMENTAL CONDITIONS ------------------------------- - 340.29 SpdSound - Speed of sound (m/s) ----------------------- UNSTEADYAERO ------------------------------------------- -"05014051_NACA" OutRootName - The name which prefixes all UnsteadyAero generated files (quoted string) - 40.36 InflowVel - Inflow velocity (m/s) - 1.48 Re - Reynolds number in millions (-) - 3 UAMod - Unsteady Aero Model Switch: 2 - Gonzalez’s variant (changes in Cn,Cc,Cm); 3 - Minnema/Pierce variant (changes in Cc and Cm) -TRUE Flookup – Flag to indicate whether a lookup for f’ will be calculated (TRUE) or whether best-fit exponential equations will be used (FALSE); if FALSE S1-S4 must be provided in airfoil input files -------------------- AIRFOIL PROPERTIES ---------------------------------------- -"05000051_AD15.dat" AirFoil - Airfoil table - 0.55 Chord - Chord length (m) -TRUE UseCm - Use Cm data in airfoil table -------------------- SIMULATION CONTROL ---------------------------------------- - 1 SimMod - Simulation model [ 1 - use reduced frequency model, 2 - use time series data stored in the TimeInputs file and ignore the remaining parameters ] - 3 NCycles - Number of angle-of-attack oscillations (cosine function) over the length of the simulation (-) - 720 StepsPerCycle - Number of timesteps per cycle (-) - 1.8 Frequency - Frequency for the airfoil oscillations (Hz) - 9.685 Amplitude - Amplitude of the oscillations (deg) - 15.195 Mean - Cycle mean (deg) - -180 Phase - Initial phase (num steps) -"UA-driver-timeseries.dat" InputsFile - Time series data in an ASCII input file (whitespace-separated data). 8 header lines, followed by column data. First column is time (sec), second column is angle-of-attack (deg), third column is InflowVel (m/s) -------------------- OUTPUT CONTROL -------------------------------------------- -True SumPrint - Write unsteady aerodynamics summary file (flag) -True WrAFITables - Write the tables of aerodynamic coefficients used internally, with extension ".Coeff.out" (flag) -END of driver input file diff --git a/docs/source/user/aerodyn/bibliography.bib b/docs/source/user/aerodyn/bibliography.bib index dc79859eb4..56ea901810 100644 --- a/docs/source/user/aerodyn/bibliography.bib +++ b/docs/source/user/aerodyn/bibliography.bib @@ -16,6 +16,14 @@ @TECHREPORT{ad-AeroDyn:manualUnsteady note = {NREL/TP-5000-66347} } +@article{ad-UAElast:torquepaper, + title = {Aeroelastic stability of a generalized wind turbine cross-section including unsteady airfoil aerodynamic and dynamic inflow}, + author = {E. Branlard and J.Jonkman and B. Jonkman and M. Singh and E. Mayda and K.Dixon and J H. Porter and G. Vijayakumar}, + year = 2024, + journal = {Jounal of Physics: Conference Series}, +} + + @book{ad-Branlard:book, author = {E. Branlard}, title = {Wind Turbine Aerodynamics and Vorticity-Based Methods: Fundamentals and Recent Applications}, @@ -108,3 +116,10 @@ @article{ad-hammam2022 volume= 1, number=1 } + +@techreport{ad-hammam_NREL:2023, + title={Modeling the Yaw Behavior of Tail Fins for Small Wind Turbines: November 22, 2021-May 21, 2024}, + author={Hammam, Mohamed M and Wood, David and Summerville, Brent}, + year={2023}, + institution={National Renewable Energy Laboratory (NREL), Golden, CO (United States)} +} diff --git a/docs/source/user/aerodyn/input.rst b/docs/source/user/aerodyn/input.rst index 3fe7ff7a38..c5d45a51f6 100644 --- a/docs/source/user/aerodyn/input.rst +++ b/docs/source/user/aerodyn/input.rst @@ -883,22 +883,26 @@ An example of tail fin input file is given below: 0 TFinIndMod - Model for induced velocity calculation {0: none, 1:rotor-average} (switch) ====== Polar-based model ================================ [used only when TFinMod=1] 1 TFinAFID - Index of Tail fin airfoil number [1 to NumAFfiles] - ====== Unsteady slender body model ===================== [used only when TFinMod=2] - [TODO inputs for model 2] + ====== Unsteady slender body model ===================== [used only when TFinMod=2] + 0.9 TFinKp - Tail fin moment of area about reference point + 0.3,0.1,0.1 TFinSigma - Tail fin empirical constant for vortex separation functions + 40,60,60 TFinAStar - Tail fin initial angles for vortex separation functions (deg) + 3.1416 TFinKv - Tail fin vortex lift coefficient + 1.3 TFinCDc - Tail fin drag coefficient General inputs ~~~~~~~~~~~~~~ -**TFinMod** Switch to select a model for the tail fin aerodynamics: +``TFinMod`` is a switch to select a model for the tail fin aerodynamics: 0) none (the aerodynamic forces are zero), 1) polar-based, 2) USB-based (see :numref:`TF-aerotheory`). (switch) -**TFinArea** Area of the tail fin. (m^2) +``TFinArea`` is the area of the tail fin. (m^2) This is the plan form area of the tail fin plate used to relate the local dynamic pressure and airfoil coefficients to aerodynamic loads. This value must not be negative and is only used when TFinMod is set to 1. (m^2) -**TFinRefP_n** Undeflected position (:math:`x_{\text{ref},x_n},x_{\text{ref},y_n}, x_{\text{ref},z_n}`) of the tail fin from the tower top in nacelle coordinates. +``TFinRefP_n`` is the undeflected position (:math:`x_{\text{ref},x_n},x_{\text{ref},y_n}, x_{\text{ref},z_n}`) of the tail fin from the tower top in nacelle coordinates. (formerly defined using ``TFinCPxn``, ``TFinCPyn``, ``TFinCPzn``). The distances defines the configuration for a furl angle of zero. For a typical upwind wind turbine, @@ -908,7 +912,7 @@ For a typical upwind wind turbine, See :numref:`figTFGeom` and :numref:`figTFcoord1`. (m) -**TFinAngles** Angles (:math:`\theta_\text{skew},\theta_\text{tilt}, \theta_\text{bank}`) of the tail fin +``TFinAngles`` are the angles (:math:`\theta_\text{skew},\theta_\text{tilt}, \theta_\text{bank}`) of the tail fin (formerly defined as ``TFinSkew``, ``TFinTilt``, ``TFinBank``). See :numref:`figTFGeom` and :numref:`figTFcoord1`. These angles define the chordline at a furl angle of zero, where the chordline is assumed to be passing through the reference point. @@ -925,7 +929,7 @@ This value must be greater than -180 and less than or equal to 180 degrees. -**TFinIndMod** +``TFinIndMod`` Switch to select a model for the calculation of the velocity induced by the rotor and its wake on the tailfin (not the induced velocity from the tailfin wing). The options available are: 0) none (the induced velocity is zero) @@ -936,7 +940,7 @@ The options available are: Polar-based model inputs ~~~~~~~~~~~~~~~~~~~~~~~~ -**TFinAFID** +``TFinAFID`` This integer tells AeroDyn which of the input airfoil files (``AFNames``) is assigned to the tail fin. For instance, a value of 2 means that the tail fin will use ``AFNames(2)`` for the local tail fin airfoil. This value must be @@ -945,7 +949,21 @@ between 1 and ``NumAFfiles`` and is only used when TFinMod is set to 1. (-) Unsteady slender body (USB) model inputs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Refer to :numref:`TF-aerotheory` and :cite:`ad-hammam_NREL:2023` for guidance on how to select parameters for the unsteady slender body theory based model. -This option is currently not available and will be documented in a future release. +``TFinKp`` +Potential lift coefficient for unsteady aerodynamics. ``TFinKp`` is used to calculate the potential flow contribution to the unsteady aerodynamic force on the tail fin. +``TFinSigma`` +Tail fin empirical constants characterizing the decay of separation functions used in the unsteady aerodynamic model. The separation functions and their dependence on ``TFinSigma`` are described in :numref:`TF-aerotheory`. + +``TFinAStar`` +Tail fin characteristics angles for separation functions used in the unsteady aerodynamic model. The separation functions and their dependence on ``TFinAStar`` are described in :numref:`TF-aerotheory`. + + +``TFinKv`` +Vortex lift coefficient for unsteady aerodynamics. ``TFinKv`` is used to calculate the vortex flow contribution to the unsteady aerodynamic force on the tail fin. + +``TFinCDc`` +Tail fin drag coefficient used for unsteady aerodynamic model. The drag on the tail fin significantly contributes to the normal force at high yaw angles. diff --git a/docs/source/user/aerodyn/theory_tailfin.rst b/docs/source/user/aerodyn/theory_tailfin.rst index 5c5a356a7e..0d18740aca 100644 --- a/docs/source/user/aerodyn/theory_tailfin.rst +++ b/docs/source/user/aerodyn/theory_tailfin.rst @@ -150,8 +150,6 @@ Where :math:`\boldsymbol{V}_{\text{ind},\text{blade}}[i_b, i_r]` is the induced More advanced models could set the induced velocity to zero when outside of the wake boundary, or include a tower-shadow-like wake model. Such option is not yet available. - - Polar-based model ----------------- @@ -163,9 +161,25 @@ The user only needs to indicate the index `TFinAFIndex` within the list `AFNames Unsteady slender body model --------------------------- -The unsteady slender body (USB) model is documented in :cite:`ad-hammam2022`. +The unsteady aerodynamics of the tail fin is modeled based on Unsteady Slender Body Theory. +The theory is extended to include the effect of high yaw angle :cite:`ad-hammam_NREL:2023`. + +The normal force on the tail fin can be described as the sum of three contributions (potential lift, vortex lift, and drag), weighted by separation functions :math:`x_i` as: + +.. math:: :label: TFUSBForce + + N = \frac{\rho}{2} A_{tf} \bigg( K_p x_1 V_{\text{rel},x} V_{\text{rel},y} + \Big[x_2 K_v+(1- x_3)C_{Dc} \Big] V_{\text{rel},y}\big|V_{\text{rel},y}\big|\bigg) + + +where :math:`\rho` is the density of air, :math:`A_{tf}` is the tail fin area, :math:`K_p` is the potential lift coefficient and :math:`K_v` is the vortex lift coefficient, and :math:`C_{Dc}` is the drag coefficient. +:math:`x_i` are the separation functions calculated using a quasi-steady approximation as: + +.. math:: :label: TFUSBxiEquation -The theory will be implemented and documented in a future release. + x_i = (1+exp{[\sigma_i (|\gamma_{tf}|-\alpha^*_i)]})^{-1} +where :math:`\sigma_i` are empirical constants characterizing the decay of separation functions, :math:`\gamma_{tf}` is the yaw angle of the tail fin with respect to the free-stream wind (:math:`V_{\text{wind}}`), :math:`\alpha^*_i` are the characteristics angles for separation functions. +:math:`x_i` takes on a value between 0 and 1, and are used to activate or deactivate a the contribution of potential lift, vortex lift and draft to the normal force on the tail fin. +The normal force is assumed to act at the user defined reference point on the tail fin and the moment of the normal force is calculated accordingly. diff --git a/docs/source/user/aerodyn/theory_ua.rst b/docs/source/user/aerodyn/theory_ua.rst index 005e478fdd..2a67b8fdd5 100644 --- a/docs/source/user/aerodyn/theory_ua.rst +++ b/docs/source/user/aerodyn/theory_ua.rst @@ -25,6 +25,12 @@ speed increases, but stall is delayed. + + + +.. _ua_theory: + + Theory ------ @@ -489,6 +495,12 @@ where :math:`\alpha_{50}` is computed the same way as :math:`\alpha_{34}` (using + + + + +.. _UA_inputs: + Inputs ------ @@ -503,6 +515,10 @@ An example of profile data (containing some of the unsteady aerodynamic paramete :download:`(here) `. +The unsteady aerodynamic driver inputs are documented in :numref:`ua_driver`. + + + .. _UA_AFI_defaults: Calculating Default Airfoil Coefficients @@ -579,17 +595,195 @@ to set preprocessor variable ``UA_OUTS`` and recompile the program (OpenFAST, Ae The outputs are written in output files with extension `*.UA.out`. To activate these outputs with `cmake`, compile using ``-DCMAKE_Fortran_FLAGS="-DUA_OUTS=ON"`` +When using the driver, there is no need to use this preprocessor variable. + +.. _ua_aeroelasttheory: + +Aeroelastic simulation of a 2D section +-------------------------------------- + +Aeroelastic simulations of an isolated 2D section are possible using the driver in order to use the unsteady aerodynamic model in a simplified context. +See :numref:`ua_driver`. +The theory and description for the aeroelastic simulation can be found in +:cite:`ad-UAElast:torquepaper`. + + + + +.. _ua_driver: + Driver ------ -A driver is available to run simulations for a single airfoil, using sinusoidal variation of the angle of attack, -or user defined time series of angle of attack, relative wind speed and pitch rate. + +A driver is available to run simulations for a single airfoil. + +Different kind of simulations are possible: + + - using sinusoidal variation of the angle of attack, + - user defined time series of angle of attack, relative wind speed and pitch rate. + - aero elastic simulations with 3 degrees of freedom for the elastic motion of the section in it's 2D plane (flap, edge and torsion), with possibility to prescribe time series of the wind speed, or prescribe the motion of the section. + +The theory and description for the aeroelastic simulation can be found in :cite:`ad-UAElast:torquepaper`. + + + + + +Compilation +~~~~~~~~~~~ Using `cmake`, the driver is compiled using `make unsteadyaero_driver`, resulting as an executable in the `aerodyn` folder. -An example of driver input file is available here: :download:`here <../aerodyn-dynamicStall/examples/UA-driver.dvr>`. -An example of time series input is available here: :download:`here <../aerodyn-dynamicStall/examples/UA-driver-timeseries.dat>` + +Driver Inputs +~~~~~~~~~~~~~ + +An example of input file for the unsteady aerodynamic driver can be found in the `r-test repository `__. + + +The differente inputs are described below. + + + +**Environmental conditions** + + +``FldDens``: Density of working fluid (kg/m^3) + +``KinVisc``: Kinematic viscosity of working fluid (m^2/s) + +``SpdSound``: Speed of sound of working fluid (m/s) + + +**Unsteady aerodynamics options** + +``UAMod`` : Unsteady Aero Model Switch (switch) {2=B-L Gonzalez, 3=B-L Minnema/Pierce, 4=B-L HGM 4-states, 5=B-L 5 states, 6=Oye, 7=Boeing-Vertol} [used only when AFAeroMod=2] + +``FLookup`` : Flag to indicate whether a lookup for f' will be calculated (TRUE) or whether best-fit exponential equations will be used (FALSE); if FALSE S1-S4 must be provided in airfoil input files (flag) [used only when AFAeroMod=2] + + +**Airfoil properties** + +``AirFoil``: Airfoil table (Column 1: Angle of Attack (AoA), column 2: Lift coeff, column 3: Drag coeff). + +``Chord`` : Chord length (m) + +``Vec_AQ`` : Vector from reference point "A" to aerodynamic center (~quarter chord) "Q" in airfoil coordinates and in chord length. If "A" is at mid chord values are likely (0, -0.25) (-) + +``Vec_AT`` : Vector from reference point "A" to three-quarter chord point "T" in airfoil coordinates and in chord length. If "A" is at mid chord values are likely (0, 0.25) (-) + +``UseCm`` : Use Cm (moment coefficient) data in airfoil table {true/false} + + +**Simulation control** + +``SimMod``: Simulation model {1=reduced frequency model, 2=prescribed-aero time series, 3=elastic cross section} + + +**Reduced-frequency simulation** (``SimMod=1``) + +``InflowVel`` : Inflow velocity (m/s) + +``NCycles`` : Number of angle-of-attack oscillations over the length of the simulation (-) + +``StepsPerCycle`` : Number of timesteps per cycle (-) + +``Frequency`` : Frequency for the airfoil oscillations (Hz) + +``Amplitude`` : Amplitude of the angle of attack oscillations (deg) + +``Mean`` : Cycle mean (deg) + +``Phase`` : Initial phase (num steps). + + +**Prescribed aerodynamic simulation inputs** (``SimMod=2``) + +``TMax_PA`` : Total run time (s) + +``DT_PA`` : Recommended module time step (s) + +``AeroTSFile``: Time series data in delimited input file (e.g. csv) with 1 header line, 4 columns: Time (s), angle-of-attack (deg), InflowVel (m/s), Pitch rate (rad/s) + + +**Aeroelastic simulation** (``SimMod=3``) + +The theory for the aeroelastic simulation can be found in :numref:`ua_aeroelasttheory`. + +``TMax`` : Total run time (s) + +``DT`` : Time step (s). + +``ActiveDOF`` : List of Degrees of freedom that are active (true or false) + +``InitPos`` : List of initial positions for the elastic degrees of freedom (m, m and rad) + +``InitVel`` : List of initial velocities for the elastic degrees of freedom (m/s, m/s, and rad/s) + +``GFScalingL1`` : Generalized force scaling factors to convert from section loads to generalized loads (3x3). Three values per line. + +``MassMatrixL1`` : Mass matrix (3x3). Three values per line. + +``DampMatrixL1`` : Damping matrix (3x3). Three values per line. + +``StifMatrixL1`` : Stiffness matrix (3x3). Three values per line. + +``Twist`` : Fixed twist of the section when torsion degree of freedom is zero (deg) + +``InflowMod`` : Model for the inflow velocity. {1: constant velocity, 2: time series} + +``Inflow`` : Inflow velocity in x and y direction [used only when InflowMod=1] + +``InflowTSFile`` : Input file for inflow velocity. Delimited file (e.g. csv) with one header line, three columns: Time (s), Ux (m/s), Uy (m/s). [used only when InflowMod=2] + +``MotionMod`` : Model for the motion of the degrees of freedom {1: dynamic, 2: prescribed} + +``MotionTSFile`` : Input file for prescribed motion. Delimited file (e.g. csv) with one header line, 10 columns: Time (s), x (m), y (m), th (rad), velocities, and accelerations. [used only when InflowMod=2] + + +**Output control** + +``SumPrint`` : Write unsteady aerodynamics summary file (flag) + +``WrAFITables`` : Write back the aerodynamic coefficients used internally (flag) + + +**Example CSV input files** + +The unsteady aerodyn driver now relies on CSV files for it's input time series. +The time column does not need to be at a constant time step, but needs to be monotonously increasing. + +Prescribed aero input (``SimMod=2``): + +.. code: + + Time_[s] , Alpha_[deg] , VRel_[m/s] , omega_[rad/s] + 0.0 , 0 , 10 , 0 + 0.01 , 0 , 10 , 0 + + +Inflow file input (``SimMod=3``, ``InflowMod=2``): + +.. code: + + Time_[s] , Ux_[m/s], Uy_[m/s] + 0.0 , 1 , 10 + 1.0 , 2 , 10 + 5.0 , 2 , 8 + 10.0 , 1 , 12 + + +Motion file input (``SimMod=3``, ``MotionMod=2``) (note in this dummy exmaple velocities and accelerations are not provided, but preferably they should be): + +.. code: + + Time_[s] , x_[m] , y_[m] , th_[rad] , xd_[m/s] , yd_[m/s] , thd_[rad/s] , xdd_[m/s^2] , ydd_[m/s^2] , thdd_[rad/s^2] + 0.0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 + 1.0 , 2 , 2 , 2 , 0 , 0 , 0 , 0 , 0 , 0 + 5.0 , 2 , 2 , 2 , 0 , 0 , 0 , 0 , 0 , 0 + 10.0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 diff --git a/docs/source/user/api_change.rst b/docs/source/user/api_change.rst index e91760a11c..5cf14c37a2 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -10,7 +10,7 @@ The line number corresponds to the resulting line number after all changes are i Thus, be sure to implement each in order so that subsequent line numbers are correct. -OpenFAST v3.5.2 to OpenFAST dev +OpenFAST v3.5.3 to OpenFAST dev ---------------------------------- The HydroDyn module was split into HydroDyn and SeaState. This results in a @@ -33,6 +33,12 @@ SubDyn 59\* \*Exact line number depends on number of entries in various preceeding tables. +OpenFAST v3.5.2 to OpenFAST v3.5.3 +---------------------------------- + +No input file changes were made. + + OpenFAST v3.5.1 to OpenFAST v3.5.2 ---------------------------------- diff --git a/docs/source/user/elastodyn/bibliography.bib b/docs/source/user/elastodyn/bibliography.bib new file mode 100644 index 0000000000..e6c7d35319 --- /dev/null +++ b/docs/source/user/elastodyn/bibliography.bib @@ -0,0 +1,6 @@ +@techreport{ed-hammam2023, + title={Modeling the Yaw Behavior of Tail Fins for Small Wind Turbines: November 22, 2021-May 21, 2024}, + author={Hammam, Mohamed M and Wood, David and Summerville, Brent}, + year={2023}, + institution={National Renewable Energy Laboratory (NREL), Golden, CO (United States)} +} diff --git a/docs/source/user/elastodyn/figs/YawFrictionModel.jpg b/docs/source/user/elastodyn/figs/YawFrictionModel.jpg new file mode 100644 index 0000000000..aa39021ee7 Binary files /dev/null and b/docs/source/user/elastodyn/figs/YawFrictionModel.jpg differ diff --git a/docs/source/user/elastodyn/index.rst b/docs/source/user/elastodyn/index.rst index c95aecd402..6b65d36e8e 100644 --- a/docs/source/user/elastodyn/index.rst +++ b/docs/source/user/elastodyn/index.rst @@ -58,3 +58,4 @@ equations of FAST v7 and the ElastoDyn module of FAST v8 and OpenFAST. coordsys.rst input.rst theory.rst + zrefs.rst diff --git a/docs/source/user/elastodyn/input.rst b/docs/source/user/elastodyn/input.rst index 97d1651845..a9f2fec2de 100644 --- a/docs/source/user/elastodyn/input.rst +++ b/docs/source/user/elastodyn/input.rst @@ -231,6 +231,17 @@ Rotor-Teeter **TeetHSSp** - Rotor-teeter hard-stop linear-spring constant (N-m/rad) [used only for 2 blades and when TeetMod=1] +Yaw-Friction +~~~~~~~~~~~~ + +**YawFrctMod** - Yaw-friction model {0: none, 1: friction without Fz term at the yaw bearing, 2: friction includes Fz term at yaw bearing, 3: user defined model} + +**M_CSmax** - Maximum Coulomb friction torque (N-m)[mu_s*D_eff when YawFrctMod=1 and Fz*mu_s*D_eff when YawFrctMod=2] + +**M_CD** - Dynamic friction moment at null yaw rate (N-m) [mu_d*D_eff when YawFrctMod=1 and Fz*mu_d*D_eff when YawFrctMod=2] + +**sig_v** - Viscous friction coefficient (N-m/(rad/s)) + Drivetrain ~~~~~~~~~~ diff --git a/docs/source/user/elastodyn/theory.rst b/docs/source/user/elastodyn/theory.rst index f687277333..3474835f05 100644 --- a/docs/source/user/elastodyn/theory.rst +++ b/docs/source/user/elastodyn/theory.rst @@ -159,7 +159,41 @@ The total moment on the given degree of freedom is: +.. _ed_yawfriction_theory: +Yaw-friction +------------ +A yaw-friction model is implemented in ElastoDyn based on a Coulomb-viscous approach. +The yaw-friction moment as a function of yaw rate (:math:`\omega`) is shown below in :numref:`figYawFriction` + +.. _figYawFriction: +.. figure:: figs/YawFrictionModel.jpg + :width: 60% + + Yaw-friction model + +The yaw-friction torque :math:`M_f` can be calcualated as follows. + +if :math:`\omega\neq0`: + +.. math:: + M_f = \mu_d\bar{D}\times\text{min}(0,F_z)\times\text{sign}(\omega) - \sigma_v\times\omega + +if :math:`\omega=0` and :math:`\dot{\omega}\neq 0`: + +.. math:: + M_f = \mu_d\bar{D}\times\text{min}(0,F_z)\times\text{sign}(\dot{\omega}) + +if :math:`\omega=0` and :math:`\dot{\omega}=0`: + +.. math:: + M_f = -\text{min}(\mu_s\bar{D}\times|\text{min}(0,F_z)|,|M_z|)\times\text{sign}(M_z) + + +where :math:`\bar{D}` is the effective yaw-bearing race diameter, :math:`\mu_d` is the dynamic friction coefficient, :math:`\mu_s` is the static friction coefficient, :math:`F_z` is effective axial load on yaw-bearing, :math:`M-z` is the external torque on yaw-bearing. +The static 'stiction' (where the static contribution exceeds the dynamic Coulomb friction) is only applied if both the yaw rotational velocity and acceleration at the current time-step are zero. +The static portion of the friction is omitted if the rotational acceleration is not null, (sign(0) is taken as 1). +This is to account for the fact that a 'warm' joint may not feel stiction when crossing through zero velocity in a dynamic sense :cite:`ed-hammam2023` .. _ed_dev_notes: diff --git a/docs/source/user/elastodyn/zrefs.rst b/docs/source/user/elastodyn/zrefs.rst new file mode 100644 index 0000000000..afb6844d57 --- /dev/null +++ b/docs/source/user/elastodyn/zrefs.rst @@ -0,0 +1,9 @@ +.. only:: html + + References + ---------- + +.. bibliography:: bibliography.bib + :labelprefix: ed- + + diff --git a/docs/source/user/subdyn/appendixD.rst b/docs/source/user/subdyn/appendixD.rst index e2bcbab592..3cf6bcef2c 100644 --- a/docs/source/user/subdyn/appendixD.rst +++ b/docs/source/user/subdyn/appendixD.rst @@ -7,7 +7,7 @@ This is a list of all possible output parameters for the SubDyn module. The names are grouped by meaning, but can be ordered in the OUTPUT CHANNELS section of the SubDyn input file as the user sees fit. :math:`M \alpha N \beta`, refers to node :math:`\beta` of member :math:`\alpha`, where :math:`\alpha` is a number in the range [1,9] and -corresponds to row :math:`\alpha` in the MEMBER OUTPUT LIST table (see Section ) and +corresponds to row :math:`\alpha` in the MEMBER OUTPUT LIST table (see :numref:`SD_Member_Output`) and :math:`\beta` is a number in the range [1,9] and corresponds to node :math:`\beta` in the **NodeCnt** list of that table entry. diff --git a/glue-codes/fast-farm/src/FASTWrapper.f90 b/glue-codes/fast-farm/src/FASTWrapper.f90 index e7a4cd176d..6bf777fcae 100644 --- a/glue-codes/fast-farm/src/FASTWrapper.f90 +++ b/glue-codes/fast-farm/src/FASTWrapper.f90 @@ -139,7 +139,7 @@ SUBROUTINE FWrap_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init end if !.... multi-turbine options .... - ExternInitData%TurbineID = InitInp%TurbNum + ExternInitData%TurbIDforName = InitInp%TurbNum ExternInitData%TurbinePos = InitInp%p_ref_Turbine ExternInitData%WaveFieldMod = InitInp%WaveFieldMod diff --git a/glue-codes/simulink/CMakeLists.txt b/glue-codes/simulink/CMakeLists.txt index b2b495ec40..736d4553b0 100644 --- a/glue-codes/simulink/CMakeLists.txt +++ b/glue-codes/simulink/CMakeLists.txt @@ -19,6 +19,7 @@ set(MEX_LIBS $ $ + $ $ $ $ diff --git a/modules/aerodyn/CMakeLists.txt b/modules/aerodyn/CMakeLists.txt index 7d5f9e4f03..859dd1e155 100644 --- a/modules/aerodyn/CMakeLists.txt +++ b/modules/aerodyn/CMakeLists.txt @@ -26,6 +26,18 @@ if (GENERATE_TYPES) generate_f90_types(src/FVW_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/FVW_Types.f90) endif() +# BasicAero Library +add_library(basicaerolib STATIC + # UnsteadyAero lib + src/UnsteadyAero.f90 + src/UnsteadyAero_Types.f90 + + # AirFoil Info lib + src/AirfoilInfo.f90 + src/AirfoilInfo_Types.f90 +) +target_link_libraries(basicaerolib ifwlib nwtclibs) + # AeroDyn Library add_library(aerodynlib STATIC src/AeroDyn.f90 @@ -46,14 +58,6 @@ add_library(aerodynlib STATIC src/AeroAcoustics_IO.f90 src/AeroAcoustics_Types.f90 - # UnsteadyAero lib - src/UnsteadyAero.f90 - src/UnsteadyAero_Types.f90 - - # AirFoil Info lib - src/AirfoilInfo.f90 - src/AirfoilInfo_Types.f90 - # FVW lib src/FVW.f90 src/FVW_IO.f90 @@ -63,19 +67,22 @@ add_library(aerodynlib STATIC src/FVW_BiotSavart.f90 src/FVW_Tests.f90 src/FVW_Types.f90 +) +target_link_libraries(aerodynlib basicaerolib nwtclibs) - # ADI lib +# ADI lib +add_library(adilib STATIC src/AeroDyn_Inflow.f90 src/AeroDyn_Inflow_Types.f90 ) -target_link_libraries(aerodynlib ifwlib nwtclibs) +target_link_libraries(adilib aerodynlib ifwlib) # AeroDyn Driver Subs Library add_library(aerodyn_driver_subs STATIC src/AeroDyn_Driver_Subs.f90 src/AeroDyn_Driver_Types.f90 ) -target_link_libraries(aerodyn_driver_subs aerodynlib versioninfolib) +target_link_libraries(aerodyn_driver_subs adilib aerodynlib versioninfolib) # AeroDyn Driver add_executable(aerodyn_driver @@ -88,18 +95,18 @@ add_executable(unsteadyaero_driver src/UnsteadyAero_Driver.f90 src/UA_Dvr_Subs.f90 ) -target_link_libraries(unsteadyaero_driver aerodyn_driver_subs) +target_link_libraries(unsteadyaero_driver basicaerolib lindynlib versioninfolib) # AeroDyn-InflowWind c-bindings interface library add_library(aerodyn_inflow_c_binding SHARED src/AeroDyn_Inflow_C_Binding.f90 ) -target_link_libraries(aerodyn_inflow_c_binding aerodyn_driver_subs versioninfolib) +target_link_libraries(aerodyn_inflow_c_binding adilib aerodyn_driver_subs versioninfolib) if(APPLE OR UNIX) target_compile_definitions(aerodyn_inflow_c_binding PRIVATE IMPLICIT_DLLEXPORT) endif() -install(TARGETS aerodynlib aerodyn_driver_subs aerodyn_driver unsteadyaero_driver aerodyn_inflow_c_binding +install(TARGETS aerodynlib basicaerolib aerodyn_driver_subs aerodyn_driver unsteadyaero_driver aerodyn_inflow_c_binding adilib EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index 9539ddff68..add1bcf5ac 100644 --- a/modules/aerodyn/python-lib/aerodyn_inflow_library.py +++ b/modules/aerodyn/python-lib/aerodyn_inflow_library.py @@ -33,7 +33,7 @@ c_byte, c_int, c_double, - c_float, + c_float, c_char, c_char_p, c_wchar, @@ -98,7 +98,7 @@ def __init__(self, library_path): self.WtrDpth = 0.0 # Water depth (m) self.MSL2SWL = 0.0 # Offset between still-water level and mean sea level (m) [positive upward] - # flags + # flags self.storeHHVel = 1 # 0=false, 1=true self.transposeDCM= 1 # 0=false, 1=true self.debuglevel = 0 # 0-4 levels @@ -149,6 +149,7 @@ def __init__(self, library_path): self.numMeshPts = 1 self.initMeshPos = np.zeros(shape=(self.numMeshPts,3),dtype=c_float ) # Nx3 array [x,y,z] self.initMeshOrient = np.zeros(shape=(self.numMeshPts,9),dtype=c_double) # Nx9 array [r11,r12,r13,r21,r22,r23,r31,r32,r33] + self.meshPtToBladeNum = np.zeros(shape=(self.numMeshPts),dtype=c_int) # Nx1 array [blade number] # OutRootName # If HD writes a file (echo, summary, or other), use this for the @@ -161,11 +162,11 @@ def _initialize_routines(self): self.ADI_C_PreInit.argtypes = [ POINTER(c_int), # numTurbines POINTER(c_int), # transposeDCM - POINTER(c_int), # debuglevel + POINTER(c_int), # debuglevel POINTER(c_int), # ErrStat_C POINTER(c_char) # ErrMsg_C ] - self.ADI_C_PreInit.restype = c_int + self.ADI_C_PreInit.restype = c_int # setup one rotor self.ADI_C_SetupRotor.argtypes = [ @@ -182,6 +183,7 @@ def _initialize_routines(self): POINTER(c_int), # numMeshPts POINTER(c_float), # initMeshPos_flat POINTER(c_double), # initMeshOrient_flat + POINTER(c_int), # meshPtToBladeNum POINTER(c_int), # ErrStat_C POINTER(c_char) # ErrMsg_C ] @@ -194,7 +196,7 @@ def _initialize_routines(self): POINTER(c_int), # IfW input file passed as string POINTER(c_char_p), # IfW input file as string POINTER(c_int), # IfW input file string length - POINTER(c_char), # OutRootName + POINTER(c_char), # OutRootName POINTER(c_float), # gravity POINTER(c_float), # defFldDens POINTER(c_float), # defKinVisc @@ -203,9 +205,9 @@ def _initialize_routines(self): POINTER(c_float), # defPvap POINTER(c_float), # WtrDpth POINTER(c_float), # MSL2SWL - POINTER(c_int), # InterpOrder + POINTER(c_int), # InterpOrder POINTER(c_double), # dt - POINTER(c_double), # tmax + POINTER(c_double), # tmax POINTER(c_int), # storeHHVel POINTER(c_int), # WrVTK POINTER(c_int), # WrVTK_Type @@ -219,16 +221,16 @@ def _initialize_routines(self): POINTER(c_int), # ErrStat_C POINTER(c_char) # ErrMsg_C ] - self.ADI_C_Init.restype = c_int + self.ADI_C_Init.restype = c_int #self.ADI_C_ReInit.argtypes = [ - # POINTER(c_double), # t_initial + # POINTER(c_double), # t_initial # POINTER(c_double), # dt - # POINTER(c_double), # tmax + # POINTER(c_double), # tmax # POINTER(c_int), # ErrStat_C # POINTER(c_char) # ErrMsg_C #] - #self.ADI_C_ReInit.restype = c_int + #self.ADI_C_ReInit.restype = c_int self.ADI_C_SetRotorMotion.argtypes = [ POINTER(c_int), # iturb @@ -322,6 +324,7 @@ def adi_setuprotor(self,iturb,isHAWT,turbRefPos): initRootOrient_flat_c = self.flatOrientArr(self._initNumBlades, self.numBlades,self.initRootOrient, 'RootOrient') initMeshPos_flat_c = self.flatPosArr( self._initNumMeshPts,self.numMeshPts,self.initMeshPos, 'MeshPos') initMeshOrient_flat_c = self.flatOrientArr(self._initNumMeshPts,self.numMeshPts,self.initMeshOrient,'MeshOrient') + initMeshPtToBladeNum_flat_c = (c_int * len(self.meshPtToBladeNum))(*self.meshPtToBladeNum) self.ADI_C_SetupRotor( c_int(iturb), # IN: iturb -- current turbine number @@ -337,6 +340,7 @@ def adi_setuprotor(self,iturb,isHAWT,turbRefPos): byref(c_int(self.numMeshPts)), # IN: number of mesh points expected initMeshPos_flat_c, # IN: initMeshPos -- initial node positions in flat array of 3*numMeshPts initMeshOrient_flat_c, # IN: initMeshOrient -- initial node orientation DCMs in flat array of 9*numMeshPts + initMeshPtToBladeNum_flat_c, # IN: initMeshPtToBladeNum -- initial mesh point to blade number mapping byref(self.error_status_c), # OUT: ErrStat_C self.error_message_c # OUT: ErrMsg_C ) @@ -402,7 +406,7 @@ def adi_init(self, AD_input_string_array, IfW_input_string_array): ) self.check_error() - + # Initialize output channels self.numChannels = self._numChannels_c.value @@ -497,7 +501,7 @@ def adi_getrotorloads(self, iturb, meshFrcMom): ) self.check_error() - + ## Reshape Force/Moment into [N,6] count = 0 for j in range(0,self.numMeshPts): @@ -518,7 +522,7 @@ def adi_calcOutput(self, time, outputChannelValues): # Run ADI_C_CalcOutput self.ADI_C_CalcOutput( - byref(c_double(time)), # IN: time at which to calculate output forces + byref(c_double(time)), # IN: time at which to calculate output forces outputChannelValues_c, # OUT: output channel values as described in input file byref(self.error_status_c), # OUT: ErrStat_C self.error_message_c # OUT: ErrMsg_C @@ -535,7 +539,7 @@ def adi_updateStates(self, time, timeNext): # Run AeroDyn_Inflow_UpdateStates_c self.ADI_C_UpdateStates( - byref(c_double(time)), # IN: time at which to calculate output forces + byref(c_double(time)), # IN: time at which to calculate output forces byref(c_double(timeNext)), # IN: time T+dt we are stepping to byref(self.error_status_c), # OUT: ErrStat_C self.error_message_c # OUT: ErrMsg_C @@ -662,7 +666,7 @@ def check_init_hubroot(self): print("Expecting a 9 element array for initNacelleOrient DCM [r11,r12,r13,r21,r22,r23,r31,r32,r33]") self.adi_end() raise Exception("\nAeroDyn terminated prematurely.") - + def check_init_mesh(self): #print("shape of initMeshPos ", self.initMeshPos.shape) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 84667523ba..bd8405a3ad 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -227,8 +227,9 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! Local variables - integer(IntKi) :: i ! loop counter + integer(IntKi) :: i,k ! loop counter integer(IntKi) :: iR ! loop on rotors + integer(IntKi) :: nNodesVelRot ! number of nodes associated with the rotor that need wind velocity (for CFD coupling) integer(IntKi) :: errStat2 ! temporary error status of the operation character(ErrMsgLen) :: errMsg2 ! temporary error message @@ -393,6 +394,11 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut p%rotors(iR)%TFin%TFinArea = InputFileData%rotors(iR)%TFin%TFinArea p%rotors(iR)%TFin%TFinIndMod = InputFileData%rotors(iR)%TFin%TFinIndMod p%rotors(iR)%TFin%TFinAFID = InputFileData%rotors(iR)%TFin%TFinAFID + p%rotors(iR)%TFin%TFinKp = InputFileData%rotors(iR)%TFin%TFinKp + p%rotors(iR)%TFin%TFinSigma = InputFileData%rotors(iR)%TFin%TFinSigma + p%rotors(iR)%TFin%TFinAStar = InputFileData%rotors(iR)%TFin%TFinAStar + p%rotors(iR)%TFin%TFinKv = InputFileData%rotors(iR)%TFin%TFinKv + p%rotors(iR)%TFin%TFinCDc = InputFileData%rotors(iR)%TFin%TFinCDc enddo @@ -519,6 +525,18 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut end do end if + ! number of nodes velocity is required at (for coupling to cfd) + InitOut%nNodesVel = 0 + do iR = 1, nRotors + if (u%rotors(iR)%HubMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%HubMotion%nNodes + do k = 1,size(u%rotors(iR)%BladeMotion) + if (u%rotors(iR)%BladeMotion(k)%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%BladeMotion(k)%nNodes + enddo + if (u%rotors(iR)%TowerMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%TowerMotion%nNodes + if (u%rotors(iR)%NacelleMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%NacelleMotion%nNodes + if (u%rotors(iR)%TFinMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%TFinMotion%nNodes + enddo + !............................................................................................ ! Initialize Jacobian: !............................................................................................ @@ -3016,7 +3034,7 @@ subroutine SetInputsForBEMT(p, u, RotInflow, m, indx, errStat, errMsg) !.......................... do k=1,p%NumBlades do j=1,p%NumBlNds - ! Velocity in "p" or "w" system (depending) on AeroProjMod + ! Velocity in "l" or "w" system (depending) on AeroProjMod tmp = m%DisturbedInflow(:,j,k) - u%BladeMotion(k)%TranslationVel(:,j) ! rel_V(j)_Blade(k) m%BEMT_u(indx)%Vx(j,k) = dot_product( tmp, m%orientationAnnulus(1,:,j,k) ) ! normal component (normal to the plane, not chord) of the inflow velocity of the jth node in the kth blade m%BEMT_u(indx)%Vy(j,k) = dot_product( tmp, m%orientationAnnulus(2,:,j,k) ) !+ TwoNorm(m%DisturbedInflow(:,j,k))*(sin()*sin(tilt)*)! tangential component (tangential to the plane, not chord) of the inflow velocity of the jth node in the kth blade @@ -3035,6 +3053,7 @@ subroutine SetInputsForBEMT(p, u, RotInflow, m, indx, errStat, errMsg) do k=1,p%NumBlades do j=1,p%NumBlNds ! inputs for CUA (and CDBEMT): + ! TODO Here we should take the rotation in the airfoil coordinate system instead of the "l" or "w" system m%BEMT_u(indx)%omega_z(j,k) = dot_product( u%BladeMotion(k)%RotationVel( :,j), m%orientationAnnulus(3,:,j,k) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade end do !j=nodes @@ -4563,9 +4582,12 @@ SUBROUTINE TFin_CalcOutput(p, p_AD, u, RotInflow, m, y, ErrStat, ErrMsg ) real(ReKi) :: V_wnd(3) ! wind velocity real(ReKi) :: V_ind(3) ! induced velocity real(ReKi) :: V_str(3) ! structural velocity + real(ReKi) :: V_wnd_tf(3) ! wind velocity real(ReKi) :: force_tf(3) ! force in tf system real(ReKi) :: moment_tf(3) ! moment in tf system real(ReKi) :: alpha, Re, Cx, Cy, q ! Cl, Cd, Cm, + real(ReKi) :: x1, x2, x3,gamma_tf! scaling functions, gamma for unsteady modeling + type(AFI_OutputType) :: AFI_interp ! Resulting values from lookup table integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 @@ -4581,24 +4603,33 @@ SUBROUTINE TFin_CalcOutput(p, p_AD, u, RotInflow, m, y, ErrStat, ErrMsg ) if (p%TFin%TFinIndMod==TFinIndMod_none) then V_ind = 0.0_ReKi + elseif(p%TFin%TFinIndMod==TFinIndMod_rotavg) then ! TODO TODO print*,'TODO TailFin: compute rotor average induced velocity' V_ind = 0.0_ReKi + else - STOP ! Will never happen + call setErrStat(ErrID_Fatal, 'TailFin model unsupported', ErrStat, ErrMsg, 'TFin_CalcOutput') + endif - V_rel = V_wnd - V_str + V_ind + + V_rel = V_wnd - V_str + V_ind ! relative wind on tail fin V_rel_tf = matmul(u%TFinMotion%Orientation(:,:,1), V_rel) ! from inertial to tf system - alpha = atan2( V_rel_tf(2), V_rel_tf(1)) ! angle of attack + alpha = atan2(V_rel_tf(2), V_rel_tf(1)) ! angle of attack + v_wnd_tf = matmul(u%TFinMotion%Orientation(:,:,1), V_wnd) ! only used for calculation of x1,x2,x3 + gamma_tf = atan2(v_wnd_tf(2), v_wnd_tf(1)) ! only used for calculation of x1,x2,x3 V_rel_orth2 = V_rel_tf(1)**2 + V_rel_tf(2)**2 ! square norm of Vrel in tf system + ! Initialize the tail fin forces to zero + force_tf(:) = 0.0_ReKi + moment_tf(:) = 0.0_ReKi + if (p%TFin%TFinMod==TFinAero_none) then - y%TFinLoad%Force(1:3,1) = 0.0_ReKi - y%TFinLoad%Moment(1:3,1) = 0.0_ReKi + ! Do nothing elseif (p%TFin%TFinMod==TFinAero_polar) then - ! Airfoil coefficients + ! Airfoil coefficients based model Re = sqrt(V_rel_orth2) * p%TFin%TFinChord/p%KinVisc call AFI_ComputeAirfoilCoefs( alpha, Re, 0.0_ReKi, p_AD%AFI(p%TFin%TFinAFID), AFI_interp, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -4606,21 +4637,28 @@ SUBROUTINE TFin_CalcOutput(p, p_AD, u, RotInflow, m, y, ErrStat, ErrMsg ) Cy = AFI_interp%Cl * cos(alpha) + AFI_interp%Cd * sin(alpha) ! Forces in tailfin system q = 0.5 * p%airDens * V_rel_orth2 * p%TFin%TFinArea - force_tf(:) = 0.0_ReKi - moment_tf(:) = 0.0_ReKi + force_tf(1) = Cx * q 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 - ! Transfer to global - y%TFinLoad%Force(1:3,1) = matmul(transpose(u%TFinMotion%Orientation(:,:,1)), force_tf) - y%TFinLoad%Moment(1:3,1) = matmul(transpose(u%TFinMotion%Orientation(:,:,1)), moment_tf) elseif (p%TFin%TFinMod==TFinAero_USB) then - call SetErrStat(ErrID_Fatal, 'Tail fin USB model not yet available', ErrStat, ErrMsg, RoutineName ) - return + ! Unsteady aerodynamic model + + ! Calculate separation function (quasi-steady) + x1 = 1.0_Reki/(1.0_Reki+exp(p%TFin%TFinSigma(1)*((ABS(gamma_tf)*180.0_ReKi/pi)-p%TFin%TFinAStar(1)))) + x2 = 1.0_Reki/(1.0_Reki+exp(p%TFin%TFinSigma(2)*((ABS(gamma_tf)*180.0_ReKi/pi)-p%TFin%TFinAStar(2)))) + x3 = 1.0_Reki/(1.0_Reki+exp(p%TFin%TFinSigma(3)*((ABS(gamma_tf)*180.0_ReKi/pi)-p%TFin%TFinAStar(3)))) + + ! Calculate unsteady force on tail fin + force_tf(2) = 0.5_ReKi * p%AirDens * p%TFin%TFinArea * & + (p%TFin%TFinKp * x1 * V_rel_tf(1) * V_rel_tf(2) + & + (x2 * p%TFin%TFinKv + (1-x3)*p%TFin%TFinCDc) * V_rel_tf(2) * ABS(V_rel_tf(2))) endif + + ! Transfer to global + y%TFinLoad%Force(1:3,1) = matmul(transpose(u%TFinMotion%Orientation(:,:,1)), force_tf) + y%TFinLoad%Moment(1:3,1) = matmul(transpose(u%TFinMotion%Orientation(:,:,1)), moment_tf) ! --- Store m%TFinAlpha = alpha @@ -4634,6 +4672,7 @@ SUBROUTINE TFin_CalcOutput(p, p_AD, u, RotInflow, m, y, ErrStat, ErrMsg ) m%TFinM_i = y%TFinLoad%Moment(1:3,1) END SUBROUTINE TFin_CalcOutput + !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine calculates the tower loads for the AeroDyn TowerLoad output mesh. SUBROUTINE ADTwr_CalcOutput(p, u, RotInflow, m, y, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index 2adecbb579..261a9ce0cc 100644 --- a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 @@ -302,7 +302,7 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, RotI 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 + if (p_AD%WakeMod == WakeMod_FVW) W2B => p_AD%FVW%Bld2Wings(iRot, :) ! From Wing index to blade index ! Initialize some things ErrMsg = '' diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 40d4b71039..39f451791b 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -1689,120 +1689,6 @@ subroutine Dvr_WriteOutputs(nt, t, dvr, out, yADI, errStat, errMsg) endif enddo end subroutine Dvr_WriteOutputs - -!---------------------------------------------------------------------------------------------------------------------------------- -!> Read a delimited file with one line of header -subroutine ReadDelimFile(Filename, nCol, Array, errStat, errMsg, nHeaderLines, priPath) - character(len=*), intent(in) :: Filename - integer, intent(in) :: nCol - real(ReKi), dimension(:,:), allocatable, intent(out) :: Array - integer(IntKi) , intent(out) :: errStat ! Status of error message - character(*) , intent(out) :: errMsg ! Error message if errStat /= ErrID_None - integer(IntKi), optional, intent(in ) :: nHeaderLines - character(*) , optional, intent(in ) :: priPath ! Primary path, to use if filename is not absolute - integer :: UnIn, i, j, nLine, nHead - character(len= 2048) :: line - integer(IntKi) :: errStat2 ! local status of error message - character(ErrMsgLen) :: errMsg2 ! temporary Error message - character(len=2048) :: Filename_Loc ! filename local to this function - errStat = ErrID_None - errMsg = "" - - Filename_Loc = Filename - if (present(priPath)) then - if (PathIsRelative(Filename_Loc)) Filename_Loc = trim(PriPath)//trim(Filename) - endif - - ! Open file - call GetNewUnit(UnIn) - call OpenFInpFile(UnIn, Filename_Loc, errStat2, errMsg2); if(Failed()) return - ! Count number of lines - nLine = line_count(UnIn) - allocate(Array(nLine-1, nCol), stat=errStat2); errMsg2='allocation failed'; if(Failed())return - ! Read header - nHead=1 - if (present(nHeaderLines)) nHead = nHeaderLines - do i=1,nHead - read(UnIn, *, IOSTAT=errStat2) line - errMsg2 = ' Error reading line '//trim(Num2LStr(1))//' of file: '//trim(Filename_Loc) - if(Failed()) return - enddo - ! Read data - do I = 1,nLine-1 - read (UnIn,*,IOSTAT=errStat2) (Array(I,J), J=1,nCol) - errMsg2 = ' Error reading line '//trim(Num2LStr(I+1))//' of file: '//trim(Filename_Loc) - if(Failed()) return - end do - close(UnIn) -contains - logical function Failed() - CALL SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile' ) - Failed = errStat >= AbortErrLev - if (Failed) then - if ((UnIn)>0) close(UnIn) - endif - end function Failed -end subroutine ReadDelimFile - -!---------------------------------------------------------------------------------------------------------------------------------- -!> Counts number of lines in a file -integer function line_count(iunit) - integer, intent(in) :: iunit - character(len=2048) :: line - ! safety for infinite loop.. - integer :: i - integer, parameter :: nline_max=100000000 ! 100 M - line_count=0 - do i=1,nline_max - line='' - read(iunit,'(A)',END=100)line - line_count=line_count+1 - enddo - if (line_count==nline_max) then - print*,'Error: maximum number of line exceeded for line_count' - STOP - endif -100 if(len(trim(line))>0) then - line_count=line_count+1 - endif - rewind(iunit) - return -end function - -!---------------------------------------------------------------------------------------------------------------------------------- -!> Perform linear interpolation of an array, where first column is assumed to be ascending time values -!! First value is used for times before, and last value is used for time beyond -subroutine interpTimeValue(array, time, iLast, values) - real(ReKi), dimension(:,:), intent(in) :: array !< vector of time steps - real(DbKi), intent(in) :: time !< time - integer, intent(inout) :: iLast - real(ReKi), dimension(:), intent(out) :: values !< vector of values at given time - integer :: i - real(ReKi) :: alpha - if (array(iLast,1)> time) then - values = array(iLast,2:) - elseif (iLast == size(array,1)) then - values = array(iLast,2:) - else - ! Look for index - do i=iLast,size(array,1) - if (array(i,1)<=time) then - iLast=i - else - exit - endif - enddo - if (iLast==size(array,1)) then - values = array(iLast,2:) - else - ! Linear interpolation - alpha = (array(iLast+1,1)-time)/(array(iLast+1,1)-array(iLast,1)) - values = array(iLast,2:)*alpha + array(iLast+1,2:)*(1-alpha) - !print*,'time', array(iLast,1), '<=', time,'<', array(iLast+1,1), 'fact', alpha - endif - endif -end subroutine interpTimeValue - !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets up the information needed for plotting VTK surfaces. subroutine setVTKParameters(p_FAST, dvr, ADI, errStat, errMsg, dirname) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index b7e061df17..0158a1f67c 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -1267,15 +1267,20 @@ SUBROUTINE ReadTailFinInputs(FileName, TFData, UnEc, ErrStat, ErrMsg) call ParseVar(FileInfo_In, iLine, 'TFinAFID' , TFData%TFinAFID , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; !====== Unsteady slender body model ===================== [used only when TFinMod=2] call ParseCom(FileInfo_in, iLine, DummyLine , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + call ParseVar(FileInfo_In, iLine, 'TFinKp' , TFData%TFinKp , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + call ParseAry(FileInfo_In, iLine, 'TFinSigma' , TFData%TFinSigma, 3 , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + call ParseAry(FileInfo_In, iLine, 'TFinAStar', TFData%TFinAStar, 3 , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + call ParseVar(FileInfo_In, iLine, 'TFinKv' , TFData%TFinKv , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + call ParseVar(FileInfo_In, iLine, 'TFinCDc' , TFData%TFinCDc , ErrStat2, ErrMsg2, UnEc); if (Failed()) return; + ! TODO ! --- Triggers TFData%TFinAngles = TFData%TFinAngles*D2R ! deg2rad ! --- Validation on the fly - !if (all((/TFinAero_none,TFinAero_polar, TFinAero_USB/) /= TFData%TFinMod)) then - if (all((/TFinAero_none,TFinAero_polar/) /= TFData%TFinMod)) then - call Fatal('TFinMod needs to be 0, or 1') + if (all((/TFinAero_none,TFinAero_polar,TFinAero_USB/) /= TFData%TFinMod)) then + call Fatal('TFinMod needs to be 0, 1 or 2') endif !if (all((/TFinIndMod_none,TFinIndMod_rotavg/) /= TFData%TFinIndMod)) then if (all((/TFinIndMod_none/) /= TFData%TFinIndMod)) then diff --git a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index 0920c4ff5e..34fb3c046a 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 @@ -27,7 +27,6 @@ MODULE AeroDyn_Inflow_C_BINDING USE NWTC_Library USE VersionInfo - IMPLICIT NONE SAVE @@ -36,7 +35,7 @@ MODULE AeroDyn_Inflow_C_BINDING PUBLIC :: ADI_C_CalcOutput PUBLIC :: ADI_C_UpdateStates PUBLIC :: ADI_C_End - PUBLIC :: ADI_C_PreInit ! Initial call to setup number of turbines + PUBLIC :: ADI_C_PreInit ! Initial call to setup number of turbines PUBLIC :: ADI_C_SetupRotor ! Initial node positions etc for a rotor PUBLIC :: ADI_C_SetRotorMotion ! Set motions for a given rotor PUBLIC :: ADI_C_GetRotorLoads ! Retrieve loads for a given rotor @@ -45,7 +44,6 @@ MODULE AeroDyn_Inflow_C_BINDING ! Version info for display type(ProgDesc), parameter :: version = ProgDesc( 'AeroDyn-Inflow library', '', '' ) - !------------------------------------------------------------------------------------ ! Debugging: debugverbose -- passed at PreInit ! 0 - none @@ -98,7 +96,7 @@ MODULE AeroDyn_Inflow_C_BINDING type(ADI_InputType) :: ADI_u !< ADI inputs -- set by AD_SetInputMotion. Copied as needed (necessary for correction steps) !------------------------------ ! Simulation data - type(Dvr_SimData) :: Sim !< data about the simulation + type(Dvr_SimData) :: Sim !< Data about the simulation !------------------------------ ! Outputs type(Dvr_Outputs) :: WrOutputsData !< Data for writing outputs to file @@ -122,7 +120,7 @@ MODULE AeroDyn_Inflow_C_BINDING ! interface and therefore must store it here analogously to how it is handled ! in the OpenFAST glue code. integer(IntKi) :: n_Global ! global timestep - integer(IntKi) :: n_VTK ! VTK timestep + integer(IntKi) :: n_VTK ! VTK timestep real(DbKi) :: InputTimePrev ! input time of last UpdateStates call ! Note that we are including the previous state info here (not done in OF this way) integer(IntKi), parameter :: STATE_LAST = 0 ! Index for previous state (not needed in OF, but necessary here) @@ -140,6 +138,37 @@ MODULE AeroDyn_Inflow_C_BINDING ! positions passed into this module and what is used inside AD. This is done ! through a pair of meshes for the motion and loads corresponding to the node ! positions passed in. + + ! ========= BladeNodeToMeshPointMapType ======= + TYPE, PUBLIC :: BladeNodeToMeshPointMapType + INTEGER(IntKi), ALLOCATABLE :: BladeNodeToMeshPoint(:) !< Blade node -> structural mesh point mapping (sized by the number of nodes on the blade) + END TYPE BladeNodeToMeshPointMapType + ! ======================= + ! ========= BladePtMeshCoordsType ======= + TYPE, PUBLIC :: BladePtMeshCoordsType + REAL(ReKi), DIMENSION(:,:), ALLOCATABLE :: Position !< Position of all blade points (sized by 3 x number of mesh points on the blade [x,y,z]) + REAL(ReKi), DIMENSION(:,:,:), ALLOCATABLE :: Orient !< Orientation of all blade points (sized by 3 x 3 x number of mesh points on the blade [r11,r12,r13,r21,r22,r23,r31,r32,r33]) + REAL(ReKi), DIMENSION(:,:), ALLOCATABLE :: Velocity !< Velocity of all blade points (sized by 6 x number of mesh points on the blade [u,v,w,p,q,r]) + REAL(ReKi), DIMENSION(:,:), ALLOCATABLE :: Accln !< Acceleration of all blade points (sized by 6 x number of mesh points on the blade [udot,vdot,wdot,pdot,qdot,rdot]) + REAL(ReKi), DIMENSION(:,:), ALLOCATABLE :: Force !< Force of all blade points (sized by 6 x number of mesh points on the blade [Fx,Fy,Fz,Mx,My,Mz]) + END TYPE BladePtMeshCoordsType + ! ======================= + ! ========= StrucPtsToBladeMapType ======= + TYPE, PUBLIC :: StrucPtsToBladeMapType + INTEGER(IntKi) :: NumBlades ! Number of blades on this rotor + INTEGER(IntKi), ALLOCATABLE :: NumMeshPtsPerBlade(:) ! Number of structural mesh points on each blade (sized by the number of blades) + INTEGER(IntKi), ALLOCATABLE :: MeshPt_2_BladeNum(:) ! Structural mesh point -> which blade on the rotor it is on (sized by the number of mesh points on the rotor) + TYPE(BladeNodeToMeshPointMapType),ALLOCATABLE:: BladeNode_2_MeshPt(:) ! Blade node on blade -> structural mesh point (sized by the number of mesh points on the blade) + TYPE(BladePtMeshCoordsType), ALLOCATABLE :: BladePtMeshCoords(:) ! Mesh point coordinates for each blade (sized by the number of blades) + END TYPE StrucPtsToBladeMapType + ! ======================= + ! ========= MeshByBladeType ======= + TYPE, PUBLIC :: MeshByBladeType + ! TODO: Sometime we should rename Mesh to BldMesh + TYPE(MeshType), ALLOCATABLE :: Mesh(:) ! Mesh for motions/loads of external nodes at each blade (sized by number of blades on the rotor) + END TYPE MeshByBladeType + ! ======================= + !------------------------------ ! Meshes for external nodes ! These point meshes are merely used to simplify the mapping of motions/loads @@ -147,31 +176,25 @@ MODULE AeroDyn_Inflow_C_BINDING ! one or multiple points. ! - 1 point -- rigid floating body assumption ! - N points -- flexible structure (either floating or fixed bottom) + ! TODO: for clarity, sometime it might be worth renaming BldPt* here to RtrPt* instead logical :: TransposeDCM !< Transpose DCMs as passed in -- test the vtk outputs to see if needed integer(IntKi), allocatable :: NumMeshPts(:) ! Number of mesh points we are interfacing motions/loads to/from AD for each rotor - type(MeshType), allocatable :: BldPtMotionMesh(:) ! mesh for motions of external nodes - type(MeshType), allocatable :: BldPtLoadMesh(:) ! mesh for loads for external nodes - type(MeshType), allocatable :: BldPtLoadMesh_tmp(:) ! mesh for loads for external nodes -- temporary -! type(MeshType), allocatable :: NacMotionMesh(:) ! mesh for motion of nacelle -- TODO: add this mesh for nacelle load transfers -! type(MeshType), allocatable :: NacLoadMesh(:) ! mesh for loads for nacelle loads -- TODO: add this mesh for nacelle load transfers + type(MeshByBladeType), allocatable :: BldPtMotionMesh(:) ! Mesh for motions of external nodes (sized by number of rotors) + type(MeshByBladeType), allocatable :: BldPtLoadMesh(:) ! Mesh for loads for external nodes (sized by number of rotors) + type(MeshByBladeType), allocatable :: BldPtLoadMesh_tmp(:) ! Mesh for loads for external nodes -- temporary storage for loads (sized by number of rotors) + ! type(MeshType), allocatable :: NacMotionMesh(:) ! mesh for motion of nacelle -- TODO: add this mesh for nacelle load transfers + ! type(MeshType), allocatable :: NacLoadMesh(:) ! mesh for loads for nacelle loads -- TODO: add this mesh for nacelle load transfers !------------------------------ ! Mesh mapping: motions ! The mapping of motions from the nodes passed in to the corresponding AD meshes - type(MeshMapType), allocatable :: Map_BldPtMotion_2_AD_Blade(:,:) ! Mesh mapping between input motion mesh for blade - type(MeshMapType), allocatable :: Map_AD_Nac_2_NacPtLoad(:) ! Mesh mapping between input motion mesh for nacelle + ! TODO: sometime restructure the Map_BldPtMotion_2_AD_Blade and Map_AD_BldLoad_P_2_BldPtLoad to 1D and place inside a rotor structure + type(MeshMapType), allocatable :: Map_BldPtMotion_2_AD_Blade(:,:) ! Mesh mapping between input motion mesh for blade (sized by the number of blades and number of rotors) + type(MeshMapType), allocatable :: Map_AD_Nac_2_NacPtLoad(:) ! Mesh mapping between input motion mesh for nacelle !------------------------------ ! Mesh mapping: loads ! The mapping of loads from the AD meshes to the corresponding external nodes - type(MeshMapType), allocatable :: Map_AD_BldLoad_P_2_BldPtLoad(:,:) ! Mesh mapping between AD output blade line2 load to BldPtLoad for return -! type(MeshMapType) :: Map_NacPtMotion_2_AD_Nac(:) ! Mesh mapping between AD output nacelle pt load to NacLoad for return - ! Motions input (so we don't have to reallocate all the time - real(ReKi), allocatable :: tmpBldPtMeshPos(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. - real(ReKi), allocatable :: tmpBldPtMeshOri(:,:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. - real(ReKi), allocatable :: tmpBldPtMeshVel(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. - real(ReKi), allocatable :: tmpBldPtMeshAcc(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. - real(ReKi), allocatable :: tmpBldPtMeshFrc(:,:) ! temp array. Probably don't need this, but makes conversion to C clearer. - !------------------------------------------------------------------------------------ - + type(StrucPtsToBladeMapType), allocatable :: StrucPts_2_Bld_Map(:) ! Array mapping info for structural mesh points to blades, and back (sized by the number of rotors/turbines) + type(MeshMapType), allocatable :: Map_AD_BldLoad_P_2_BldPtLoad(:,:) ! Mesh mapping between AD output blade line2 load to BldPtLoad for return (sized by the number of blades and number of rotors) ! NOTE on turbine origin ! The turbine origin is set by TurbOrigin_C during the ADI_C_SetupRotor routine. This is the tower base location. All @@ -180,7 +203,6 @@ MODULE AeroDyn_Inflow_C_BINDING ! TurbOrigin_C (stored as Sim%WT(iWT)%OriginInit). When the mesh and other points are passed in, they are relative to ! their respective rotor origin. - CONTAINS !> This routine sets the error status in C_CHAR for export to calling code. @@ -225,7 +247,7 @@ subroutine ADI_C_PreInit(NumTurbines_C,TransposeDCM_in,debuglevel,ErrStat_C,ErrM character(ErrMsgLen) :: ErrMsg !< aggregated error message integer :: ErrStat2 !< temporary error status from a call character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call - character(*), parameter :: RoutineName = 'ADI_C_PreInit' !< for error handling + character(*), parameter :: RoutineName = 'ADI_C_PreInit' !< for error handling ! Initialize error handling ErrStat = ErrID_None @@ -255,7 +277,6 @@ subroutine ADI_C_PreInit(NumTurbines_C,TransposeDCM_in,debuglevel,ErrStat_C,ErrM if (Failed()) return; endif - ! Set number of turbines Sim%NumTurbines = int(NumTurbines_C,IntKi) @@ -279,27 +300,31 @@ subroutine ADI_C_PreInit(NumTurbines_C,TransposeDCM_in,debuglevel,ErrStat_C,ErrM Sim%WT(iWT)%NumBlades = -999 enddo - ! storage for numnber of meshpoints + ! Storage for number of meshpoints if (allocated(NumMeshPts)) deallocate(NumMeshPts) allocate(NumMeshPts(Sim%NumTurbines),stat=errStat2); if (Failed0('NumMeshPts')) return NumMeshPts = -999 - ! allocate meshes and meshmappings + ! Allocate meshes and mesh mappings if (allocated(BldPtMotionMesh )) deallocate(BldPtMotionMesh ) if (allocated(BldPtLoadMesh )) deallocate(BldPtLoadMesh ) if (allocated(BldPtLoadMesh_tmp)) deallocate(BldPtLoadMesh_tmp) - !if (allocated(NacMotionMesh )) deallocate(NacMotionMesh ) - !if (allocated(NacLoadMesh )) deallocate(NacLoadMesh ) - if (allocated(Map_BldPtMotion_2_AD_Blade )) deallocate(Map_BldPtMotion_2_AD_Blade ) - if (allocated(Map_AD_BldLoad_P_2_BldPtLoad)) deallocate(Map_AD_BldLoad_P_2_BldPtLoad) - !if (allocated(Map_NacPtMotion_2_AD_Nac )) deallocate(Map_NacPtMotion_2_AD_Nac ) + ! if (allocated(NacMotionMesh )) deallocate(NacMotionMesh ) + ! if (allocated(NacLoadMesh )) deallocate(NacLoadMesh ) allocate(BldPtMotionMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('BldPtMotionMesh' )) return allocate(BldPtLoadMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('BldPtLoadMesh' )) return allocate(BldPtLoadMesh_tmp(Sim%NumTurbines), STAT=ErrStat2); if (Failed0('BldPtLoadMesh_tmp')) return - !allocate(NacMotionMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('NacMotionMesh' )) return - !allocate(NacLoadMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('NacLoadMesh' )) return - !allocate(Map_NacPtMotion_2_AD_Nac(Sim%NumTurbines),STAT=ErrStat2); if (Failed0('Map_AD_BldLoad_P_2_BldPtLoad')) return + ! allocate(NacMotionMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('NacMotionMesh' )) return + ! allocate(NacLoadMesh( Sim%NumTurbines), STAT=ErrStat2); if (Failed0('NacLoadMesh' )) return + if (allocated(Map_BldPtMotion_2_AD_Blade )) deallocate(Map_BldPtMotion_2_AD_Blade ) + if (allocated(Map_AD_BldLoad_P_2_BldPtLoad )) deallocate(Map_AD_BldLoad_P_2_BldPtLoad) + ! if (allocated(Map_NacPtMotion_2_AD_Nac )) deallocate(Map_NacPtMotion_2_AD_Nac ) + ! allocate(Map_NacPtMotion_2_AD_Nac(Sim%NumTurbines),STAT=ErrStat2); if (Failed0('Map_AD_BldLoad_P_2_BldPtLoad')) returns + + ! Allocate the StrucPtsToBladeMapType array used for mapping structural points to blades of the rotor + if (allocated(StrucPts_2_Bld_Map)) deallocate(StrucPts_2_Bld_Map) + allocate(StrucPts_2_Bld_Map(Sim%NumTurbines), STAT=ErrStat2); if (Failed0('StrucPts_2_Bld_Map' )) return call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) @@ -341,7 +366,7 @@ subroutine ShowPassedData() call WrScr("-----------------------------------------------------------") end subroutine ShowPassedData -end subroutine ADI_C_PreInit +end subroutine ADI_C_PreInit !=============================================================================================================== !--------------------------------------------- AeroDyn Init---------------------------------------------------- @@ -391,7 +416,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString real(c_float), intent(in ) :: VTKNacDim_in(6) !< Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m) real(c_float), intent(in ) :: VTKHubrad_in !< Hub radius for VTK surface rendering integer(c_int), intent(in ) :: wrOuts_C !< Write ADI output file - real(c_double), intent(in ) :: DT_Outs_C !< Timestep to write output file from ADI + real(c_double), intent(in ) :: DT_Outs_C !< Timestep to write output file from ADI ! Output integer(c_int), intent( out) :: NumChannels_C !< Number of output channels requested from the input file character(kind=c_char), intent( out) :: OutputChannelNames_C(ChanLen*MaxADIOutputs+1) !< NOTE: if MaxADIOutputs is sufficiently large, we may overrun the buffer on the Python side. @@ -399,7 +424,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString integer(c_int), intent( out) :: ErrStat_C !< Error status character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) !< Error message (C_NULL_CHAR terminated) - ! Local Variable4 + ! Local variables character(IntfStrLen) :: OutRootName !< Root name to use for echo files and other character(IntfStrLen) :: TmpFileName !< Temporary file name if not passing AD or IfW input file contents directly character(kind=C_char, len=ADinputFileStringLength_C), pointer :: ADinputFileString !< Input file as a single string with NULL chracter separating lines @@ -409,7 +434,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString character(ErrMsgLen) :: ErrMsg !< aggregated error message integer(IntKi) :: ErrStat2 !< temporary error status from a call character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call - integer(IntKi) :: i,j,k !< generic counters + integer(IntKi) :: i,j,k !< generic index variables integer(IntKi) :: iWT !< current turbine number (iterate through during setup for ADI_Init call) integer(IntKi) :: AeroProjMod !< for checking that all turbines use the same AeroProjMod character(*), parameter :: RoutineName = 'ADI_C_Init' !< for error handling @@ -787,9 +812,9 @@ subroutine SetupFileOutputs() call concatOutputHeaders(WrOutputsData%WriteOutputHdr, WrOutputsData%WriteOutputUnt, InitOutData%WriteOutputHdr, InitOutData%WriteOutputUnt, errStat2, errMsg2); if(Failed()) return ! allocate output file handling and set formats - WrOutputsData%outFmt = "ES15.8E2" + WrOutputsData%outFmt = "ES15.8E2" WrOutputsData%delim = TAB - WrOutputsData%AD_ver = InitOutData%Ver + WrOutputsData%AD_ver = InitOutData%Ver allocate(WrOutputsData%unOutFile(Sim%numTurbines), STAT=ErrStat2); if(Failed0("unOutFile")) return; WrOutputsData%unOutFile = -1 !FIXME: number of timesteps is incorrect! @@ -847,82 +872,61 @@ end subroutine ShowPassedData !! meshes subroutine SetupMotionLoadsInterfaceMeshes() integer(IntKi) :: iWT !< current rotor/turbine - integer(IntKi) :: iNode - integer(IntKi) :: maxBlades !< find out maximum number of blades on all turbine rotors + integer(IntKi) :: iBlade !< current blade + integer(IntKi) :: maxBlades !< maximum number of blades on all turbine rotors + ! Find out maximum number of blades on all turbine rotors maxBlades = 0_IntKi do iWT=1,Sim%NumTurbines maxBlades = max(maxBlades,Sim%WT(iWT)%NumBlades) enddo - allocate(Map_BldPtMotion_2_AD_Blade( maxBlades,Sim%NumTurbines),STAT=ErrStat2); if (Failed0('Map_BldPtMotion_2_AD_Blade' )) return - allocate(Map_AD_BldLoad_P_2_BldPtLoad(maxBlades,Sim%NumTurbines),STAT=ErrStat2); if (Failed0('Map_AD_BldLoad_P_2_BldPtLoad')) return + ! NOTE: storing mappings in 2D this way may increase memory usage slightly if one turbine has many more blades than another. However + ! the speed an memory penalties are negligible, so I don't see much reason to change that at this point. + allocate(Map_BldPtMotion_2_AD_Blade( maxBlades, Sim%NumTurbines), STAT=ErrStat2); if (Failed0('Map_BldPtMotion_2_AD_Blade' )) return + allocate(Map_AD_BldLoad_P_2_BldPtLoad(maxBlades, Sim%NumTurbines), STAT=ErrStat2); if (Failed0('Map_AD_BldLoad_P_2_BldPtLoad')) return - ! step through all turbine rotors + ! Step through all turbine rotors do iWT=1,Sim%NumTurbines - !------------------------------------------------------------- ! Load mesh for blades - CALL MeshCopy( SrcMesh = BldPtMotionMesh(iWT) ,& - DestMesh = BldPtLoadMesh(iWT) ,& - CtrlCode = MESH_SIBLING ,& - IOS = COMPONENT_OUTPUT ,& - ErrStat = ErrStat2 ,& - ErrMess = ErrMsg2 ,& - Force = .TRUE. ,& - Moment = .TRUE. ) - if(Failed()) return - BldPtLoadMesh(iWT)%RemapFlag = .FALSE. - - ! Temp mesh for load transfer - CALL MeshCopy( SrcMesh = BldPtLoadMesh(iWT) ,& - DestMesh = BldPtLoadMesh_tmp(iWT),& - CtrlCode = MESH_COUSIN ,& - IOS = COMPONENT_OUTPUT ,& - ErrStat = ErrStat2 ,& - ErrMess = ErrMsg2 ,& - Force = .TRUE. ,& - Moment = .TRUE. ) - if(Failed()) return - BldPtLoadMesh_tmp(iWT)%RemapFlag = .FALSE. - - - ! For checking the mesh - ! note: CU is is output unit (platform dependent). - if (debugverbose >= 4) call MeshPrintInfo( CU, BldPtLoadMesh(iWT), MeshName='BldPtLoadMesh'//trim(Num2LStr(iWT)) ) - - -! !------------------------------------------------------------- -! ! Load mesh for nacelle -! CALL MeshCopy( SrcMesh = NacMotionMesh(iWT) ,& -! DestMesh = NacLoadMesh(iWT) ,& -! CtrlCode = MESH_SIBLING ,& -! IOS = COMPONENT_OUTPUT ,& -! ErrStat = ErrStat2 ,& -! ErrMess = ErrMsg2 ,& -! Force = .TRUE. ,& -! Moment = .TRUE. ) -! if(Failed()) return -! NacLoadMesh(iWT)%RemapFlag = .FALSE. -! -! ! For checking the mesh, uncomment this. -! ! note: CU is is output unit (platform dependent). -! if (debugverbose >= 4) call MeshPrintInfo( CU, NacLoadMesh(iWT), MeshName='NacLoadMesh'//trim(Num2LStr(iWT)) ) - - - !------------------------------------------------------------- - ! Set the mapping meshes - ! blades - do i=1,Sim%WT(iWT)%NumBlades - call MeshMapCreate( BldPtMotionMesh(iWT), ADI%u(1)%AD%rotors(iWT)%BladeMotion(i), Map_BldPtMotion_2_AD_Blade(i,iWT), ErrStat2, ErrMsg2 ); if(Failed()) return - call MeshMapCreate( ADI%y%AD%rotors(iWT)%BladeLoad(i), BldPtLoadMesh(iWT), Map_AD_BldLoad_P_2_BldPtLoad(i,iWT), ErrStat2, ErrMsg2 ); if(Failed()) return - enddo - ! nacelle -- TODO: add this mesh for nacelle load transfers -! if ( ADI%y%AD%rotors(iWT)%NacelleLoad%Committed ) then -! call MeshMapCreate( NacMotionMesh(iWT), ADI%u(1)%AD%rotors(iWT)%NacelleMotion, Map_NacPtMotion_2_AD_Nac(iWT), ErrStat2, ErrMsg2 ); if(Failed()) return -! call MeshMapCreate( ADI%y%AD%rotors(iWT)%NacelleLoad, NacLoadMesh(iWT), Map_AD_Nac_2_NacPtLoad(iWT), ErrStat2, ErrMsg2 ); if(Failed()) return -! endif - + ! Step through all blades on this rotor + do iBlade=1,Sim%WT(iWT)%NumBlades + !------------------------------------------------------------- + ! Load mesh for blades + CALL MeshCopy( SrcMesh = BldPtMotionMesh(iWT)%Mesh(iBlade) ,& + DestMesh = BldPtLoadMesh(iWT)%Mesh(iBlade) ,& + CtrlCode = MESH_SIBLING ,& + IOS = COMPONENT_OUTPUT ,& + ErrStat = ErrStat2 ,& + ErrMess = ErrMsg2 ,& + Force = .TRUE. ,& + Moment = .TRUE. ) + if(Failed()) return + BldPtMotionMesh(iWT)%Mesh(iBlade)%RemapFlag = .FALSE. + + ! Temp mesh for load transfer + CALL MeshCopy( SrcMesh = BldPtLoadMesh(iWT)%Mesh(iBlade) ,& + DestMesh = BldPtLoadMesh_tmp(iWT)%Mesh(iBlade) ,& + CtrlCode = MESH_COUSIN ,& + IOS = COMPONENT_OUTPUT ,& + ErrStat = ErrStat2 ,& + ErrMess = ErrMsg2 ,& + Force = .TRUE. ,& + Moment = .TRUE. ) + if(Failed()) return + BldPtLoadMesh_tmp(iWT)%Mesh(iBlade)%RemapFlag = .FALSE. + + ! For checking the mesh + ! Note: CU is is output unit (platform dependent). + if (debugverbose >= 4) call MeshPrintInfo( CU, BldPtLoadMesh(iWT)%Mesh(iBlade), MeshName='BldPtLoadMesh'//trim(Num2LStr(iWT))//'_'//trim(Num2LStr(iBlade)) ) + + !------------------------------------------------------------- + ! Set the mapping meshes + ! blades + call MeshMapCreate( BldPtMotionMesh(iWT)%Mesh(iBlade), ADI%u(1)%AD%rotors(iWT)%BladeMotion(iBlade), Map_BldPtMotion_2_AD_Blade(iBlade, iWT), ErrStat2, ErrMsg2 ); if(Failed()) return + call MeshMapCreate( ADI%y%AD%rotors(iWT)%BladeLoad(iBlade), BldPtLoadMesh(iWT)%Mesh(iBlade), Map_AD_BldLoad_P_2_BldPtLoad(iBlade, iWT), ErrStat2, ErrMsg2 ); if(Failed()) return + enddo ! iBlade enddo ! iWT end subroutine SetupMotionLoadsInterfaceMeshes @@ -1291,7 +1295,7 @@ subroutine ADI_C_SetupRotor(iWT_c, TurbineIsHAWT_c, TurbOrigin_C, & NacPos_C, NacOri_C, & NumBlades_C, BldRootPos_C, BldRootOri_C, & NumMeshPts_C, InitMeshPos_C, InitMeshOri_C, & - ErrStat_C, ErrMsg_C) BIND (C, NAME='ADI_C_SetupRotor') + MeshPtToBladeNum_C, ErrStat_C, ErrMsg_C) BIND (C, NAME='ADI_C_SetupRotor') implicit none #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: ADI_C_SetupRotor @@ -1308,21 +1312,23 @@ subroutine ADI_C_SetupRotor(iWT_c, TurbineIsHAWT_c, TurbOrigin_C, & integer(c_int), intent(in ) :: NumBlades_C !< Number of blades real(c_float), intent(in ) :: BldRootPos_C( 3*NumBlades_C ) !< Blade root positions real(c_double), intent(in ) :: BldRootOri_C( 9*NumBlades_C ) !< Blade root orientations - ! Initial nodes - integer(c_int), intent(in ) :: NumMeshPts_C !< Number of mesh points we are transfering motions to and output loads to + ! Initial nodes + integer(c_int), intent(in ) :: NumMeshPts_C !< Number of mesh points we are transferring motions and outputting loads to real(c_float), intent(in ) :: InitMeshPos_C( 3*NumMeshPts_C ) !< A 3xNumMeshPts_C array [x,y,z] real(c_double), intent(in ) :: InitMeshOri_C( 9*NumMeshPts_C ) !< A 9xNumMeshPts_C array [r11,r12,r13,r21,r22,r23,r31,r32,r33] + integer(c_int), intent(in ) :: MeshPtToBladeNum_C( NumMeshPts_C ) !< A NumMeshPts_C array of blade numbers associated with each mesh point integer(c_int), intent( out) :: ErrStat_C !< Error status character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) !< Error message (C_NULL_CHAR terminated) - ! local vars - integer(IntKi) :: iWT !< current turbine + ! Local variables + integer(IntKi) :: iWT !< current turbine + integer(IntKi) :: iBlade !< current blade logical :: TurbineIsHAWT !< true for HAWT, false for VAWT integer(IntKi) :: ErrStat !< aggregated error messagNumBlades_ee character(ErrMsgLen) :: ErrMsg !< aggregated error message integer(IntKi) :: ErrStat2 !< temporary error status from a call character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call - integer(IntKi) :: i,j,k !< generic counters + integer(IntKi) :: i,j,k !< generic index variables character(*), parameter :: RoutineName = 'ADI_C_Init' !< for error handling ! Initialize error handling @@ -1375,7 +1381,7 @@ subroutine ADI_C_SetupRotor(iWT_c, TurbineIsHAWT_c, TurbOrigin_C, & enddo endif - ! Remap the orientation DCM just in case there is some issue with passed + ! Remap the orientation DCM just in case there is some issue with passed call OrientRemap(InitInp%AD%rotors(iWT)%HubOrientation) call OrientRemap(InitInp%AD%rotors(iWT)%NacelleOrientation) do i=1,Sim%WT(iWT)%NumBlades @@ -1472,56 +1478,112 @@ end subroutine ShowPassedData subroutine SetupMotionMesh() real(ReKi) :: InitPos(3) real(R8Ki) :: Orient(3,3) - integer(IntKi) :: iNode - ! this may not be super efficient since we are allocating for every turbine, but this makes things a bit simpler - if ( allocated(tmpBldPtMeshPos) ) deallocate(tmpBldPtMeshPos) - if ( allocated(tmpBldPtMeshOri) ) deallocate(tmpBldPtMeshOri) - call AllocAry( tmpBldPtMeshPos, 3, NumMeshPts(iWT), "tmpBldPtMeshPos", ErrStat2, ErrMsg2 ); if (Failed()) return - call AllocAry( tmpBldPtMeshOri, 3, 3, NumMeshPts(iWT), "tmpBldPtMeshOri", ErrStat2, ErrMsg2 ); if (Failed()) return + integer(IntKi) :: count - ! Reshape mesh position, orientation, velocity, acceleration - tmpBldPtMeshPos(1:3,1:NumMeshPts(iWT)) = reshape( real(InitMeshPos_C(1:3*NumMeshPts(iWT)),ReKi), (/3, NumMeshPts(iWT)/) ) - tmpBldPtMeshOri(1:3,1:3,1:NumMeshPts(iWT)) = reshape( real(InitMeshOri_C(1:9*NumMeshPts(iWT)),R8Ki), (/3,3,NumMeshPts(iWT)/) ) + !------------------------------------------------------------- + ! Allocate and define the components of StrucPts_2_Bld_Map + !------------------------------------------------------------- + StrucPts_2_Bld_Map(iWT)%NumBlades = Sim%WT(iWT)%NumBlades + + call AllocAry(StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade, Sim%WT(iWT)%NumBlades, "NumMeshPtsPerBlade", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( StrucPts_2_Bld_Map(iWT)%MeshPt_2_BladeNum, NumMeshPts(iWT), "MeshPt_2_BladeNum", ErrStat2, ErrMsg2 ); if (Failed()) return + + allocate(StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt( Sim%WT(iWT)%NumBlades ), STAT=ErrStat2); if (Failed0('StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt' )) return + + ! Calculate the number of mesh points per blade + do i=1,Sim%WT(iWT)%NumBlades + count = 0 + do j=1,NumMeshPts(iWT) + if (MeshPtToBladeNum_C(j) == i) then + count = count + 1 + endif + enddo + StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i) = count + enddo + + StrucPts_2_Bld_Map(iWT)%MeshPt_2_BladeNum(1:NumMeshPts(iWT)) = MeshPtToBladeNum_C(1:NumMeshPts(iWT)) + + ! Allocate remaining components of StrucPts_2_Bld_Map based on the number of mesh points per blade + do i=1,Sim%WT(iWT)%NumBlades + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladeNodeToMeshPoint", ErrStat2, ErrMsg2); if (Failed()) return + enddo + + do i=1,Sim%WT(iWT)%NumBlades + count = 0 + do j=1,NumMeshPts(iWT) + if (MeshPtToBladeNum_C(j) == i) then + count = count + 1 + StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(count) = j + endif + enddo + enddo + + ! Allocate and define the components of BladePtMeshCoords + allocate(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(Sim%WT(iWT)%NumBlades), STAT=ErrStat2); if (Failed0('StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords')) return + do i=1,Sim%WT(iWT)%NumBlades + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Position, 3, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladePtMeshCoords(i)%Position", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Orient, 3, 3, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladePtMeshCoords(i)%Orient", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Velocity, 6, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladePtMeshCoords(i)%Velocity", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Accln, 6, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladePtMeshCoords(i)%Accln", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Force, 6, StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i), "BladePtMeshCoords(i)%Force", ErrStat2, ErrMsg2 ); if (Failed()) return + enddo + + do i=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Position(1:3,j) = reshape( real(InitMeshPos_C(3 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 2 : 3 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),ReKi), (/3/) ) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Orient(1:3,1:3,j) = reshape( real(InitMeshOri_C(9 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 8 : 9 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),R8Ki), (/3,3/) ) + enddo + enddo + + ! Allocate the meshes + allocate(BldPtMotionMesh(iWT)%Mesh( Sim%WT(iWT)%NumBlades ), STAT=ErrStat2); if (Failed0('BldPtMotionMesh( iWT )%Mesh' )) return + allocate(BldPtLoadMesh(iWT)%Mesh( Sim%WT(iWT)%NumBlades ), STAT=ErrStat2); if (Failed0('BldPtLoadMesh( iWT )%Mesh' )) return + allocate(BldPtLoadMesh_tmp(iWT)%Mesh( Sim%WT(iWT)%NumBlades ), STAT=ErrStat2); if (Failed0('BldPtLoadMesh_tmp( iWT )%Mesh' )) return !------------------------------------------------------------- ! Set the interface meshes for motion inputs and loads output !------------------------------------------------------------- ! Motion mesh for blades - call MeshCreate( BldPtMotionMesh(iWT) , & - IOS = COMPONENT_INPUT , & - Nnodes = NumMeshPts(iWT) , & - ErrStat = ErrStat2 , & - ErrMess = ErrMsg2 , & - TranslationDisp = .TRUE., Orientation = .TRUE., & - TranslationVel = .TRUE., RotationVel = .TRUE., & - TranslationAcc = .TRUE., RotationAcc = .FALSE. ) - if(Failed()) return - - do iNode=1,NumMeshPts(iWT) - ! initial position and orientation of node - InitPos = tmpBldPtMeshPos(1:3,iNode) + Sim%WT(iWT)%OriginInit(1:3) - if (TransposeDCM) then - Orient = transpose(tmpBldPtMeshOri(1:3,1:3,iNode)) - else - Orient = tmpBldPtMeshOri(1:3,1:3,iNode) - endif - call OrientRemap(Orient) - call MeshPositionNode( BldPtMotionMesh(iWT) , & - iNode , & - InitPos , & ! position - ErrStat2, ErrMsg2 , & - Orient ) ! orientation + do iBlade=1,Sim%WT(iWT)%NumBlades + call MeshCreate( BldPtMotionMesh(iWT)%Mesh(iBlade) , & + IOS = COMPONENT_INPUT , & + Nnodes = StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(iBlade) , & + ErrStat = ErrStat2 , & + ErrMess = ErrMsg2 , & + TranslationDisp = .TRUE., Orientation = .TRUE. , & + TranslationVel = .TRUE., RotationVel = .TRUE. , & + TranslationAcc = .TRUE., RotationAcc = .FALSE. ) if(Failed()) return - call MeshConstructElement ( BldPtMotionMesh(iWT), ELEMENT_POINT, ErrStat2, ErrMsg2, iNode ); if(Failed()) return enddo - call MeshCommit ( BldPtMotionMesh(iWT), ErrStat2, ErrMsg2 ); if(Failed()) return - BldPtMotionMesh(iWT)%RemapFlag = .FALSE. + do iBlade=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(iBlade) + ! Initial position and orientation of node + InitPos = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Position(1:3,j) + Sim%WT(iWT)%OriginInit(1:3) + if (TransposeDCM) then + Orient = transpose(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Orient(1:3,1:3,j)) + else + Orient = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Orient(1:3,1:3,j) + endif + call OrientRemap(Orient) + call MeshPositionNode( BldPtMotionMesh(iWT)%Mesh(iBlade) , & + j , & + InitPos , & ! position + ErrStat2, ErrMsg2 , & + Orient ) ! orientation + if(Failed()) return + call MeshConstructElement ( BldPtMotionMesh(iWT)%Mesh(iBlade), ELEMENT_POINT, ErrStat2, ErrMsg2, j ); if(Failed()) return + enddo + enddo - ! For checking the mesh, uncomment this. - ! note: CU is is output unit (platform dependent). - if (debugverbose >= 4) call MeshPrintInfo( CU, BldPtMotionMesh(iWT), MeshName='BldPtMotionMesh'//trim(Num2LStr(iWT)) ) + do iBlade=1,Sim%WT(iWT)%NumBlades + call MeshCommit ( BldPtMotionMesh(iWT)%Mesh(iBlade), ErrStat2, ErrMsg2 ); if(Failed()) return + BldPtMotionMesh(iWT)%Mesh(iBlade)%RemapFlag = .FALSE. + ! For checking the mesh + ! Note: CU is is output unit (platform dependent) + if (debugverbose >= 4) call MeshPrintInfo( CU, BldPtMotionMesh(iWT)%Mesh(iBlade), MeshName='BldPtMotionMesh'//trim(Num2LStr(iWT))//'_'//trim(Num2LStr(iBlade)) ) + enddo ! !------------------------------------------------------------- ! ! Motion mesh for nacelle -- TODO: add this mesh for nacelle load transfers @@ -1554,11 +1616,8 @@ subroutine SetupMotionMesh() ! ! note: CU is is output unit (platform dependent). ! if (debugverbose >= 4) call MeshPrintInfo( CU, NacMotionMesh(iWT), MeshName='NacMotionMesh'//trim(Num2LStr(iWT)) ) - ! clear the tmp stuff (will need to resize this later) - if ( allocated(tmpBldPtMeshPos) ) deallocate(tmpBldPtMeshPos) - if ( allocated(tmpBldPtMeshOri) ) deallocate(tmpBldPtMeshOri) end subroutine SetupMotionMesh -end subroutine ADI_C_SetupRotor +end subroutine ADI_C_SetupRotor !=============================================================================================================== !--------------------------------------------- AeroDyn SetRotorMotion ------------------------------------------ @@ -1576,7 +1635,7 @@ subroutine ADI_C_SetRotorMotion( iWT_c, & !DEC$ ATTRIBUTES DLLEXPORT :: ADI_C_SetRotorMotion !GCC$ ATTRIBUTES DLLEXPORT :: ADI_C_SetRotorMotion #endif - integer(c_int), intent(in ) :: iWT_c !< Wind turbine / rotor number + integer(c_int), intent(in ) :: iWT_c !< Wind turbine / rotor number real(c_float), intent(in ) :: HubPos_C( 3 ) !< Hub position real(c_double), intent(in ) :: HubOri_C( 9 ) !< Hub orientation real(c_float), intent(in ) :: HubVel_C( 6 ) !< Hub velocity @@ -1600,8 +1659,8 @@ subroutine ADI_C_SetRotorMotion( iWT_c, & ! Local variables real(DbKi) :: Time - integer(IntKi) :: iNode integer(IntKi) :: iWT !< current wind turbine / rotor + integer(IntKi) :: i,j !< generic index variables integer(IntKi) :: ErrStat !< aggregated error status character(ErrMsgLen) :: ErrMsg !< aggregated error message integer(IntKi) :: ErrStat2 !< temporary error status from a call @@ -1628,11 +1687,14 @@ subroutine ADI_C_SetRotorMotion( iWT_c, & endif ! Reshape mesh position, orientation, velocity, acceleration - tmpBldPtMeshPos(1:3,1:NumMeshPts(iWT)) = reshape( real(MeshPos_C(1:3*NumMeshPts(iWT)),ReKi), (/3, NumMeshPts(iWT)/) ) - tmpBldPtMeshOri(1:3,1:3,1:NumMeshPts(iWT)) = reshape( real(MeshOri_C(1:9*NumMeshPts(iWT)),R8Ki), (/3,3,NumMeshPts(iWT)/) ) - tmpBldPtMeshVel(1:6,1:NumMeshPts(iWT)) = reshape( real(MeshVel_C(1:6*NumMeshPts(iWT)),ReKi), (/6, NumMeshPts(iWT)/) ) - tmpBldPtMeshAcc(1:6,1:NumMeshPts(iWT)) = reshape( real(MeshAcc_C(1:6*NumMeshPts(iWT)),ReKi), (/6, NumMeshPts(iWT)/) ) - + do i=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Position( 1:3,j) = reshape( real(MeshPos_C(3 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 2 : 3 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),ReKi), (/3/) ) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Orient(1:3,1:3,j) = reshape( real(MeshOri_C(9 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 8 : 9 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),R8Ki), (/3,3/) ) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Velocity( 1:6,j) = reshape( real(MeshVel_C(6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 5 : 6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),ReKi), (/6/) ) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Accln( 1:6,j) = reshape( real(MeshAcc_C(6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 5 : 6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)),ReKi), (/6/) ) + enddo + enddo ! Transfer motions to input meshes do iWT=1,Sim%NumTurbines @@ -1738,7 +1800,7 @@ end subroutine ADI_C_SetRotorMotion !--------------------------------------------- AeroDyn GetRotorLoads ------------------------------------------- !=============================================================================================================== !> Get the loads from a single rotor. This must be called after ADI_C_CalcOutput -subroutine ADI_C_GetRotorLoads(iWT_C, & +subroutine ADI_C_GetRotorLoads(iWT_C, & NumMeshPts_C, MeshFrc_C, & ErrStat_C, ErrMsg_C) BIND (C, NAME='ADI_C_GetRotorLoads') implicit none @@ -1746,7 +1808,7 @@ subroutine ADI_C_GetRotorLoads(iWT_C, & !DEC$ ATTRIBUTES DLLEXPORT :: ADI_C_GetRotorLoads !GCC$ ATTRIBUTES DLLEXPORT :: ADI_C_GetRotorLoads #endif - integer(c_int), intent(in ) :: iWT_C !< Wind turbine / rotor number + integer(c_int), intent(in ) :: iWT_C !< Wind turbine / rotor number integer(c_int), intent(in ) :: NumMeshPts_C !< Number of mesh points we are transfering motions to and output loads to real(c_float), intent( out) :: MeshFrc_C( 6*NumMeshPts_C ) !< A 6xNumMeshPts_C array [Fx,Fy,Fz,Mx,My,Mz] -- forces and moments (global) integer(c_int), intent( out) :: ErrStat_C @@ -1759,6 +1821,7 @@ subroutine ADI_C_GetRotorLoads(iWT_C, & integer(IntKi) :: ErrStat2 !< temporary error status from a call character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call character(*), parameter :: RoutineName = 'ADI_C_SetRotorMotion' !< for error handling + integer(IntKi) :: i,j !< generic index variables ! Initialize error handling ErrStat = ErrID_None @@ -1785,7 +1848,11 @@ subroutine ADI_C_GetRotorLoads(iWT_C, & ! Set output force/moment array call Set_OutputLoadArray(iWT) - MeshFrc_C(1:6*NumMeshPts(iWT)) = reshape( real(tmpBldPtMeshFrc(1:6,1:NumMeshPts(iWT)), c_float), (/6*NumMeshPts(iWT)/) ) + do i=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(i) + MeshFrc_C(6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j) - 5 : 6 * StrucPts_2_Bld_Map(iWT)%BladeNode_2_MeshPt(i)%BladeNodeToMeshPoint(j)) = real(StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(i)%Force(1:6,j), c_float) + enddo + enddo ! Set error status call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) @@ -1809,8 +1876,7 @@ subroutine ShowPassedData() call WrScr(" NumMeshPts_C "//trim(Num2LStr( NumMeshPts_C )) ) call WrScr("-----------------------------------------------------------") end subroutine ShowPassedData -end subroutine ADI_C_GetRotorLoads - +end subroutine ADI_C_GetRotorLoads !=================================================================================================================================== @@ -1820,24 +1886,27 @@ end subroutine ADI_C_GetRotorLoads !> This routine is operating on module level data. Error handling here in case checks added !! NOTE: the OriginInit is not included in the data passed in and must be added to the the position info here subroutine Set_MotionMesh(iWT, ErrStat3, ErrMsg3) - integer(IntKi), intent(in ) :: iWT !< current rotor/turbine + integer(IntKi), intent(in ) :: iWT !< current rotor/turbine integer(IntKi), intent( out) :: ErrStat3 character(ErrMsgLen), intent( out) :: ErrMsg3 - integer(IntKi) :: iNode + integer(IntKi) :: iBlade !< current blade + integer(IntKi) :: j !< generic index variables + ErrStat3 = 0_IntKi ErrMsg3 = '' ! Set mesh corresponding to input motions - do iNode=1,NumMeshPts(iWT) - BldPtMotionMesh(iWT)%TranslationDisp(1:3,iNode) = tmpBldPtMeshPos(1:3,iNode) + Sim%WT(iWT)%OriginInit(1:3) - real(BldPtMotionMesh(iWT)%Position(1:3,iNode), R8Ki) - BldPtMotionMesh(iWT)%Orientation(1:3,1:3,iNode) = tmpBldPtMeshOri(1:3,1:3,iNode) - BldPtMotionMesh(iWT)%TranslationVel( 1:3,iNode) = tmpBldPtMeshVel(1:3,iNode) - BldPtMotionMesh(iWT)%RotationVel( 1:3,iNode) = tmpBldPtMeshVel(4:6,iNode) - BldPtMotionMesh(iWT)%TranslationAcc( 1:3,iNode) = tmpBldPtMeshAcc(1:3,iNode) - !BldPtMotionMesh(iWT)%RotationAcc( 1:3,iNode) = tmpBldPtMeshAcc(4:6,iNode) ! Rotational acc not included - call OrientRemap(BldPtMotionMesh(iWT)%Orientation(1:3,1:3,iNode)) - if (TransposeDCM) then - BldPtMotionMesh(iWT)%Orientation(1:3,1:3,iNode) = transpose(BldPtMotionMesh(iWT)%Orientation(1:3,1:3,iNode)) - endif + do iBlade=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(iBlade) + BldPtMotionMesh(iWT)%Mesh(iBlade)%TranslationDisp(1:3,j) = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Position(1:3,j) + Sim%WT(iWT)%OriginInit(1:3) - real(BldPtMotionMesh(iWT)%Mesh(iBlade)%Position(1:3,j), R8Ki) + BldPtMotionMesh(iWT)%Mesh(iBlade)%Orientation(1:3,1:3,j) = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Orient(1:3,1:3,j) + BldPtMotionMesh(iWT)%Mesh(iBlade)%TranslationVel( 1:3,j) = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Velocity(1:3,j) + BldPtMotionMesh(iWT)%Mesh(iBlade)%RotationVel( 1:3,j) = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Velocity(4:6,j) + BldPtMotionMesh(iWT)%Mesh(iBlade)%TranslationAcc( 1:3,j) = StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Accln(1:3,j) + call OrientRemap(BldPtMotionMesh(iWT)%Mesh(iBlade)%Orientation(1:3,1:3,j)) + if (TransposeDCM) then + BldPtMotionMesh(iWT)%Mesh(iBlade)%Orientation(1:3,1:3,j) = transpose(BldPtMotionMesh(iWT)%Mesh(iBlade)%Orientation(1:3,1:3,j)) + endif + enddo enddo end subroutine Set_MotionMesh @@ -1849,7 +1918,7 @@ subroutine AD_SetInputMotion( iWT, u_local, & NacPos_C, NacOri_C, NacVel_C, NacAcc_C, & BldRootPos_C, BldRootOri_C, BldRootVel_C, BldRootAcc_C, & ErrStat, ErrMsg ) - integer(IntKi), intent(in ) :: iWT !< this turbine + integer(IntKi), intent(in ) :: iWT !< this turbine type(ADI_InputType), intent(inout) :: u_local ! Only one input (probably at T) real(c_float), intent(in ) :: HubPos_C( 3 ) !< Hub position real(c_double), intent(in ) :: HubOri_C( 9 ) !< Hub orientation @@ -1865,9 +1934,12 @@ subroutine AD_SetInputMotion( iWT, u_local, & real(c_float), intent(in ) :: BldRootAcc_C( 6*Sim%WT(iWT)%NumBlades ) !< Blade root accelerations integer(IntKi), intent( out) :: ErrStat character(ErrMsgLen), intent( out) :: ErrMsg - integer(IntKi) :: i + integer(IntKi) :: iBlade !< current blade + integer(IntKi) :: i,j !< generic index variables + integer(IntKi) :: n_elems !< number of elements in the mesh ErrStat = 0_IntKi ErrMsg = '' + ! Hub -- NOTE: RotationalAcc not present in the mesh if ( u_local%AD%rotors(iWT)%HubMotion%Committed ) then u_local%AD%rotors(iWT)%HubMotion%TranslationDisp(1:3,1) = real(HubPos_C(1:3),R8Ki) + Sim%WT(iWT)%OriginInit(1:3) - real(u_local%AD%rotors(iWT)%HubMotion%Position(1:3,1), R8Ki) @@ -1880,6 +1952,7 @@ subroutine AD_SetInputMotion( iWT, u_local, & u_local%AD%rotors(iWT)%HubMotion%Orientation(1:3,1:3,1) = transpose(u_local%AD%rotors(iWT)%HubMotion%Orientation(1:3,1:3,1)) endif endif + ! Nacelle -- NOTE: RotationalVel and RotationalAcc not present in the mesh if ( u_local%AD%rotors(iWT)%NacelleMotion%Committed ) then u_local%AD%rotors(iWT)%NacelleMotion%TranslationDisp(1:3,1) = real(NacPos_C(1:3),R8Ki) + Sim%WT(iWT)%OriginInit(1:3) - real(u_local%AD%rotors(iWT)%NacelleMotion%Position(1:3,1), R8Ki) @@ -1891,6 +1964,7 @@ subroutine AD_SetInputMotion( iWT, u_local, & u_local%AD%rotors(iWT)%NacelleMotion%Orientation(1:3,1:3,1) = transpose(u_local%AD%rotors(iWT)%NacelleMotion%Orientation(1:3,1:3,1)) endif endif + ! Blade root do i=0,Sim%WT(iWT)%numBlades-1 if ( u_local%AD%rotors(iWT)%BladeRootMotion(i+1)%Committed ) then @@ -1908,9 +1982,10 @@ subroutine AD_SetInputMotion( iWT, u_local, & enddo ! Blade mesh - do i=1,Sim%WT(iWT)%numBlades - if ( u_local%AD%rotors(iWT)%BladeMotion(i)%Committed ) then - call Transfer_Point_to_Line2( BldPtMotionMesh(iWT), u_local%AD%rotors(iWT)%BladeMotion(i), Map_BldPtMotion_2_AD_Blade(i,iWT), ErrStat, ErrMsg ) + do iBlade=1,Sim%WT(iWT)%numBlades + n_elems = size(BldPtMotionMesh(iWT)%Mesh(iBlade)%Position, 2) + if (( u_local%AD%rotors(iWT)%BladeMotion(iBlade)%Committed ) .and. (n_elems > 0)) then + call Transfer_Point_to_Line2( BldPtMotionMesh(iWT)%Mesh(iBlade), u_local%AD%rotors(iWT)%BladeMotion(iBlade), Map_BldPtMotion_2_AD_Blade(i,iWT), ErrStat, ErrMsg ) if (ErrStat >= AbortErrLev) return endif enddo @@ -1919,36 +1994,51 @@ end subroutine AD_SetInputMotion !> Map the loads of the output mesh to the intermediate output mesh. !! This routine is operating on module level data, hence few inputs subroutine AD_TransferLoads( iWT, u_local, y_local, ErrStat3, ErrMsg3 ) - integer(IntKi), intent(in ) :: iWT !< this turbine - type(ADI_InputType), intent(in ) :: u_local ! Only one input (probably at T) - type(ADI_OutputType), intent(in ) :: y_local ! Only one input (probably at T) + integer(IntKi), intent(in ) :: iWT !< Current rotor/turbine + type(ADI_InputType), intent(in ) :: u_local !< Only one input (probably at T) + type(ADI_OutputType), intent(in ) :: y_local !< Only one input (probably at T) integer(IntKi), intent( out) :: ErrStat3 character(ErrMsgLen), intent( out) :: ErrMsg3 - integer(IntKi) :: i - BldPtLoadMesh(iWT)%Force = 0.0_ReKi - BldPtLoadMesh(iWT)%Moment = 0.0_ReKi - do i=1,Sim%WT(iWT)%NumBlades - if ( y_local%AD%rotors(iWT)%BladeLoad(i)%Committed ) then - if (debugverbose > 4) call MeshPrintInfo( CU, y_local%AD%rotors(iWT)%BladeLoad(i), MeshName='AD%rotors('//trim(Num2LStr(1))//')%BladeLoad('//trim(Num2LStr(i))//')' ) - call Transfer_Line2_to_Point( ADI%y%AD%rotors(iWT)%BladeLoad(i), BldPtLoadMesh_tmp(iWT), Map_AD_BldLoad_P_2_BldPtLoad(i,iWT), & - ErrStat3, ErrMsg3, u_local%AD%rotors(iWT)%BladeMotion(i), BldPtMotionMesh(iWT) ) - if (ErrStat3 >= AbortErrLev) return - BldPtLoadMesh(iWT)%Force = BldPtLoadMesh(iWT)%Force + BldPtLoadMesh_tmp(iWT)%Force - BldPtLoadMesh(iWT)%Moment = BldPtLoadMesh(iWT)%Moment + BldPtLoadMesh_tmp(iWT)%Moment + integer(IntKi) :: iBlade !< current blade + integer(IntKi) :: n_elems !< number of elements in the mesh + + + do iBlade=1,Sim%WT(iWT)%NumBlades + n_elems = size(BldPtMotionMesh(iWT)%Mesh(iBlade)%Position, 2) + if (n_elems > 0) then + BldPtLoadMesh(iWT)%Mesh(iBlade)%Force = 0.0_ReKi + BldPtLoadMesh(iWT)%Mesh(iBlade)%Moment = 0.0_ReKi endif enddo - if (debugverbose > 4) call MeshPrintInfo( CU, BldPtLoadMesh(iWT), MeshName='BldPtLoadMesh'//trim(Num2LStr(iWT)) ) + + do iBlade=1,Sim%WT(iWT)%NumBlades + if ( y_local%AD%rotors(iWT)%BladeLoad(iBlade)%Committed ) then + if (debugverbose > 4) call MeshPrintInfo( CU, y_local%AD%rotors(iWT)%BladeLoad(iBlade), MeshName='AD%rotors('//trim(Num2LStr(iWT))//')%BladeLoad('//trim(Num2LStr(iBlade))//')' ) + n_elems = size(BldPtMotionMesh(iWT)%Mesh(iBlade)%Position, 2) + if (n_elems > 0) then + call Transfer_Line2_to_Point( ADI%y%AD%rotors(iWT)%BladeLoad(iBlade), BldPtLoadMesh_tmp(iWT)%Mesh(iBlade), Map_AD_BldLoad_P_2_BldPtLoad(iBlade,iWT), & + ErrStat3, ErrMsg3, u_local%AD%rotors(iWT)%BladeMotion(iBlade), BldPtMotionMesh(iWT)%Mesh(iBlade) ) + if (ErrStat3 >= AbortErrLev) return + BldPtLoadMesh(iWT)%Mesh(iBlade)%Force = BldPtLoadMesh(iWT)%Mesh(iBlade)%Force + BldPtLoadMesh_tmp(iWT)%Mesh(iBlade)%Force + BldPtLoadMesh(iWT)%Mesh(iBlade)%Moment = BldPtLoadMesh(iWT)%Mesh(iBlade)%Moment + BldPtLoadMesh_tmp(iWT)%Mesh(iBlade)%Moment + endif + endif + if (debugverbose > 4) call MeshPrintInfo( CU, BldPtLoadMesh(iWT)%Mesh(iBlade), MeshName='BldPtLoadMesh'//trim(Num2LStr(iWT))//'_'//trim(Num2LStr(iBlade)) ) + enddo end subroutine AD_TransferLoads !> Transfer the loads from the load mesh to the temporary array for output !! This routine is operating on module level data, hence few inputs subroutine Set_OutputLoadArray(iWT) integer(IntKi), intent(in ) :: iWT !< current rotor/turbine - integer(IntKi) :: iNode + integer(IntKi) :: iBlade !< current blade + integer(IntKi) :: j !< generic index variables ! Set mesh corresponding to input motions - do iNode=1,NumMeshPts(iWT) - tmpBldPtMeshFrc(1:3,iNode) = BldPtLoadMesh(iWT)%Force (1:3,iNode) - tmpBldPtMeshFrc(4:6,iNode) = BldPtLoadMesh(iWT)%Moment(1:3,iNode) + do iBlade=1,Sim%WT(iWT)%NumBlades + do j=1,StrucPts_2_Bld_Map(iWT)%NumMeshPtsPerBlade(iBlade) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Force(1:3,j) = BldPtLoadMesh(iWT)%Mesh(iBlade)%Force( 1:3,j) + StrucPts_2_Bld_Map(iWT)%BladePtMeshCoords(iBlade)%Force(4:6,j) = BldPtLoadMesh(iWT)%Mesh(iBlade)%Moment(1:3,j) + enddo enddo end subroutine Set_OutputLoadArray @@ -1976,7 +2066,7 @@ subroutine WrVTK_refMeshes(rot_u, RefPoint, ErrStat, ErrMsg) integer(IntKi), intent( out) :: ErrStat !< error status character(ErrMsgLen), intent( out) :: ErrMsg !< error message integer(IntKi) :: nBlades - integer(IntKi) :: iWT, nWT, k + integer(IntKi) :: iWT, nWT, iBlade character(*), parameter :: RoutineName = 'WrVTK_refMeshes' !< for error handling integer(IntKi) :: ErrStat2 !< temporary error status character(ErrMsgLen) :: ErrMsg2 !< temporary error message @@ -1993,7 +2083,7 @@ subroutine WrVTK_refMeshes(rot_u, RefPoint, ErrStat, ErrMsg) else sWT = '.T'//trim(num2lstr(iWT)) endif - + select case (WrOutputsData%WrVTK_Type) case (1) ! surfaces -- don't write any surface references call WrVTK_PointsRef( ErrStat2,ErrMsg2); if (Failed()) return; @@ -2005,6 +2095,7 @@ subroutine WrVTK_refMeshes(rot_u, RefPoint, ErrStat, ErrMsg) call WrVTK_LinesRef( ErrStat2,ErrMsg2); if (Failed()) return; end select enddo + contains logical function Failed() CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -2019,20 +2110,22 @@ subroutine WrVTK_PointsRef(ErrStat3,ErrMsg3) ErrMsg3 = '' ! Blade point motion (structural mesh from driver) - call MeshWrVTKreference(RefPoint, BldPtMotionMesh(iWT), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldPtMotionMesh', ErrStat3, ErrMsg3) - if (ErrStat3 >= AbortErrLev) return + do iBlade=1,Sim%WT(iWT)%NumBlades + call MeshWrVTKreference(RefPoint, BldPtMotionMesh(iWT)%Mesh(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldPtMotionMesh', ErrStat3, ErrMsg3) + if (ErrStat3 >= AbortErrLev) return + enddo ! Blade root motion (point only) if (allocated(rot_u(iWT)%BladeRootMotion)) then - do k=1,Sim%WT(iWT)%NumBlades - if (rot_u(iWT)%BladeRootMotion(k)%Committed) then - call MeshWrVTKreference(RefPoint, rot_u(iWT)%BladeRootMotion(k), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(k)), ErrStat3, ErrMsg3 ) + do iBlade=1,Sim%WT(iWT)%NumBlades + if (rot_u(iWT)%BladeRootMotion(iBlade)%Committed) then + call MeshWrVTKreference(RefPoint, rot_u(iWT)%BladeRootMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(iBlade)), ErrStat3, ErrMsg3 ) if (ErrStat3 >= AbortErrLev) return endif enddo endif - ! Nacelle (structural point input + ! Nacelle (structural point input) if ( rot_u(iWT)%NacelleMotion%Committed ) call MeshWrVTKreference(RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.NacelleMotion', ErrStat3, ErrMsg3) if (ErrStat3 >= AbortErrLev) return end subroutine WrVTK_PointsRef @@ -2058,9 +2151,9 @@ subroutine WrVTK_LinesRef(ErrStat3,ErrMsg3) ! Blades if (allocated(rot_u(iWT)%BladeMotion)) then - do k=1,Sim%WT(iWT)%NumBlades - if (rot_u(iWT)%BladeMotion(k)%Committed) then - call MeshWrVTKreference(RefPoint, rot_u(iWT)%BladeMotion(k), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(k)), ErrStat3, ErrMsg3 ) + do iBlade=1,Sim%WT(iWT)%NumBlades + if (rot_u(iWT)%BladeMotion(iBlade)%Committed) then + call MeshWrVTKreference(RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade)), ErrStat3, ErrMsg3 ) if (ErrStat3 >= AbortErrLev) return endif enddo @@ -2076,7 +2169,7 @@ subroutine WrVTK_Meshes(rot_u, RefPoint, ErrStat, ErrMsg) integer(IntKi), intent( out) :: ErrStat !< error status character(ErrMsgLen), intent( out) :: ErrMsg !< error message integer(IntKi) :: nBlades - integer(IntKi) :: iWT, nWT, k + integer(IntKi) :: iWT, nWT, iBlade character(IntfStrLen) :: TmpFileName character(*), parameter :: RoutineName = 'WrVTK_Meshes' !< for error handling integer(IntKi) :: ErrStat2 !< temporary error status @@ -2094,7 +2187,7 @@ subroutine WrVTK_Meshes(rot_u, RefPoint, ErrStat, ErrMsg) else sWT = '.T'//trim(num2lstr(iWT)) endif - + select case (WrOutputsData%WrVTK_Type) case (1) ! surfaces call WrVTK_Points( ErrStat2,ErrMsg2); if (Failed()) return; @@ -2124,14 +2217,16 @@ subroutine WrVTK_Points(ErrStat3,ErrMsg3) ErrMsg3 = '' ! Blade point motion (structural mesh from driver) - call MeshWrVTK(RefPoint, BldPtMotionMesh(iWT), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldPtMotionMesh', n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) - if (ErrStat3 >= AbortErrLev) return + do iBlade=1,Sim%WT(iWT)%NumBlades + call MeshWrVTK(RefPoint, BldPtMotionMesh(iWT)%Mesh(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldPtMotionMesh'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + if (ErrStat3 >= AbortErrLev) return + enddo ! Blade root motion (point only) if (allocated(rot_u(iWT)%BladeRootMotion)) then - do k=1,Sim%WT(iWT)%NumBlades - if (rot_u(iWT)%BladeRootMotion(k)%Committed) then - call MeshWrVTK(RefPoint, rot_u(iWT)%BladeRootMotion(k), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(k)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + do iBlade=1,Sim%WT(iWT)%NumBlades + if (rot_u(iWT)%BladeRootMotion(iBlade)%Committed) then + call MeshWrVTK(RefPoint, rot_u(iWT)%BladeRootMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return endif enddo @@ -2159,8 +2254,8 @@ subroutine WrVTK_Surfaces(ErrStat3,ErrMsg3) ErrStat3 = 0_IntKi ErrMsg3 = '' -!TODO: use this routine when it is moved out of the driver and into ADI -! call AD_WrVTK_Surfaces(ADI%u(1)%AD, ADI%y%AD, RefPoint, ADI%m%VTK_Surfaces, n_Global, WrOutputsData%Root, WrOutputsData%VTK_tWidth, 25, WrOutputsData%VTKHubRad) + ! TODO: use this routine when it is moved out of the driver and into ADI + ! call AD_WrVTK_Surfaces(ADI%u(1)%AD, ADI%y%AD, RefPoint, ADI%m%VTK_Surfaces, n_Global, WrOutputsData%Root, WrOutputsData%VTK_tWidth, 25, WrOutputsData%VTKHubRad) ! Nacelle if ( rot_u(iWT)%NacelleMotion%Committed ) then @@ -2186,11 +2281,11 @@ subroutine WrVTK_Surfaces(ErrStat3,ErrMsg3) ! Blades if (allocated(rot_u(iWT)%BladeMotion)) then - do k=1,Sim%WT(iWT)%NumBlades - if (rot_u(iWT)%BladeMotion(k)%Committed) then - call MeshWrVTK_Ln2Surface (RefPoint, rot_u(iWT)%BladeMotion(k), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(k))//'Surface', & - n_Global, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth , verts=ADI%m%VTK_Surfaces(iWT)%BladeShape(k)%AirfoilCoords, & - Sib=ADI%y%AD%rotors(iWT)%BladeLoad(k) ) + do iBlade=1,Sim%WT(iWT)%NumBlades + if (rot_u(iWT)%BladeMotion(iBlade)%Committed) then + call MeshWrVTK_Ln2Surface (RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade))//'Surface', & + n_Global, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth , verts=ADI%m%VTK_Surfaces(iWT)%BladeShape(iBlade)%AirfoilCoords, & + Sib=ADI%y%AD%rotors(iWT)%BladeLoad(iBlade) ) if (ErrStat3 >= AbortErrLev) return endif enddo @@ -2218,9 +2313,9 @@ subroutine WrVTK_Lines(ErrStat3,ErrMsg3) ! Blades if (allocated(rot_u(iWT)%BladeMotion)) then - do k=1,Sim%WT(iWT)%NumBlades - if (rot_u(iWT)%BladeMotion(k)%Committed) then - call MeshWrVTK(RefPoint, rot_u(iWT)%BladeMotion(k), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(k)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + do iBlade=1,Sim%WT(iWT)%NumBlades + if (rot_u(iWT)%BladeMotion(iBlade)%Committed) then + call MeshWrVTK(RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return endif enddo @@ -2250,7 +2345,7 @@ subroutine WrVTK_Ground (RefPoint, HalfLengths, FileRootName, errStat, errMsg) errStat = ErrID_None errMsg = "" FileName = TRIM(FileRootName)//'.vtp' - call WrVTK_header( FileName, NumberOfPoints, NumberOfLines, NumberOfPolys, Un, errStat2, errMsg2 ) + call WrVTK_header( FileName, NumberOfPoints, NumberOfLines, NumberOfPolys, Un, errStat2, errMsg2 ) call SetErrStat(errStat2,errMsg2,errStat,errMsg,'WrVTK_Ground'); if (errStat >= AbortErrLev) return WRITE(Un,'(A)') ' ' WRITE(Un,'(A)') ' ' @@ -2260,16 +2355,16 @@ subroutine WrVTK_Ground (RefPoint, HalfLengths, FileRootName, errStat, errMsg) WRITE(Un,VTK_AryFmt) RefPoint(1) - HalfLengths(1) , RefPoint(2) + HalfLengths(2), RefPoint(3) WRITE(Un,'(A)') ' ' WRITE(Un,'(A)') ' ' - WRITE(Un,'(A)') ' ' - WRITE(Un,'(A)') ' ' - WRITE(Un,'('//trim(num2lstr(NumberOfPoints))//'(i7))') (ix, ix=0,NumberOfPoints-1) - WRITE(Un,'(A)') ' ' - - WRITE(Un,'(A)') ' ' + WRITE(Un,'(A)') ' ' + WRITE(Un,'(A)') ' ' + WRITE(Un,'('//trim(num2lstr(NumberOfPoints))//'(i7))') (ix, ix=0,NumberOfPoints-1) + WRITE(Un,'(A)') ' ' + + WRITE(Un,'(A)') ' ' WRITE(Un,'(i7)') NumberOfPoints WRITE(Un,'(A)') ' ' - WRITE(Un,'(A)') ' ' - call WrVTK_footer( Un ) + WRITE(Un,'(A)') ' ' + call WrVTK_footer( Un ) end subroutine WrVTK_Ground @@ -2278,7 +2373,6 @@ end subroutine WrVTK_Ground subroutine SetTempStorage(ErrStat,ErrMsg) INTEGER(IntKi), intent(out) :: errStat !< Indicates whether an error occurred (see NWTC_Library) character(*), intent(out) :: errMsg !< Error message associated with the errStat - integer(IntKi) :: maxMeshPts, iWT INTEGER(IntKi) :: errStat2 CHARACTER(ErrMsgLen) :: errMsg2 character(*), parameter :: RoutineName = 'SetTempStorage' !< for error handling @@ -2288,28 +2382,12 @@ subroutine SetTempStorage(ErrStat,ErrMsg) ErrStat = ErrID_Fatal ErrMSg = "Pre-Init has not been called yet" return - endif + endif if (minval(NumMeshPts) < 0) then ErrStat = ErrID_Fatal ErrMSg = "ADI_C_SetupRotor haven't been called for all rotors" return - endif - - ! Allocate temporary arrays to simplify data conversions - maxMeshPts=0_IntKi - do iWT=1,Sim%NumTurbines - maxMeshPts=max(maxMeshPts,NumMeshPts(iWT)) - enddo - if ( allocated(tmpBldPtMeshPos) ) deallocate(tmpBldPtMeshPos) - if ( allocated(tmpBldPtMeshOri) ) deallocate(tmpBldPtMeshOri) - if ( allocated(tmpBldPtMeshVel) ) deallocate(tmpBldPtMeshVel) - if ( allocated(tmpBldPtMeshAcc) ) deallocate(tmpBldPtMeshAcc) - if ( allocated(tmpBldPtMeshFrc) ) deallocate(tmpBldPtMeshFrc) - call AllocAry( tmpBldPtMeshPos, 3, maxMeshPts, "tmpBldPtMeshPos", ErrStat2, ErrMsg2 ); if (Failed()) return - call AllocAry( tmpBldPtMeshOri, 3, 3, maxMeshPts, "tmpBldPtMeshOri", ErrStat2, ErrMsg2 ); if (Failed()) return - call AllocAry( tmpBldPtMeshVel, 6, maxMeshPts, "tmpBldPtMeshVel", ErrStat2, ErrMsg2 ); if (Failed()) return - call AllocAry( tmpBldPtMeshAcc, 6, maxMeshPts, "tmpBldPtMeshAcc", ErrStat2, ErrMsg2 ); if (Failed()) return - call AllocAry( tmpBldPtMeshFrc, 6, maxMeshPts, "tmpBldPtMeshFrc", ErrStat2, ErrMsg2 ); if (Failed()) return + endif contains logical function Failed() @@ -2318,26 +2396,21 @@ logical function Failed() end function Failed end subroutine SetTempStorage - +!-------------------------------------------------------------------- +!> Don't leave junk in memory. So destroy meshes and mappings. subroutine ClearTmpStorage() - INTEGER(IntKi) :: errStat2 + INTEGER(IntKi) :: errStat2, iWT CHARACTER(ErrMsgLen) :: errMsg2 - ! Arrays - if (allocated(tmpBldPtMeshPos)) deallocate(tmpBldPtMeshPos) - if (allocated(tmpBldPtMeshOri)) deallocate(tmpBldPtMeshOri) - if (allocated(tmpBldPtMeshVel)) deallocate(tmpBldPtMeshVel) - if (allocated(tmpBldPtMeshAcc)) deallocate(tmpBldPtMeshAcc) - if (allocated(tmpBldPtMeshFrc)) deallocate(tmpBldPtMeshFrc) ! Meshes - if (allocated(BldPtMotionMesh )) call ClearMeshArr1(BldPtMotionMesh ) - if (allocated(BldPtLoadMesh )) call ClearMeshArr1(BldPtLoadMesh ) - if (allocated(BldPtLoadMesh_tmp)) call ClearMeshArr1(BldPtLoadMesh_tmp) - !if (allocated(NacMotionMesh )) call ClearMeshArr1(NacMotionMesh ) - !if (allocated(NacLoadMesh )) call ClearMeshArr1(NacLoadMesh ) + do iWT=1,Sim%NumTurbines + if (allocated(BldPtMotionMesh(iWT)%Mesh)) call ClearMeshArr1(BldPtMotionMesh(iWT)%Mesh) + if (allocated(BldPtLoadMesh(iWT)%Mesh)) call ClearMeshArr1(BldPtLoadMesh(iWT)%Mesh) + if (allocated(BldPtLoadMesh_tmp(iWT)%Mesh)) call ClearMeshArr1(BldPtLoadMesh_tmp(iWT)%Mesh) + enddo + ! if (allocated(NacMotionMesh )) call ClearMeshArr1(NacMotionMesh ) + ! if (allocated(NacLoadMesh )) call ClearMeshArr1(NacLoadMesh ) if (allocated(Map_BldPtMotion_2_AD_Blade )) call ClearMeshMapArr2(Map_BldPtMotion_2_AD_Blade ) - if (allocated(Map_AD_BldLoad_P_2_BldPtLoad)) call ClearMeshMapArr2(Map_AD_BldLoad_P_2_BldPtLoad) contains - !> Don't leave junk in memory. So destroy meshes and mappings. subroutine ClearMeshArr1(MeshName) type(MeshType), allocatable :: MeshName(:) integer :: i diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 2cf0ea4ac4..b981e8cf72 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -55,6 +55,11 @@ typedef ^ TFinParameterType ReKi TFinChord - - - "Tail fin chord [u typedef ^ TFinParameterType ReKi TFinArea - - - "Tail fin planform area [used only when TFinMod=1]" m^2 typedef ^ TFinParameterType IntKi TFinIndMod - - - "Model for induced velocity calculation {0=none, 1=rotor-average}" (switch) typedef ^ TFinParameterType IntKi TFinAFID - - - "Index of Tail fin airfoil number [1 to NumAFfiles]" - +typedef ^ TFinParameterType ReKi TFinKp - - - "Tail fin potential lift coefficient for unsteady aerodynamics [used only when TFMod=2]" - +typedef ^ TFinParameterType ReKi TFinSigma 3 - - "Tail fin empirical constants characterizing the decay of separation functions [used only when TFMod=2]" - +typedef ^ TFinParameterType ReKi TFinAStar 3 - - "Tail fin characteristics angles for separation functions [used only when TFMod=2]" deg +typedef ^ TFinParameterType ReKi TFinKv - - - "Tail fin vortex lift coefficient for unsteady aerodynamics [used only when TFMod=2]" - +typedef ^ TFinParameterType ReKi TFinCDc - - - "Tail fin drag coefficient for unsteady aerodynamics [used only when TFMod=2]" - # Tail Fin input file typedef ^ TFinInputFileType IntKi TFinMod - - 0 "Tail fin aerodynamics model {0=none, 1=polar-based, 2=USB-based}" (switch) @@ -64,6 +69,11 @@ typedef ^ TFinInputFileType ReKi TFinRefP_n 3 - - "Undeflected posit typedef ^ TFinInputFileType ReKi TFinAngles 3 - - "Tail fin chordline skew, tilt, and bank angles about the reference point" (deg) typedef ^ TFinInputFileType IntKi TFinIndMod - - - "Model for induced velocity calculation {0=none, 1=rotor-average}" (switch) typedef ^ TFinInputFileType IntKi TFinAFID - - - "Index of Tail fin airfoil number [1 to NumAFfiles]" - +typedef ^ TFinInputFileType ReKi TFinKp - - - "Tail fin potential lift coefficient for unsteady aerodynamics [used only when TFMod=2]" - +typedef ^ TFinInputFileType ReKi TFinSigma 3 - - "Tail fin empirical constants characterizing the decay of separation functions [used only when TFMod=2]" - +typedef ^ TFinInputFileType ReKi TFinAStar 3 - - "Tail fin characteristics angles for separation functions [used only when TFMod=2]" deg +typedef ^ TFinInputFileType ReKi TFinKv - - - "Tail fin vortex lift coefficient for unsteady aerodynamics [used only when TFMod=2]" - +typedef ^ TFinInputFileType ReKi TFinCDc - - - "Tail fin drag coefficient for unsteady aerodynamics [used only when TFMod=2]" - @@ -141,6 +151,7 @@ typedef ^ RotInitOutputType ReKi TwrDiam {:} - - "Diameter of tower at node" m typedef ^ InitOutputType RotInitOutputType rotors {:} - - "Rotor init output type" - typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - +typedef ^ InitOutputType IntKi nNodesVel - - - "number of nodes velocity values are needed at (for ExtLoads coupling)" - # ..... Input file data ........................................................................................................... # ..... Primary Input file data ................................................................................................... diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 1204d8f96e..f06dca2366 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -67,6 +67,11 @@ MODULE AeroDyn_Types REAL(ReKi) :: TFinArea = 0.0_ReKi !< Tail fin planform area [used only when TFinMod=1] [m^2] INTEGER(IntKi) :: TFinIndMod = 0_IntKi !< Model for induced velocity calculation {0=none, 1=rotor-average} [(switch)] INTEGER(IntKi) :: TFinAFID = 0_IntKi !< Index of Tail fin airfoil number [1 to NumAFfiles] [-] + REAL(ReKi) :: TFinKp = 0.0_ReKi !< Tail fin potential lift coefficient for unsteady aerodynamics [used only when TFMod=2] [-] + REAL(ReKi) , DIMENSION(1:3) :: TFinSigma = 0.0_ReKi !< Tail fin empirical constants characterizing the decay of separation functions [used only when TFMod=2] [-] + REAL(ReKi) , DIMENSION(1:3) :: TFinAStar = 0.0_ReKi !< Tail fin characteristics angles for separation functions [used only when TFMod=2] [deg] + REAL(ReKi) :: TFinKv = 0.0_ReKi !< Tail fin vortex lift coefficient for unsteady aerodynamics [used only when TFMod=2] [-] + REAL(ReKi) :: TFinCDc = 0.0_ReKi !< Tail fin drag coefficient for unsteady aerodynamics [used only when TFMod=2] [-] END TYPE TFinParameterType ! ======================= ! ========= TFinInputFileType ======= @@ -78,6 +83,11 @@ MODULE AeroDyn_Types REAL(ReKi) , DIMENSION(1:3) :: TFinAngles = 0.0_ReKi !< Tail fin chordline skew, tilt, and bank angles about the reference point [(deg)] INTEGER(IntKi) :: TFinIndMod = 0_IntKi !< Model for induced velocity calculation {0=none, 1=rotor-average} [(switch)] INTEGER(IntKi) :: TFinAFID = 0_IntKi !< Index of Tail fin airfoil number [1 to NumAFfiles] [-] + REAL(ReKi) :: TFinKp = 0.0_ReKi !< Tail fin potential lift coefficient for unsteady aerodynamics [used only when TFMod=2] [-] + REAL(ReKi) , DIMENSION(1:3) :: TFinSigma = 0.0_ReKi !< Tail fin empirical constants characterizing the decay of separation functions [used only when TFMod=2] [-] + REAL(ReKi) , DIMENSION(1:3) :: TFinAStar = 0.0_ReKi !< Tail fin characteristics angles for separation functions [used only when TFMod=2] [deg] + REAL(ReKi) :: TFinKv = 0.0_ReKi !< Tail fin vortex lift coefficient for unsteady aerodynamics [used only when TFMod=2] [-] + REAL(ReKi) :: TFinCDc = 0.0_ReKi !< Tail fin drag coefficient for unsteady aerodynamics [used only when TFMod=2] [-] END TYPE TFinInputFileType ! ======================= ! ========= AD_VTK_BLSurfaceType ======= @@ -169,6 +179,7 @@ MODULE AeroDyn_Types TYPE, PUBLIC :: AD_InitOutputType TYPE(RotInitOutputType) , DIMENSION(:), ALLOCATABLE :: rotors !< Rotor init output type [-] TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] + INTEGER(IntKi) :: nNodesVel = 0_IntKi !< number of nodes velocity values are needed at (for ExtLoads coupling) [-] END TYPE AD_InitOutputType ! ======================= ! ========= RotInputFile ======= @@ -523,6 +534,11 @@ subroutine AD_CopyTFinParameterType(SrcTFinParameterTypeData, DstTFinParameterTy DstTFinParameterTypeData%TFinArea = SrcTFinParameterTypeData%TFinArea DstTFinParameterTypeData%TFinIndMod = SrcTFinParameterTypeData%TFinIndMod DstTFinParameterTypeData%TFinAFID = SrcTFinParameterTypeData%TFinAFID + DstTFinParameterTypeData%TFinKp = SrcTFinParameterTypeData%TFinKp + DstTFinParameterTypeData%TFinSigma = SrcTFinParameterTypeData%TFinSigma + DstTFinParameterTypeData%TFinAStar = SrcTFinParameterTypeData%TFinAStar + DstTFinParameterTypeData%TFinKv = SrcTFinParameterTypeData%TFinKv + DstTFinParameterTypeData%TFinCDc = SrcTFinParameterTypeData%TFinCDc end subroutine subroutine AD_DestroyTFinParameterType(TFinParameterTypeData, ErrStat, ErrMsg) @@ -544,6 +560,11 @@ subroutine AD_PackTFinParameterType(RF, Indata) call RegPack(RF, InData%TFinArea) call RegPack(RF, InData%TFinIndMod) call RegPack(RF, InData%TFinAFID) + call RegPack(RF, InData%TFinKp) + call RegPack(RF, InData%TFinSigma) + call RegPack(RF, InData%TFinAStar) + call RegPack(RF, InData%TFinKv) + call RegPack(RF, InData%TFinCDc) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -557,6 +578,11 @@ subroutine AD_UnPackTFinParameterType(RF, OutData) call RegUnpack(RF, OutData%TFinArea); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinIndMod); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinAFID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinKp); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinSigma); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinAStar); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinKv); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinCDc); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyTFinInputFileType(SrcTFinInputFileTypeData, DstTFinInputFileTypeData, CtrlCode, ErrStat, ErrMsg) @@ -575,6 +601,11 @@ subroutine AD_CopyTFinInputFileType(SrcTFinInputFileTypeData, DstTFinInputFileTy DstTFinInputFileTypeData%TFinAngles = SrcTFinInputFileTypeData%TFinAngles DstTFinInputFileTypeData%TFinIndMod = SrcTFinInputFileTypeData%TFinIndMod DstTFinInputFileTypeData%TFinAFID = SrcTFinInputFileTypeData%TFinAFID + DstTFinInputFileTypeData%TFinKp = SrcTFinInputFileTypeData%TFinKp + DstTFinInputFileTypeData%TFinSigma = SrcTFinInputFileTypeData%TFinSigma + DstTFinInputFileTypeData%TFinAStar = SrcTFinInputFileTypeData%TFinAStar + DstTFinInputFileTypeData%TFinKv = SrcTFinInputFileTypeData%TFinKv + DstTFinInputFileTypeData%TFinCDc = SrcTFinInputFileTypeData%TFinCDc end subroutine subroutine AD_DestroyTFinInputFileType(TFinInputFileTypeData, ErrStat, ErrMsg) @@ -598,6 +629,11 @@ subroutine AD_PackTFinInputFileType(RF, Indata) call RegPack(RF, InData%TFinAngles) call RegPack(RF, InData%TFinIndMod) call RegPack(RF, InData%TFinAFID) + call RegPack(RF, InData%TFinKp) + call RegPack(RF, InData%TFinSigma) + call RegPack(RF, InData%TFinAStar) + call RegPack(RF, InData%TFinKv) + call RegPack(RF, InData%TFinCDc) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -613,6 +649,11 @@ subroutine AD_UnPackTFinInputFileType(RF, OutData) call RegUnpack(RF, OutData%TFinAngles); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinIndMod); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinAFID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinKp); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinSigma); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinAStar); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinKv); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TFinCDc); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyVTK_BLSurfaceType(SrcVTK_BLSurfaceTypeData, DstVTK_BLSurfaceTypeData, CtrlCode, ErrStat, ErrMsg) @@ -1683,6 +1724,7 @@ subroutine AD_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, Err call NWTC_Library_CopyProgDesc(SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + DstInitOutputData%nNodesVel = SrcInitOutputData%nNodesVel end subroutine subroutine AD_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) @@ -1726,6 +1768,7 @@ subroutine AD_PackInitOutput(RF, Indata) end do end if call NWTC_Library_PackProgDesc(RF, InData%Ver) + call RegPack(RF, InData%nNodesVel) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -1752,6 +1795,7 @@ subroutine AD_UnPackInitOutput(RF, OutData) end do end if call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver + call RegUnpack(RF, OutData%nNodesVel); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyRotInputFile(SrcRotInputFileData, DstRotInputFileData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/aerodyn/src/BEMT.f90 b/modules/aerodyn/src/BEMT.f90 index c71362ca7f..b99c3a6658 100644 --- a/modules/aerodyn/src/BEMT.f90 +++ b/modules/aerodyn/src/BEMT.f90 @@ -126,7 +126,7 @@ subroutine BEMT_Set_UA_InitData( InitInp, interval, Init_UA_Data, errStat, errMs call move_alloc(InitInp%UAOff_outerNode, Init_UA_Data%UAOff_outerNode) Init_UA_Data%dt = interval - Init_UA_Data%OutRootName = InitInp%RootName ! was 'Debug.UA' + Init_UA_Data%OutRootName = trim(InitInp%RootName)//'.UA' Init_UA_Data%numBlades = InitInp%numBlades Init_UA_Data%nNodesPerBlade = InitInp%numBladeNodes @@ -137,6 +137,9 @@ subroutine BEMT_Set_UA_InitData( InitInp, interval, Init_UA_Data, errStat, errMs Init_UA_Data%ShedEffect = .true. ! This should be true when coupled to BEM Init_UA_Data%WrSum = InitInp%SumPrint + Init_UA_Data%UA_OUTS = 0 + Init_UA_Data%d_34_to_ac = 0.5_ReKi + end subroutine BEMT_Set_UA_InitData @@ -2322,6 +2325,11 @@ subroutine SetInputs_for_UA(BEM_Mod, phi, theta, cantAngle, toeAngle, axInductio call GetReynoldsNumber(BEM_Mod, axInduction, tanInduction, Vx, Vy, Vz, chord, kinVisc, theta, phi, cantAngle, toeAngle, u_UA%Re) endif + ! NOTE: + ! U: is here is the norm of the velocity made of Vx(1-a) and Vy(1+a'). + ! Ideally we would go back to the airfoil coordinate system + ! Below, v_ac is in the airfoil coordinate system. In baseline configurations, v_ac(1)>0 and v_ac(2)>0 + u_UA%v_ac(1) = sin(u_UA%alpha)*u_UA%U u_UA%v_ac(2) = cos(u_UA%alpha)*u_UA%U diff --git a/modules/aerodyn/src/FVW.f90 b/modules/aerodyn/src/FVW.f90 index ade7d76f1f..e501b2d9c7 100644 --- a/modules/aerodyn/src/FVW.f90 +++ b/modules/aerodyn/src/FVW.f90 @@ -1595,7 +1595,7 @@ subroutine UA_Init_Wrapper(AFInfo, InitInp, interval, p, x, xd, OtherState, m, E Init_UA_Data%c(i,1) = p%W(iW)%chord_LL(i) ! NOTE: InitInp chord move-allocd to p end do Init_UA_Data%dt = interval - Init_UA_Data%OutRootName = trim(InitInp%RootName)//'W'//num2lstr(iW) + Init_UA_Data%OutRootName = trim(InitInp%RootName)//'W'//num2lstr(iW)//'.UA' Init_UA_Data%numBlades = 1 Init_UA_Data%nNodesPerBlade = InitInp%numBladeNodes ! At AeroDyn ndoes, not CP @@ -1604,6 +1604,9 @@ subroutine UA_Init_Wrapper(AFInfo, InitInp, interval, p, x, xd, OtherState, m, E Init_UA_Data%a_s = InitInp%a_s ! Speed of sound, m/s Init_UA_Data%ShedEffect = .False. ! Important, when coupling UA wih vortex code, shed vorticity is inherently accounted for Init_UA_Data%WrSum = InitInp%SumPrint + Init_UA_Data%UA_OUTS = 0 + Init_UA_Data%d_34_to_ac = 0.5_ReKi + allocate(Init_UA_Data%UAOff_innerNode(1), stat=errStat2) allocate(Init_UA_Data%UAOff_outerNode(1), stat=errStat2) Init_UA_Data%UAOff_innerNode(1) = InitInp%W(iW)%UAOff_innerNode diff --git a/modules/aerodyn/src/FVW_Subs.f90 b/modules/aerodyn/src/FVW_Subs.f90 index f10b38f0a5..f2345493b3 100644 --- a/modules/aerodyn/src/FVW_Subs.f90 +++ b/modules/aerodyn/src/FVW_Subs.f90 @@ -130,10 +130,11 @@ subroutine ReadAndInterpGamma(CirculationFileName, s_CP_LL, L, Gamma_CP_LL, ErrS real(ReKi), parameter :: ReNaN = huge(1.0_ReKi) ErrStat = ErrID_None ErrMsg = '' + ! TODO Poentially use ReadDelimFile Instead ! --- call GetNewUnit(iUnit) call OpenFInpFile(iUnit, CirculationFileName, errStat2, errMsg2); if(Failed()) return - nLines=line_count(iUnit)-1 + nLines=line_count(iUnit, errStat2, errMsg2)-1 ! Read Header read(iUnit,*, iostat=errStat2) line ; if(Failed()) return ! Read table: s/L [-], GammaPresc [m^2/s] @@ -172,28 +173,6 @@ logical function Failed() if (Failed) call CleanUp() end function Failed - !> Counts number of lines in a file - integer function line_count(iunit) - integer(IntKi), intent(in) :: iunit - character(len=1054) :: line - ! safety for infinite loop.. - integer(IntKi), parameter :: nline_max=100000000 ! 100 M - integer(IntKi) :: i - line_count=0 - do i=1,nline_max - line='' - read(iunit,'(A)',END=100)line - line_count=line_count+1 - enddo - if (line_count==nline_max) then - print*,'Error: maximum number of line exceeded' - endif - 100 if(len(trim(line))>0) then - line_count=line_count+1 - endif - rewind(iunit) - end function - endsubroutine ReadAndInterpGamma ! ===================================================================================== diff --git a/modules/aerodyn/src/UA_Dvr_Subs.f90 b/modules/aerodyn/src/UA_Dvr_Subs.f90 index 0577387f87..066bde369e 100644 --- a/modules/aerodyn/src/UA_Dvr_Subs.f90 +++ b/modules/aerodyn/src/UA_Dvr_Subs.f90 @@ -5,21 +5,41 @@ module UA_Dvr_Subs use AirfoilInfo_Types use UnsteadyAero_Types use UnsteadyAero + use LinDyn + use LinDyn_Types implicit none - - type UA_Dvr_InitInput + integer, parameter :: NumAFfiles = 1 + integer(IntKi), parameter :: NumInp = 2 ! Number of inputs sent to UA_UpdateStates (must be at least 2) + integer(IntKi), parameter :: InflowMod_Cst = 1 ! Inflow is constant + integer(IntKi), parameter :: InflowMod_File = 2 ! Inflow is read from file + integer(IntKi), parameter, dimension(2) :: InflowMod_Valid = (/InflowMod_Cst, InflowMod_File/) + integer(IntKi), parameter :: MotionMod_Cst = 1 ! Motion is constant + integer(IntKi), parameter :: MotionMod_File = 2 ! Motion is read from file + integer(IntKi), parameter, dimension(2) :: MotionMod_Valid = (/MotionMod_Cst, MotionMod_File/) + real(ReKi), parameter :: myNaN = -9999.9_ReKi + integer(IntKi), parameter :: idFmt_Ascii = 1 + integer(IntKi), parameter :: idFmt_Binary = 2 + integer(IntKi), parameter :: idFmt_Both = 3 + integer(IntKi), parameter, dimension(3) :: idFmt_Valid = (/idFmt_Ascii, idFmt_Binary, idFmt_Both/) + + type Dvr_Parameters logical :: Echo + ! Environment + real(ReKi) :: KinVisc + real(ReKi) :: FldDens real(ReKi) :: SpdSound - character(1024) :: OutRootName - real(ReKi) :: InflowVel + ! integer :: UAMod logical :: Flookup logical :: UseCm character(1024) :: AirFoil1 real(ReKi) :: Chord + ! integer :: SimMod + ! Reduced frequency - SimMod = 1 + real(ReKi) :: InflowVel real(ReKi) :: NCycles real(ReKi) :: Frequency real(ReKi) :: Re @@ -27,516 +47,409 @@ module UA_Dvr_Subs real(ReKi) :: Amplitude real(ReKi) :: Mean integer :: Phase - character(1024) :: InputsFile + ! Prescribed Aero - SimMod = 2 + real(ReKi) :: TMax_PA + real(DbKi) :: dt_PA + character(1024) :: AeroTSFile + ! AeroElastic Section - SimMod =3 + real(ReKi) :: TMax + real(DbKi) :: dt + real(ReKi) :: MM(3,3) + real(ReKi) :: CC(3,3) + real(ReKi) :: KK(3,3) + logical :: activeDOFs(3) + real(ReKi) :: GFScaling(3,3) + real(ReKi) :: initPos(3) + real(ReKi) :: initVel(3) + real(ReKi) :: Vec_AQ(2) ! Vector from A to quarter chord /aerodynamic center + real(ReKi) :: Vec_AT(2) ! Vector from A to three quarter chord + real(ReKi) :: Twist ! Twist of the airfoil section (input deg, but stored in rad afterwards) + ! Inflow + integer :: InflowMod = InflowMod_Cst + real(ReKi) :: Inflow(2) + character(1024) :: InflowTSFile + ! Motion + integer :: MotionMod = MotionMod_Cst + character(1024) :: MotionTSFile + ! Outputs logical :: SumPrint logical :: WrAFITables - end type UA_Dvr_InitInput - - contains - - subroutine ReadDriverInputFile( inputFile, InitInp, ErrStat, ErrMsg ) + ! ---- Parameters + real(ReKi) :: d_34_to_ac + !real(DbKi) :: dt + real(DbKi) :: simTime + integer :: numSteps + character(1024) :: OutRootName ! Automatically obtained from input file name + ! Prescribed AoA simulations + real(DbKi), allocatable :: timeArr(:) + real(ReKi), allocatable :: vPrescrAero(:,:) ! Aero as function of time, shape nt x 4: Time, AOA, U, Omega + ! Prescribed inflow simulations + real(ReKi), allocatable :: vU0(:,:) ! Inflow as function of time, shape nt x 3 : Time, U0x, U0y + end type Dvr_Parameters - character(1024), intent( in ) :: inputFile - type(UA_Dvr_InitInput), intent( out ) :: InitInp - integer, intent( out ) :: ErrStat ! returns a non-zero value when an error occurs - character(*), intent( out ) :: ErrMsg ! Error message if ErrStat /= ErrID_None - - ! Local variables - integer :: UnIn ! Unit number for the input file - integer :: UnEchoLocal ! The local unit number for this module's echo file - character(1024) :: EchoFile ! Name of HydroDyn echo file - character(1024) :: FileName ! Name of HydroDyn input file - integer(IntKi) :: errStat2 ! Status of error message - character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None - character(*), parameter :: RoutineName = 'ReadDriverInputFile' + type :: Dvr_Outputs + integer(intki) :: unOutFile = -1 !< unit number for writing output file + !integer(intki) :: actualchanlen !< actual length of channels written to text file (less than or equal to chanlen) [-] + integer(intki) :: ny !< total number of outputs for the driver + integer(intki) :: ny_dvr !< number of outputs for the driver (without UA and LD, and Time) + integer(intki) :: ny_UA !< number of outputs for UA + integer(intki) :: ny_LD !< number of outputs for LD + !character(20) :: fmt_t !< format specifier for time channel [-] + !character(25) :: fmt_a !< format specifier for each column (including delimiter) [-] + !character(1) :: delim !< column delimiter [-] + !character(20) :: outfmt !< format specifier [-] + integer(intki) :: fileFmt = idFmt_Binary !< output format 1=text, 2=binary, 3=both [-] + character(1024) :: root = '' !< output file rootname [-] + character(ChanLen) , dimension(:), allocatable :: WriteOutputHdr !< channel headers [-] + character(ChanLen) , dimension(:), allocatable :: WriteOutputUnt !< channel units [-] + real(ReKi) , dimension(:,:), allocatable :: storage !< nchannel x ntime [-] + real(ReKi) , dimension(:), allocatable :: outline !< output line to be written to disk [-] + !real(dbki) :: dt_outs !< output time resolution [s] + !integer(intki) :: n_dt_out !< number of time steps between writing a line in the time-marching output files [-] + end type Dvr_Outputs - character(1024) :: PriPath ! the path to the primary input file - CALL GetPath( inputFile, PriPath ) ! Input files will be relative to the path where the primary input file is located. + type :: Dvr_Misc + ! Reminder: + ! Q: 1/4 chord / aerodynamic center + ! T: 3/4 chord + ! A: Airfoil origin + real(ReKi) :: Vst_Q(2) !< Structural velocity at Q [m/s] + real(ReKi) :: Vst_T(2) !< Structural velocity at T [m/s] + real(ReKi) :: Vrel_Q(2) !< Relative velocity at Q [m/s] + real(ReKi) :: Vrel_T(2) !< Relative velocity at T [m/s] + real(ReKi) :: Vrel_norm2_T !< Squared velocity norm at T [m^2/s^2] + real(ReKi) :: Vrel_norm2_Q !< Squared velocity norm at Q [m^2/s^2] + real(ReKi) :: alpha_Q !< Angle of attack at Q [rad] + real(ReKi) :: alpha_T !< Angle of attack at T [rad] + real(ReKi) :: phi_Q !< Flow angle at Q [rad] + real(ReKi) :: phi_T !< Flow angle at T [rad] + real(ReKi) :: Re !< Reynolds number (NOT in Million!) + real(ReKi) :: L, D, tau_Q !< Aerodynamic loads at Q [N/m & Nm/m] + real(ReKi) :: FxA, FyA, tau_A !< Aerodynamic loads at A [N/m & Nm/m] + real(ReKi) :: GF(3) !< Generalized force, Scaled aerodynamic loads to be representative of the blade + real(ReKi) :: twist_full !< Full twist (includes initial twist, potential pitch, and torsion) + integer :: iU0Last = 1 !< Index for faster interpolation of wind speed + integer :: iPALast = 1 !< Index for faster interpolation of prescribed aero + real(ReKi) :: uPA(3) !< Prescribed Aero inputs + end type Dvr_Misc - - ! Initialize the echo file unit to -1 which is the default to prevent echoing, we will alter this based on user input - UnEchoLocal = -1 - ErrStat = ErrID_None - ErrMsg = '' - FileName = trim(inputFile) - - call GetNewUnit( UnIn ) - call OpenFInpFile( UnIn, FileName, errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + type Dvr_Data + ! Time control + real(DbKi) :: uTimes(NumInp) + ! Parameters / initinp set as the same... + type(Dvr_Parameters) :: p ! Initialization/parameter data for the driver program + type(Dvr_Misc) :: m ! Misc variables for aerodynamic calculations + ! Outputs + type(Dvr_Outputs) :: out + ! Inflow + real(ReKi) :: U0(NumInp, 2) ! Inflow velocity vector at time t and t+dt + ! AFI + type(AFI_ParameterType) :: AFI_Params(NumAFfiles) + integer, allocatable :: AFIndx(:,:) + ! UA + type(UA_InitInputType) :: UA_InitInData ! Input data for initialization + type(UA_InitOutputType) :: UA_InitOutData ! Output data from initialization + type(UA_ContinuousStateType) :: UA_x ! Continuous states + type(UA_DiscreteStateType) :: UA_xd ! Discrete states + type(UA_OtherStateType) :: UA_OtherState ! Other/optimization states + type(UA_MiscVarType) :: UA_m ! Misc/optimization variables + type(UA_ParameterType) :: UA_p ! Parameters + type(UA_InputType) :: UA_u(NumInp) ! System inputs + type(UA_OutputType) :: UA_y ! System outputs + ! Dynamics + type(LD_InitInputType) :: LD_InitInData ! Input data for initialization + type(LD_InitOutputType) :: LD_InitOutData ! Output data from initialization + type(LD_ContinuousStateType) :: LD_x ! Continuous states + type(LD_DiscreteStateType) :: LD_xd ! Discrete states + type(LD_OtherStateType) :: LD_OtherState ! Other/optimization states + type(LD_ConstraintStateType) :: LD_z ! Constraint states + type(LD_MiscVarType) :: LD_m ! Misc/optimization variables + type(LD_ParameterType) :: LD_p ! Parameters + type(LD_InputType) :: LD_u(NumInp) ! System inputs + type(LD_OutputType) :: LD_y ! System outputs + ! + type(LD_ContinuousStateType) :: LD_x_swp ! Continuous states + type(LD_OtherStateType) :: LD_OtherState_swp ! Other/optimization states + type(UA_ContinuousStateType) :: UA_x_swp ! Continuous states + type(UA_DiscreteStateType) :: UA_xd_swp ! Discrete states + type(UA_OtherStateType) :: UA_OtherState_swp ! Other/optimization states + end type Dvr_Data +contains - call WrScr( ' Opening UnsteadyAero Driver input file: '//FileName ) - - - !------------------------------------------------------------------------------------------------- - ! File header - !------------------------------------------------------------------------------------------------- - - call ReadCom( UnIn, FileName, ' UnsteadyAero Driver input file header line 1', errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if +!-------------------------------------------------------------------------------------------------------------- +subroutine ReadDriverInputFile( FileName, InitInp, ErrStat, ErrMsg ) + character(1024), intent( in ) :: filename + type(Dvr_Parameters), intent( out ) :: InitInp + integer, intent( out ) :: ErrStat ! returns a non-zero value when an error occurs + character(*), intent( out ) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! Local variables + integer :: UnEcho ! The local unit number for this module's echo file + integer :: iLine + character(1024) :: EchoFile ! Name of HydroDyn echo file + character(1024) :: PriPath ! the path to the primary input file + character(1024) :: Line ! the path to the primary input file + type(FileInfoType) :: FI !< The derived type for holding the file information. + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'ReadDriverInputFile' + ! Initialize the echo file unit to -1 which is the default to prevent echoing, we will alter this based on user input + UnEcho = -1 + ErrStat = ErrID_None + ErrMsg = '' + ! Read all input file lines into fileinfo + call WrScr(' Opening UnsteadyAero Driver input file: '//trim(FileName) ) + call ProcessComFile(FileName, FI, errStat2, errMsg2); if (Failed()) return + CALL GetPath( FileName, PriPath ) ! Input files will be relative to the path where the primary input file is located. + !call GetRoot(FileName, dvr%root) - call ReadCom( UnIn, FileName, 'UnsteadyAero Driver input file header line 2', errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + ! --- Header and echo + iLine = 3 ! Skip the first two lines as they are known to be header lines and separators + call ParseVar(FI, iLine, 'Echo', InitInp%Echo, errStat2, errMsg2); if (Failed()) return; + if ( InitInp%Echo ) then + EchoFile = trim(FileName)//'.ech' + call OpenEcho (UnEcho, EchoFile, errStat2, errMsg2 ); if(Failed()) return + do iLine = 1, 3 + write(UnEcho, '(A)') trim(FI%Lines(iLine)) + enddo + end if + iLine = 4 + ! --- Environmental conditions section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'FldDens', InitInp%FldDens , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'KinVisc', InitInp%KinVisc , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'SpdSound', InitInp%SpdSound, errStat2, errMsg2, UnEcho); if(Failed()) return + + ! --- UNSTEADYAERO section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'UAMod' , InitInp%UAMod , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Flookup' , InitInp%Flookup , errStat2, errMsg2, UnEcho); if(Failed()) return - ! Echo Input Files. - - call ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo Input', errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - + ! --- AIRFOIL PROPERTIES section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'AirFoil' , InitInp%AirFoil1, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Chord' , InitInp%Chord , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'Vec_AQ' , InitInp%Vec_AQ , 2, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'Vec_AT' , InitInp%Vec_AT , 2, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'UseCm' , InitInp%UseCm , errStat2, errMsg2, UnEcho); if(Failed()) return - ! If we are Echoing the input then we should re-read the first three lines so that we can echo them - ! using the NWTC_Library routines. The echoing is done inside those routines via a global variable - ! which we must store, set, and then replace on error or completion. - - if ( InitInp%Echo ) then - - EchoFile = TRIM(FileName)//'.ech' - call GetNewUnit( UnEchoLocal ) - call OpenEcho ( UnEchoLocal, EchoFile, errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - rewind(UnIn) - - call ReadCom( UnIn, FileName, 'UnsteadyAero Driver input file header line 1', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + ! --- SIMULATION CONTROL section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'SimMod' , InitInp%SimMod , errStat2, errMsg2, UnEcho); if(Failed()) return + ! --- REDUCED FREQUENCY + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'InflowVel' , InitInp%InflowVel , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'NCycles' , InitInp%NCycles , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'StepsPerCycle', InitInp%StepsPerCycle, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Frequency' , InitInp%Frequency , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Amplitude' , InitInp%Amplitude , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Mean' , InitInp%Mean , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Phase' , InitInp%Phase , errStat2, errMsg2, UnEcho); if(Failed()) return - call ReadCom( UnIn, FileName, 'UnsteadyAero Driver input file header line 2', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + ! --- PRESCRIBED AERO section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'TMax_PA' , InitInp%Tmax_PA , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'DT_PA' , InitInp%dt_PA , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'AeroTSFile' , InitInp%AeroTSFile , errStat2, errMsg2, UnEcho); if(Failed()) return - - ! Echo Input Files. Note this line is prevented from being echoed by the ReadVar routine. - - call ReadVar ( UnIn, FileName, InitInp%Echo, 'Echo', 'Echo the input file data', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - end if - - !------------------------------------------------------------------------------------------------- - ! Environmental conditions section - !------------------------------------------------------------------------------------------------- + ! --- ELASTIC SECTION section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'TMax' , InitInp%Tmax , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'DT' , InitInp%dt , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'activeDOFs' , InitInp%activeDOFs, 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'initPos' , InitInp%initPos , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'initVel' , InitInp%initVel , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'GFScaling1' , InitInp%GFScaling(1,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'GFScaling2' , InitInp%GFScaling(2,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'GFScaling3' , InitInp%GFScaling(3,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'MassMatrix1' , InitInp%MM(1,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'MassMatrix2' , InitInp%MM(2,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'MassMatrix3' , InitInp%MM(3,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'DampMatrix1' , InitInp%CC(1,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'DampMatrix2' , InitInp%CC(2,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'DampMatrix3' , InitInp%CC(3,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'StifMatrix1' , InitInp%KK(1,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'StifMatrix2' , InitInp%KK(2,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'StifMatrix3' , InitInp%KK(3,:) , 3, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'Twist' , InitInp%Twist , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'InflowMod' , InitInp%InflowMod , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseAry(FI, iLine, 'Inflow' , InitInp%Inflow , 2, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'InflowTSFile' , InitInp%InflowTSFile, errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'MotionMod' , InitInp%MotionMod , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'MotionTSFile' , InitInp%MotionTSFile, errStat2, errMsg2, UnEcho); if(Failed()) return - ! Header - - call ReadCom( UnIn, FileName, 'Environmental conditions header', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + ! --- OUTPUT section + call ParseCom(FI, iLine, Line , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'SumPrint' , InitInp%SumPrint , errStat2, errMsg2, UnEcho); if(Failed()) return + call ParseVar(FI, iLine, 'WrAFITables', InitInp%WrAFITables, errStat2, errMsg2, UnEcho); if(Failed()) return + ! --- Triggers + call GetRoot(FileName, InitInp%OutRootName) ! OutRootName is inferred from current filename. + !InitInp%OutRootName=trim(InitInp%OutRootName)//'.UA' ! For backward compatibility + !if (PathIsRelative(InitInp%OutRootName)) InitInp%OutRootName = TRIM(PriPath)//TRIM(InitInp%OutRootName) + if (PathIsRelative(InitInp%Airfoil1)) InitInp%Airfoil1 = TRIM(PriPath)//TRIM(InitInp%Airfoil1) + if (PathIsRelative(InitInp%AeroTSFile )) InitInp%AeroTSFile = TRIM(PriPath)//TRIM(InitInp%AeroTSFile ) + if (PathIsRelative(InitInp%InflowTSFile )) InitInp%InflowTSFile = TRIM(PriPath)//TRIM(InitInp%InflowTSFile) + if (PathIsRelative(InitInp%MotionTSFile )) InitInp%MotionTSFile = TRIM(PriPath)//TRIM(InitInp%MotionTSFile) - ! SpdSound - Speed of Sound. - - call ReadVar ( UnIn, FileName, InitInp%SpdSound, 'SpdSound', 'SpdSound', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + ! --- Checks + !if (Check(.not.(any(dvr%out%fileFmt==idFmt_Valid )), 'FileFormat not implemented: '//trim(Num2LStr(InitInp%InflowMod)))) return + if (Check(.not.(any(InitInp%InflowMod==InflowMod_Valid)), 'InflowMod not implemented: '//trim(Num2LStr(InitInp%MotionMod)))) return + if (Check(.not.(any(InitInp%MotionMod==MotionMod_Valid)), 'MotionMod not implemented: '//trim(Num2LStr(InitInp%MotionMod)))) return + if (InitInp%SimMod==3) then ! Temporary to avoid changing r-test for now + !if (Check(.not.EqualRealNos(InitInp%MM(1,1), InitInp%MM(2,2), 'Mass matrix entries 11 and 22 should match.') return - - !------------------------------------------------------------------------------------------------- - ! UNSTEADYAERO section - !------------------------------------------------------------------------------------------------- + if (InitInp%Vec_AT(2)<0) call WrScr('[WARN] Vec_AT(2) is negative, but this value is usually positive (for A between T and Q)') + if (InitInp%Vec_AQ(2)>0) call WrScr('[WARN] Vec_AQ(2) is positive, but this value is usually negative (for A between T and Q)') + endif - ! Header - - call ReadCom( UnIn, FileName, 'UNSTEADYAERO header', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + call Cleanup() +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call Cleanup() + end function Failed - - ! OutRootName - call ReadVar ( UnIn, FileName, InitInp%OutRootName, 'OutRootName', & - 'UnsteadyAero output root filename', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - if (PathIsRelative(InitInp%OutRootName)) InitInp%OutRootName = TRIM(PriPath)//TRIM(InitInp%OutRootName) - - ! InflowVel - - call ReadVar ( UnIn, FileName, InitInp%InflowVel, 'InflowVel', & - 'Inflow velocity', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Re - - call ReadVar ( UnIn, FileName, InitInp%Re, 'Re', & - 'Reynolds number in millions', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! UAMod - call ReadVar ( UnIn, FileName, InitInp%UAMod, 'UAMod', & - 'Unsteady Aero Model Switch', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Flookup - call ReadVar ( UnIn, FileName, InitInp%Flookup, 'Flookup', & - "Lookup used to determine f'", errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - - - - !------------------------------------------------------------------------------------------------- - ! AIRFOIL PROPERTIES section - !------------------------------------------------------------------------------------------------- + subroutine Cleanup() + ! Close this module's echo file + if ( InitInp%Echo ) then + close(UnEcho) + end if + Call NWTC_Library_Destroyfileinfotype(FI, errStat2, errMsg2) + end subroutine Cleanup - ! Header - - call ReadCom( UnIn, FileName, 'AIRFOIL PROPERTIES header', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - - - ! AirFoil1 - - call ReadVar ( UnIn, FileName, InitInp%AirFoil1, 'AirFoil1', & - 'Filename for the airfoil table and properties', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - if (PathIsRelative(InitInp%Airfoil1)) InitInp%Airfoil1 = TRIM(PriPath)//TRIM(InitInp%Airfoil1) - - ! Chord - - call ReadVar ( UnIn, FileName, InitInp%Chord, 'Chord', & - 'Chord length', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Using Cm column - call ReadVar ( UnIn, FileName, InitInp%UseCm, 'UseCm', & - "Using Cm Airfoil table data", errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - !------------------------------------------------------------------------------------------------- - ! SIMULATION CONTROL section - !------------------------------------------------------------------------------------------------- + logical function Check(Condition, errMsg_in) + logical, intent(in) :: Condition + character(len=*), intent(in) :: errMsg_in + Check=Condition + if (Check) then + call SetErrStat( ErrID_Fatal, errMsg_in, errStat, errMsg, RoutineName ) + endif + end function Check - ! Header - - call ReadCom( UnIn, FileName, 'SIMULATION CONTROL header', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - - ! SimMod - call ReadVar ( UnIn, FileName, InitInp%SimMod, 'SimMod', & - 'Simulation model', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! NCycles - call ReadVar ( UnIn, FileName, InitInp%NCycles, 'NCycles', & - 'Number of cycles for angle-of-attack inputs', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! StepsPerCycle - call ReadVar ( UnIn, FileName, InitInp%StepsPerCycle, 'StepsPerCycle', & - 'Number of timesteps per cycle', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Frequency - call ReadVar ( UnIn, FileName, InitInp%Frequency, 'Frequency', & - 'Frequency of angle-of-attack inputs', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Amplitude - call ReadVar ( UnIn, FileName, InitInp%Amplitude, 'Amplitude', & - 'Amplitude for angle-of-attack inputs', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Mean - call ReadVar ( UnIn, FileName, InitInp%Mean, 'Mean', & - 'Mean for angle-of-attack inputs', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - ! Phase - call ReadVar ( UnIn, FileName, InitInp%Phase, 'Phase', & - 'Initial phase for angle-of-attack inputs', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if +end subroutine ReadDriverInputFile +!-------------------------------------------------------------------------------------------------------------- +subroutine Dvr_SetParameters(p, errStat, errMsg) + type(Dvr_Parameters), intent(inout) :: p + integer, intent(out ) :: errStat ! returns a non-zero value when an error occurs + character(*), intent(out ) :: errMsg ! Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + errStat2= ErrID_None + errStat = ErrID_None + errMsg = '' + ! Unit conversions + p%Twist = p%Twist * D2R + p%d_34_to_ac = (-p%Vec_AQ(2) + p%Vec_AT(2)) ! d_34_to_ac = d_QT ~0.5 [-], Approximated using y coordinate + p%Vec_AT = p%Vec_AT * p%chord + p%Vec_AQ = p%Vec_AQ * p%chord + + if ( p%SimMod == 1 ) then + call WrScr('[WARN] The behavior of SimMod=1 might change in the future.') + + ! We will use a constant Reynolds.. + p%Re = p%InflowVel * p%chord/ p%KinVisc ! NOT IN MILLIONS + print*,' Re ',p%Re + ! Using the frequency and NCycles, determine how long the simulation needs to run + p%simTime = p%NCycles/p%Frequency + p%numSteps = p%StepsPerCycle*p%NCycles ! we could add 1 here to make this a complete cycle + p%dt = p%simTime / p%numSteps - ! InputsFile - call ReadVar ( UnIn, FileName, InitInp%InputsFile, 'InputsFile', & - 'Filename for Time series data in an ASCII input file', errStat2, errMsg2, UnEchoLocal ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - - !------------------------------------------------------------------------------------------------- - ! OUTPUT section - !------------------------------------------------------------------------------------------------- - call ReadCom( UnIn, FileName, 'Output conditions header', errStat2, errMsg2, UnEchoLocal ); if(Failed()) return - call ReadVar( UnIn, FileName, InitInp%SumPrint, 'SumPrint', 'Write unsteady aerodynamic summary file', errStat2, errMsg2, UnEchoLocal ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - call ReadVar( UnIn, FileName, InitInp%WrAFITables, 'WrAFITables', 'Write airfoil coefficients used by Airfoil Info', errStat2, errMsg2, UnEchoLocal ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - ! Temporarily allowing backward compatibility.. - call WrScr('') - call WrScr('[WARN] An error occured when reading the output section of the UA Driver input file.') - call WrScr(' Make sure it is at the latest version. See error message below:') - call WrScr(trim(ErrMsg)) - call WrScr('') - call WrScr('[INFO] Continuing using default output options.') - call WrScr('') - InitInp%SumPrint = .True. - InitInp%WrAFITables = .True. - ErrStat = ErrID_None - ErrMsg = '' + else if ( p%SimMod == 2 ) then + ! Read time-series data file with columns:( time, Angle-of-attack, Vrel, omega ) + call WrScr( ' Opening prescribed-aero time-series input file: '//trim(p%AeroTSFile) ) + call ReadDelimFile(p%AeroTSFile, 4, p%vPrescrAero, errStat2, errMsg2); if(Failed()) return + p%vPrescrAero(:,2) = p%vPrescrAero(:,2)*D2R ! Deg 2 rad + p%dt = p%dt_PA + p%simTime = p%TMax_PA + p%numSteps = int(p%simTime/p%dt) + + elseif ( p%SimMod == 3 ) then + p%simTime = p%TMax + p%numSteps = int(p%simTime/p%dt) + + if (p%InflowMod==InflowMod_File) then + ! Read inflow file + call ReadDelimFile(p%InflowTSFile, 3, p%vU0, errStat2, errMsg2); if(Failed()) return endif - call Cleanup() - contains - logical function Failed() - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - Failed = ErrStat >= AbortErrLev - if (Failed) call Cleanup() - end function Failed - subroutine Cleanup() - ! Close this module's echo file - if ( InitInp%Echo ) then - close(UnEchoLocal) - end if - close( UnIn ) - end subroutine Cleanup - end subroutine ReadDriverInputFile - - subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, OmegaArr, ErrStat, ErrMsg ) - character(1024), intent( in ) :: inputsFile - integer, intent( out ) :: nSimSteps - real(DbKi),allocatable, intent( out ) :: timeArr(:) - real(ReKi),allocatable, intent( out ) :: AOAarr(:) - real(ReKi),allocatable, intent( out ) :: Uarr(:) !RRD - real(ReKi),allocatable, intent( out ) :: OmegaArr(:) - integer, intent( out ) :: ErrStat ! returns a non-zero value when an error occurs - character(*), intent( out ) :: ErrMsg ! Error message if ErrStat /= ErrID_None - - real(SiKi) :: dt - real(DbKi) :: tmpArr(4) - integer(IntKi) :: errStat2 ! Status of error message - character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None - character(*), parameter :: RoutineName = 'ReadTimeSeriesData' - character(1024) :: FileName - integer :: UnIn - integer :: i - integer, PARAMETER ::hdrlines=8 ! RRD - - ErrStat = ErrID_None - ErrMsg = '' - nSimSteps = 0 ! allocate here in case errors occur - - FileName = trim(inputsFile) - - call GetNewUnit( UnIn ) - call OpenFInpFile( UnIn, FileName, errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + endif + if(Failed()) return +contains + logical function Failed() + call setErrStat(errStat2, errMsg2, errStat, errMsg, 'Dvr_SetParameters') + Failed = ErrStat >= AbortErrLev + end function Failed +end subroutine Dvr_SetParameters +!-------------------------------------------------------------------------------------------------------------- +subroutine driverInputsToUAInitData(p, InitInData, AFI_Params, AFIndx, errStat, errMsg) + type(Dvr_Parameters) , intent(in ) :: p ! Initialization data for the driver program + type(UA_InitInputType) , intent(out) :: InitInData ! Input data for initialization + type(AFI_ParameterType), intent(out) :: AFI_Params(NumAFfiles) + integer, allocatable , intent(out) :: AFIndx(:,:) + integer(IntKi), intent(out) :: errStat ! Error status. + character(*), intent(out) :: errMsg ! Error message. + logical :: UA_f_cn ! Should the separation function be computed using Cn or Cl + character(1024) :: afNames(NumAFfiles) + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'driverInputsToUAInitData' + errStat = ErrID_None + errMsg = '' + InitInData%UA_OUTS = 1 ! 0=None, 1=Write Outputs, 2=Separate File +#ifdef ADD_UA_OUTS + InitInData%UA_OUTS = 2 ! Compiler Flag Override, 2=Write a separate file +#endif - call WrScr( ' Opening UnsteadyAero time-series input file: '//FileName ) - - - !------------------------------------------------------------------------------------------------- - ! Determine how many lines of data are in the file: - !------------------------------------------------------------------------------------------------- - do i=1,hdrlines !RRD - call ReadCom( UnIn, FileName, ' UnsteadyAero time-series input file header line 1', errStat2, errMsg2 ) - call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - enddo - - do - call ReadAry( UnIn, FileName, tmpArr, 4, 'Data', 'Time-series data', errStat2, errMsg2 ) - ! The assumption is that the only parsing error occurs at the end of the file and therefore we stop reading data - if (errStat2 > ErrID_None) then - exit - else - nSimSteps = nSimSteps + 1 - end if - end do - - !------------------------------------------------------------------------------------------------- - ! Allocate arrays to be read - !------------------------------------------------------------------------------------------------- - allocate ( timeArr( nSimSteps ), STAT=ErrStat2 ) - if ( ErrStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate timeArr.', ErrStat, ErrMsg, RoutineName) - call Cleanup() - return - end if - - allocate ( AOAarr( nSimSteps ), STAT=ErrStat2 ) - if ( ErrStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate AOAarr.', ErrStat, ErrMsg, RoutineName) - call Cleanup() - return - end if - allocate ( Uarr( nSimSteps ), OmegaArr( nSimSteps ), STAT=ErrStat2 ) - if ( ErrStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate Uarr and OmegaArr.', ErrStat, ErrMsg, RoutineName) - call Cleanup() - return - end if - - - !------------------------------------------------------------------------------------------------- - ! Read arrays from file - !------------------------------------------------------------------------------------------------- - rewind(UnIn) - do i=1,hdrlines !RRD - call ReadCom( UnIn, FileName, ' UnsteadyAero time-series input file header line 1', errStat2, errMsg2 ) - enddo - do i = 1,nSimSteps - call ReadAry( UnIn, FileName, tmpArr, 4, 'Data', 'Time-series data', errStat2, errMsg2 ) - timeArr(i) = tmpArr(1) - AOAarr(i) = real(tmpArr(2),ReKi) - Uarr(i) = real(tmpArr(3),ReKi) - OmegaArr(i) = real(tmpArr(4),ReKi) - end do - - if (nSimSteps > 1) then - dt = timeArr(2) - timeArr(1) - - do i = 2,nSimSteps-1 - if (.not. EqualRealNos(dt, REAL(timeArr(i+1)-timeArr(i), SiKi) ) ) then - call SetErrStat( ErrID_Fatal, 'Times in InputsFile must be contain the same delta t.', ErrStat, ErrMsg, RoutineName) - exit !exit the do loop - end if - end do - end if - - call Cleanup() - - contains - !==================================================================================================== - subroutine Cleanup() - ! The routine cleans up the module echo file and resets the NWTC_Library, reattaching it to - ! any existing echo information - !---------------------------------------------------------------------------------------------------- - ! logical, intent( in ) :: EchoFlag ! local version of echo flag - ! integer, intent( in ) :: UnEcho ! echo unit number - - ! Close this module's echo file - - - close( UnIn ) - - end subroutine Cleanup - end subroutine ReadTimeSeriesData -!-------------------------------------------------------------------------------------------------------------- - subroutine Init_AFI(UAMod, NumAFfiles, afNames, UseCm, UA_f_cn, AFI_Params, ErrStat, ErrMsg) + ! -- UA Init Input Data + InitInData%nNodesPerBlade = 1 + InitInData%numBlades = 1 + call AllocAry(InitInData%c, InitInData%nNodesPerBlade, InitInData%numBlades, 'chord', errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInData%UAOff_innerNode , InitInData%numBlades, 'UAO' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInData%UAOff_outerNode , InitInData%numBlades, 'UAO' , errStat2, errMsg2); if(Failed()) return + + ! don't turn off UA based on span location: + InitInData%UAOff_innerNode = 0 + InitInData%UAOff_outerNode = InitInData%nNodesPerBlade + 1 + InitInData%a_s = p%SpdSound + InitInData%c(1,1) = p%Chord + InitInData%UAMod = p%UAMod + InitInData%Flookup = p%Flookup + InitInData%OutRootName = trim(p%OutRootName)//'.UA' + InitInData%WrSum = p%SumPrint + InitInData%d_34_to_ac = p%d_34_to_ac ! d_34_to_ac = d_QT ~0.5 [-], Approximated using y coordinate + + ! --- AFI + allocate(AFIndx(InitInData%nNodesPerBlade,InitInData%numBlades), STAT = errStat2) + if ( errStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error trying to allocate InitInData%AFIndx.', errStat, errMsg, RoutineName) + return + end if + AFIndx(1,1) = 1 + + UA_f_cn = (InitInData%UAMod /= UA_HGM).and.(InitInData%UAMod /= UA_OYE) ! HGM and OYE use the separation function based on cl instead of cn + afNames(1) = p%AirFoil1 ! All nodes/blades are using the same 2D airfoil + call Init_AFI( InitInData%UAMod, NumAFfiles, afNames, p%UseCm, UA_f_cn, AFI_Params, errStat2, errMsg2); if(Failed()) return + + if (p%WrAFITables) then + call WriteAFITables(AFI_Params(1), p%OutRootName, p%UseCm, UA_f_cn) + endif +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed +endsubroutine driverInputsToUAInitData +!-------------------------------------------------------------------------------------------------------------- +subroutine Init_AFI(UAMod, NumAFfiles, afNames, UseCm, UA_f_cn, AFI_Params, ErrStat, ErrMsg) integer, intent(in ) :: UAMod integer, intent(in ) :: NumAFfiles CHARACTER(1024), intent(in ) :: afNames(NumAFfiles) @@ -552,16 +465,10 @@ subroutine Init_AFI(UAMod, NumAFfiles, afNames, UseCm, UA_f_cn, AFI_Params, ErrS integer(IntKi) :: errStat2 ! Status of error message character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None character(*), parameter :: RoutineName = 'Init_AFI' - - ! Initialize the Airfoil Info module - ! Setup Airfoil info - + UnEc = 0 - ErrStat = ErrID_None ErrMsg = "" - - ! Set this to 1 to use the UA coefs !AFI_InitInputs%UA_Model = 1 ! This is the number of columns of coefs in the AOA table: Cl, Cd, Cm, for example, but doesn't include Alpha @@ -575,15 +482,15 @@ subroutine Init_AFI(UAMod, NumAFfiles, afNames, UseCm, UA_f_cn, AFI_Params, ErrS else AFI_InitInputs%InCol_Cm = 0 end if - + AFI_InitInputs%InCol_Cpmin = 0 AFI_InitInputs%AFTabMod = AFITable_1 ! 1D-interpolation (on AoA only) AFI_InitInputs%UA_f_cn = UA_f_cn - + do i=1,NumAFfiles AFI_InitInputs%FileName = afNames(i) !InitInp%AF_File(i) - ! Call AFI_Init to read in and process the airfoil files. + ! Read in and process the airfoil files. ! This includes creating the spline coefficients to be used for interpolation. call AFI_Init ( AFI_InitInputs, AFI_Params(i), errStat2, errMsg2, UnEc ) @@ -595,128 +502,625 @@ subroutine Init_AFI(UAMod, NumAFfiles, afNames, UseCm, UA_f_cn, AFI_Params, ErrS end do call Cleanup() - - - contains - - !==================================================================================================== - subroutine Cleanup() - ! The routine cleans up data arrays framework structures - ! - !---------------------------------------------------------------------------------------------------- - !Clean up initialization inputs - call AFI_DestroyInitInput(AFI_InitInputs, errStat2, errMsg2) - - - - end subroutine Cleanup - end subroutine Init_AFI - - - subroutine WriteAFITables(AFI_Params, OutRootName, UseCm, UA_f_cn) - - type(AFI_ParameterType), intent(in), target :: AFI_Params - character(len=*) , intent(in) :: OutRootName - logical , intent(in) :: UseCm - logical , intent(in) :: UA_f_cn - - integer(IntKi) :: unOutFile - integer(IntKi) :: ErrStat - character(ErrMsgLen) :: ErrMsg - - Real(ReKi), allocatable :: cl_smooth(:) - Real(ReKi), allocatable :: cn_smooth(:) - Real(ReKi), allocatable :: cn(:) - Real(ReKi), allocatable :: cl_lin(:) - Real(ReKi), allocatable :: cn_lin(:) - character(len=3) :: Prefix - character(len=11) :: sFullyAtt - character(len=8) :: sCm - integer :: iTab, iRow, iStartUA - type(AFI_Table_Type), pointer :: tab !< Alias - - if (UA_f_cn) then - Prefix='Cn_' - sFullyAtt='Cn_FullyAtt' + +contains + subroutine Cleanup() + call AFI_DestroyInitInput(AFI_InitInputs, errStat2, errMsg2) + end subroutine Cleanup +end subroutine Init_AFI +!-------------------------------------------------------------------------------------------------------------- +!> Set Inflow inputs +subroutine setInflow(t, p, U0, m) + real(DbKi), intent(in) :: t + type(Dvr_Parameters), intent(in) :: p + type(Dvr_Misc ), intent(inout) :: m + real(ReKi), dimension(:), intent(out) :: U0 + if (p%InflowMod == InflowMod_Cst) then + U0(:) = p%Inflow + else if (p%InflowMod == InflowMod_File) then + call interpTimeValue(p%vU0, t, m%iU0Last, U0(:)) + else + print*,'Should never happen' + STOP + endif +end subroutine setInflow +!-------------------------------------------------------------------------------------------------------------- +!> Compute aerodynamic kinematics quantities (velocities and angles) at different points +subroutine AeroKinematics(U0, q, qd, p, m) + real(ReKi), intent(in) :: U0(2) !< Free stream + real(ReKi), intent(in) :: q(3) !< Elastic positions x,y,th + real(ReKi), intent(in) :: qd(3) !< Elastic velocities + type(Dvr_Parameters), intent(in ) :: p !< Parameters + type(Dvr_Misc), intent(inout) :: m !< Misc aero var + real(ReKi), parameter :: W(2) =0 ! Induced velocities + real(ReKi) :: ST, CT + + ! Full twist + m%twist_full = q(3) + p%Twist ! + Pitch if a controller is added + ST = sin(m%twist_full) + CT = cos(m%twist_full) + + ! Structual velocity including torsional velocity + m%Vst_T(1) = qd(1) + qd(3) * (-p%Vec_AT(1)*ST + p%Vec_AT(2)*CT) + m%Vst_T(2) = qd(2) + qd(3) * ( p%Vec_AT(1)*CT + p%Vec_AT(2)*ST) + + m%Vst_Q(1) = qd(1) + qd(3) * (-p%Vec_AQ(1)*ST + p%Vec_AQ(2)*CT) + m%Vst_Q(2) = qd(2) + qd(3) * ( p%Vec_AQ(1)*CT + p%Vec_AQ(2)*ST) + + ! Relative velocity, Vrel = U0 - Vst + W + m%Vrel_T = U0 - m%Vst_T + W + m%Vrel_Q = U0 - m%Vst_Q + W + + ! Squared velocity norm + m%Vrel_norm2_T = m%Vrel_T(1)**2 + m%Vrel_T(2)**2 + m%Vrel_norm2_Q = m%Vrel_Q(1)**2 + m%Vrel_Q(2)**2 + + ! Flow angle + m%phi_Q = atan2(m%Vrel_Q(1), m%Vrel_Q(2)) + m%phi_T = atan2(m%Vrel_T(1), m%Vrel_T(2)) + + ! Angle of attack + m%alpha_Q = m%phi_Q - m%twist_full + m%alpha_T = m%phi_T - m%twist_full + + ! Reynolds at 1/4 chord + m%Re = sqrt(m%Vrel_norm2_Q) * p%chord / p%KinVisc +end subroutine AeroKinematics + +!-------------------------------------------------------------------------------------------------------------- +!> Compute aerodynamic kinetics quantities (loads) +subroutine AeroKinetics(U0, q, qd, C_dyn, p, m) + real(ReKi), intent(in) :: U0(2) !< Free stream + real(ReKi), intent(in) :: q(3) !< Elastic positions x,y,th + real(ReKi), intent(in) :: qd(3) !< Elastic velocities + real(ReKi), intent(in) :: C_dyn(3) !< Dynamic aerodynamic coefficients (Cl, Cd, Cm) + type(Dvr_Parameters), intent(in ) :: p !< Parameters + type(Dvr_Misc), intent(inout) :: m !< Misc aero var + real(ReKi) :: ST, CT + real(ReKi) :: SP, CP + real(ReKi) :: q_dyn + + ! First get kinematics + call AeroKinematics(U0, q, qd, p, m) + + ST = sin(m%twist_full) + CT = cos(m%twist_full) + + ! Loads at Q + q_dyn = 0.5_ReKi * p%FldDens * p%chord * m%Vrel_norm2_Q + m%L = q_dyn * C_dyn(1) + m%D = q_dyn * C_dyn(2) + m%tau_Q = q_dyn * C_dyn(3) * p%chord + + ! Loads at A + SP = sin(m%phi_Q) + CP = cos(m%phi_Q) + m%FxA = m%L * CP + m%D * SP + m%FyA = -m%L * SP + m%D * CP + ! Tau A (Positive about "z") - version 1 + m%tau_A = m%tau_Q + m%tau_A = m%tau_A - m%FxA * (- p%Vec_AQ(1) * ST + p%Vec_AQ(2) * CT) + m%tau_A = m%tau_A + m%FyA * ( p%Vec_AQ(1) * CT + p%Vec_AQ(2) * ST) + ! Tau A (Positive about "z") - version 2 + !SA = sin(m%alpha_Q) + !CA = cos(m%alpha_Q) + !tau_A2 = m%tau_Q + !tau_A2 = tau_A2 - q_dyn *C_dyn(1)* ( p%Vec_AQ(1) * SA + p%Vec_AQ(2) * CA) + !tau_A2 = tau_A2 + q_dyn *C_dyn(2)* ( p%Vec_AQ(1) * CA - p%Vec_AQ(2) * SA) + + ! Generalized loads + m%GF(1) = m%FxA * p%GFScaling(1,1) + m%FyA * p%GFScaling(1,2) - m%tau_A * p%GFScaling(1,3) + m%GF(2) = m%FxA * p%GFScaling(2,1) + m%FyA * p%GFScaling(2,2) - m%tau_A * p%GFScaling(2,3) + m%GF(3) = m%FxA * p%GFScaling(3,1) + m%FyA * p%GFScaling(3,2) - m%tau_A * p%GFScaling(3,3) + +end subroutine AeroKinetics +!---------------------------------------------------------------------------------------------------- + +!> Set LinDyn inputs (scaled aerodynamic forces at point A) +subroutine setLDinputs(U0, LD_x, UA_y, p, m, LD_u) + real(ReKi) , intent(in ) :: U0(2) !< Parameters + type(LD_ContinuousStateType), intent(in ) :: LD_x !< LinDyn states + type(UA_OutputType), intent(in ) :: UA_y !< UA outputs + type(Dvr_Parameters), intent(in ) :: p !< Parameters + type(Dvr_Misc), intent(inout) :: m !< Misc aero var + type(LD_InputType), intent(inout) :: LD_u !< LinDyn inputs + + call AeroKinetics (U0, LD_x%q(1:3), LD_x%q(4:6), (/UA_y%Cl, UA_y%Cd, UA_y%Cm/), p, m) + LD_u%Fext(1) = m%GF(1) + LD_u%Fext(2) = m%GF(2) + LD_u%Fext(3) = m%GF(3) + +end subroutine setLDinputs + +!---------------------------------------------------------------------------------------------------- +!> Set UA Inputs from Flow and LinDyn +subroutine setUAinputs(U0, LD_x, p, m, UA_u) + real(ReKi) , intent(in ) :: U0(2) !< Parameters + type(LD_ContinuousStateType), intent(in ) :: LD_x !< LinDyn states + type(Dvr_Parameters), intent(in ) :: p !< Parameters + type(Dvr_Misc), intent(inout) :: m !< Misc aero var + type(UA_InputType), intent(inout) :: UA_u !< UA inputs + + call AeroKinematics(U0, LD_x%q(1:3), LD_x%q(4:6), p, m) + UA_u%UserProp = 0 + UA_u%Re = m%Re + UA_u%omega = -LD_x%q(6) ! NOTE: theta convention for the driver is negative along z, but UA expect an omega along z + ! Angle of attack and relative velocity at 1/4 point/aerodynamic center point "Q" + UA_u%alpha = m%alpha_Q + UA_u%U = sqrt(m%Vrel_norm2_Q) + UA_u%v_ac(1) = UA_u%U * sin(UA_u%alpha) ! In airfoil coordinate system (a) + UA_u%v_ac(2) = UA_u%U * cos(UA_u%alpha) ! In airfoil coordinate system (a) +end subroutine setUAinputs + +!---------------------------------------------------------------------------------------------------- +!> Set UA inptus for a simulation where the angle of attack is prescribed and the relative velocity is constant +subroutine setUAinputsAlphaSim(n, u, t, p, m, errStat, errMsg) + integer, intent(in) :: n + type(UA_InputType), intent(inout) :: u ! System inputs + real(DbKi), intent( out) :: t + type(Dvr_Parameters), intent(in) :: p ! Initialization data for the driver program + type(Dvr_Misc ), intent(inout) :: m ! Initialization data for the driver program + integer, intent(out) :: errStat + character(len=*), intent(out) :: errMsg + integer :: indx + real(ReKi) :: phase + real(ReKi) :: d_ref2AC + real(ReKi) :: alpha_ref + real(ReKi) :: U_ref + real(ReKi) :: v_ref(2) + real(ReKi) :: v_34(2) + logical, parameter :: OscillationAtMidChord=.true. ! for legacy, use false + logical, parameter :: VelocityAt34 =.true. ! for legacy, use false + + ! Initialize error handling variables + ErrMsg = '' + ErrStat = ErrID_None + + u%UserProp = 0 + t = (n-1)*p%dt + + if ( p%SimMod == 1 ) then + if (OscillationAtMidChord) then + d_ref2AC = -0.25_ReKi ! -0.25: oscillations at mid_chord + d_ref2AC = -p%d_34_to_ac/2. ! TODO else - Prefix='Cl_' - sFullyAtt='Dummy' + d_ref2AC = 0.0_ReKi ! 0: oscillations at AC endif - if (UseCm) then - sCm='Cm' + U_ref = p%InflowVel ! m/s + + phase = (n+p%Phase-1)*2*pi/p%StepsPerCycle + alpha_ref = (p%Amplitude * sin(phase) + p%Mean)*D2R ! This needs to be in radians + v_ref(1) = sin(alpha_ref)*U_ref + v_ref(2) = cos(alpha_ref)*U_ref + u%omega = p%Amplitude * cos(phase) * 2*pi/p%StepsPerCycle / p%dt * D2R ! This needs to be in radians derivative: d_alpha /d_t + + u%v_ac(1) = v_ref(1) + u%omega * d_ref2AC* p%Chord + u%v_ac(2) = v_ref(2) + + v_34(1) = u%v_ac(1) + u%omega * 0.5* p%Chord + v_34(2) = u%v_ac(2) + + u%alpha = atan2(u%v_ac(1), u%v_ac(2) ) ! + if (VelocityAt34) then + u%U = sqrt(v_34(1)**2 + v_34(2)**2) ! Using U at 3/4 else - sCm='Cm_Dummy' + u%U = sqrt(u%v_ac(1)**2 + u%v_ac(2)**2) ! Using U at 1/4 endif + u%Re = p%Re ! Option for constant Reynolds or not? + else + ! Interpolate at current time + call interpTimeValue(p%vPrescrAero, t, m%iPALast, m%uPA) + u%alpha = m%uPA(1) ! rad + u%U = m%uPA(2) + u%omega = m%uPA(3) + u%v_ac(1) = sin(u%alpha)*u%U + u%v_ac(2) = cos(u%alpha)*u%U + u%Re = u%U * p%chord / p%KinVisc + end if - ! Loop on tables, write a different file for each table. - do iTab = 1, size(AFI_Params%Table) - tab => AFI_Params%Table(iTab) +end subroutine setUAinputsAlphaSim - ! Compute derived parameters from cl and cd, and UA_BL - if(allocated(cl_smooth)) deallocate(cl_smooth) - if(allocated(cn_smooth)) deallocate(cn_smooth) - if(allocated(cn )) deallocate(cn ) - if(allocated(cl_lin )) deallocate(cl_lin ) - if(allocated(cn_lin )) deallocate(cn_lin ) - allocate(cl_smooth(tab%NumAlf)) - allocate(cn_smooth(tab%NumAlf)) - allocate(cn (tab%NumAlf)) - allocate(cl_lin (tab%NumAlf)) - allocate(cn_lin (tab%NumAlf)) +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine Dvr_EndSim(dvr, errStat, errMsg) + type(Dvr_Data), target, intent(inout) :: dvr ! driver data + integer(IntKi) , intent(out) :: errStat ! Status of error message + character(*) , intent(out) :: errMsg ! Error message if errStat /= ErrID_None + character(ErrMsgLen) :: errMsg2 ! temporary Error message if errStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + character(*), parameter :: RoutineName = 'Dvr_EndSim' + type(Dvr_Outputs), pointer :: out ! driver output, data + out => dvr%out + errStat = ErrID_None + errMsg = '' + ! Close the output file + if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Ascii) then + if (out%unOutFile > 0) close(out%unOutFile) + endif + if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Binary) then + call WrScr(' Writing output file: '//trim(out%Root)//'.outb') + call WrBinFAST(trim(out%Root)//'.outb', FileFmtID_ChanLen_In, 'AeroDynDriver', out%WriteOutputHdr, out%WriteOutputUnt, (/0.0_DbKi, dvr%p%dt/), out%storage(:,:), errStat2, errMsg2) + call SetErrStat(errStat2, errMsg2, errStat, errMsg, RoutineName) + endif +end subroutine Dvr_EndSim - - cn = tab%Coefs(:,AFI_Params%ColCl) * cos(tab%alpha) + (tab%Coefs(:,AFI_Params%ColCd) - tab%UA_BL%Cd0) * sin(tab%alpha); - cn_lin = tab%UA_BL%C_nalpha * (tab%alpha - tab%UA_BL%alpha0) - cl_lin = tab%UA_BL%C_lalpha * (tab%alpha - tab%UA_BL%alpha0) - - do iRow = 1, tab%NumAlf - if ((tab%alpha(iRow)tab%UA_BL%alphaUpperWrap) then - cl_lin(iRow) =0.0_ReKi - cn_lin(iRow) =0.0_ReKi - endif - enddo - - ! Smoothing (used priot to compute slope in CalculateUACoeffs) - call kernelSmoothing(tab%alpha, cn , kernelType_TRIWEIGHT, 2.0_ReKi*D2R, cn_smooth) - call kernelSmoothing(tab%alpha, tab%Coefs(:,AFI_Params%ColCl), kernelType_TRIWEIGHT, 2.0_ReKi*D2R, cl_smooth) - - ! Write to file - - CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) - IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( unOutFile, trim(OutRootName)//'.UA.Coefs.'//trim(num2lstr(iTab))//'.out', ErrStat, ErrMsg ) - if (ErrStat >= AbortErrLev) then - call WrScr(Trim(ErrMsg)) - return - end if - - WRITE (unOutFile,'(/,A/)') 'These predictions were generated by UnsteadyAero Driver on '//CurDate()//' at '//CurTime()//'.' - WRITE (unOutFile,'(/,A/)') ' ' - - WRITE(unOutFile, '(20(A20,1x))') 'Alpha', 'Cl', 'Cd', sCm, 'Cn', 'f_st', Prefix//'FullySep', sFullyAtt , 'Cl_lin','Cn_lin','Cl_smooth', 'Cn_smooth' - WRITE(unOutFile, '(20(A20,1x))') '(deg)', '(-)', '(-)', '(-)', '(-)', '(-)', '(-)' , '(-)' , '(-)' , '(-)' , '(-)' ,'(-)' - - ! TODO, we could do something with ColCpmim and ColUAf - if (UseCm) then - iStartUA = 4 - do iRow=1,size(tab%Alpha) - WRITE(unOutFile, '(20(F20.6,1x))') tab%Alpha(iRow)*R2D, tab%Coefs(iRow,AFI_Params%ColCl), tab%Coefs(iRow,AFI_Params%ColCd), tab%Coefs(iRow,AFI_Params%ColCm), & - cn(iRow), tab%Coefs(iRow,iStartUA:), cl_lin(iRow), cn_lin(iRow), cl_smooth(iRow), cn_smooth(iRow) - end do - else - iStartUA = 3 - do iRow=1,size(tab%Alpha) - WRITE(unOutFile, '(20(F20.6,1x))') tab%Alpha(iRow)*R2D, tab%Coefs(iRow,AFI_Params%ColCl), tab%Coefs(iRow,AFI_Params%ColCd), 0.0_ReKi, & - cn(iRow), tab%Coefs(iRow,iStartUA:), cl_lin(iRow), cn_lin(iRow), cl_smooth(iRow), cn_smooth(iRow) - end do + + + + +! -------------------------------------------------------------------------------- +! --- IO +! -------------------------------------------------------------------------------- +!---------------------------------------------------------------------------------------------------------------------------------- +!> Concatenate new output channels info to the extisting ones in the driver +!! TODO COPY PASTED FROM AeroDyn_Inflow. Should be placed in NWTC_Lib NWTC_Str +subroutine concatOutputHeaders(WriteOutputHdr0, WriteOutputUnt0, WriteOutputHdr, WriteOutputUnt, errStat, errMsg) + character(ChanLen), dimension(:), allocatable, intent(inout) :: WriteOutputHdr0 !< Channel headers + character(ChanLen), dimension(:), allocatable, intent(inout) :: WriteOutputUnt0 !< Channel units + character(ChanLen), dimension(:), allocatable, intent(inout) :: WriteOutputHdr !< Channel headers + character(ChanLen), dimension(:), allocatable, intent(inout) :: WriteOutputUnt !< Channel units + integer(IntKi) , intent( out) :: errStat !< Status of error message + character(*) , intent( out) :: errMsg !< Error message if errStat /= ErrID_None + ! Locals + character(ChanLen), allocatable :: TmpHdr(:) + character(ChanLen), allocatable :: TmpUnt(:) + integer :: nOld, nAdd + errStat = ErrID_None + errMsg = '' + if (.not.allocated(WriteOutputHdr)) return + if (.not.allocated(WriteOutputHdr0)) then + call move_alloc(WriteOutputHdr, WriteOutputHdr0) + call move_alloc(WriteOutputUnt, WriteOutputUnt0) + else + nOld = size(WriteOutputHdr0) + nAdd = size(WriteOutputHdr) + + call move_alloc(WriteOutputHdr0, TmpHdr) + call move_alloc(WriteOutputUnt0, TmpUnt) + + allocate(WriteOutputHdr0(nOld+nAdd)) + allocate(WriteOutputUnt0(nOld+nAdd)) + WriteOutputHdr0(1:nOld) = TmpHdr + WriteOutputUnt0(1:nOld) = TmpUnt + WriteOutputHdr0(nOld+1:nOld+nAdd) = WriteOutputHdr + WriteOutputUnt0(nOld+1:nOld+nAdd) = WriteOutputUnt + deallocate(TmpHdr) + deallocate(TmpUnt) + endif +end subroutine concatOutputHeaders +!---------------------------------------------------------------------------------------------------------------------------------- +!> Initialize outputs to file for driver +subroutine Dvr_InitializeOutputs(out, numSteps, errStat, errMsg) + type(Dvr_Outputs), intent(inout) :: out + integer(IntKi) , intent(in ) :: numSteps ! Number of time steps + integer(IntKi) , intent( out) :: errStat ! Status of error message + character(*) , intent( out) :: errMsg ! Error message if errStat /= ErrID_None + ! locals + integer(IntKi) :: numOuts +! integer(IntKi) :: i +! integer(IntKi) :: numSpaces +! integer(IntKi) :: iWT +! character(ChanLen) :: colTxt +! character(ChanLen) :: caseTxt +! + numOuts = size(out%WriteOutputHdr) + + call AllocAry(out%outLine, numOuts-1, 'outLine', errStat, errMsg); ! NOTE: time not stored + out%outLine=0.0_ReKi +! +! ! --- Ascii +! if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Ascii) then +! +! ! compute the width of the column output +! numSpaces = out%ActualChanLen ! the size of column produced by OutFmt +! out%ActualChanLen = max( out%ActualChanLen, MinChanLen ) ! set this to at least MinChanLen , or the size of the column produced by OutFmt +! do i=1,numOuts +! out%ActualChanLen = max(out%ActualChanLen, LEN_TRIM(out%WriteOutputHdr(i))) +! out%ActualChanLen = max(out%ActualChanLen, LEN_TRIM(out%WriteOutputUnt(i))) +! end do +! +! ! create format statements for time and the array outputs: +! out%Fmt_t = '(F'//trim(num2lstr(out%ActualChanLen))//'.4)' +! out%Fmt_a = '"'//out%delim//'"'//trim(out%outFmt) ! format for array elements from individual modules +! numSpaces = out%ActualChanLen - numSpaces ! the difference between the size of the headers and what is produced by OutFmt +! if (numSpaces > 0) then +! out%Fmt_a = trim(out%Fmt_a)//','//trim(num2lstr(numSpaces))//'x' +! end if +! +! ! --- Start writing to ascii input file +! do iWT=1,nWT +! if (nWT>1) then +! sWT = '.T'//trim(num2lstr(iWT)) +! else +! sWT = '' +! endif +! call GetNewUnit(out%unOutFile(iWT), errStat, errMsg) +! if ( errStat >= AbortErrLev ) then +! out%unOutFile(iWT) = -1 +! return +! end if +! call OpenFOutFile ( out%unOutFile(iWT), trim(out%Root)//trim(sWT)//'.out', errStat, errMsg ) +! if ( errStat >= AbortErrLev ) return +! write (out%unOutFile(iWT),'(/,A)') 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//trim( version%Name ) +! write (out%unOutFile(iWT),'(1X,A)') trim(GetNVD(out%AD_ver)) +! write (out%unOutFile(iWT),'()' ) !print a blank line +! write (out%unOutFile(iWT),'()' ) !print a blank line +! write (out%unOutFile(iWT),'()' ) !print a blank line +! +! ! Write the names of the output parameters on one line: +! do i=1,numOuts +! call WrFileNR ( out%unOutFile(iWT), out%delim//out%WriteOutputHdr(i)(1:out%ActualChanLen) ) +! end do ! i +! write (out%unOutFile(iWT),'()') +! +! ! Write the units of the output parameters on one line: +! do i=1,numOuts +! call WrFileNR ( out%unOutFile(iWT), out%delim//out%WriteOutputUnt(i)(1:out%ActualChanLen) ) +! end do ! i +! write (out%unOutFile(iWT),'()') +! enddo +! endif +! + ! --- Binary + if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Binary) then + call AllocAry(out%storage, numOuts-1, numSteps, 'storage', errStat, errMsg) + out%storage= myNaN !0.0_ReKi ! Alternative: myNaN + endif +end subroutine Dvr_InitializeOutputs +!---------------------------------------------------------------------------------------------------------------------------------- +!> Initialize driver (not module-level) output channels +subroutine Dvr_InitializeDriverOutputs(dvr, out, errStat, errMsg) + type(Dvr_Data), intent(inout) :: dvr ! driver data + type(Dvr_Outputs), intent(inout) :: out ! driver output data + integer(IntKi) , intent( out) :: errStat ! Status of error message + character(*) , intent( out) :: errMsg ! Error message if errStat /= ErrID_None + integer(IntKi) :: errStat2 ! Status of error message + character(ErrMsgLen) :: errMsg2 ! Error message + integer :: j + errStat = ErrID_None + errMsg = '' + + out%ny_UA = size(dvr%UA_InitOutData%WriteOutputHdr) + if (dvr%p%SimMod==3) then + out%ny_dvr = 27 ! Driver only ! TODO + out%ny_LD = size(dvr%LD_InitOutData%WriteOutputHdr) + else + out%ny_dvr = 0 + out%ny_LD = 0 + endif + + + ! --- Allocate driver-level outputs + call AllocAry(out%WriteOutputHdr, 1+out%ny_dvr, 'WriteOutputHdr', errStat2, errMsg2); if(Failed()) return + call AllocAry(out%WriteOutputUnt, 1+out%ny_dvr, 'WriteOutputUnt', errStat2, errMsg2); if(Failed()) return + + j=1 + out%WriteOutputHdr(j) = 'Time' ; out%WriteOutputUnt(j) = '(s)' ; j=j+1 + if (dvr%p%SimMod==3) then + ! TODO SIMMOD HARMONIZATION + ! Driver Variables + out%WriteOutputHdr(j) = 'VUndx' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'VUndy' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'VSTx_Q' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'VSTy_Q' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'VSTx_T' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'VSTy_T' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrelx_Q' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrely_Q' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrelx_T' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrely_T' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrel_Q' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'Vrel_T' ; out%WriteOutputUnt(j) = '(m/s)' ; j=j+1 + out%WriteOutputHdr(j) = 'alpha_Q' ; out%WriteOutputUnt(j) = '(deg)' ; j=j+1 + out%WriteOutputHdr(j) = 'alpha_T' ; out%WriteOutputUnt(j) = '(deg)' ; j=j+1 + out%WriteOutputHdr(j) = 'phi_Q' ; out%WriteOutputUnt(j) = '(deg)' ; j=j+1 + out%WriteOutputHdr(j) = 'phi_T' ; out%WriteOutputUnt(j) = '(deg)' ; j=j+1 + out%WriteOutputHdr(j) = 'twist_full' ; out%WriteOutputUnt(j) = '(deg)' ; j=j+1 + out%WriteOutputHdr(j) = 'Re_T' ; out%WriteOutputUnt(j) = '(-)' ; j=j+1 + out%WriteOutputHdr(j) = 'L' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'D' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'M' ; out%WriteOutputUnt(j) = '(Nm/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'Fx_A' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'Fy_A' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'M_A' ; out%WriteOutputUnt(j) = '(Nm/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'GFx' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'GFy' ; out%WriteOutputUnt(j) = '(N/m)' ; j=j+1 + out%WriteOutputHdr(j) = 'GFM' ; out%WriteOutputUnt(j) = '(Nm/m)' ; j=j+1 + ! Dynamics + call concatOutputHeaders(out%WriteOutputHdr, out%WriteOutputUnt, dvr%LD_InitOutData%WriteOutputHdr, dvr%LD_InitOutData%WriteOutputUnt, errStat2, errMsg2) + endif + ! UA + call concatOutputHeaders(out%WriteOutputHdr, out%WriteOutputUnt, dvr%UA_InitOutData%WriteOutputHdr, dvr%UA_InitOutData%WriteOutputUnt, errStat2, errMsg2) + + out%ny = size(out%WriteOutputHdr) + ! Debug Write + !do j = 1, out%ny + ! print*,'Write Out: ',j, trim(out%WriteOutputHdr(j)), ' ', trim(out%WriteOutputUnt(j)) + !enddo +contains + logical function Failed() + CALL SetErrStat(errStat2, errMsg2, errStat, errMsg, 'Dvr_InitializeDriverOutputs' ) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine Dvr_InitializeDriverOutputs +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine Dvr_WriteOutputs(nt, t, dvr, out, errStat, errMsg) + integer(IntKi) , intent(in ) :: nt ! simulation time step + real(DbKi) , intent(in ) :: t ! simulation time (s) + type(Dvr_Data), intent(inout) :: dvr ! driver data + type(Dvr_Outputs) , intent(inout) :: out ! driver uotput options + integer(IntKi) , intent(inout) :: errStat ! Status of error message + character(*) , intent(inout) :: errMsg ! Error message if errStat /= ErrID_None +! ! Local variables. +! character(ChanLen) :: tmpStr ! temporary string to print the time output as text + integer :: nDV , nUA, nLD,j + errStat = ErrID_None + errMsg = '' + out%outLine = myNaN ! Safety +! + ! --- Packing all outputs except time into one array + nDV = out%ny_dvr + nLD = out%ny_LD + nUA = out%ny_UA + ! Driver outputs + j = 1 + if (dvr%p%SimMod==3) then + ! TODO harmonization + out%outLine(j) = dvr%U0(1, 1) ; j=j+1 ! Ux + out%outLine(j) = dvr%U0(1, 2) ; j=j+1 ! Uy + out%outLine(j) = dvr%m%Vst_Q(1) ; j=j+1 ! VSTx_Q + out%outLine(j) = dvr%m%Vst_Q(2) ; j=j+1 ! VSTy_Q + out%outLine(j) = dvr%m%Vst_T(1) ; j=j+1 ! VSTx_T + out%outLine(j) = dvr%m%Vst_T(2) ; j=j+1 ! VSTy_T + out%outLine(j) = dvr%m%Vrel_Q(1) ; j=j+1 ! Vrelx_Q + out%outLine(j) = dvr%m%Vrel_Q(2) ; j=j+1 ! Vrely_Q + out%outLine(j) = dvr%m%Vrel_T(1) ; j=j+1 ! Vrelx_T + out%outLine(j) = dvr%m%Vrel_T(2) ; j=j+1 ! Vrely_T + out%outLine(j) = sqrt(dvr%m%Vrel_norm2_Q) ; j=j+1 ! Vrel_Q + out%outLine(j) = sqrt(dvr%m%Vrel_norm2_T) ; j=j+1 ! Vrel_T + out%outLine(j) = dvr%m%alpha_Q*R2D ; j=j+1 ! alpha_Q + out%outLine(j) = dvr%m%alpha_T*R2D ; j=j+1 ! alpha_T + out%outLine(j) = dvr%m%phi_Q *R2D ; j=j+1 ! phi_Q + out%outLine(j) = dvr%m%phi_T *R2D ; j=j+1 ! phi_T + out%outLine(j) = dvr%m%twist_full*R2D ; j=j+1 ! twist_full + out%outLine(j) = dvr%m%Re ; j=j+1 ! Re_T + out%outLine(j) = dvr%m%L ; j=j+1 ! L + out%outLine(j) = dvr%m%D ; j=j+1 ! D + out%outLine(j) = dvr%m%tau_Q ; j=j+1 ! M + out%outLine(j) = dvr%m%FxA ; j=j+1 ! Fx_A + out%outLine(j) = dvr%m%FyA ; j=j+1 ! Fy_A + out%outLine(j) = dvr%m%tau_A ; j=j+1 ! M_A + out%outLine(j) = dvr%m%GF(1) ; j=j+1 ! GFx + out%outLine(j) = dvr%m%GF(2) ; j=j+1 ! GFy + out%outLine(j) = dvr%m%GF(3) ; j=j+1 ! GFM + ! LD Outputs + out%outLine(nDV+1:nDV+nLD) = dvr%LD_y%WriteOutput(1:nLD) + endif + ! UA Outputs + out%outLine(nDV+nLD+1:nDV+nLD+nUA) = dvr%UA_y%WriteOutput(1:nUA) + + !if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Ascii) then + ! ! ASCII + ! ! time + ! write( tmpStr, out%Fmt_t ) t ! '(F15.4)' + ! call WrFileNR( out%unOutFile, tmpStr(1:out%ActualChanLen) ) + ! call WrNumAryFileNR(out%unOutFile, out%outLine, out%Fmt_a, errStat, errMsg) + ! ! write a new line (advance to the next line) + ! write(out%unOutFile,'()') + !endif + if (out%fileFmt==idFmt_Both .or. out%fileFmt == idFmt_Binary) then + ! Store for binary + out%storage(:, nt) = out%outLine(:) + !out%storage(1:nDV+nAD+nIW, nt) = out%outLine(1:nDV+nAD+nIW) + endif +end subroutine Dvr_WriteOutputs +! + + +subroutine WriteAFITables(AFI_Params, OutRootName, UseCm, UA_f_cn) + + type(AFI_ParameterType), intent(in), target :: AFI_Params + character(len=*) , intent(in) :: OutRootName + logical , intent(in) :: UseCm + logical , intent(in) :: UA_f_cn + + integer(IntKi) :: unOutFile + integer(IntKi) :: ErrStat + character(ErrMsgLen) :: ErrMsg + + Real(ReKi), allocatable :: cl_smooth(:) + Real(ReKi), allocatable :: cn_smooth(:) + Real(ReKi), allocatable :: cn(:) + Real(ReKi), allocatable :: cl_lin(:) + Real(ReKi), allocatable :: cn_lin(:) + character(len=3) :: Prefix + character(len=11) :: sFullyAtt + character(len=8) :: sCm + integer :: iTab, iRow, iStartUA + type(AFI_Table_Type), pointer :: tab !< Alias + + if (UA_f_cn) then + Prefix='Cn_' + sFullyAtt='Cn_FullyAtt' + else + Prefix='Cl_' + sFullyAtt='Dummy' + endif + if (UseCm) then + sCm='Cm' + else + sCm='Cm_Dummy' + endif + + + ! Loop on tables, write a different file for each table. + do iTab = 1, size(AFI_Params%Table) + tab => AFI_Params%Table(iTab) + + ! Compute derived parameters from cl and cd, and UA_BL + if(allocated(cl_smooth)) deallocate(cl_smooth) + if(allocated(cn_smooth)) deallocate(cn_smooth) + if(allocated(cn )) deallocate(cn ) + if(allocated(cl_lin )) deallocate(cl_lin ) + if(allocated(cn_lin )) deallocate(cn_lin ) + allocate(cl_smooth(tab%NumAlf)) + allocate(cn_smooth(tab%NumAlf)) + allocate(cn (tab%NumAlf)) + allocate(cl_lin (tab%NumAlf)) + allocate(cn_lin (tab%NumAlf)) + + + cn = tab%Coefs(:,AFI_Params%ColCl) * cos(tab%alpha) + (tab%Coefs(:,AFI_Params%ColCd) - tab%UA_BL%Cd0) * sin(tab%alpha); + cn_lin = tab%UA_BL%C_nalpha * (tab%alpha - tab%UA_BL%alpha0) + cl_lin = tab%UA_BL%C_lalpha * (tab%alpha - tab%UA_BL%alpha0) + + do iRow = 1, tab%NumAlf + if ((tab%alpha(iRow)tab%UA_BL%alphaUpperWrap) then + cl_lin(iRow) =0.0_ReKi + cn_lin(iRow) =0.0_ReKi endif - - CLOSE(unOutFile) enddo + + ! Smoothing (used priot to compute slope in CalculateUACoeffs) + call kernelSmoothing(tab%alpha, cn , kernelType_TRIWEIGHT, 2.0_ReKi*D2R, cn_smooth) + call kernelSmoothing(tab%alpha, tab%Coefs(:,AFI_Params%ColCl), kernelType_TRIWEIGHT, 2.0_ReKi*D2R, cl_smooth) + + ! Write to file + + CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) + IF ( ErrStat /= ErrID_None ) RETURN + + CALL OpenFOutFile ( unOutFile, trim(OutRootName)//'.Coefs.'//trim(num2lstr(iTab))//'.out', ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) then + call WrScr(Trim(ErrMsg)) + return + end if + + WRITE (unOutFile,'(/,A/)') 'These predictions were generated by UnsteadyAero Driver on '//CurDate()//' at '//CurTime()//'.' + WRITE (unOutFile,'(/,A/)') ' ' + + WRITE(unOutFile, '(20(A20,1x))') 'Alpha', 'Cl', 'Cd', sCm, 'Cn', 'f_st', Prefix//'FullySep', sFullyAtt , 'Cl_lin','Cn_lin','Cl_smooth', 'Cn_smooth' + WRITE(unOutFile, '(20(A20,1x))') '(deg)', '(-)', '(-)', '(-)', '(-)', '(-)', '(-)' , '(-)' , '(-)' , '(-)' , '(-)' ,'(-)' + + ! TODO, we could do something with ColCpmim and ColUAf + if (UseCm) then + iStartUA = 4 + do iRow=1,size(tab%Alpha) + WRITE(unOutFile, '(20(F20.6,1x))') tab%Alpha(iRow)*R2D, tab%Coefs(iRow,AFI_Params%ColCl), tab%Coefs(iRow,AFI_Params%ColCd), tab%Coefs(iRow,AFI_Params%ColCm), & + cn(iRow), tab%Coefs(iRow,iStartUA:), cl_lin(iRow), cn_lin(iRow), cl_smooth(iRow), cn_smooth(iRow) + end do + else + iStartUA = 3 + do iRow=1,size(tab%Alpha) + WRITE(unOutFile, '(20(F20.6,1x))') tab%Alpha(iRow)*R2D, tab%Coefs(iRow,AFI_Params%ColCl), tab%Coefs(iRow,AFI_Params%ColCd), 0.0_ReKi, & + cn(iRow), tab%Coefs(iRow,iStartUA:), cl_lin(iRow), cn_lin(iRow), cl_smooth(iRow), cn_smooth(iRow) + end do + endif - end subroutine WriteAFITables + CLOSE(unOutFile) + enddo + +end subroutine WriteAFITables end module UA_Dvr_Subs diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index 268757ecd9..ffb217631c 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -522,7 +522,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%Cn_q_circ = KC%C_nalpha_circ*KC%q_f_cur/2.0 - KC%X3 - KC%X4 ! Eqn 1.16 - else ! these aren't used (they are possibly output to UA output file (when UA_OUTS defined) file, though) + else ! these aren't used (they are possibly output to UA output file when UA_OUTS is > 0 file, though) KC%X3 = 0.0_ReKi KC%X4 = 0.0_ReKi KC%Cn_q_circ = 0.0_ReKi @@ -740,12 +740,14 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) if (ErrStat >= AbortErrLev) return p%c = InitInp%c ! this can't be 0 + p%d_34_to_ac = InitInp%d_34_to_ac ! In the future, set this for all nodes! p%numBlades = InitInp%numBlades p%nNodesPerBlade = InitInp%nNodesPerBlade p%UAMod = InitInp%UAMod p%a_s = InitInp%a_s ! this can't be 0 p%Flookup = InitInp%Flookup p%ShedEffect = InitInp%ShedEffect + p%UA_OUTS = InitInp%UA_OUTS if (p%UAMod==UA_HGM .or. p%UAMod==UA_HGMV) then UA_NumLinStates = 4 @@ -755,6 +757,9 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) else if (p%UAMod==UA_OYE) then UA_NumLinStates = 1 p%lin_nx = p%numBlades*p%nNodesPerBlade*UA_NumLinStates ! continuous state per node per blade, but stored at position 4 + else if (p%UAMod==UA_None) then + p%lin_nx = 0 + UA_NumLinStates = 0 else p%lin_nx = 0 UA_NumLinStates = 0 @@ -944,13 +949,12 @@ subroutine UA_InitStates_Misc( p, x, xd, OtherState, m, ErrStat, ErrMsg ) call AllocAry(OtherState%sigma1m ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1m',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AllocAry(OtherState%sigma3 ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma3',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - -# ifdef UA_OUTS + if(p%UA_OUTS>0) then call AllocAry(m%TESF ,p%nNodesPerBlade,p%numBlades,'m%TESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AllocAry(m%LESF ,p%nNodesPerBlade,p%numBlades,'m%LESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AllocAry(m%VRTX ,p%nNodesPerBlade,p%numBlades,'m%VRTX',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AllocAry(m%T_Sh ,p%nNodesPerBlade,p%numBlades,'m%T_Sh',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) -# endif + endif end if call AllocAry(m%weight ,p%nNodesPerBlade,p%numBlades,'m%weight',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -1041,12 +1045,12 @@ subroutine UA_ReInit( p, x, xd, OtherState, m, ErrStat, ErrMsg ) OtherState%sigma1m = 1.0_ReKi OtherState%sigma3 = 1.0_ReKi -# ifdef UA_OUTS + if (p%UA_OUTS>0) then m%TESF = .FALSE. m%LESF = .FALSE. m%VRTX = .FALSE. m%T_sh = 0.0_ReKi -# endif + endif xd%Cn_prime_minus1 = 0.0_ReKi xd%alpha_minus1 = 0.0_ReKi @@ -1120,12 +1124,6 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & integer(IntKi) :: errStat2 ! temporary Error status of the operation character(*), parameter :: RoutineName = 'UA_Init' -#ifdef UA_OUTS - CHARACTER(6) :: TmpChar ! Temporary char array to hold the node digits (3 places only!!!!) - integer(IntKi) :: i,j, iNode, iOffset - character(64) :: chanPrefix -#endif - ! Initialize variables for this routine ErrStat = ErrID_None ErrMsg = "" @@ -1135,30 +1133,55 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & call NWTC_Init( EchoLibVer=.FALSE. ) if (InitInp%WrSum) then - call UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return + call UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat2, ErrMsg2); if(Failed()) return end if - call UA_ValidateInput(InitInp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return + call UA_ValidateInput(InitInp, ErrStat2, ErrMsg2); if(Failed()) return ! Allocate and set parameter data structure using initialization data - call UA_SetParameters( interval, InitInp, p, AFInfo, AFIndx, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return + call UA_SetParameters( interval, InitInp, p, AFInfo, AFIndx, ErrStat2, ErrMsg2 ); if(Failed()) return - ! initialize the discrete states, other states, and misc variables - call UA_InitStates_Misc( p, x, xd, OtherState, m, ErrStat2, ErrMsg2 ) ! initialize the continuous states - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return + ! initialize the states, and misc variables + call UA_InitStates_Misc( p, x, xd, OtherState, m, ErrStat2, ErrMsg2 ); if(Failed()) return + ! --- Write Outputs + call UA_Init_Outputs(InitInp, p, y, InitOut, errStat2, errMsg2); if(Failed()) return -#ifdef UA_OUTS +contains + logical function Failed() + call SetErrStat( errStat2, errMsg2, errStat, errMsg, 'UA_Init' ) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine UA_Init + +!============================================================================== +subroutine UA_Init_Outputs(InitInp, p, y, InitOut, errStat, errMsg) + type(UA_InitInputType), intent(in ) :: InitInp ! input data for initialization routine ; we're moving allocated data from InitInp to p so must also be intent(out) + type(UA_ParameterType), intent(inout) :: p ! Parameters + type(UA_OutputType), intent(inout) :: y ! Initial system outputs (outputs are not calculated; + !type(UA_MiscVarType), intent( out) :: m ! Initial misc/optimization variables + type(UA_InitOutputType), intent( out) :: 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 + character(6) :: TmpChar ! Temporary char array to hold the node digits (3 places only!!!!) + integer(IntKi) :: i,j, iNode, iOffset + character(64) :: chanPrefix + character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + character(*), parameter :: RoutineName = 'UA_Init' + errStat = errID_None + errMsg = "" + + if (p%UA_OUTS==0) then + p%NumOuts = 0 + p%unOutFile = -1 + return + endif ! Allocate and set the InitOut data - if (p%UAMod == UA_HGM .or. p%UAMod == UA_OYE) then + if (p%UAMod == UA_None) then + p%NumOuts = 11 + elseif (p%UAMod == UA_HGM .or. p%UAMod == UA_OYE) then p%NumOuts = 20 elseif(p%UAMod == UA_HGMV) then p%NumOuts = 21 @@ -1184,8 +1207,12 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & iOffset = (i-1)*p%NumOuts + (j-1)*p%nNodesPerBlade*p%NumOuts !chanPrefix = "B"//trim(num2lstr(j))//"N"//trim(num2lstr(i)) - write (TmpChar,'(I3.3)') i ! 3 digit number - chanPrefix = 'AB' // TRIM(Num2LStr(j)) // 'N' // TRIM(TmpChar) + if ((p%numBlades==1) .and. (p%nNodesPerBlade==1) .and. p%UA_OUTS==1) then + chanPrefix='' ! UA_Driver + else + write (TmpChar,'(I3.3)') i ! 3 digit number + chanPrefix = 'AB' // TRIM(Num2LStr(j)) // 'N' // TRIM(TmpChar) + endif InitOut%WriteOutputHdr(iOffset+ 1) = trim(chanPrefix)//'Alpha' InitOut%WriteOutputHdr(iOffset+ 2) = trim(chanPrefix)//'Vrel' @@ -1203,7 +1230,20 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & InitOut%WriteOutputUnt(iOffset+ 6) ='(-)' InitOut%WriteOutputUnt(iOffset+ 7) ='(-)' - if (p%UAmod == UA_HGM .or. p%UAMod == UA_HGMV .or. p%UAMod == UA_OYE) then + if (p%UAmod == UA_None) then + + InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'omega' + InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'alphaE' + InitOut%WriteOutputHdr(iOffset+10) = trim(chanPrefix)//'Tu' + InitOut%WriteOutputHdr(iOffset+11) = trim(chanPrefix)//'alpha_34' + + InitOut%WriteOutputUnt(iOffset+ 8) = '(deg/sec)' + InitOut%WriteOutputUnt(iOffset+ 9) = '(deg)' + InitOut%WriteOutputUnt(iOffset+10) = '(s)' + InitOut%WriteOutputUnt(iOffset+11) = '(deg)' + + + elseif (p%UAmod == UA_HGM .or. p%UAMod == UA_HGMV .or. p%UAMod == UA_OYE) then InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'omega' InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'alphaE' @@ -1282,7 +1322,7 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & InitOut%WriteOutputUnt(iOffset+25) = '(m/s)' InitOut%WriteOutputUnt(iOffset+26) = '(m/s)' - else + else if (p%UAmod == UA_Baseline .or. p%UAMod == UA_Gonzalez .or. p%UAMod == UA_MinnemaPierce) then InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'Cn_aq_circ' InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'Cn_aq_nc' @@ -1363,6 +1403,8 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & InitOut%WriteOutputUnt(iOffset+44) ='(-)' InitOut%WriteOutputUnt(iOffset+45) ='(deg)' + else + call SetErrStat( ErrID_Fatal, 'Programming error UAmod case not accounted for.', ErrStat, ErrMsg, RoutineName ); return end if end do @@ -1372,11 +1414,13 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & p%OutFmt = 'ES19.5e3' p%Delim ='' - if (p%NumOuts > 0) then + ! --- Write to File + if ((p%NumOuts > 0) .and. p%UA_OUTS==2) then + call WrScr(' UA: Writing separate output file: '//trim((InitInp%OutRootName)//'.out')) CALL GetNewUnit( p%unOutFile, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - CALL OpenFOutFile ( p%unOutFile, trim(InitInp%OutRootName)//'.UA.out', ErrStat2, ErrMsg2 ) + CALL OpenFOutFile ( p%unOutFile, trim(InitInp%OutRootName)//'.out', ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -1396,35 +1440,27 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & WRITE (p%unOutFile,'(:,A,'//trim( p%OutSFmt )//')', ADVANCE='no' ) p%Delim, trim(InitOut%WriteOutputUnt(i)) end do WRITE (p%unOutFile,'()', IOSTAT=ErrStat2) ! write the line return - end if - + else -#else - p%NumOuts = 0 - p%unOutFile = -1 - !..................................... - ! add the following two lines only to avoid compiler warnings about uninitialized variables when not building the UA driver: - y%cm = 0.0_ReKi - InitOut%Version = ProgDesc( 'Unsteady Aero', '', '' ) - !..................................... - -#endif - -end subroutine UA_Init + call WrScr(' UA: saving write outputs') + + end if +end subroutine UA_Init_Outputs !============================================================================== subroutine UA_ValidateInput(InitInp, ErrStat, ErrMsg) type(UA_InitInputType), intent(in ) :: InitInp ! Input data for initialization routine integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None + integer, parameter :: UA_VALID(7) = (/UA_None, UA_Gonzalez, UA_MinnemaPierce, UA_HGM ,UA_HGMV, UA_Oye, UA_BV/) character(*), parameter :: RoutineName = 'UA_ValidateInput' ErrStat = ErrID_None ErrMsg = "" - if (InitInp%UAMod < UA_Gonzalez .or. InitInp%UAMod > UA_BV ) call SetErrStat( ErrID_Fatal, & - "In this version, UAMod must be 2 (Gonzalez's variant), 3 (Minnema/Pierce variant), 4 (continuous HGM model), 5 (HGM with vortex), & - &6 (Oye), 7 (Boeing-Vertol)", ErrStat, ErrMsg, RoutineName ) ! NOTE: for later- 1 (baseline/original) + if (.not.(any(InitInp%UAMod==UA_VALID))) call SetErrStat( ErrID_Fatal, & + "In this version, UAMod must be 0 (None), 2 (Gonzalez's variant), 3 (Minnema/Pierce variant), 4 (continuous HGM model), 5 (HGM with vortex), & + &6 (Oye), 7 (Boing-Vertol)", ErrStat, ErrMsg, RoutineName ) ! NOTE: for later- 1 (baseline/original) if (.not. InitInp%FLookUp ) call SetErrStat( ErrID_Fatal, 'FLookUp must be TRUE for this version.', ErrStat, ErrMsg, RoutineName ) @@ -1613,8 +1649,10 @@ subroutine UA_TurnOff_param(p, AFInfo, ErrStat, ErrMsg) end if end do + if (p%UAMod == UA_None) then + ! pass - if (p%UAMod == UA_HGM .or. p%UAMod == UA_OYE) then + else if (p%UAMod == UA_HGM .or. p%UAMod == UA_OYE) then ! unsteady aerodynamics will be turned off if Cl,alpha = 0 do j=1, AFInfo%NumTabs if ( EqualRealNos(AFInfo%Table(j)%UA_BL%C_lalpha, 0.0_ReKi) ) then @@ -1698,7 +1736,7 @@ subroutine UA_UpdateDiscOtherState_BV( i, j, u, p, xd, OtherState, AFInfo, m, Er ! --- Filter angle of attack ! Using angle of attack at AC or 3/4 point - alpha_34 = Get_Alpha34(u%v_ac, u%omega, 0.5_ReKi*p%c(i,j)) + alpha_34 = Get_Alpha34(u%v_ac, u%omega, p%d_34_to_ac*p%c(i,j)) ! Angle of attack at previous time if (OtherState%FirstPass(i,j)) then alpha_minus1 = alpha_34 @@ -1767,7 +1805,7 @@ subroutine BV_getAlphas(i, j, u, p, xd, BL_p, tc, alpha_34, alphaE_L, alphaLag_D real(ReKi), parameter :: umach = 0.0_ReKi !< Mach number umach=Urel*Minf, Minf (freestrem Mach) for incompressible ! Angle of attack at 3/4 chord point - alpha_34 = Get_Alpha34(u%v_ac, u%omega, 0.5_ReKi*p%c(i,j)) + alpha_34 = Get_Alpha34(u%v_ac, u%omega, p%d_34_to_ac*p%c(i,j)) ! --- Intermediate variables, using CACTUS notations adotnorm = xd%alpha_dot(i,j) * Get_Tu(u%u, p%c(i,j)) @@ -2218,12 +2256,12 @@ subroutine UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrSt end if end if -#ifdef UA_OUTS + if (p%UA_OUTS>0) then m%TESF(i,j) = TESF m%LESF(i,j) = LESF m%VRTX(i,j) = VRTX m%T_sh(i,j) = T_sh -#endif + endif end subroutine UA_UpdateDiscOtherState @@ -2270,6 +2308,7 @@ subroutine UA_UpdateStates( i, j, t, n, u, uTimes, p, x, xd, OtherState, AFInfo, !BJJ: u%u == 0 seems to be the root cause of all sorts of numerical problems.... + if (p%UAMod == UA_None) return ! we don't have any states to update here if (p%UA_off_forGood(i,j)) return ! we don't have any states to update here @@ -2740,7 +2779,7 @@ SUBROUTINE Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) Tu = Get_Tu(u%u, p%c(i,j)) if (present(alpha_34)) then - alpha_34 = Get_Alpha34(u%v_ac, u%omega, 0.5_ReKi*p%c(i,j)) + alpha_34 = Get_Alpha34(u%v_ac, u%omega, p%d_34_to_ac*p%c(i,j)) if (present(alphaE)) then ! Variables derived from states @@ -2756,19 +2795,19 @@ SUBROUTINE Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) END SUBROUTINE Get_HGM_constants !> Compute angle of attack at 3/4 chord point based on values at Aerodynamic center -real(ReKi) function Get_Alpha34(v_ac, omega, d_ac_to_34) - real(ReKi), intent(in) :: v_ac(2) !< Velocity at aerodynamic center +real(ReKi) function Get_Alpha34(v_ac, omega, d_34_to_ac) + real(ReKi), intent(in) :: v_ac(2) !< Velocity at aerodynamic center (AC) real(ReKi), intent(in) :: omega !< pitching rate of airfoil - real(ReKi), intent(in) :: d_ac_to_34 !< distance from aerodynamic center to 3/4 chord point - Get_Alpha34 = atan2(v_ac(1) + omega * d_ac_to_34, v_ac(2) ) ! Uaero - Uelast + real(ReKi), intent(in) :: d_34_to_ac !< distance from 3/4 chord to AC point, assumed >0, e.g. =0.5c + Get_Alpha34 = atan2(v_ac(1) + omega * d_34_to_ac, v_ac(2) ) ! Uaero - Uelast end function Get_Alpha34 !> Compute angle of attack at 2/4 chord point based on values at Aerodynamic center -real(ReKi) function Get_Alpha24(v_ac, omega, d_ac_to_24) - real(ReKi), intent(in) :: v_ac(2) !< Velocity at aerodynamic center +real(ReKi) function Get_Alpha24(v_ac, omega, d_24_to_ac) + real(ReKi), intent(in) :: v_ac(2) !< Velocity at aerodynamic center (AC) real(ReKi), intent(in) :: omega !< pitching rate of airfoil - real(ReKi), intent(in) :: d_ac_to_24 !< distance from aerodynamic center to 2/4 chord point - Get_Alpha24 = atan2(v_ac(1) + omega * d_ac_to_24, v_ac(2) ) ! Uaero - Uelast + real(ReKi), intent(in) :: d_24_to_ac !< distance from 2/4 chord to AC point, assumed >0, e.g. =0.25c + Get_Alpha24 = atan2(v_ac(1) + omega * d_24_to_ac, v_ac(2) ) ! Uaero - Uelast end function Get_Alpha24 !> Compute time constant based on relative velocity u_rel @@ -3315,19 +3354,14 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, real(ReKi) :: alphaE_L, alphaE_D ! effective angle of attack for lift and drag real(ReKi) :: alphaLag_D ! lagged angle of attack for drag calculation real(ReKi) :: adotnorm -#ifdef UA_OUTS real(ReKi) :: delN real(ReKi) :: delP real(ReKi) :: gammaL real(ReKi) :: gammaD real(ReKi) :: TransA -#endif type(AFI_OutputType) :: AFI_interp -#ifdef UA_OUTS - integer :: iOffset -#endif ErrStat = ErrID_None ! no error has occurred ErrMsg = "" @@ -3342,8 +3376,21 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, call UA_fixInputs(u_in, u, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) k = abs(u%omega * p%c(i, j) / (2.0_ReKi* u%u)) - - if ( p%UA_off_forGood(i,j) .or. (OtherState%FirstPass(i, j) .and. p%UAMod < UA_HGM) ) then ! note: if u%U isn't zero because we've called UA_fixInputs + + if ( p%UAMod == UA_None) then + + ! Compute steady aero using alpha 34 to be consistent with most UA models + Tu = Get_Tu(u%u, p%c(i,j)) + alpha_34 = Get_Alpha34(u%v_ac, u%omega, p%d_34_to_ac*p%c(i,j)) + call AFI_ComputeAirfoilCoefs( alpha_34, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + y%Cl = AFI_interp%Cl + y%Cd = AFI_interp%Cd + y%Cm = AFI_interp%Cm + y%Cn = y%Cl*cos(u%alpha) + y%Cd*sin(u%alpha) + y%Cc = y%Cl*sin(u%alpha) - y%Cd*cos(u%alpha) + if (AFInfo%ColCm == 0) y%Cm = 0.0_ReKi + + else if ( p%UA_off_forGood(i,j) .or. (OtherState%FirstPass(i, j) .and. p%UAMod < UA_HGM) ) then ! note: if u%U isn't zero because we've called UA_fixInputs misc%weight(i,j) = 0.0 @@ -3458,7 +3505,8 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, y%Cn = y%Cl*cos(u%alpha) + y%Cd*sin(u%alpha) y%Cc = y%Cl*sin(u%alpha) - y%Cd*cos(u%alpha) - else + + elseif (p%UAMod == UA_HGMV) then ! limit x5?: x5 = x_in%x(5) @@ -3486,6 +3534,9 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, ! alphaF = x_in%x(3) / BL_p%c_lalpha + BL_p%alpha0 y%Cm = AFI_interp%Cm + cn_circ * delta_c_mf_primeprime - 0.0_ReKi * piBy2 * Tu * u%omega - 0.25_ReKi*(1.0_ReKi - cos(pi * tV_ratio ))*x5 end if + + else + call SetErrStat(ErrID_Fatal, "Programming error, UAMod continuous model not accounted for", ErrStat, ErrMsg, RoutineName) end if @@ -3493,7 +3544,7 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, call UA_BlendSteady(u, p, AFInfo, y, misc%FirstWarn_UA_off, misc%weight(i,j), ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - else + elseif (p%UAMod == UA_Baseline .or. p%UAMod == UA_Gonzalez .or. p%UAMod == UA_MinnemaPierce) then ! --- CalcOutput Beddoes-Leishman type models M = u%U / p%a_s @@ -3641,11 +3692,22 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, call UA_BlendSteady(u, p, AFInfo, y, misc%FirstWarn_UA_off, misc%weight(i,j), ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + else + call SetErrStat(ErrID_Fatal, "Programming error, UAMod not accounted for", ErrStat, ErrMsg, RoutineName) + end if ! Switch on UAMod + + if (p%UA_OUTS>0) then + if (allocated(y%WriteOutput)) then !bjj: because BEMT uses local variables for UA output, y%WriteOutput is not necessarially allocated. Need to figure out a better solution. + call CalcWriteOutputs() + endif + endif -#ifdef UA_OUTS - iOffset = (i-1)*p%NumOuts + (j-1)*p%nNodesPerBlade*p%NumOuts - if (allocated(y%WriteOutput)) then !bjj: because BEMT uses local variables for UA output, y%WriteOutput is not necessarially allocated. Need to figure out a better solution. +contains + + subroutine CalcWriteOutputs() + integer :: iOffset + iOffset = (i-1)*p%NumOuts + (j-1)*p%nNodesPerBlade*p%NumOuts y%WriteOutput(iOffset+ 1) = u%alpha*R2D y%WriteOutput(iOffset+ 2) = u%U @@ -3654,8 +3716,14 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, y%WriteOutput(iOffset+ 5) = y%Cl y%WriteOutput(iOffset+ 6) = y%Cd y%WriteOutput(iOffset+ 7) = y%Cm + + if (p%UAMod == UA_None) then + y%WriteOutput(iOffset+ 8) = u%omega*R2D + y%WriteOutput(iOffset+ 9) = alpha_34*R2D + y%WriteOutput(iOffset+10) = Tu + y%WriteOutput(iOffset+11) = alpha_34*R2D - if (p%UAMod == UA_HGM .or. p%UAMod == UA_HGMV .or. p%UAMod == UA_OYE) then + elseif (p%UAMod == UA_HGM .or. p%UAMod == UA_HGMV .or. p%UAMod == UA_OYE) then y%WriteOutput(iOffset+ 8) = u%omega*R2D y%WriteOutput(iOffset+ 9) = alphaE*R2D y%WriteOutput(iOffset+10) = Tu @@ -3752,11 +3820,9 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, y%WriteOutput(iOffset+45) = KC%alpha_filt_cur*R2D end if - end if -#endif + end subroutine CalcWriteOutputs -contains - !> Calc Outputs for Boeing-Vertol dynamic stall + !> Calc Outputs for Boieng-Vertol dynamic stall !! See BV_DynStall.f95 of CACTUS, and [70], notations kept more or less consistent subroutine BV_CalcOutput() real(ReKi) :: alpha_50 @@ -3772,15 +3838,13 @@ subroutine BV_CalcOutput() call BV_getAlphas(i, j, u, p, xd, BL_p, AFInfo%RelThickness, alpha_34, alphaE_L, alphaLag_D, adotnorm) alphaE_D = BV_alphaE_D(adotnorm, alpha_34, alphaLag_D, BL_p, OtherState%activeD(i,j)) -#ifdef UA_OUTS ! --- Recompute variables, for temporary output to file only ! Calculate deltas to negative and positive stall angle (delN, and delP) - call BV_delNP(adotnorm, alpha_34, alphaLag_D, BL_p, OtherState%activeD(i,j), delN, delP) - call BV_getGammas(tc=AFInfo%RelThickness, umach=0.0_ReKi, gammaL=gammaL, gammaD=gammaD) - TransA = BV_TransA(BL_p) -#endif - - + if (p%UA_OUTS>0) then + call BV_delNP(adotnorm, alpha_34, alphaLag_D, BL_p, OtherState%activeD(i,j), delN, delP) + call BV_getGammas(tc=AFInfo%RelThickness, umach=0.0_ReKi, gammaL=gammaL, gammaD=gammaD) + TransA = BV_TransA(BL_p) + endif ! --- Cl, _, at effective angle of attack alphaE if (OtherState%activeL(i,j)) then @@ -3808,7 +3872,7 @@ subroutine BV_CalcOutput() Cm25_stat = AFI_interp%Cm endif ! Static coeffs at 1/2 chord (alpha_50) - alpha_50 = Get_Alpha24(u%v_ac, u%omega, 0.25_ReKi*p%c(i,j)) + alpha_50 = Get_Alpha24(u%v_ac, u%omega, (p%d_34_to_ac-0.25)*p%c(i,j)) ! NOTE: d_24_to_ac = (d_34_to_ac - 1/4) call AFI_ComputeAirfoilCoefs(alpha_50, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Cl50_stat = AFI_interp%Cl ! Static coeffs at 3/4 chord (alpha_34) @@ -3845,8 +3909,7 @@ subroutine UA_WriteOutputToFile(t, p, y) integer :: k ! Generate file outputs -#ifdef UA_OUTS - if (p%unOutFile > 0 .and. allocated(y%WriteOutput)) then + if (p%UA_OUTS==2 .and. p%unOutFile > 0 .and. allocated(y%WriteOutput)) then write (p%unOutFile,"(F19.6)",ADVANCE='no') t do k=1,size(y%WriteOutput) @@ -3855,10 +3918,10 @@ subroutine UA_WriteOutputToFile(t, p, y) WRITE (p%unOutFile,'()') ! write the line return end if -#endif end subroutine UA_WriteOutputToFile !============================================================================== +! TODO Somehow merge this content with the unsteady aero driver summary file? subroutine UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat, ErrMsg) type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data (for all airfoils) type(UA_InitInputType), intent(in ) :: InitInp ! input data for initialization routine @@ -3938,7 +4001,7 @@ subroutine UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat, ErrMsg) CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) IF ( ErrStat /= ErrID_None ) RETURN - CALL OpenFOutFile ( unOutFile, trim(InitInp%OutRootName)//'.UA.sum', ErrStat2, ErrMsg2 ) + CALL OpenFOutFile ( unOutFile, trim(InitInp%OutRootName)//'.sum', ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return diff --git a/modules/aerodyn/src/UnsteadyAero_Driver.f90 b/modules/aerodyn/src/UnsteadyAero_Driver.f90 index 1ffac32865..f04e4391b7 100644 --- a/modules/aerodyn/src/UnsteadyAero_Driver.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Driver.f90 @@ -19,10 +19,6 @@ ! limitations under the License. ! !********************************************************************************************************************************** - - - - program UnsteadyAero_Driver use NWTC_Library @@ -31,45 +27,24 @@ program UnsteadyAero_Driver use UnsteadyAero_Types use UnsteadyAero use UA_Dvr_Subs - USE VersionInfo + use VersionInfo - implicit none + use LinDyn - - - - + implicit none ! Variables - integer(IntKi), parameter :: NumInp = 2 ! Number of inputs sent to UA_UpdateStates (must be at least 2) - real(DbKi) :: dt, t, uTimes(NumInp) + real(DbKi) :: t, tnext integer :: i, j, n, iu - type(UA_InitInputType) :: InitInData ! Input data for initialization - type(UA_InitOutputType) :: InitOutData ! Output data from initialization - type(UA_ContinuousStateType) :: x ! Continuous states - type(UA_DiscreteStateType) :: xd ! Discrete states - type(UA_OtherStateType) :: OtherState ! Other/optimization states - type(UA_MiscVarType) :: m ! Misc/optimization variables - type(UA_ParameterType) :: p ! Parameters - type(UA_InputType) :: u(NumInp) ! System inputs - type(UA_OutputType) :: y ! System outputs + + ! --- All Data + type(Dvr_Data) :: dvr + integer(IntKi) :: ErrStat ! Status of error message character(ErrMsgLen) :: ErrMsg ! Error message if ErrStat /= ErrID_None - integer, parameter :: NumAFfiles = 1 - character(1024) :: afNames(NumAFfiles) - type(AFI_ParameterType) :: AFI_Params(NumAFfiles) - integer, allocatable :: AFIndx(:,:) CHARACTER(1024) :: dvrFilename ! Filename and path for the driver input file. This is passed in as a command line argument when running the Driver exe. - TYPE(UA_Dvr_InitInput) :: dvrInitInp ! Initialization data for the driver program - real(DbKi) :: simTime - integer :: nSimSteps character(*), parameter :: RoutineName = 'UnsteadyAero_Driver' - real(DbKi), allocatable :: timeArr(:) - real(ReKi), allocatable :: AOAarr(:) - real(ReKi), allocatable :: Uarr(:) - real(ReKi), allocatable :: OmegaArr(:) - logical :: UA_f_cn ! Should the separation function be computed using Cn or Cl CHARACTER(200) :: git_commit TYPE(ProgDesc), PARAMETER :: version = ProgDesc( 'UnsteadyAero Driver', '', '' ) ! The version number of this program. @@ -80,189 +55,230 @@ program UnsteadyAero_Driver ErrMsg = '' ErrStat = ErrID_None - ! Display the copyright notice CALL DispCopyrightLicense( version%Name ) ! Obtain OpenFAST git commit hash git_commit = QueryGitVersion() ! Tell our users what they're running - CALL WrScr( ' Running '//TRIM( version%Name )//' a part of OpenFAST - '//TRIM(git_Commit)//NewLine//' linked with '//TRIM( NWTC_Ver%Name )//NewLine ) + CALL WrScr(' Running '//TRIM( version%Name )//' a part of OpenFAST - '//TRIM(git_Commit)) - ! Parse the driver file if one was provided, if not, then set driver parameters using hardcoded values + ! --- Parse the driver file if one if ( command_argument_count() > 1 ) then call print_help() - call checkError() - end if - - - ! Establish initialization inputs which are fixed for the stand-alone driver, but would be - ! variable for a coupled simulation - InitInData%nNodesPerBlade = 1 - InitInData%numBlades = 1 - - ! Set up initialization data - allocate(AFIndx(InitInData%nNodesPerBlade,InitInData%numBlades), STAT = ErrStat) - if ( ErrStat /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate InitInData%AFIndx.', ErrStat, ErrMsg, RoutineName) - call checkError() - end if - - allocate(InitInData%c(InitInData%nNodesPerBlade,InitInData%numBlades), STAT = ErrStat) - if ( ErrStat /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate InitInData%c.', ErrStat, ErrMsg, RoutineName) - call checkError() - end if - - allocate( InitInData%UAOff_innerNode(InitInData%numBlades), InitInData%UAOff_outerNode(InitInData%numBlades), STAT = ErrStat) - if ( ErrStat /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate UAOff_innerNode and UAOff_outerNode.', ErrStat, ErrMsg, RoutineName) - call checkError() - end if - ! don't turn off UA based on span location: - InitInData%UAOff_innerNode = 0 - InitInData%UAOff_outerNode = InitInData%nNodesPerBlade + 1 - - ! Parse the driver input file and run the simulation based on that file - - if ( command_argument_count() == 1 ) then - - call get_command_argument(1, dvrFilename) - call ReadDriverInputFile( dvrFilename, dvrInitInp, errStat, errMsg ) - call checkError() - InitInData%a_s = dvrInitInp%SpdSound - InitInData%c(1,1) = dvrInitInp%Chord - InitInData%UAMod = dvrInitInp%UAMod - InitInData%Flookup = dvrInitInp%Flookup - - else - - dvrInitInp%OutRootName = './TestingUA_Driver' - InitInData%UAMod = 1 - InitInData%Flookup = .FALSE. - InitInData%a_s = 340.29 ! m/s - InitInData%c(1,1) = 1.0 - - dvrInitInp%InflowVel = 30.0 ! m/s - dvrInitInp%Re = 75 ! million - dvrInitInp%AirFoil1 = './OSU075_FAST.txt' - dvrInitInp%SimMod = 1 - dvrInitInp%NCycles = 3.0 - dvrInitInp%Frequency = 1.2 ! Hz - dvrInitInp%StepsPerCycle= 180 - dvrInitInp%Amplitude = 10.0 ! deg - dvrInitInp%Mean = 2.0 ! deg - dvrInitInp%Phase = 0 ! steps of a cycle - dvrInitInp%InputsFile = '' - - end if - InitInData%OutRootName = dvrInitInp%OutRootName - - InitInData%WrSum = dvrInitInp%SumPrint ! write all the AFI data + call NormStop() + endif + call get_command_argument(1, dvrFilename) + call ReadDriverInputFile( dvrFilename, dvr%p, errStat, errMsg ); call checkError() - - if ( dvrInitInp%SimMod == 1 ) then - ! Using the frequency and NCycles, determine how long the simulation needs to run - simTime = dvrInitInp%NCycles/dvrInitInp%Frequency - nSimSteps = dvrInitInp%StepsPerCycle*dvrInitInp%NCycles ! we could add 1 here to make this a complete cycle - dt = simTime / nSimSteps - - else - ! Read time-series data file with a 1 line header and then each row contains time-step data with 4, white-space-separated columns - ! time, Angle-of-attack, Vrel, omega - call ReadTimeSeriesData( dvrInitInp%InputsFile, nSimSteps, timeArr, AOAarr, Uarr, OmegaArr, errStat, errMsg ) - call checkError() - dt = (timeArr(nSimSteps) - timeArr(1)) / (nSimSteps-1) - nSimSteps = nSimSteps-NumInp + 1 - - end if - - ! Initialize the Airfoil Info Params - afNames(1) = dvrInitInp%AirFoil1 ! All nodes/blades are using the same 2D airfoil - AFIndx(1,1) = 1 - UA_f_cn = (InitInData%UAMod /= UA_HGM).and.(InitInData%UAMod /= UA_OYE) ! HGM and OYE use the separation function based on cl instead of cn - call Init_AFI( InitInData%UAMod, NumAFfiles, afNames, dvrInitInp%UseCm, UA_f_cn, AFI_Params, errStat, errMsg ) - call checkError() + ! --- Driver Parameters + call Dvr_SetParameters(dvr%p, errStat, errMsg); call checkError() - if (dvrInitInp%WrAFITables) then - call WriteAFITables(AFI_Params(1), dvrInitInp%OutRootName, dvrInitInp%UseCm, UA_f_cn) - endif - - - ! Initialize UnsteadyAero (after AFI) - call UA_Init( InitInData, u(1), p, x, xd, OtherState, y, m, dt, AFI_Params, AFIndx, InitOutData, errStat, errMsg ) - call checkError() + ! --- Initialize Elastic Section + if ( dvr%p%SimMod == 3 ) then + call LD_InitInputData(3, dvr%LD_InitInData, errStat, errMsg); call checkError() + dvr%LD_InitInData%dt = dvr%p%dt + dvr%LD_InitInData%IntMethod = 1 ! 1=RK4, TODO expose to user + dvr%LD_InitInData%prefix = '' ! for output channel names + dvr%LD_InitInData%MM = dvr%p%MM + dvr%LD_InitInData%CC = dvr%p%CC + dvr%LD_InitInData%KK = dvr%p%KK + dvr%LD_InitInData%x0 = dvr%p%initPos + dvr%LD_InitInData%xd0 = dvr%p%initVel + dvr%LD_InitInData%activeDOFs = dvr%p%activeDOFs + dvr%LD_InitInData%DOFsNames = (/'x ','y ','th '/) + dvr%LD_InitInData%DOFsUnits = (/'m ','m ','rad'/) + if (dvr%p%MotionMod==MotionMod_File) then + dvr%LD_InitInData%PrescribedMotionFile = dvr%p%MotionTSFile + else + dvr%LD_InitInData%PrescribedMotionFile = '' + endif + call LD_Init(dvr%LD_InitInData, dvr%LD_u(1), dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_y, dvr%LD_m, dvr%LD_InitOutData, errStat, errMsg); call checkError() + ! Allocate other inputs of LD + do iu = 2,NumInp + call AllocAry(dvr%LD_u(iu)%Fext, dvr%LD_p%nx, 'Fext', errStat, errMsg); call checkError() + enddo + end if + ! --- Init UA input data based on driver inputs + call driverInputsToUAInitData(dvr%p, dvr%UA_InitInData, dvr%AFI_Params, dvr%AFIndx, errStat, errMsg); call checkError() - if (p%NumOuts <= 0) then - ErrStat = ErrID_Fatal - ErrMsg = "No outputs have been selected. Rebuild the executable with -DUA_OUTS" + ! --- Initialize UnsteadyAero (need AFI) + call UA_Init( dvr%UA_InitInData, dvr%UA_u(1), dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%UA_y, dvr%UA_m, dvr%p%dt, dvr%AFI_Params, dvr%AFIndx, dvr%UA_InitOutData, errStat, errMsg ); call checkError() + if (dvr%UA_p%NumOuts <= 0) then + ErrStat = ErrID_Warn + ErrMsg = "No outputs from UA are generated." call checkError() end if - ! set inputs: + ! --- Driver Outputs + dvr%out%Root = dvr%p%OutRootName + call Dvr_InitializeDriverOutputs(dvr, dvr%out, errStat, errMsg); call checkError() + + i = 1 ! nodes per blade + j = 1 ! number of blades + ! --- Initialize Inputs !u(1) = time at n=1 (t= 0) !u(2) = time at n=0 (t= -dt) !u(3) = time at n=-1 (t= -2dt) if NumInp > 2 + if ( dvr%p%SimMod == 3 ) then + ! General inputs + do iu = 1, NumInp !u(NumInp) is overwritten in time-sim loop, so no need to init here + dvr%uTimes(iu) = (2-iu-1)*dvr%p%dt + enddo + ! Inflow "inputs" + do iu = 1,NumInp + call setInflow(t=dvr%uTimes(iu), p=dvr%p, m=dvr%m, U0=dvr%U0(iu,:)) + enddo + ! UA inputs at t=0, stored in u(1) + do iu = 1, NumInp-1 !u(NumInp) is overwritten in time-sim loop, so no need to init here + call setUAinputs(dvr%U0(iu,:), dvr%LD_x, dvr%p, dvr%m, dvr%UA_u(iu)) + enddo + ! LD inputs + do iu = 1, NumInp-1 !u(NumInp) is overwritten in time-sim loop, so no need to init here + call UA_CalcOutput(i, j, dvr%uTimes(iu), dvr%UA_u(iu), dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_y, dvr%UA_m, errStat, errMsg ); call checkError() + call setLDinputs(dvr%U0(iu,:), dvr%LD_x, dvr%UA_y, dvr%p, dvr%m, dvr%LD_u(iu)) + enddo - DO iu = 1, NumInp-1 !u(NumInp) is overwritten in time-sim loop, so no need to init here - call setUAinputs(2-iu, u(iu), uTimes(iu), dt, dvrInitInp, timeArr, AOAarr, Uarr, OmegaArr, errStat, errMsg) - call checkError() - END DO - - ! Set inputs which do not vary with node or time + else + ! UA inputs at t=0, stored in u(1) + do iu = 1, NumInp-1 !u(NumInp) is overwritten in time-sim loop, so no need to init here + call setUAinputsAlphaSim(2-iu, dvr%UA_u(iu), dvr%uTimes(iu), dvr%p, dvr%m, errStat, errMsg); call checkError() + end do + endif - ! time marching loop - do n = 1, nSimSteps + ! --- Time marching loop + call Dvr_InitializeOutputs(dvr%out, dvr%p%numSteps, errStat, errMsg) - i = 1 ! nodes per blade - j = 1 ! number of blades - - ! set inputs: - DO iu = NumInp-1, 1, -1 - u( iu+1) = u( iu) - uTimes(iu+1) = uTimes(iu) - END DO - - ! first value of uTimes/u contain inputs at t+dt - call setUAinputs(n+1, u(1), uTimes(1), dt, dvrInitInp, timeArr, AOAarr, Uarr, OmegaArr, errStat, errMsg) - call checkError() - - t = uTimes(2) + if ( dvr%p%SimMod == 3 ) then + + ! --- Time marching loop + call WrScr(' Aeroelastic simulation - TMax = '//trim(num2lstr(dvr%p%numSteps*dvr%p%dt))) + do n = 1, dvr%p%numSteps + ! --- Set inputs at t by storing in u(2) what was in u(1) at previous time step + !u(1) = time at n=n+1 (t=t+dt) + !u(2) = time at n=n (t=t ) + do iu = NumInp-1, 1, -1 + dvr%uTimes(iu+1) = dvr%uTimes(iu) + dvr%U0( iu+1,:)= dvr%U0(iu,:) + dvr%UA_u( iu+1) = dvr%UA_u( iu) + dvr%LD_u( iu+1) = dvr%LD_u( iu) + end do + + ! ---------------------------------------------------------------------------- + ! --- t + ! ---------------------------------------------------------------------------- + iu = 2 ! Index 2 is t + dvr%uTimes(iu) = (n -1)*dvr%p%dt ! t + t = dvr%uTimes(iu) ! t(2)= t + ! --- Calc Outputs at t ! Use existing states to compute the outputs - call UA_CalcOutput(i, j, t, u(2), p, x, xd, OtherState, AFI_Params(AFIndx(i,j)), y, m, errStat, errMsg ) - call checkError() - + call UA_CalcOutput(i, j, t, dvr%UA_u(iu), dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_y, dvr%UA_m, errStat, errMsg ); call checkError() + ! "True" force based on UA outputs - Also compute Misc outputs + !call AeroKinetics(dvr%U0(iu,:), dvr%LD_x%q(1:3), dvr%LD_x%q(4:6), (/dvr%UA_y%Cl, dvr%UA_y%Cd, dvr%UA_y%Cm/), dvr%p, dvr%m) + call setLDinputs(dvr%U0(iu,:), dvr%LD_x, dvr%UA_y, dvr%p, dvr%m, dvr%LD_u(iu)) + ! Use existing states to compute the outputs + call LD_CalcOutput(t, dvr%LD_u(iu), dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_y, dvr%LD_m, errStat, errMsg); call checkError() ! Generate file outputs - call UA_WriteOutputToFile(t, p, y) + call UA_WriteOutputToFile(t, dvr%UA_p, dvr%UA_y) + ! Write/Store outputs + call Dvr_WriteOutputs(n, t, dvr, dvr%out, errStat, errMsg); call checkError() - - ! Prepare states for next time step - call UA_UpdateStates(i, j, t, n, u, uTimes, p, x, xd, OtherState, AFI_Params(AFIndx(i,j)), m, errStat, errMsg ) - call checkError() + ! Backup at t - if iteration needed + !call backupStates() + ! ---------------------------------------------------------------------------- + ! --- From t to t+dt + ! ---------------------------------------------------------------------------- + iu = 1 ! Index 1 is t+dt + dvr%uTimes(iu) = (n+1-1)*dvr%p%dt ! t+dt + tnext = dvr%uTimes(iu) ! t(2)= t+dt + ! --- Set inputs at t+dt in u(1) + ! Inflow inputs + call setInflow(t=tnext, p=dvr%p, m=dvr%m, U0=dvr%U0(iu,:)) + ! LinDyn inputs at t+dt + call LD_Input_ExtrapInterp(dvr%LD_u(:), dvr%uTimes(:), dvr%LD_u(iu), tnext, errStat, errMsg); call checkError() + + ! --- Integrate LinDyn from t to t+dt + call LD_UpdateStates(t, n, dvr%LD_u, dvr%uTimes, dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_m, errStat, errMsg); call checkError() + ! Calc LinDyn outputs at t+dt + call LD_CalcOutput(t, dvr%LD_u(iu), dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_y, dvr%LD_m, errStat, errMsg); call checkError() + + ! --- Set UA Inputs at t+dt + call setUAinputs(dvr%U0(iu,:), dvr%LD_x, dvr%p, dvr%m, dvr%UA_u(iu)) + + ! --- Integrate UA from t to t+dt + call UA_UpdateStates(i, j, t, n, dvr%UA_u, dvr%uTimes, dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_m, errStat, errMsg ); call checkError() + + ! --- One extra iteration with better LD inputs at t+dt + !call UA_CalcOutput(i, j, tnext, dvr%UA_u(iu), dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_y, dvr%UA_m, errStat, errMsg ); call checkError() + !call setLDinputs(dvr%U0(iu,:), dvr%LD_x, dvr%UA_y, dvr%p, dvr%m, dvr%LD_u(iu)) + !call restoreLDStates() + !call LD_UpdateStates(t, n, dvr%LD_u, dvr%uTimes, dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_m, errStat, errMsg); call checkError() + !call LD_CalcOutput(tnext, dvr%LD_u(iu), dvr%LD_p, dvr%LD_x, dvr%LD_xd, dvr%LD_z, dvr%LD_OtherState, dvr%LD_y, dvr%LD_m, errStat, errMsg); call checkError() + !call setUAinputs(dvr%U0(iu,:), dvr%LD_x, dvr%p, dvr%m, dvr%UA_u(iu)) + !call restoreUAStates() + !call UA_UpdateStates(i, j, t, n, dvr%UA_u, dvr%uTimes, dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_m, errStat, errMsg ); call checkError() + end do + + else + ! --- Time marching loop + call WrScr(' UA time simulation - TMax = '//trim(num2lstr(dvr%p%numSteps*dvr%p%dt))) + do n = 1, dvr%p%numSteps + + ! --- Set inputs at t by storing in u(2) what was in u(1) at previous time step + !u(1) = time at n=n+1 (t=t+dt) + !u(2) = time at n=n (t=t ) + do iu = NumInp-1, 1, -1 + dvr%UA_u( iu+1) = dvr%UA_u( iu) + dvr%uTimes(iu+1) = dvr%uTimes(iu) + end do + + ! first value of uTimes/u contain inputs at t+dt + call setUAinputsAlphaSim(n+1, dvr%UA_u(1), dvr%uTimes(1), dvr%p, dvr%m, errStat, errMsg); call checkError() + + t = dvr%uTimes(2) + + ! Use existing states to compute the outputs + call UA_CalcOutput(i, j, t, dvr%UA_u(2), dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_y, dvr%UA_m, errStat, errMsg ); call checkError() - - end do - - - !------------------------------------------------------------------------------------------------- - ! Close our output file - !------------------------------------------------------------------------------------------------- + ! Generate file outputs + call UA_WriteOutputToFile(t, dvr%UA_p, dvr%UA_y) + ! Write/Store outputs + call Dvr_WriteOutputs(n, t, dvr, dvr%out, errStat, errMsg); call checkError() + + ! Prepare states for next time step + call UA_UpdateStates(i, j, t, n, dvr%UA_u, dvr%uTimes, dvr%UA_p, dvr%UA_x, dvr%UA_xd, dvr%UA_OtherState, dvr%AFI_Params(dvr%AFIndx(i,j)), dvr%UA_m, errStat, errMsg ); call checkError() + + end do + endif + call Dvr_EndSim(dvr, errStat, errMsg) + ! --- Exit call Cleanup() call NormStop() - - contains - + +contains + subroutine backupStates() + call UA_CopyContState (dvr%UA_x , dvr%UA_x_swp , MESH_UPDATECOPY , errStat , errMsg) + call UA_CopyDiscState (dvr%UA_xd , dvr%UA_xd_swp , MESH_UPDATECOPY , errStat , errMsg) + call UA_CopyOtherState(dvr%UA_OtherState , dvr%UA_OtherState_swp , MESH_UPDATECOPY , errStat , errMsg) + call LD_CopyContState (dvr%LD_x , dvr%LD_x_swp , MESH_UPDATECOPY , errStat , errMsg) + call LD_CopyOtherState(dvr%LD_OtherState , dvr%LD_OtherState_swp , MESH_UPDATECOPY , errStat , errMsg) + end subroutine + subroutine restoreUAStates() + call UA_CopyContState (dvr%UA_x_swp , dvr%UA_x , MESH_UPDATECOPY , errStat , errMsg) + call UA_CopyDiscState (dvr%UA_xd_swp , dvr%UA_xd , MESH_UPDATECOPY , errStat , errMsg) + call UA_CopyOtherState(dvr%UA_OtherState_swp, dvr%UA_OtherState , MESH_UPDATECOPY , errStat , errMsg) + end subroutine + subroutine restoreLDStates() + call LD_CopyContState (dvr%LD_x_swp , dvr%LD_x , MESH_UPDATECOPY , errStat , errMsg) + call LD_CopyOtherState(dvr%LD_OtherState_swp, dvr%LD_OtherState , MESH_UPDATECOPY , errStat , errMsg) + end subroutine !==================================================================================================== subroutine Cleanup() - ! The routine cleans up the module echo file and resets the NWTC_Library, reattaching it to - ! any existing echo information - !---------------------------------------------------------------------------------------------------- - call UA_End(p) - - ! probably should also deallocate driver variables here + call UA_End(dvr%UA_p) + ! probably should also deallocate driver variables here... end subroutine Cleanup @@ -282,94 +298,6 @@ subroutine checkError() end subroutine checkError !---------------------------------------------------------------------------------------------------- - subroutine setUAinputs(n,u,t,dt,dvrInitInp,timeArr,AOAarr,Uarr,OmegaArr,errStat,errMsg) - - integer, intent(in) :: n - type(UA_InputType), intent(inout) :: u ! System inputs - real(DbKi), intent( out) :: t - real(DbKi), intent(in) :: dt - TYPE(UA_Dvr_InitInput), intent(in) :: dvrInitInp ! Initialization data for the driver program - real(DbKi), intent(in), allocatable :: timeArr(:) - real(ReKi), intent(in), allocatable :: AOAarr(:) - real(ReKi), intent(in), allocatable :: Uarr(:) - real(ReKi), intent(in), allocatable :: OmegaArr(:) - integer, intent(out) :: errStat - character(len=*), intent(out) :: errMsg - integer :: indx - real(ReKi) :: phase - real(ReKi) :: d_ref2AC - real(ReKi) :: alpha_ref - real(ReKi) :: U_ref - real(ReKi) :: v_ref(2) - real(ReKi) :: v_34(2) - logical, parameter :: OscillationAtMidChord=.true. ! for legacy, use false - logical, parameter :: VelocityAt34 =.true. ! for legacy, use false - - ! Initialize error handling variables - ErrMsg = '' - ErrStat = ErrID_None - - u%UserProp = 0 - u%Re = dvrInitInp%Re - - if ( dvrInitInp%SimMod == 1 ) then - if (OscillationAtMidChord) then - d_ref2AC =-0.25_ReKi ! -0.25: oscillations at mid_chord - else - d_ref2AC = 0.0_ReKi ! 0: oscillations at AC - endif - U_ref = dvrInitInp%InflowVel ! m/s - - t = (n-1)*dt - phase = (n+dvrInitInp%Phase-1)*2*pi/dvrInitInp%StepsPerCycle - alpha_ref = (dvrInitInp%Amplitude * sin(phase) + dvrInitInp%Mean)*D2R ! This needs to be in radians - v_ref(1) = sin(alpha_ref)*U_ref - v_ref(2) = cos(alpha_ref)*U_ref - u%omega = dvrInitInp%Amplitude * cos(phase) * 2*pi/dvrInitInp%StepsPerCycle / dt * D2R ! This needs to be in radians derivative: d_alpha /d_t - - u%v_ac(1) = v_ref(1) + u%omega * d_ref2AC* dvrInitInp%Chord - u%v_ac(2) = v_ref(2) - - v_34(1) = u%v_ac(1) + u%omega * 0.5* dvrInitInp%Chord - v_34(2) = u%v_ac(2) - - - u%alpha = atan2(u%v_ac(1), u%v_ac(2) ) ! - if (VelocityAt34) then - u%U = sqrt(v_34(1)**2 + v_34(2)**2) ! Using U at 3/4 - else - u%U = sqrt(u%v_ac(1)**2 + u%v_ac(2)**2) ! Using U at 1/4 - endif - - - else - ! check optional variables and allocation status - if (all( (/ allocated(timeArr),allocated(AOAarr),allocated(OmegaArr),allocated(Uarr) /) )) then - - indx = min(n,size(timeArr)) - indx = max(1, indx) ! use constant data at initialization - - ! Load timestep data from the time-series inputs which were previous read from input file - t = timeArr(indx) - u%alpha = AOAarr(indx)*pi/180.0 ! This needs to be in radians - u%omega = OmegaArr(indx) - u%U = Uarr(indx) - if (n> size(timeArr)) then - t = t + dt*(n - size(timeArr) ) ! update for NumInp>1; - elseif (n < 1) then - t = (n-1)*dt - end if - u%v_ac(1) = sin(u%alpha)*u%U - u%v_ac(2) = cos(u%alpha)*u%U - else - errStat = ErrID_Fatal - errMsg = 'mandatory input arrays are not allocated: timeArr,AOAarr,OmegaArr,Uarr' - end if - - end if - - end subroutine setUAinputs - !---------------------------------------------------------------------------------------------------- subroutine print_help() print '(a)', 'usage: ' diff --git a/modules/aerodyn/src/UnsteadyAero_Registry.txt b/modules/aerodyn/src/UnsteadyAero_Registry.txt index d3eb0ef03a..1c5c704c63 100644 --- a/modules/aerodyn/src/UnsteadyAero_Registry.txt +++ b/modules/aerodyn/src/UnsteadyAero_Registry.txt @@ -17,6 +17,7 @@ usefrom AirfoilInfo_Registry.txt # # +param UnsteadyAero/UA - INTEGER UA_None - 0 - "Steady aerodynamics, using same angle of attack convention as UA" - param UnsteadyAero/UA - INTEGER UA_Baseline - 1 - "UAMod = 1 [Baseline model (Original)]" - param UnsteadyAero/UA - INTEGER UA_Gonzalez - 2 - "UAMod = 2 [Gonzalez's variant (changes in Cn,Cc,Cm)]" - param UnsteadyAero/UA - INTEGER UA_MinnemaPierce - 3 - "[Minnema/Pierce variant (changes in Cc and Cm)]" - @@ -32,6 +33,7 @@ param UnsteadyAero/UA - INTEGER UA_BV typedef UnsteadyAero/UA InitInputType DbKi dt - - - "time step" s typedef ^ ^ CHARACTER(1024) OutRootName - - - "Supplied by Driver: The name of the root file (without extension) including the full path" - typedef ^ ^ ReKi c {:}{:} - - "Chord length at node" m +typedef ^ ^ ReKi d_34_to_ac - 0.5 - "Distance from 3/4 chord to aerodynamic center (typically 0.5) in chord length (no dimension)" - typedef ^ ^ INTEGER numBlades - - - "Number nodes of all blades" - typedef ^ ^ INTEGER nNodesPerBlade - - - "Number nodes per blades" - typedef ^ ^ INTEGER UAMod - - - "Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema]" - @@ -41,13 +43,14 @@ typedef ^ ^ Logical typedef ^ ^ LOGICAL WrSum - .false. - "Write UA AFI parameters to summary file?" - typedef ^ ^ INTEGER UAOff_innerNode {:} - - "Last node on each blade where UA should be turned off based on span location from blade root (0 if always on)" - typedef ^ ^ INTEGER UAOff_outerNode {:} - - "First node on each blade where UA should be turned off based on span location from blade tip (>nNodesPerBlade if always on)" - +typedef ^ ^ IntKi UA_OUTS - 0 - "Store write outputs 0=None, 1=WriteOutpus, 2=WriteToFile" - # # Define outputs from the initialization routine here: # typedef ^ InitOutputType ProgDesc Version - - - "Version structure" - -typedef ^ InitOutputType CHARACTER(19) WriteOutputHdr {:} - - "The is the list of all UA-related output channel header strings (includes all sub-module channels)" - -typedef ^ ^ CHARACTER(19) WriteOutputUnt {:} - - "The is the list of all UA-related output channel unit strings (includes all sub-module channels)" - +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "The is the list of all UA-related output channel header strings (includes all sub-module channels)" - +typedef ^ ^ CHARACTER(ChanLen) WriteOutputUnt {:} - - "The is the list of all UA-related output channel unit strings (includes all sub-module channels)" - # Variables local to the Kelvin Chain: @@ -189,6 +192,7 @@ typedef ^ MiscVarType ReKi # Define parameters here: typedef ^ ParameterType DbKi dt - - - "time step" s typedef ^ ^ ReKi c {:}{:} - - "Chord length at node" m +typedef ^ ^ ReKi d_34_to_ac - 0.5 - "Distance from 3/4 chord to aerodynamic center (typically 0.5) in chord length (no dimension)" - typedef ^ ^ INTEGER numBlades - - - "Number nodes of all blades" - typedef ^ ^ INTEGER nNodesPerBlade - - - "Number nodes per blades" - typedef ^ ^ INTEGER UAMod - - - "Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema]" - @@ -205,6 +209,7 @@ typedef ^ ParameterType IntKi 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" - +typedef ^ ^ IntKi UA_OUTS - 0 - "Store write outputs 0=None, 1=WriteOutpus, 2=WriteToFile" - # ..... 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 8fad9bcdcf..eac8874e36 100644 --- a/modules/aerodyn/src/UnsteadyAero_Types.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Types.f90 @@ -34,6 +34,7 @@ MODULE UnsteadyAero_Types USE AirfoilInfo_Types USE NWTC_Library IMPLICIT NONE + INTEGER(IntKi), PUBLIC, PARAMETER :: UA_None = 0 ! Steady aerodynamics, using same angle of attack convention as UA [-] INTEGER(IntKi), PUBLIC, PARAMETER :: UA_Baseline = 1 ! UAMod = 1 [Baseline model (Original)] [-] INTEGER(IntKi), PUBLIC, PARAMETER :: UA_Gonzalez = 2 ! UAMod = 2 [Gonzalez's variant (changes in Cn,Cc,Cm)] [-] INTEGER(IntKi), PUBLIC, PARAMETER :: UA_MinnemaPierce = 3 ! [Minnema/Pierce variant (changes in Cc and Cm)] [-] @@ -46,6 +47,7 @@ MODULE UnsteadyAero_Types REAL(DbKi) :: dt = 0.0_R8Ki !< time step [s] CHARACTER(1024) :: OutRootName !< Supplied by Driver: The name of the root file (without extension) including the full path [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: c !< Chord length at node [m] + REAL(ReKi) :: d_34_to_ac = 0.5 !< Distance from 3/4 chord to aerodynamic center (typically 0.5) in chord length (no dimension) [-] INTEGER(IntKi) :: numBlades = 0_IntKi !< Number nodes of all blades [-] INTEGER(IntKi) :: nNodesPerBlade = 0_IntKi !< Number nodes per blades [-] INTEGER(IntKi) :: UAMod = 0_IntKi !< Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema] [-] @@ -55,13 +57,14 @@ MODULE UnsteadyAero_Types LOGICAL :: WrSum = .false. !< Write UA AFI parameters to summary file? [-] INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: UAOff_innerNode !< Last node on each blade where UA should be turned off based on span location from blade root (0 if always on) [-] INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: UAOff_outerNode !< First node on each blade where UA should be turned off based on span location from blade tip (>nNodesPerBlade if always on) [-] + INTEGER(IntKi) :: UA_OUTS = 0 !< Store write outputs 0=None, 1=WriteOutpus, 2=WriteToFile [-] END TYPE UA_InitInputType ! ======================= ! ========= UA_InitOutputType ======= TYPE, PUBLIC :: UA_InitOutputType TYPE(ProgDesc) :: Version !< Version structure [-] - CHARACTER(19) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< The is the list of all UA-related output channel header strings (includes all sub-module channels) [-] - CHARACTER(19) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< The is the list of all UA-related output channel unit strings (includes all sub-module channels) [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< The is the list of all UA-related output channel header strings (includes all sub-module channels) [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< The is the list of all UA-related output channel unit strings (includes all sub-module channels) [-] END TYPE UA_InitOutputType ! ======================= ! ========= UA_KelvinChainType ======= @@ -208,6 +211,7 @@ MODULE UnsteadyAero_Types TYPE, PUBLIC :: UA_ParameterType REAL(DbKi) :: dt = 0.0_R8Ki !< time step [s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: c !< Chord length at node [m] + REAL(ReKi) :: d_34_to_ac = 0.5 !< Distance from 3/4 chord to aerodynamic center (typically 0.5) in chord length (no dimension) [-] INTEGER(IntKi) :: numBlades = 0_IntKi !< Number nodes of all blades [-] INTEGER(IntKi) :: nNodesPerBlade = 0_IntKi !< Number nodes per blades [-] INTEGER(IntKi) :: UAMod = 0_IntKi !< Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema] [-] @@ -224,6 +228,7 @@ MODULE UnsteadyAero_Types 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 [-] + INTEGER(IntKi) :: UA_OUTS = 0 !< Store write outputs 0=None, 1=WriteOutpus, 2=WriteToFile [-] END TYPE UA_ParameterType ! ======================= ! ========= UA_InputType ======= @@ -273,6 +278,7 @@ subroutine UA_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrSta end if DstInitInputData%c = SrcInitInputData%c end if + DstInitInputData%d_34_to_ac = SrcInitInputData%d_34_to_ac DstInitInputData%numBlades = SrcInitInputData%numBlades DstInitInputData%nNodesPerBlade = SrcInitInputData%nNodesPerBlade DstInitInputData%UAMod = SrcInitInputData%UAMod @@ -304,6 +310,7 @@ subroutine UA_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrSta end if DstInitInputData%UAOff_outerNode = SrcInitInputData%UAOff_outerNode end if + DstInitInputData%UA_OUTS = SrcInitInputData%UA_OUTS end subroutine subroutine UA_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -332,6 +339,7 @@ subroutine UA_PackInitInput(RF, Indata) call RegPack(RF, InData%dt) call RegPack(RF, InData%OutRootName) call RegPackAlloc(RF, InData%c) + call RegPack(RF, InData%d_34_to_ac) call RegPack(RF, InData%numBlades) call RegPack(RF, InData%nNodesPerBlade) call RegPack(RF, InData%UAMod) @@ -341,6 +349,7 @@ subroutine UA_PackInitInput(RF, Indata) call RegPack(RF, InData%WrSum) call RegPackAlloc(RF, InData%UAOff_innerNode) call RegPackAlloc(RF, InData%UAOff_outerNode) + call RegPack(RF, InData%UA_OUTS) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -355,6 +364,7 @@ subroutine UA_UnPackInitInput(RF, OutData) call RegUnpack(RF, OutData%dt); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%OutRootName); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%c); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%d_34_to_ac); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%numBlades); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%nNodesPerBlade); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%UAMod); if (RegCheckErr(RF, RoutineName)) return @@ -364,6 +374,7 @@ subroutine UA_UnPackInitInput(RF, OutData) call RegUnpack(RF, OutData%WrSum); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%UAOff_innerNode); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%UAOff_outerNode); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%UA_OUTS); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine UA_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) @@ -1927,6 +1938,7 @@ subroutine UA_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) end if DstParamData%c = SrcParamData%c end if + DstParamData%d_34_to_ac = SrcParamData%d_34_to_ac DstParamData%numBlades = SrcParamData%numBlades DstParamData%nNodesPerBlade = SrcParamData%nNodesPerBlade DstParamData%UAMod = SrcParamData%UAMod @@ -1965,6 +1977,7 @@ subroutine UA_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%lin_xIndx = SrcParamData%lin_xIndx end if DstParamData%dx = SrcParamData%dx + DstParamData%UA_OUTS = SrcParamData%UA_OUTS end subroutine subroutine UA_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -1992,6 +2005,7 @@ subroutine UA_PackParam(RF, Indata) if (RF%ErrStat >= AbortErrLev) return call RegPack(RF, InData%dt) call RegPackAlloc(RF, InData%c) + call RegPack(RF, InData%d_34_to_ac) call RegPack(RF, InData%numBlades) call RegPack(RF, InData%nNodesPerBlade) call RegPack(RF, InData%UAMod) @@ -2008,6 +2022,7 @@ subroutine UA_PackParam(RF, Indata) call RegPackAlloc(RF, InData%UA_off_forGood) call RegPackAlloc(RF, InData%lin_xIndx) call RegPack(RF, InData%dx) + call RegPack(RF, InData%UA_OUTS) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -2021,6 +2036,7 @@ subroutine UA_UnPackParam(RF, OutData) if (RF%ErrStat /= ErrID_None) return call RegUnpack(RF, OutData%dt); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%c); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%d_34_to_ac); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%numBlades); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%nNodesPerBlade); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%UAMod); if (RegCheckErr(RF, RoutineName)) return @@ -2037,6 +2053,7 @@ subroutine UA_UnPackParam(RF, OutData) call RegUnpackAlloc(RF, OutData%UA_off_forGood); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%lin_xIndx); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%dx); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%UA_OUTS); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine UA_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index b8a40c272e..62f055188c 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -958,6 +958,9 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO IfW_InitInp%lidar%HubPosition = 0.0_ReKi IfW_InitInp%lidar%SensorType = SensorType_None IfW_InitInp%Use4Dext = .false. + IfW_InitInp%MHK = MHK_None + IfW_InitInp%WtrDpth = 0.0_ReKi + IfW_InitInp%MSL2SWL = 0.0_ReKi if ( p%Mod_AmbWind == 2 ) then ! one InflowWind module diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index 35f1c75d86..33ff645fb6 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -59,7 +59,7 @@ MODULE BeamDyn ! follow the moving BladeRootMotion mesh. This requires changing the states after an UpdateStates call to be relative to ! the new BladeRootMotion mesh orientation and position. ! Upadate the reference frame after each State update (or use the old method)? - LOGICAL, PARAMETER :: ChangeRefFrame = .true. + LOGICAL, PARAMETER :: ChangeRefFrame = .false. CONTAINS @@ -94,7 +94,6 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I REAL(BDKi) :: temp_CRV(3) REAL(BDKi),ALLOCATABLE :: GLL_nodes(:) REAL(BDKi) :: TmpDCM(3,3) - REAL(BDKi) :: denom LOGICAL :: QuasiStaticInitialized !< True if quasi-static solution was found @@ -153,7 +152,7 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I ! set mass and stiffness matrices: p%Stif0_QP and p%Mass0_QP call InitializeMassStiffnessMatrices(InputFileData, p, ErrStat2,ErrMsg2); if (Failed()) return - ! Set the initial displacements: p%uu0, p%E10 + ! Set the initial displacements: p%uu0, p%rrN0, p%E10 CALL BD_QuadraturePointDataAt0(p) @@ -163,8 +162,6 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I CALL BD_ComputeBladeMassNew( p, ErrStat2, ErrMsg2 ); if (Failed()) return !computes p%blade_mass,p%blade_CG,p%blade_IN - ! Actuator - if (p%UsePitchAct) then ! Calculate the pitch angle @@ -591,12 +588,8 @@ 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 @@ -733,11 +726,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 - DO i=1,3 - Gup0(i) = dot_product(p%ShpDer(:,idx_qp), p%uuN0(i,:,nelem)) + Gup0(:) = 0.0_BDKi + DO i=1,p%nodes_per_elem + Gup0(:) = Gup0(:) + p%ShpDer(i,idx_qp)*p%uuN0(1:3,i,nelem) ENDDO p%Jacobian(idx_qp,nelem) = TwoNorm(Gup0) ENDDO @@ -894,11 +887,10 @@ subroutine SetParameters(InitInp, InputFileData, p, OtherState, ErrStat, ErrMsg) INTEGER(IntKi) :: i, j ! generic counter index INTEGER(IntKi) :: indx ! counter into index array (p%NdIndx) INTEGER(IntKi) :: nUniqueQP ! number of unique quadrature points (not double-counting nodes at element boundaries) - + REAL(BDKi) :: denom integer(intKi) :: ErrStat2 ! temporary Error status character(ErrMsgLen) :: ErrMsg2 ! temporary Error message character(*), parameter :: RoutineName = 'SetParameters' - real(DbKi) :: denom @@ -929,6 +921,7 @@ subroutine SetParameters(InitInp, InputFileData, p, OtherState, ErrStat, ErrMsg) p%RotStates = InputFileData%RotStates ! Rotate states in linearization? + if (ChangeRefFrame) p%RotStates = .true. p%RelStates = InputFileData%RelStates ! Define states relative to root motion in linearization? p%rhoinf = InputFileData%rhoinf ! Numerical damping coefficient: [0,1]. No numerical damping if rhoinf = 1; maximum numerical damping if rhoinf = 0. @@ -969,25 +962,7 @@ subroutine SetParameters(InitInp, InputFileData, p, OtherState, 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 @@ -1009,7 +984,7 @@ subroutine SetParameters(InitInp, InputFileData, p, OtherState, 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%twN0, p%nodes_per_elem, p%elem_total,'twN0 (initial twist) 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%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 ) @@ -1147,6 +1122,26 @@ subroutine SetParameters(InitInp, InputFileData, p, OtherState, ErrStat, ErrMsg) ! set parameters for pitch actuator: !............................................... + ! 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) + return + else + p%torqM(:,:) = p%torqM / denom + end if + end if !............................................... ! set parameters for File I/O data: @@ -2256,58 +2251,73 @@ SUBROUTINE BD_QuadraturePointDataAt0( p ) TYPE(BD_ParameterType), INTENT(INOUT) :: p !< Parameters - CHARACTER(*), PARAMETER :: RoutineName = 'BD_QuadraturePointDataAt0' - INTEGER(IntKi) :: ErrStat2 ! The error status code - CHARACTER(ErrMsgLen) :: ErrMsg2 ! The error message, if an error occurred + REAL(BDKi) :: rot0_temp(3) + REAL(BDKi) :: rotu_temp(3) + REAL(BDKi) :: rot_temp(3) + REAL(BDKi) :: R0_temp(3,3) + INTEGER(IntKi) :: nelem ! number of current element INTEGER(IntKi) :: idx_qp ! index of current quadrature point - INTEGER(IntKi) :: i - REAL(BDKi) :: twist, tan_vect(3), R0(3), u0(3) + INTEGER(IntKi) :: idx_node ! index of current GLL node - ! Loop through elements - DO nelem = 1,p%elem_total + CHARACTER(*), PARAMETER :: RoutineName = 'BD_QuadraturePointDataAt0' - ! Loop through quadrature points - do idx_qp = 1, p%nqp - ! Loop through displacement DOFs - do i = 1,3 + ! Initialize to zero for the summation + p%uu0(:,:,:) = 0.0_BDKi + p%rrN0(:,:,:) = 0.0_BDKi + p%E10(:,:,:) = 0.0_BDKi - ! 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)) - ! 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) + ! calculate rrN0 (Initial relative rotation array) + 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 - end do - ! Interpolate the twist to QP from the shape function and node values - twist = dot_product(p%Shp(:,idx_qp), p%twN0(:,nelem)) + 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$ - ! 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) + ! Note that p%uu0 was set to zero prior to this routine call, so the following is the summation. - ! Save initial position and rotation - p%uu0(1:3,idx_qp,nelem) = u0 - p%uu0(4:6,idx_qp,nelem) = R0 + 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 - ! Save initial tangent vector for calculating strain - p%E10(1:3,idx_qp,nelem) = tan_vect - 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 + + 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 + + + !> 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 + END SUBROUTINE BD_QuadraturePointDataAt0 @@ -2355,43 +2365,48 @@ 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) :: 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 + 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 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 @@ -2742,6 +2757,8 @@ subroutine Calc_Fc_Fd() REAL(BDKi) :: e1s REAL(BDKi) :: eee(6) !< intermediate array for calculation Strain and curvature terms of Fc REAL(BDKi) :: fff(6) !< intermediate array for calculation of the elastic force, Fc + REAL(BDKi) :: R(3,3) !< rotation matrix at quatrature point + REAL(BDKi) :: Rx0p(3) !< \f$ \underline{R} \underline{x}^\prime_0 \f$ !REAL(BDKi) :: Wrk(3) @@ -2755,8 +2772,10 @@ subroutine Calc_Fc_Fd() !! !! Note: \f$ \underline{\underline{R}}\underline{\underline{R}}_0 \f$ is used to go from the material basis into the inertial basis !! and the transpose for the other direction. - eee(1:3) = m%qp%E1(1:3,idx_qp,nelem) - m%qp%RR0(1:3,3,idx_qp,nelem) ! Using RR0 z direction in IEC coords - + ! eee(1:3) = m%qp%E1(1:3,idx_qp,nelem) - m%qp%RR0(1:3,3,idx_qp,nelem) ! Using RR0 z direction in IEC coords + call BD_CrvMatrixR(m%qp%uuu(4:6,idx_qp,nelem), R) ! Get rotation at QP as a matrix + Rx0p = matmul(R,p%E10(:,idx_qp,nelem)) ! Calculate rotated initial tangent + eee(1:3) = m%qp%E1(1:3,idx_qp,nelem) - Rx0p ! Use rotated initial tangent in place of RR0*i1 to eliminate likely mismatch between R0*i1 and x0' !> ### Set the 1D sectional curvature, \f$ \underline{\kappa} \f$, equation (5) !! \f$ \underline{\kappa} = \underline{k} + \underline{\underline{R}}\underline{k}_i \f$ @@ -6035,7 +6054,8 @@ SUBROUTINE BD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM end if if (p%RotStates) then - RotateStates = matmul( u%RootMotion%Orientation(:,:,1), transpose( u%RootMotion%RefOrientation(:,:,1) ) ) + ! Calculate difference between input root orientation and root reference orientation + RotateStates = matmul( u%RootMotion%Orientation(:,:,1), OtherState%GlbRot ) do i=1,size(dXdu,1),3 dXdu(i:i+2, :) = matmul( RotateStates, dXdu(i:i+2, :) ) end do @@ -6131,7 +6151,8 @@ SUBROUTINE BD_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (p%RotStates) then - RotateStates = matmul( u%RootMotion%Orientation(:,:,1), transpose( u%RootMotion%RefOrientation(:,:,1) ) ) + ! Calculate difference between input root orientation and root reference orientation + RotateStates = matmul( u%RootMotion%Orientation(:,:,1), OtherState%GlbRot ) RotateStatesTranspose = transpose( RotateStates ) if ( present(StateRotation) ) then diff --git a/modules/beamdyn/src/BeamDyn_Types.f90 b/modules/beamdyn/src/BeamDyn_Types.f90 index 1d3be92983..6980255649 100644 --- a/modules/beamdyn/src/BeamDyn_Types.f90 +++ b/modules/beamdyn/src/BeamDyn_Types.f90 @@ -162,8 +162,7 @@ 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 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 :: uuN0 !< Initial Postion Vector 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 -- intertial frame!!! [m/s^2] @@ -181,6 +180,7 @@ 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 [-] @@ -1304,18 +1304,6 @@ 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, kind=B8Ki) - UB(1:2) = ubound(SrcParamData%twN0, kind=B8Ki) - 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, kind=B8Ki) UB(1:3) = ubound(SrcParamData%Stif0_QP, kind=B8Ki) @@ -1443,6 +1431,18 @@ 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, kind=B8Ki) + UB(1:3) = ubound(SrcParamData%rrN0, kind=B8Ki) + 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, kind=B8Ki) UB(1:3) = ubound(SrcParamData%E10, kind=B8Ki) @@ -1701,9 +1701,6 @@ 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 @@ -1734,6 +1731,9 @@ 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 @@ -1809,7 +1809,6 @@ subroutine BD_PackParam(RF, Indata) call RegPack(RF, InData%coef) call RegPack(RF, InData%rhoinf) call RegPackAlloc(RF, InData%uuN0) - call RegPackAlloc(RF, InData%twN0) call RegPackAlloc(RF, InData%Stif0_QP) call RegPackAlloc(RF, InData%Mass0_QP) call RegPack(RF, InData%gravity) @@ -1827,6 +1826,7 @@ subroutine BD_PackParam(RF, Indata) call RegPackAlloc(RF, InData%ShpDer) call RegPackAlloc(RF, InData%Jacobian) call RegPackAlloc(RF, InData%uu0) + call RegPackAlloc(RF, InData%rrN0) call RegPackAlloc(RF, InData%E10) call RegPack(RF, InData%nodes_per_elem) call RegPackAlloc(RF, InData%node_elem_idx) @@ -1915,7 +1915,6 @@ subroutine BD_UnPackParam(RF, OutData) call RegUnpack(RF, OutData%coef); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%rhoinf); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%uuN0); if (RegCheckErr(RF, RoutineName)) return - call RegUnpackAlloc(RF, OutData%twN0); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%Stif0_QP); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%Mass0_QP); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%gravity); if (RegCheckErr(RF, RoutineName)) return @@ -1933,6 +1932,7 @@ subroutine BD_UnPackParam(RF, OutData) call RegUnpackAlloc(RF, OutData%ShpDer); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%Jacobian); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%uu0); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%rrN0); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%E10); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%nodes_per_elem); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%node_elem_idx); if (RegCheckErr(RF, RoutineName)) return diff --git a/modules/beamdyn/src/Registry_BeamDyn.txt b/modules/beamdyn/src/Registry_BeamDyn.txt index 54037d8a73..448cd81abe 100644 --- a/modules/beamdyn/src/Registry_BeamDyn.txt +++ b/modules/beamdyn/src/Registry_BeamDyn.txt @@ -170,8 +170,7 @@ 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 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 R8Ki uuN0 {:}{:}{:} - - "Initial Postion Vector 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 -- intertial frame!!!" m/s^2 @@ -189,6 +188,7 @@ 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 #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 b/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 index 6101e47b92..fcf4f75a4f 100644 --- a/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 +++ b/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 @@ -27,6 +27,7 @@ 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(:,:,:) @@ -90,6 +91,7 @@ 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) @@ -102,10 +104,6 @@ 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) @@ -125,19 +123,27 @@ 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.42032456079463276,-0.10798264336200536,0.61929246125947701 /) - baseline_E10(1:3,1,1) = (/ -0.21838554154630824,0.34664371674017153,0.91222030721097547 /) - + 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. /) ! Build the shape functions and derivative of shape functions evaluated at QP points; this is tested elsewhere call BD_InitShpDerJaco(gll_nodes, p) @@ -145,6 +151,9 @@ 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 @@ -183,7 +192,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.018791738328546054, 0.34071428474330018, 1.1956471566614264 /) + baseline_E1(1:3, idx_qp,nelem) = (/ 0.01384921969632566, 0.33901907914467033, 1.1950929627825897 /) call BD_DisplacementQP( nelem, p, x, m ) @@ -205,9 +214,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.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/) + 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 /) CALL BD_RotationalInterpQP( nelem, p, x, m ) @@ -233,12 +242,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.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/) + 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 /) CALL BD_StifAtDeformedQP( nelem, p, m ) @@ -251,6 +260,9 @@ 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 b936d3bffa..1f64ec584e 100644 --- a/modules/beamdyn/tests/test_tools.F90 +++ b/modules/beamdyn/tests/test_tools.F90 @@ -132,10 +132,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/src/ED_UserSubs.f90 b/modules/elastodyn/src/ED_UserSubs.f90 index de368c02eb..47e2abd8fd 100644 --- a/modules/elastodyn/src/ED_UserSubs.f90 +++ b/modules/elastodyn/src/ED_UserSubs.f90 @@ -101,6 +101,35 @@ SUBROUTINE UserTeet ( TeetDef, TeetRate, ZTime, DirRoot, TeetMom ) RETURN END SUBROUTINE UserTeet !======================================================================= +SUBROUTINE UserYawFrict ( ZTime, Fz, Mzz, Omg, OmgDot, DirRoot, YawFriMf ) + + ! This is a dummy routine for holding the place of a user-specified + ! Yaw Friction. Modify this code to create your own device. + + +USE Precision + + +IMPLICIT NONE + + + ! Passed Variables: +REAL(DbKi), INTENT(IN ) :: ZTime ! Current simulation time, sec. +REAL(R8Ki), INTENT(IN ) :: Fz, Mzz ! Yaw Bering normal force (positive if upward) and torque, N and N*m +REAL(R8Ki), INTENT(IN ) :: Omg ! Yaw rotational speed, rad/s. +REAL(R8Ki), INTENT(IN ) :: OmgDot ! Yaw rotational acceleration, rad/s^2. + +CHARACTER(1024), INTENT(IN ) :: DirRoot ! The name of the root file including the full path to the current working directory. This may be useful if you want this routine to write a permanent record of what it does to be stored with the simulation results: the results should be stored in a file whose name (including path) is generated by appending any suitable extension to DirRoot. + +REAL(ReKi), INTENT(OUT) :: YawFriMf ! Yaw friction moment, N*m. + + + +YawFriMf = 0.0 + +RETURN +END SUBROUTINE UserYawFrict +!======================================================================= SUBROUTINE UserTFrl ( TFrlDef, TFrlRate, ZTime, DirRoot, TFrlMom ) diff --git a/modules/elastodyn/src/ElastoDyn.f90 b/modules/elastodyn/src/ElastoDyn.f90 index 021eedaa85..4fc2f01560 100644 --- a/modules/elastodyn/src/ElastoDyn.f90 +++ b/modules/elastodyn/src/ElastoDyn.f90 @@ -1224,7 +1224,12 @@ SUBROUTINE ED_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) m%AllOuts( YawBrMzn) = DOT_PRODUCT( MomBNcRt, m%CoordSys%d2 ) m%AllOuts( YawBrMxp) = DOT_PRODUCT( MomBNcRt, m%CoordSys%b1 ) m%AllOuts( YawBrMyp) = -DOT_PRODUCT( MomBNcRt, m%CoordSys%b3 ) - + m%AllOuts(YawFriMom) = OtherState%Mfhat*0.001_ReKi !KBF add YawFricMom as an output based on HSSBrTq (kN-m) + m%AllOuts(YawFriMfp) = OtherState%YawFriMfp*0.001_ReKi + m%AllOuts(YawFriMz) = m%YawFriMz*0.001_ReKi + m%FrcONcRt = m%AllOuts( YawBrFzn)*1000_ReKi + m%AllOuts(OmegaYF) = OtherState%OmegaTn*R2D + m%AllOuts(dOmegaYF) = OtherState%OmegaDotTn*R2D ! Tower Base Loads: @@ -1956,6 +1961,9 @@ SUBROUTINE ED_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrSta INTEGER(IntKi) :: ErrStat2 ! The error status code CHARACTER(ErrMsgLen) :: ErrMsg2 ! The error message, if an error occurred CHARACTER(*), PARAMETER :: RoutineName = 'ED_CalcContStateDeriv' + Real(R8Ki) :: YawFriMz ! Loops through some or all of the DOFs. + Real(R8Ki) :: Fz ! Loops through some or all of the DOFs. + ! Initialize ErrStat @@ -1993,6 +2001,13 @@ SUBROUTINE ED_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrSta CALL Teeter ( t, p, m%RtHS%TeetAng, m%RtHS%TeetAngVel, m%RtHS%TeetMom ) ! Compute moment from teeter springs and dampers, TeetMom; NOTE: TeetMom will be zero for a 3-blader since TeetAng = TeetAngVel = 0 CALL RFurling( t, p, x%QT(DOF_RFrl), x%QDT(DOF_RFrl), m%RtHS%RFrlMom ) ! Compute moment from rotor-furl springs and dampers, RFrlMom CALL TFurling( t, p, x%QT(DOF_TFrl), x%QDT(DOF_TFrl), m%RtHS%TFrlMom ) ! Compute moment from tail-furl springs and dampers, TFrlMom + ! Compute the yaw friction torque + Fz= m%FrcONcRt !YawBrFzn force from CalcOutput + YawFriMz=DOT_PRODUCT( m%RtHS%MomBNcRtt, m%CoordSys%d2 ) + u%YawMom + m%YawFriMz = YawFriMz + + CALL YawFriction( t, p, Fz, YawFriMz, OtherState%OmegaTn, OtherState%OmegaDotTn, m%RtHS%YawFriMom ) !Compute yaw Friction #RRD + !bjj: note m%RtHS%GBoxEffFac needed in OtherState only to fix HSSBrTrq (and used in FillAugMat) m%RtHS%GBoxEffFac = p%GBoxEff**OtherState%SgnPrvLSTQ ! = GBoxEff if SgnPrvLSTQ = 1 OR 1/GBoxEff if SgnPrvLSTQ = -1 @@ -3545,6 +3560,11 @@ SUBROUTINE SetPrimaryParameters( InitInp, p, InputFileData, ErrStat, ErrMsg ) p%TeetHSSp = 0.0 END IF + p%YawFrctMod = InputFileData%YawFrctMod + p%M_CD = InputFileData%M_CD + p%M_CSmax = InputFileData%M_CSmax + p%sig_v = InputFileData%sig_v + CALL AllocAry( p%TipMass, p%NumBl, 'TipMass', ErrStat, ErrMsg ) IF ( ErrStat >= AbortErrLev ) RETURN @@ -3908,6 +3928,10 @@ SUBROUTINE Init_MiscOtherStates( m, OtherState, p, x, InputFileData, ErrStat, Er OtherState%HSSBrTrqC = 0.0_ReKi OtherState%SgnPrvLSTQ = 1 OtherState%SgnLSTQ = 1 + OtherState%OmegaTn = 0.0_R8Ki + OtherState%OmegaDotTn = 0.0_R8Ki + OtherState%Mfhat = 0.0_ReKi + OtherState%YawFriMfp = 0.0_ReKi END SUBROUTINE Init_MiscOtherStates @@ -3925,393 +3949,400 @@ END SUBROUTINE Init_MiscOtherStates !! 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 25-Jan-2021 13:23:51. +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx. SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) !.................................................................................................................................. - + IMPLICIT NONE - + ! Passed variables - - CHARACTER(ChanLen), INTENT(IN) :: OutList(:) !< The list out user-requested outputs + + CHARACTER(ChanLen), INTENT(IN) :: OutList(:) !< The list of user-requested outputs TYPE(ED_ParameterType), INTENT(INOUT) :: p !< The module parameters INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status code CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if an error occurred - + ! Local variables - + INTEGER :: ErrStat2 ! temporary (local) error status INTEGER :: I ! Generic loop-counting index INTEGER :: J ! Generic loop-counting index INTEGER :: INDX ! Index for valid arrays 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 - CHARACTER(ChanLen) :: OutListTmp ! A string to temporarily hold OutList(I) CHARACTER(*), PARAMETER :: RoutineName = "SetOutParam" - - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1110) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1115) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically "AZIMUTH ","BLDPITCH1 ","BLDPITCH2 ","BLDPITCH3 ","BLPITCH1 ","BLPITCH2 ","BLPITCH3 ", & - "GENACCEL ","GENSPEED ","HSSBRTQ ","HSSHFTA ","HSSHFTPWR ","HSSHFTTQ ","HSSHFTV ", & - "IPDEFL1 ","IPDEFL2 ","IPDEFL3 ","LSSGAGA ","LSSGAGAXA ","LSSGAGAXS ","LSSGAGFXA ", & - "LSSGAGFXS ","LSSGAGFYA ","LSSGAGFYS ","LSSGAGFZA ","LSSGAGFZS ","LSSGAGMXA ","LSSGAGMXS ", & - "LSSGAGMYA ","LSSGAGMYS ","LSSGAGMZA ","LSSGAGMZS ","LSSGAGP ","LSSGAGPXA ","LSSGAGPXS ", & - "LSSGAGV ","LSSGAGVXA ","LSSGAGVXS ","LSSHFTFXA ","LSSHFTFXS ","LSSHFTFYA ","LSSHFTFYS ", & - "LSSHFTFZA ","LSSHFTFZS ","LSSHFTMXA ","LSSHFTMXS ","LSSHFTPWR ","LSSHFTTQ ","LSSTIPA ", & - "LSSTIPAXA ","LSSTIPAXS ","LSSTIPMYA ","LSSTIPMYS ","LSSTIPMZA ","LSSTIPMZS ","LSSTIPP ", & - "LSSTIPPXA ","LSSTIPPXS ","LSSTIPV ","LSSTIPVXA ","LSSTIPVXS ","NACYAW ","NACYAWA ", & - "NACYAWP ","NACYAWV ","NCIMURAXS ","NCIMURAYS ","NCIMURAZS ","NCIMURVXS ","NCIMURVYS ", & - "NCIMURVZS ","NCIMUTAGXS","NCIMUTAGYS","NCIMUTAGZS","NCIMUTAXS ","NCIMUTAYS ","NCIMUTAZS ", & - "NCIMUTVXS ","NCIMUTVYS ","NCIMUTVZS ","OOPDEFL1 ","OOPDEFL2 ","OOPDEFL3 ","PTCHDEFL1 ", & - "PTCHDEFL2 ","PTCHDEFL3 ","PTCHPMZB1 ","PTCHPMZB2 ","PTCHPMZB3 ","PTCHPMZC1 ","PTCHPMZC2 ", & - "PTCHPMZC3 ","PTFMHEAVE ","PTFMPITCH ","PTFMRAXI ","PTFMRAXT ","PTFMRAYI ","PTFMRAYT ", & - "PTFMRAZI ","PTFMRAZT ","PTFMRDXI ","PTFMRDYI ","PTFMRDZI ","PTFMROLL ","PTFMRVXI ", & - "PTFMRVXT ","PTFMRVYI ","PTFMRVYT ","PTFMRVZI ","PTFMRVZT ","PTFMSURGE ","PTFMSWAY ", & - "PTFMTAGXI ","PTFMTAGXT ","PTFMTAGYI ","PTFMTAGYT ","PTFMTAGZI ","PTFMTAGZT ","PTFMTAXI ", & - "PTFMTAXT ","PTFMTAYI ","PTFMTAYT ","PTFMTAZI ","PTFMTAZT ","PTFMTDXI ","PTFMTDXT ", & - "PTFMTDYI ","PTFMTDYT ","PTFMTDZI ","PTFMTDZT ","PTFMTVXI ","PTFMTVXT ","PTFMTVYI ", & - "PTFMTVYT ","PTFMTVZI ","PTFMTVZT ","PTFMYAW ","QD2_B1E1 ","QD2_B1F1 ","QD2_B1F2 ", & - "QD2_B2E1 ","QD2_B2F1 ","QD2_B2F2 ","QD2_B3E1 ","QD2_B3F1 ","QD2_B3F2 ","QD2_DRTR ", & - "QD2_GEAZ ","QD2_HV ","QD2_P ","QD2_R ","QD2_RFRL ","QD2_SG ","QD2_SW ", & - "QD2_TEET ","QD2_TFA1 ","QD2_TFA2 ","QD2_TFRL ","QD2_TSS1 ","QD2_TSS2 ","QD2_Y ", & - "QD2_YAW ","QD_B1E1 ","QD_B1F1 ","QD_B1F2 ","QD_B2E1 ","QD_B2F1 ","QD_B2F2 ", & - "QD_B3E1 ","QD_B3F1 ","QD_B3F2 ","QD_DRTR ","QD_GEAZ ","QD_HV ","QD_P ", & - "QD_R ","QD_RFRL ","QD_SG ","QD_SW ","QD_TEET ","QD_TFA1 ","QD_TFA2 ", & - "QD_TFRL ","QD_TSS1 ","QD_TSS2 ","QD_Y ","QD_YAW ","Q_B1E1 ","Q_B1F1 ", & - "Q_B1F2 ","Q_B2E1 ","Q_B2F1 ","Q_B2F2 ","Q_B3E1 ","Q_B3F1 ","Q_B3F2 ", & - "Q_DRTR ","Q_GEAZ ","Q_HV ","Q_P ","Q_R ","Q_RFRL ","Q_SG ", & - "Q_SW ","Q_TEET ","Q_TFA1 ","Q_TFA2 ","Q_TFRL ","Q_TSS1 ","Q_TSS2 ", & - "Q_Y ","Q_YAW ","RFRLBRM ","ROLLDEFL1 ","ROLLDEFL2 ","ROLLDEFL3 ","ROOTFXB1 ", & - "ROOTFXB2 ","ROOTFXB3 ","ROOTFXC1 ","ROOTFXC2 ","ROOTFXC3 ","ROOTFYB1 ","ROOTFYB2 ", & - "ROOTFYB3 ","ROOTFYC1 ","ROOTFYC2 ","ROOTFYC3 ","ROOTFZB1 ","ROOTFZB2 ","ROOTFZB3 ", & - "ROOTFZC1 ","ROOTFZC2 ","ROOTFZC3 ","ROOTMEDG1 ","ROOTMEDG2 ","ROOTMEDG3 ","ROOTMFLP1 ", & - "ROOTMFLP2 ","ROOTMFLP3 ","ROOTMIP1 ","ROOTMIP2 ","ROOTMIP3 ","ROOTMOOP1 ","ROOTMOOP2 ", & - "ROOTMOOP3 ","ROOTMXB1 ","ROOTMXB2 ","ROOTMXB3 ","ROOTMXC1 ","ROOTMXC2 ","ROOTMXC3 ", & - "ROOTMYB1 ","ROOTMYB2 ","ROOTMYB3 ","ROOTMYC1 ","ROOTMYC2 ","ROOTMYC3 ","ROOTMZB1 ", & - "ROOTMZB2 ","ROOTMZB3 ","ROOTMZC1 ","ROOTMZC2 ","ROOTMZC3 ","ROTACCEL ","ROTFURL ", & - "ROTFURLA ","ROTFURLP ","ROTFURLV ","ROTPWR ","ROTSPEED ","ROTTEETA ","ROTTEETP ", & - "ROTTEETV ","ROTTHRUST ","ROTTORQ ","SPN1ALGXB1","SPN1ALGXB2","SPN1ALGXB3","SPN1ALGYB1", & - "SPN1ALGYB2","SPN1ALGYB3","SPN1ALGZB1","SPN1ALGZB2","SPN1ALGZB3","SPN1ALXB1 ","SPN1ALXB2 ", & - "SPN1ALXB3 ","SPN1ALYB1 ","SPN1ALYB2 ","SPN1ALYB3 ","SPN1ALZB1 ","SPN1ALZB2 ","SPN1ALZB3 ", & - "SPN1FLXB1 ","SPN1FLXB2 ","SPN1FLXB3 ","SPN1FLYB1 ","SPN1FLYB2 ","SPN1FLYB3 ","SPN1FLZB1 ", & - "SPN1FLZB2 ","SPN1FLZB3 ","SPN1MLXB1 ","SPN1MLXB2 ","SPN1MLXB3 ","SPN1MLYB1 ","SPN1MLYB2 ", & - "SPN1MLYB3 ","SPN1MLZB1 ","SPN1MLZB2 ","SPN1MLZB3 ","SPN1RDXB1 ","SPN1RDXB2 ","SPN1RDXB3 ", & - "SPN1RDYB1 ","SPN1RDYB2 ","SPN1RDYB3 ","SPN1RDZB1 ","SPN1RDZB2 ","SPN1RDZB3 ","SPN1TDXB1 ", & - "SPN1TDXB2 ","SPN1TDXB3 ","SPN1TDYB1 ","SPN1TDYB2 ","SPN1TDYB3 ","SPN1TDZB1 ","SPN1TDZB2 ", & - "SPN1TDZB3 ","SPN2ALGXB1","SPN2ALGXB2","SPN2ALGXB3","SPN2ALGYB1","SPN2ALGYB2","SPN2ALGYB3", & - "SPN2ALGZB1","SPN2ALGZB2","SPN2ALGZB3","SPN2ALXB1 ","SPN2ALXB2 ","SPN2ALXB3 ","SPN2ALYB1 ", & - "SPN2ALYB2 ","SPN2ALYB3 ","SPN2ALZB1 ","SPN2ALZB2 ","SPN2ALZB3 ","SPN2FLXB1 ","SPN2FLXB2 ", & - "SPN2FLXB3 ","SPN2FLYB1 ","SPN2FLYB2 ","SPN2FLYB3 ","SPN2FLZB1 ","SPN2FLZB2 ","SPN2FLZB3 ", & - "SPN2MLXB1 ","SPN2MLXB2 ","SPN2MLXB3 ","SPN2MLYB1 ","SPN2MLYB2 ","SPN2MLYB3 ","SPN2MLZB1 ", & - "SPN2MLZB2 ","SPN2MLZB3 ","SPN2RDXB1 ","SPN2RDXB2 ","SPN2RDXB3 ","SPN2RDYB1 ","SPN2RDYB2 ", & - "SPN2RDYB3 ","SPN2RDZB1 ","SPN2RDZB2 ","SPN2RDZB3 ","SPN2TDXB1 ","SPN2TDXB2 ","SPN2TDXB3 ", & - "SPN2TDYB1 ","SPN2TDYB2 ","SPN2TDYB3 ","SPN2TDZB1 ","SPN2TDZB2 ","SPN2TDZB3 ","SPN3ALGXB1", & - "SPN3ALGXB2","SPN3ALGXB3","SPN3ALGYB1","SPN3ALGYB2","SPN3ALGYB3","SPN3ALGZB1","SPN3ALGZB2", & - "SPN3ALGZB3","SPN3ALXB1 ","SPN3ALXB2 ","SPN3ALXB3 ","SPN3ALYB1 ","SPN3ALYB2 ","SPN3ALYB3 ", & - "SPN3ALZB1 ","SPN3ALZB2 ","SPN3ALZB3 ","SPN3FLXB1 ","SPN3FLXB2 ","SPN3FLXB3 ","SPN3FLYB1 ", & - "SPN3FLYB2 ","SPN3FLYB3 ","SPN3FLZB1 ","SPN3FLZB2 ","SPN3FLZB3 ","SPN3MLXB1 ","SPN3MLXB2 ", & - "SPN3MLXB3 ","SPN3MLYB1 ","SPN3MLYB2 ","SPN3MLYB3 ","SPN3MLZB1 ","SPN3MLZB2 ","SPN3MLZB3 ", & - "SPN3RDXB1 ","SPN3RDXB2 ","SPN3RDXB3 ","SPN3RDYB1 ","SPN3RDYB2 ","SPN3RDYB3 ","SPN3RDZB1 ", & - "SPN3RDZB2 ","SPN3RDZB3 ","SPN3TDXB1 ","SPN3TDXB2 ","SPN3TDXB3 ","SPN3TDYB1 ","SPN3TDYB2 ", & - "SPN3TDYB3 ","SPN3TDZB1 ","SPN3TDZB2 ","SPN3TDZB3 ","SPN4ALGXB1","SPN4ALGXB2","SPN4ALGXB3", & - "SPN4ALGYB1","SPN4ALGYB2","SPN4ALGYB3","SPN4ALGZB1","SPN4ALGZB2","SPN4ALGZB3","SPN4ALXB1 ", & - "SPN4ALXB2 ","SPN4ALXB3 ","SPN4ALYB1 ","SPN4ALYB2 ","SPN4ALYB3 ","SPN4ALZB1 ","SPN4ALZB2 ", & - "SPN4ALZB3 ","SPN4FLXB1 ","SPN4FLXB2 ","SPN4FLXB3 ","SPN4FLYB1 ","SPN4FLYB2 ","SPN4FLYB3 ", & - "SPN4FLZB1 ","SPN4FLZB2 ","SPN4FLZB3 ","SPN4MLXB1 ","SPN4MLXB2 ","SPN4MLXB3 ","SPN4MLYB1 ", & - "SPN4MLYB2 ","SPN4MLYB3 ","SPN4MLZB1 ","SPN4MLZB2 ","SPN4MLZB3 ","SPN4RDXB1 ","SPN4RDXB2 ", & - "SPN4RDXB3 ","SPN4RDYB1 ","SPN4RDYB2 ","SPN4RDYB3 ","SPN4RDZB1 ","SPN4RDZB2 ","SPN4RDZB3 ", & - "SPN4TDXB1 ","SPN4TDXB2 ","SPN4TDXB3 ","SPN4TDYB1 ","SPN4TDYB2 ","SPN4TDYB3 ","SPN4TDZB1 ", & - "SPN4TDZB2 ","SPN4TDZB3 ","SPN5ALGXB1","SPN5ALGXB2","SPN5ALGXB3","SPN5ALGYB1","SPN5ALGYB2", & - "SPN5ALGYB3","SPN5ALGZB1","SPN5ALGZB2","SPN5ALGZB3","SPN5ALXB1 ","SPN5ALXB2 ","SPN5ALXB3 ", & - "SPN5ALYB1 ","SPN5ALYB2 ","SPN5ALYB3 ","SPN5ALZB1 ","SPN5ALZB2 ","SPN5ALZB3 ","SPN5FLXB1 ", & - "SPN5FLXB2 ","SPN5FLXB3 ","SPN5FLYB1 ","SPN5FLYB2 ","SPN5FLYB3 ","SPN5FLZB1 ","SPN5FLZB2 ", & - "SPN5FLZB3 ","SPN5MLXB1 ","SPN5MLXB2 ","SPN5MLXB3 ","SPN5MLYB1 ","SPN5MLYB2 ","SPN5MLYB3 ", & - "SPN5MLZB1 ","SPN5MLZB2 ","SPN5MLZB3 ","SPN5RDXB1 ","SPN5RDXB2 ","SPN5RDXB3 ","SPN5RDYB1 ", & - "SPN5RDYB2 ","SPN5RDYB3 ","SPN5RDZB1 ","SPN5RDZB2 ","SPN5RDZB3 ","SPN5TDXB1 ","SPN5TDXB2 ", & - "SPN5TDXB3 ","SPN5TDYB1 ","SPN5TDYB2 ","SPN5TDYB3 ","SPN5TDZB1 ","SPN5TDZB2 ","SPN5TDZB3 ", & - "SPN6ALGXB1","SPN6ALGXB2","SPN6ALGXB3","SPN6ALGYB1","SPN6ALGYB2","SPN6ALGYB3","SPN6ALGZB1", & - "SPN6ALGZB2","SPN6ALGZB3","SPN6ALXB1 ","SPN6ALXB2 ","SPN6ALXB3 ","SPN6ALYB1 ","SPN6ALYB2 ", & - "SPN6ALYB3 ","SPN6ALZB1 ","SPN6ALZB2 ","SPN6ALZB3 ","SPN6FLXB1 ","SPN6FLXB2 ","SPN6FLXB3 ", & - "SPN6FLYB1 ","SPN6FLYB2 ","SPN6FLYB3 ","SPN6FLZB1 ","SPN6FLZB2 ","SPN6FLZB3 ","SPN6MLXB1 ", & - "SPN6MLXB2 ","SPN6MLXB3 ","SPN6MLYB1 ","SPN6MLYB2 ","SPN6MLYB3 ","SPN6MLZB1 ","SPN6MLZB2 ", & - "SPN6MLZB3 ","SPN6RDXB1 ","SPN6RDXB2 ","SPN6RDXB3 ","SPN6RDYB1 ","SPN6RDYB2 ","SPN6RDYB3 ", & - "SPN6RDZB1 ","SPN6RDZB2 ","SPN6RDZB3 ","SPN6TDXB1 ","SPN6TDXB2 ","SPN6TDXB3 ","SPN6TDYB1 ", & - "SPN6TDYB2 ","SPN6TDYB3 ","SPN6TDZB1 ","SPN6TDZB2 ","SPN6TDZB3 ","SPN7ALGXB1","SPN7ALGXB2", & - "SPN7ALGXB3","SPN7ALGYB1","SPN7ALGYB2","SPN7ALGYB3","SPN7ALGZB1","SPN7ALGZB2","SPN7ALGZB3", & - "SPN7ALXB1 ","SPN7ALXB2 ","SPN7ALXB3 ","SPN7ALYB1 ","SPN7ALYB2 ","SPN7ALYB3 ","SPN7ALZB1 ", & - "SPN7ALZB2 ","SPN7ALZB3 ","SPN7FLXB1 ","SPN7FLXB2 ","SPN7FLXB3 ","SPN7FLYB1 ","SPN7FLYB2 ", & - "SPN7FLYB3 ","SPN7FLZB1 ","SPN7FLZB2 ","SPN7FLZB3 ","SPN7MLXB1 ","SPN7MLXB2 ","SPN7MLXB3 ", & - "SPN7MLYB1 ","SPN7MLYB2 ","SPN7MLYB3 ","SPN7MLZB1 ","SPN7MLZB2 ","SPN7MLZB3 ","SPN7RDXB1 ", & - "SPN7RDXB2 ","SPN7RDXB3 ","SPN7RDYB1 ","SPN7RDYB2 ","SPN7RDYB3 ","SPN7RDZB1 ","SPN7RDZB2 ", & - "SPN7RDZB3 ","SPN7TDXB1 ","SPN7TDXB2 ","SPN7TDXB3 ","SPN7TDYB1 ","SPN7TDYB2 ","SPN7TDYB3 ", & - "SPN7TDZB1 ","SPN7TDZB2 ","SPN7TDZB3 ","SPN8ALGXB1","SPN8ALGXB2","SPN8ALGXB3","SPN8ALGYB1", & - "SPN8ALGYB2","SPN8ALGYB3","SPN8ALGZB1","SPN8ALGZB2","SPN8ALGZB3","SPN8ALXB1 ","SPN8ALXB2 ", & - "SPN8ALXB3 ","SPN8ALYB1 ","SPN8ALYB2 ","SPN8ALYB3 ","SPN8ALZB1 ","SPN8ALZB2 ","SPN8ALZB3 ", & - "SPN8FLXB1 ","SPN8FLXB2 ","SPN8FLXB3 ","SPN8FLYB1 ","SPN8FLYB2 ","SPN8FLYB3 ","SPN8FLZB1 ", & - "SPN8FLZB2 ","SPN8FLZB3 ","SPN8MLXB1 ","SPN8MLXB2 ","SPN8MLXB3 ","SPN8MLYB1 ","SPN8MLYB2 ", & - "SPN8MLYB3 ","SPN8MLZB1 ","SPN8MLZB2 ","SPN8MLZB3 ","SPN8RDXB1 ","SPN8RDXB2 ","SPN8RDXB3 ", & - "SPN8RDYB1 ","SPN8RDYB2 ","SPN8RDYB3 ","SPN8RDZB1 ","SPN8RDZB2 ","SPN8RDZB3 ","SPN8TDXB1 ", & - "SPN8TDXB2 ","SPN8TDXB3 ","SPN8TDYB1 ","SPN8TDYB2 ","SPN8TDYB3 ","SPN8TDZB1 ","SPN8TDZB2 ", & - "SPN8TDZB3 ","SPN9ALGXB1","SPN9ALGXB2","SPN9ALGXB3","SPN9ALGYB1","SPN9ALGYB2","SPN9ALGYB3", & - "SPN9ALGZB1","SPN9ALGZB2","SPN9ALGZB3","SPN9ALXB1 ","SPN9ALXB2 ","SPN9ALXB3 ","SPN9ALYB1 ", & - "SPN9ALYB2 ","SPN9ALYB3 ","SPN9ALZB1 ","SPN9ALZB2 ","SPN9ALZB3 ","SPN9FLXB1 ","SPN9FLXB2 ", & - "SPN9FLXB3 ","SPN9FLYB1 ","SPN9FLYB2 ","SPN9FLYB3 ","SPN9FLZB1 ","SPN9FLZB2 ","SPN9FLZB3 ", & - "SPN9MLXB1 ","SPN9MLXB2 ","SPN9MLXB3 ","SPN9MLYB1 ","SPN9MLYB2 ","SPN9MLYB3 ","SPN9MLZB1 ", & - "SPN9MLZB2 ","SPN9MLZB3 ","SPN9RDXB1 ","SPN9RDXB2 ","SPN9RDXB3 ","SPN9RDYB1 ","SPN9RDYB2 ", & - "SPN9RDYB3 ","SPN9RDZB1 ","SPN9RDZB2 ","SPN9RDZB3 ","SPN9TDXB1 ","SPN9TDXB2 ","SPN9TDXB3 ", & - "SPN9TDYB1 ","SPN9TDYB2 ","SPN9TDYB3 ","SPN9TDZB1 ","SPN9TDZB2 ","SPN9TDZB3 ","TAILFURL ", & - "TAILFURLA ","TAILFURLP ","TAILFURLV ","TEETAYA ","TEETDEFL ","TEETPYA ","TEETVYA ", & - "TFRLBRM ","TIP2TWR1 ","TIP2TWR2 ","TIP2TWR3 ","TIPALGXB1 ","TIPALGXB2 ","TIPALGXB3 ", & - "TIPALGYB1 ","TIPALGYB2 ","TIPALGYB3 ","TIPALGZB1 ","TIPALGZB2 ","TIPALGZB3 ","TIPALXB1 ", & - "TIPALXB2 ","TIPALXB3 ","TIPALYB1 ","TIPALYB2 ","TIPALYB3 ","TIPALZB1 ","TIPALZB2 ", & - "TIPALZB3 ","TIPCLRNC1 ","TIPCLRNC2 ","TIPCLRNC3 ","TIPDXB1 ","TIPDXB2 ","TIPDXB3 ", & - "TIPDXC1 ","TIPDXC2 ","TIPDXC3 ","TIPDYB1 ","TIPDYB2 ","TIPDYB3 ","TIPDYC1 ", & - "TIPDYC2 ","TIPDYC3 ","TIPDZB1 ","TIPDZB2 ","TIPDZB3 ","TIPDZC1 ","TIPDZC2 ", & - "TIPDZC3 ","TIPRDXB1 ","TIPRDXB2 ","TIPRDXB3 ","TIPRDYB1 ","TIPRDYB2 ","TIPRDYB3 ", & - "TIPRDZB1 ","TIPRDZB2 ","TIPRDZB3 ","TIPRDZC1 ","TIPRDZC2 ","TIPRDZC3 ","TTDSPAX ", & - "TTDSPFA ","TTDSPPTCH ","TTDSPROLL ","TTDSPSS ","TTDSPTWST ","TWHT1ALGXT","TWHT1ALGYT", & - "TWHT1ALGZT","TWHT1ALXT ","TWHT1ALYT ","TWHT1ALZT ","TWHT1FLXT ","TWHT1FLYT ","TWHT1FLZT ", & - "TWHT1MLXT ","TWHT1MLYT ","TWHT1MLZT ","TWHT1RDXT ","TWHT1RDYT ","TWHT1RDZT ","TWHT1RPXI ", & - "TWHT1RPYI ","TWHT1RPZI ","TWHT1TDXT ","TWHT1TDYT ","TWHT1TDZT ","TWHT1TPXI ","TWHT1TPYI ", & - "TWHT1TPZI ","TWHT2ALGXT","TWHT2ALGYT","TWHT2ALGZT","TWHT2ALXT ","TWHT2ALYT ","TWHT2ALZT ", & - "TWHT2FLXT ","TWHT2FLYT ","TWHT2FLZT ","TWHT2MLXT ","TWHT2MLYT ","TWHT2MLZT ","TWHT2RDXT ", & - "TWHT2RDYT ","TWHT2RDZT ","TWHT2RPXI ","TWHT2RPYI ","TWHT2RPZI ","TWHT2TDXT ","TWHT2TDYT ", & - "TWHT2TDZT ","TWHT2TPXI ","TWHT2TPYI ","TWHT2TPZI ","TWHT3ALGXT","TWHT3ALGYT","TWHT3ALGZT", & - "TWHT3ALXT ","TWHT3ALYT ","TWHT3ALZT ","TWHT3FLXT ","TWHT3FLYT ","TWHT3FLZT ","TWHT3MLXT ", & - "TWHT3MLYT ","TWHT3MLZT ","TWHT3RDXT ","TWHT3RDYT ","TWHT3RDZT ","TWHT3RPXI ","TWHT3RPYI ", & - "TWHT3RPZI ","TWHT3TDXT ","TWHT3TDYT ","TWHT3TDZT ","TWHT3TPXI ","TWHT3TPYI ","TWHT3TPZI ", & - "TWHT4ALGXT","TWHT4ALGYT","TWHT4ALGZT","TWHT4ALXT ","TWHT4ALYT ","TWHT4ALZT ","TWHT4FLXT ", & - "TWHT4FLYT ","TWHT4FLZT ","TWHT4MLXT ","TWHT4MLYT ","TWHT4MLZT ","TWHT4RDXT ","TWHT4RDYT ", & - "TWHT4RDZT ","TWHT4RPXI ","TWHT4RPYI ","TWHT4RPZI ","TWHT4TDXT ","TWHT4TDYT ","TWHT4TDZT ", & - "TWHT4TPXI ","TWHT4TPYI ","TWHT4TPZI ","TWHT5ALGXT","TWHT5ALGYT","TWHT5ALGZT","TWHT5ALXT ", & - "TWHT5ALYT ","TWHT5ALZT ","TWHT5FLXT ","TWHT5FLYT ","TWHT5FLZT ","TWHT5MLXT ","TWHT5MLYT ", & - "TWHT5MLZT ","TWHT5RDXT ","TWHT5RDYT ","TWHT5RDZT ","TWHT5RPXI ","TWHT5RPYI ","TWHT5RPZI ", & - "TWHT5TDXT ","TWHT5TDYT ","TWHT5TDZT ","TWHT5TPXI ","TWHT5TPYI ","TWHT5TPZI ","TWHT6ALGXT", & - "TWHT6ALGYT","TWHT6ALGZT","TWHT6ALXT ","TWHT6ALYT ","TWHT6ALZT ","TWHT6FLXT ","TWHT6FLYT ", & - "TWHT6FLZT ","TWHT6MLXT ","TWHT6MLYT ","TWHT6MLZT ","TWHT6RDXT ","TWHT6RDYT ","TWHT6RDZT ", & - "TWHT6RPXI ","TWHT6RPYI ","TWHT6RPZI ","TWHT6TDXT ","TWHT6TDYT ","TWHT6TDZT ","TWHT6TPXI ", & - "TWHT6TPYI ","TWHT6TPZI ","TWHT7ALGXT","TWHT7ALGYT","TWHT7ALGZT","TWHT7ALXT ","TWHT7ALYT ", & - "TWHT7ALZT ","TWHT7FLXT ","TWHT7FLYT ","TWHT7FLZT ","TWHT7MLXT ","TWHT7MLYT ","TWHT7MLZT ", & - "TWHT7RDXT ","TWHT7RDYT ","TWHT7RDZT ","TWHT7RPXI ","TWHT7RPYI ","TWHT7RPZI ","TWHT7TDXT ", & - "TWHT7TDYT ","TWHT7TDZT ","TWHT7TPXI ","TWHT7TPYI ","TWHT7TPZI ","TWHT8ALGXT","TWHT8ALGYT", & - "TWHT8ALGZT","TWHT8ALXT ","TWHT8ALYT ","TWHT8ALZT ","TWHT8FLXT ","TWHT8FLYT ","TWHT8FLZT ", & - "TWHT8MLXT ","TWHT8MLYT ","TWHT8MLZT ","TWHT8RDXT ","TWHT8RDYT ","TWHT8RDZT ","TWHT8RPXI ", & - "TWHT8RPYI ","TWHT8RPZI ","TWHT8TDXT ","TWHT8TDYT ","TWHT8TDZT ","TWHT8TPXI ","TWHT8TPYI ", & - "TWHT8TPZI ","TWHT9ALGXT","TWHT9ALGYT","TWHT9ALGZT","TWHT9ALXT ","TWHT9ALYT ","TWHT9ALZT ", & - "TWHT9FLXT ","TWHT9FLYT ","TWHT9FLZT ","TWHT9MLXT ","TWHT9MLYT ","TWHT9MLZT ","TWHT9RDXT ", & - "TWHT9RDYT ","TWHT9RDZT ","TWHT9RPXI ","TWHT9RPYI ","TWHT9RPZI ","TWHT9TDXT ","TWHT9TDYT ", & - "TWHT9TDZT ","TWHT9TPXI ","TWHT9TPYI ","TWHT9TPZI ","TWRBSFXT ","TWRBSFYT ","TWRBSFZT ", & - "TWRBSMXT ","TWRBSMYT ","TWRBSMZT ","TWRCLRNC1 ","TWRCLRNC2 ","TWRCLRNC3 ","TWRTPTDXI ", & - "TWRTPTDYI ","TWRTPTDZI ","TWSTDEFL1 ","TWSTDEFL2 ","TWSTDEFL3 ","YAWACCEL ","YAWAZN ", & - "YAWAZP ","YAWBRFXN ","YAWBRFXP ","YAWBRFYN ","YAWBRFYP ","YAWBRFZN ","YAWBRFZP ", & - "YAWBRMXN ","YAWBRMXP ","YAWBRMYN ","YAWBRMYP ","YAWBRMZN ","YAWBRMZP ","YAWBRRAXP ", & - "YAWBRRAYP ","YAWBRRAZP ","YAWBRRDXT ","YAWBRRDYT ","YAWBRRDZT ","YAWBRRVXP ","YAWBRRVYP ", & - "YAWBRRVZP ","YAWBRTAGXP","YAWBRTAGYP","YAWBRTAGZP","YAWBRTAXP ","YAWBRTAYP ","YAWBRTAZP ", & - "YAWBRTDXI ","YAWBRTDXP ","YAWBRTDXT ","YAWBRTDYI ","YAWBRTDYP ","YAWBRTDYT ","YAWBRTDZI ", & - "YAWBRTDZP ","YAWBRTDZT ","YAWBRTVXP ","YAWBRTVYP ","YAWBRTVZP ","YAWPOS ","YAWPZN ", & - "YAWPZP ","YAWRATE ","YAWVZN ","YAWVZP "/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(1110) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + "DOMEGAYF ","GENACCEL ","GENSPEED ","HSSBRTQ ","HSSHFTA ","HSSHFTPWR ","HSSHFTTQ ", & + "HSSHFTV ","IPDEFL1 ","IPDEFL2 ","IPDEFL3 ","LSSGAGA ","LSSGAGAXA ","LSSGAGAXS ", & + "LSSGAGFXA ","LSSGAGFXS ","LSSGAGFYA ","LSSGAGFYS ","LSSGAGFZA ","LSSGAGFZS ","LSSGAGMXA ", & + "LSSGAGMXS ","LSSGAGMYA ","LSSGAGMYS ","LSSGAGMZA ","LSSGAGMZS ","LSSGAGP ","LSSGAGPXA ", & + "LSSGAGPXS ","LSSGAGV ","LSSGAGVXA ","LSSGAGVXS ","LSSHFTFXA ","LSSHFTFXS ","LSSHFTFYA ", & + "LSSHFTFYS ","LSSHFTFZA ","LSSHFTFZS ","LSSHFTMXA ","LSSHFTMXS ","LSSHFTPWR ","LSSHFTTQ ", & + "LSSTIPA ","LSSTIPAXA ","LSSTIPAXS ","LSSTIPMYA ","LSSTIPMYS ","LSSTIPMZA ","LSSTIPMZS ", & + "LSSTIPP ","LSSTIPPXA ","LSSTIPPXS ","LSSTIPV ","LSSTIPVXA ","LSSTIPVXS ","NACYAW ", & + "NACYAWA ","NACYAWP ","NACYAWV ","NCIMURAXS ","NCIMURAYS ","NCIMURAZS ","NCIMURVXS ", & + "NCIMURVYS ","NCIMURVZS ","NCIMUTAGXS","NCIMUTAGYS","NCIMUTAGZS","NCIMUTAXS ","NCIMUTAYS ", & + "NCIMUTAZS ","NCIMUTVXS ","NCIMUTVYS ","NCIMUTVZS ","OMEGAYF ","OOPDEFL1 ","OOPDEFL2 ", & + "OOPDEFL3 ","PTCHDEFL1 ","PTCHDEFL2 ","PTCHDEFL3 ","PTCHPMZB1 ","PTCHPMZB2 ","PTCHPMZB3 ", & + "PTCHPMZC1 ","PTCHPMZC2 ","PTCHPMZC3 ","PTFMHEAVE ","PTFMPITCH ","PTFMRAXI ","PTFMRAXT ", & + "PTFMRAYI ","PTFMRAYT ","PTFMRAZI ","PTFMRAZT ","PTFMRDXI ","PTFMRDYI ","PTFMRDZI ", & + "PTFMROLL ","PTFMRVXI ","PTFMRVXT ","PTFMRVYI ","PTFMRVYT ","PTFMRVZI ","PTFMRVZT ", & + "PTFMSURGE ","PTFMSWAY ","PTFMTAGXI ","PTFMTAGXT ","PTFMTAGYI ","PTFMTAGYT ","PTFMTAGZI ", & + "PTFMTAGZT ","PTFMTAXI ","PTFMTAXT ","PTFMTAYI ","PTFMTAYT ","PTFMTAZI ","PTFMTAZT ", & + "PTFMTDXI ","PTFMTDXT ","PTFMTDYI ","PTFMTDYT ","PTFMTDZI ","PTFMTDZT ","PTFMTVXI ", & + "PTFMTVXT ","PTFMTVYI ","PTFMTVYT ","PTFMTVZI ","PTFMTVZT ","PTFMYAW ","QD2_B1E1 ", & + "QD2_B1F1 ","QD2_B1F2 ","QD2_B2E1 ","QD2_B2F1 ","QD2_B2F2 ","QD2_B3E1 ","QD2_B3F1 ", & + "QD2_B3F2 ","QD2_DRTR ","QD2_GEAZ ","QD2_HV ","QD2_P ","QD2_R ","QD2_RFRL ", & + "QD2_SG ","QD2_SW ","QD2_TEET ","QD2_TFA1 ","QD2_TFA2 ","QD2_TFRL ","QD2_TSS1 ", & + "QD2_TSS2 ","QD2_Y ","QD2_YAW ","QD_B1E1 ","QD_B1F1 ","QD_B1F2 ","QD_B2E1 ", & + "QD_B2F1 ","QD_B2F2 ","QD_B3E1 ","QD_B3F1 ","QD_B3F2 ","QD_DRTR ","QD_GEAZ ", & + "QD_HV ","QD_P ","QD_R ","QD_RFRL ","QD_SG ","QD_SW ","QD_TEET ", & + "QD_TFA1 ","QD_TFA2 ","QD_TFRL ","QD_TSS1 ","QD_TSS2 ","QD_Y ","QD_YAW ", & + "Q_B1E1 ","Q_B1F1 ","Q_B1F2 ","Q_B2E1 ","Q_B2F1 ","Q_B2F2 ","Q_B3E1 ", & + "Q_B3F1 ","Q_B3F2 ","Q_DRTR ","Q_GEAZ ","Q_HV ","Q_P ","Q_R ", & + "Q_RFRL ","Q_SG ","Q_SW ","Q_TEET ","Q_TFA1 ","Q_TFA2 ","Q_TFRL ", & + "Q_TSS1 ","Q_TSS2 ","Q_Y ","Q_YAW ","RFRLBRM ","ROLLDEFL1 ","ROLLDEFL2 ", & + "ROLLDEFL3 ","ROOTFXB1 ","ROOTFXB2 ","ROOTFXB3 ","ROOTFXC1 ","ROOTFXC2 ","ROOTFXC3 ", & + "ROOTFYB1 ","ROOTFYB2 ","ROOTFYB3 ","ROOTFYC1 ","ROOTFYC2 ","ROOTFYC3 ","ROOTFZB1 ", & + "ROOTFZB2 ","ROOTFZB3 ","ROOTFZC1 ","ROOTFZC2 ","ROOTFZC3 ","ROOTMEDG1 ","ROOTMEDG2 ", & + "ROOTMEDG3 ","ROOTMFLP1 ","ROOTMFLP2 ","ROOTMFLP3 ","ROOTMIP1 ","ROOTMIP2 ","ROOTMIP3 ", & + "ROOTMOOP1 ","ROOTMOOP2 ","ROOTMOOP3 ","ROOTMXB1 ","ROOTMXB2 ","ROOTMXB3 ","ROOTMXC1 ", & + "ROOTMXC2 ","ROOTMXC3 ","ROOTMYB1 ","ROOTMYB2 ","ROOTMYB3 ","ROOTMYC1 ","ROOTMYC2 ", & + "ROOTMYC3 ","ROOTMZB1 ","ROOTMZB2 ","ROOTMZB3 ","ROOTMZC1 ","ROOTMZC2 ","ROOTMZC3 ", & + "ROTACCEL ","ROTFURL ","ROTFURLA ","ROTFURLP ","ROTFURLV ","ROTPWR ","ROTSPEED ", & + "ROTTEETA ","ROTTEETP ","ROTTEETV ","ROTTHRUST ","ROTTORQ ","SPN1ALGXB1","SPN1ALGXB2", & + "SPN1ALGXB3","SPN1ALGYB1","SPN1ALGYB2","SPN1ALGYB3","SPN1ALGZB1","SPN1ALGZB2","SPN1ALGZB3", & + "SPN1ALXB1 ","SPN1ALXB2 ","SPN1ALXB3 ","SPN1ALYB1 ","SPN1ALYB2 ","SPN1ALYB3 ","SPN1ALZB1 ", & + "SPN1ALZB2 ","SPN1ALZB3 ","SPN1FLXB1 ","SPN1FLXB2 ","SPN1FLXB3 ","SPN1FLYB1 ","SPN1FLYB2 ", & + "SPN1FLYB3 ","SPN1FLZB1 ","SPN1FLZB2 ","SPN1FLZB3 ","SPN1MLXB1 ","SPN1MLXB2 ","SPN1MLXB3 ", & + "SPN1MLYB1 ","SPN1MLYB2 ","SPN1MLYB3 ","SPN1MLZB1 ","SPN1MLZB2 ","SPN1MLZB3 ","SPN1RDXB1 ", & + "SPN1RDXB2 ","SPN1RDXB3 ","SPN1RDYB1 ","SPN1RDYB2 ","SPN1RDYB3 ","SPN1RDZB1 ","SPN1RDZB2 ", & + "SPN1RDZB3 ","SPN1TDXB1 ","SPN1TDXB2 ","SPN1TDXB3 ","SPN1TDYB1 ","SPN1TDYB2 ","SPN1TDYB3 ", & + "SPN1TDZB1 ","SPN1TDZB2 ","SPN1TDZB3 ","SPN2ALGXB1","SPN2ALGXB2","SPN2ALGXB3","SPN2ALGYB1", & + "SPN2ALGYB2","SPN2ALGYB3","SPN2ALGZB1","SPN2ALGZB2","SPN2ALGZB3","SPN2ALXB1 ","SPN2ALXB2 ", & + "SPN2ALXB3 ","SPN2ALYB1 ","SPN2ALYB2 ","SPN2ALYB3 ","SPN2ALZB1 ","SPN2ALZB2 ","SPN2ALZB3 ", & + "SPN2FLXB1 ","SPN2FLXB2 ","SPN2FLXB3 ","SPN2FLYB1 ","SPN2FLYB2 ","SPN2FLYB3 ","SPN2FLZB1 ", & + "SPN2FLZB2 ","SPN2FLZB3 ","SPN2MLXB1 ","SPN2MLXB2 ","SPN2MLXB3 ","SPN2MLYB1 ","SPN2MLYB2 ", & + "SPN2MLYB3 ","SPN2MLZB1 ","SPN2MLZB2 ","SPN2MLZB3 ","SPN2RDXB1 ","SPN2RDXB2 ","SPN2RDXB3 ", & + "SPN2RDYB1 ","SPN2RDYB2 ","SPN2RDYB3 ","SPN2RDZB1 ","SPN2RDZB2 ","SPN2RDZB3 ","SPN2TDXB1 ", & + "SPN2TDXB2 ","SPN2TDXB3 ","SPN2TDYB1 ","SPN2TDYB2 ","SPN2TDYB3 ","SPN2TDZB1 ","SPN2TDZB2 ", & + "SPN2TDZB3 ","SPN3ALGXB1","SPN3ALGXB2","SPN3ALGXB3","SPN3ALGYB1","SPN3ALGYB2","SPN3ALGYB3", & + "SPN3ALGZB1","SPN3ALGZB2","SPN3ALGZB3","SPN3ALXB1 ","SPN3ALXB2 ","SPN3ALXB3 ","SPN3ALYB1 ", & + "SPN3ALYB2 ","SPN3ALYB3 ","SPN3ALZB1 ","SPN3ALZB2 ","SPN3ALZB3 ","SPN3FLXB1 ","SPN3FLXB2 ", & + "SPN3FLXB3 ","SPN3FLYB1 ","SPN3FLYB2 ","SPN3FLYB3 ","SPN3FLZB1 ","SPN3FLZB2 ","SPN3FLZB3 ", & + "SPN3MLXB1 ","SPN3MLXB2 ","SPN3MLXB3 ","SPN3MLYB1 ","SPN3MLYB2 ","SPN3MLYB3 ","SPN3MLZB1 ", & + "SPN3MLZB2 ","SPN3MLZB3 ","SPN3RDXB1 ","SPN3RDXB2 ","SPN3RDXB3 ","SPN3RDYB1 ","SPN3RDYB2 ", & + "SPN3RDYB3 ","SPN3RDZB1 ","SPN3RDZB2 ","SPN3RDZB3 ","SPN3TDXB1 ","SPN3TDXB2 ","SPN3TDXB3 ", & + "SPN3TDYB1 ","SPN3TDYB2 ","SPN3TDYB3 ","SPN3TDZB1 ","SPN3TDZB2 ","SPN3TDZB3 ","SPN4ALGXB1", & + "SPN4ALGXB2","SPN4ALGXB3","SPN4ALGYB1","SPN4ALGYB2","SPN4ALGYB3","SPN4ALGZB1","SPN4ALGZB2", & + "SPN4ALGZB3","SPN4ALXB1 ","SPN4ALXB2 ","SPN4ALXB3 ","SPN4ALYB1 ","SPN4ALYB2 ","SPN4ALYB3 ", & + "SPN4ALZB1 ","SPN4ALZB2 ","SPN4ALZB3 ","SPN4FLXB1 ","SPN4FLXB2 ","SPN4FLXB3 ","SPN4FLYB1 ", & + "SPN4FLYB2 ","SPN4FLYB3 ","SPN4FLZB1 ","SPN4FLZB2 ","SPN4FLZB3 ","SPN4MLXB1 ","SPN4MLXB2 ", & + "SPN4MLXB3 ","SPN4MLYB1 ","SPN4MLYB2 ","SPN4MLYB3 ","SPN4MLZB1 ","SPN4MLZB2 ","SPN4MLZB3 ", & + "SPN4RDXB1 ","SPN4RDXB2 ","SPN4RDXB3 ","SPN4RDYB1 ","SPN4RDYB2 ","SPN4RDYB3 ","SPN4RDZB1 ", & + "SPN4RDZB2 ","SPN4RDZB3 ","SPN4TDXB1 ","SPN4TDXB2 ","SPN4TDXB3 ","SPN4TDYB1 ","SPN4TDYB2 ", & + "SPN4TDYB3 ","SPN4TDZB1 ","SPN4TDZB2 ","SPN4TDZB3 ","SPN5ALGXB1","SPN5ALGXB2","SPN5ALGXB3", & + "SPN5ALGYB1","SPN5ALGYB2","SPN5ALGYB3","SPN5ALGZB1","SPN5ALGZB2","SPN5ALGZB3","SPN5ALXB1 ", & + "SPN5ALXB2 ","SPN5ALXB3 ","SPN5ALYB1 ","SPN5ALYB2 ","SPN5ALYB3 ","SPN5ALZB1 ","SPN5ALZB2 ", & + "SPN5ALZB3 ","SPN5FLXB1 ","SPN5FLXB2 ","SPN5FLXB3 ","SPN5FLYB1 ","SPN5FLYB2 ","SPN5FLYB3 ", & + "SPN5FLZB1 ","SPN5FLZB2 ","SPN5FLZB3 ","SPN5MLXB1 ","SPN5MLXB2 ","SPN5MLXB3 ","SPN5MLYB1 ", & + "SPN5MLYB2 ","SPN5MLYB3 ","SPN5MLZB1 ","SPN5MLZB2 ","SPN5MLZB3 ","SPN5RDXB1 ","SPN5RDXB2 ", & + "SPN5RDXB3 ","SPN5RDYB1 ","SPN5RDYB2 ","SPN5RDYB3 ","SPN5RDZB1 ","SPN5RDZB2 ","SPN5RDZB3 ", & + "SPN5TDXB1 ","SPN5TDXB2 ","SPN5TDXB3 ","SPN5TDYB1 ","SPN5TDYB2 ","SPN5TDYB3 ","SPN5TDZB1 ", & + "SPN5TDZB2 ","SPN5TDZB3 ","SPN6ALGXB1","SPN6ALGXB2","SPN6ALGXB3","SPN6ALGYB1","SPN6ALGYB2", & + "SPN6ALGYB3","SPN6ALGZB1","SPN6ALGZB2","SPN6ALGZB3","SPN6ALXB1 ","SPN6ALXB2 ","SPN6ALXB3 ", & + "SPN6ALYB1 ","SPN6ALYB2 ","SPN6ALYB3 ","SPN6ALZB1 ","SPN6ALZB2 ","SPN6ALZB3 ","SPN6FLXB1 ", & + "SPN6FLXB2 ","SPN6FLXB3 ","SPN6FLYB1 ","SPN6FLYB2 ","SPN6FLYB3 ","SPN6FLZB1 ","SPN6FLZB2 ", & + "SPN6FLZB3 ","SPN6MLXB1 ","SPN6MLXB2 ","SPN6MLXB3 ","SPN6MLYB1 ","SPN6MLYB2 ","SPN6MLYB3 ", & + "SPN6MLZB1 ","SPN6MLZB2 ","SPN6MLZB3 ","SPN6RDXB1 ","SPN6RDXB2 ","SPN6RDXB3 ","SPN6RDYB1 ", & + "SPN6RDYB2 ","SPN6RDYB3 ","SPN6RDZB1 ","SPN6RDZB2 ","SPN6RDZB3 ","SPN6TDXB1 ","SPN6TDXB2 ", & + "SPN6TDXB3 ","SPN6TDYB1 ","SPN6TDYB2 ","SPN6TDYB3 ","SPN6TDZB1 ","SPN6TDZB2 ","SPN6TDZB3 ", & + "SPN7ALGXB1","SPN7ALGXB2","SPN7ALGXB3","SPN7ALGYB1","SPN7ALGYB2","SPN7ALGYB3","SPN7ALGZB1", & + "SPN7ALGZB2","SPN7ALGZB3","SPN7ALXB1 ","SPN7ALXB2 ","SPN7ALXB3 ","SPN7ALYB1 ","SPN7ALYB2 ", & + "SPN7ALYB3 ","SPN7ALZB1 ","SPN7ALZB2 ","SPN7ALZB3 ","SPN7FLXB1 ","SPN7FLXB2 ","SPN7FLXB3 ", & + "SPN7FLYB1 ","SPN7FLYB2 ","SPN7FLYB3 ","SPN7FLZB1 ","SPN7FLZB2 ","SPN7FLZB3 ","SPN7MLXB1 ", & + "SPN7MLXB2 ","SPN7MLXB3 ","SPN7MLYB1 ","SPN7MLYB2 ","SPN7MLYB3 ","SPN7MLZB1 ","SPN7MLZB2 ", & + "SPN7MLZB3 ","SPN7RDXB1 ","SPN7RDXB2 ","SPN7RDXB3 ","SPN7RDYB1 ","SPN7RDYB2 ","SPN7RDYB3 ", & + "SPN7RDZB1 ","SPN7RDZB2 ","SPN7RDZB3 ","SPN7TDXB1 ","SPN7TDXB2 ","SPN7TDXB3 ","SPN7TDYB1 ", & + "SPN7TDYB2 ","SPN7TDYB3 ","SPN7TDZB1 ","SPN7TDZB2 ","SPN7TDZB3 ","SPN8ALGXB1","SPN8ALGXB2", & + "SPN8ALGXB3","SPN8ALGYB1","SPN8ALGYB2","SPN8ALGYB3","SPN8ALGZB1","SPN8ALGZB2","SPN8ALGZB3", & + "SPN8ALXB1 ","SPN8ALXB2 ","SPN8ALXB3 ","SPN8ALYB1 ","SPN8ALYB2 ","SPN8ALYB3 ","SPN8ALZB1 ", & + "SPN8ALZB2 ","SPN8ALZB3 ","SPN8FLXB1 ","SPN8FLXB2 ","SPN8FLXB3 ","SPN8FLYB1 ","SPN8FLYB2 ", & + "SPN8FLYB3 ","SPN8FLZB1 ","SPN8FLZB2 ","SPN8FLZB3 ","SPN8MLXB1 ","SPN8MLXB2 ","SPN8MLXB3 ", & + "SPN8MLYB1 ","SPN8MLYB2 ","SPN8MLYB3 ","SPN8MLZB1 ","SPN8MLZB2 ","SPN8MLZB3 ","SPN8RDXB1 ", & + "SPN8RDXB2 ","SPN8RDXB3 ","SPN8RDYB1 ","SPN8RDYB2 ","SPN8RDYB3 ","SPN8RDZB1 ","SPN8RDZB2 ", & + "SPN8RDZB3 ","SPN8TDXB1 ","SPN8TDXB2 ","SPN8TDXB3 ","SPN8TDYB1 ","SPN8TDYB2 ","SPN8TDYB3 ", & + "SPN8TDZB1 ","SPN8TDZB2 ","SPN8TDZB3 ","SPN9ALGXB1","SPN9ALGXB2","SPN9ALGXB3","SPN9ALGYB1", & + "SPN9ALGYB2","SPN9ALGYB3","SPN9ALGZB1","SPN9ALGZB2","SPN9ALGZB3","SPN9ALXB1 ","SPN9ALXB2 ", & + "SPN9ALXB3 ","SPN9ALYB1 ","SPN9ALYB2 ","SPN9ALYB3 ","SPN9ALZB1 ","SPN9ALZB2 ","SPN9ALZB3 ", & + "SPN9FLXB1 ","SPN9FLXB2 ","SPN9FLXB3 ","SPN9FLYB1 ","SPN9FLYB2 ","SPN9FLYB3 ","SPN9FLZB1 ", & + "SPN9FLZB2 ","SPN9FLZB3 ","SPN9MLXB1 ","SPN9MLXB2 ","SPN9MLXB3 ","SPN9MLYB1 ","SPN9MLYB2 ", & + "SPN9MLYB3 ","SPN9MLZB1 ","SPN9MLZB2 ","SPN9MLZB3 ","SPN9RDXB1 ","SPN9RDXB2 ","SPN9RDXB3 ", & + "SPN9RDYB1 ","SPN9RDYB2 ","SPN9RDYB3 ","SPN9RDZB1 ","SPN9RDZB2 ","SPN9RDZB3 ","SPN9TDXB1 ", & + "SPN9TDXB2 ","SPN9TDXB3 ","SPN9TDYB1 ","SPN9TDYB2 ","SPN9TDYB3 ","SPN9TDZB1 ","SPN9TDZB2 ", & + "SPN9TDZB3 ","TAILFURL ","TAILFURLA ","TAILFURLP ","TAILFURLV ","TEETAYA ","TEETDEFL ", & + "TEETPYA ","TEETVYA ","TFRLBRM ","TIP2TWR1 ","TIP2TWR2 ","TIP2TWR3 ","TIPALGXB1 ", & + "TIPALGXB2 ","TIPALGXB3 ","TIPALGYB1 ","TIPALGYB2 ","TIPALGYB3 ","TIPALGZB1 ","TIPALGZB2 ", & + "TIPALGZB3 ","TIPALXB1 ","TIPALXB2 ","TIPALXB3 ","TIPALYB1 ","TIPALYB2 ","TIPALYB3 ", & + "TIPALZB1 ","TIPALZB2 ","TIPALZB3 ","TIPCLRNC1 ","TIPCLRNC2 ","TIPCLRNC3 ","TIPDXB1 ", & + "TIPDXB2 ","TIPDXB3 ","TIPDXC1 ","TIPDXC2 ","TIPDXC3 ","TIPDYB1 ","TIPDYB2 ", & + "TIPDYB3 ","TIPDYC1 ","TIPDYC2 ","TIPDYC3 ","TIPDZB1 ","TIPDZB2 ","TIPDZB3 ", & + "TIPDZC1 ","TIPDZC2 ","TIPDZC3 ","TIPRDXB1 ","TIPRDXB2 ","TIPRDXB3 ","TIPRDYB1 ", & + "TIPRDYB2 ","TIPRDYB3 ","TIPRDZB1 ","TIPRDZB2 ","TIPRDZB3 ","TIPRDZC1 ","TIPRDZC2 ", & + "TIPRDZC3 ","TTDSPAX ","TTDSPFA ","TTDSPPTCH ","TTDSPROLL ","TTDSPSS ","TTDSPTWST ", & + "TWHT1ALGXT","TWHT1ALGYT","TWHT1ALGZT","TWHT1ALXT ","TWHT1ALYT ","TWHT1ALZT ","TWHT1FLXT ", & + "TWHT1FLYT ","TWHT1FLZT ","TWHT1MLXT ","TWHT1MLYT ","TWHT1MLZT ","TWHT1RDXT ","TWHT1RDYT ", & + "TWHT1RDZT ","TWHT1RPXI ","TWHT1RPYI ","TWHT1RPZI ","TWHT1TDXT ","TWHT1TDYT ","TWHT1TDZT ", & + "TWHT1TPXI ","TWHT1TPYI ","TWHT1TPZI ","TWHT2ALGXT","TWHT2ALGYT","TWHT2ALGZT","TWHT2ALXT ", & + "TWHT2ALYT ","TWHT2ALZT ","TWHT2FLXT ","TWHT2FLYT ","TWHT2FLZT ","TWHT2MLXT ","TWHT2MLYT ", & + "TWHT2MLZT ","TWHT2RDXT ","TWHT2RDYT ","TWHT2RDZT ","TWHT2RPXI ","TWHT2RPYI ","TWHT2RPZI ", & + "TWHT2TDXT ","TWHT2TDYT ","TWHT2TDZT ","TWHT2TPXI ","TWHT2TPYI ","TWHT2TPZI ","TWHT3ALGXT", & + "TWHT3ALGYT","TWHT3ALGZT","TWHT3ALXT ","TWHT3ALYT ","TWHT3ALZT ","TWHT3FLXT ","TWHT3FLYT ", & + "TWHT3FLZT ","TWHT3MLXT ","TWHT3MLYT ","TWHT3MLZT ","TWHT3RDXT ","TWHT3RDYT ","TWHT3RDZT ", & + "TWHT3RPXI ","TWHT3RPYI ","TWHT3RPZI ","TWHT3TDXT ","TWHT3TDYT ","TWHT3TDZT ","TWHT3TPXI ", & + "TWHT3TPYI ","TWHT3TPZI ","TWHT4ALGXT","TWHT4ALGYT","TWHT4ALGZT","TWHT4ALXT ","TWHT4ALYT ", & + "TWHT4ALZT ","TWHT4FLXT ","TWHT4FLYT ","TWHT4FLZT ","TWHT4MLXT ","TWHT4MLYT ","TWHT4MLZT ", & + "TWHT4RDXT ","TWHT4RDYT ","TWHT4RDZT ","TWHT4RPXI ","TWHT4RPYI ","TWHT4RPZI ","TWHT4TDXT ", & + "TWHT4TDYT ","TWHT4TDZT ","TWHT4TPXI ","TWHT4TPYI ","TWHT4TPZI ","TWHT5ALGXT","TWHT5ALGYT", & + "TWHT5ALGZT","TWHT5ALXT ","TWHT5ALYT ","TWHT5ALZT ","TWHT5FLXT ","TWHT5FLYT ","TWHT5FLZT ", & + "TWHT5MLXT ","TWHT5MLYT ","TWHT5MLZT ","TWHT5RDXT ","TWHT5RDYT ","TWHT5RDZT ","TWHT5RPXI ", & + "TWHT5RPYI ","TWHT5RPZI ","TWHT5TDXT ","TWHT5TDYT ","TWHT5TDZT ","TWHT5TPXI ","TWHT5TPYI ", & + "TWHT5TPZI ","TWHT6ALGXT","TWHT6ALGYT","TWHT6ALGZT","TWHT6ALXT ","TWHT6ALYT ","TWHT6ALZT ", & + "TWHT6FLXT ","TWHT6FLYT ","TWHT6FLZT ","TWHT6MLXT ","TWHT6MLYT ","TWHT6MLZT ","TWHT6RDXT ", & + "TWHT6RDYT ","TWHT6RDZT ","TWHT6RPXI ","TWHT6RPYI ","TWHT6RPZI ","TWHT6TDXT ","TWHT6TDYT ", & + "TWHT6TDZT ","TWHT6TPXI ","TWHT6TPYI ","TWHT6TPZI ","TWHT7ALGXT","TWHT7ALGYT","TWHT7ALGZT", & + "TWHT7ALXT ","TWHT7ALYT ","TWHT7ALZT ","TWHT7FLXT ","TWHT7FLYT ","TWHT7FLZT ","TWHT7MLXT ", & + "TWHT7MLYT ","TWHT7MLZT ","TWHT7RDXT ","TWHT7RDYT ","TWHT7RDZT ","TWHT7RPXI ","TWHT7RPYI ", & + "TWHT7RPZI ","TWHT7TDXT ","TWHT7TDYT ","TWHT7TDZT ","TWHT7TPXI ","TWHT7TPYI ","TWHT7TPZI ", & + "TWHT8ALGXT","TWHT8ALGYT","TWHT8ALGZT","TWHT8ALXT ","TWHT8ALYT ","TWHT8ALZT ","TWHT8FLXT ", & + "TWHT8FLYT ","TWHT8FLZT ","TWHT8MLXT ","TWHT8MLYT ","TWHT8MLZT ","TWHT8RDXT ","TWHT8RDYT ", & + "TWHT8RDZT ","TWHT8RPXI ","TWHT8RPYI ","TWHT8RPZI ","TWHT8TDXT ","TWHT8TDYT ","TWHT8TDZT ", & + "TWHT8TPXI ","TWHT8TPYI ","TWHT8TPZI ","TWHT9ALGXT","TWHT9ALGYT","TWHT9ALGZT","TWHT9ALXT ", & + "TWHT9ALYT ","TWHT9ALZT ","TWHT9FLXT ","TWHT9FLYT ","TWHT9FLZT ","TWHT9MLXT ","TWHT9MLYT ", & + "TWHT9MLZT ","TWHT9RDXT ","TWHT9RDYT ","TWHT9RDZT ","TWHT9RPXI ","TWHT9RPYI ","TWHT9RPZI ", & + "TWHT9TDXT ","TWHT9TDYT ","TWHT9TDZT ","TWHT9TPXI ","TWHT9TPYI ","TWHT9TPZI ","TWRBSFXT ", & + "TWRBSFYT ","TWRBSFZT ","TWRBSMXT ","TWRBSMYT ","TWRBSMZT ","TWRCLRNC1 ","TWRCLRNC2 ", & + "TWRCLRNC3 ","TWRTPTDXI ","TWRTPTDYI ","TWRTPTDZI ","TWSTDEFL1 ","TWSTDEFL2 ","TWSTDEFL3 ", & + "YAWACCEL ","YAWAZN ","YAWAZP ","YAWBRFXN ","YAWBRFXP ","YAWBRFYN ","YAWBRFYP ", & + "YAWBRFZN ","YAWBRFZP ","YAWBRMXN ","YAWBRMXP ","YAWBRMYN ","YAWBRMYP ","YAWBRMZN ", & + "YAWBRMZP ","YAWBRRAXP ","YAWBRRAYP ","YAWBRRAZP ","YAWBRRDXT ","YAWBRRDYT ","YAWBRRDZT ", & + "YAWBRRVXP ","YAWBRRVYP ","YAWBRRVZP ","YAWBRTAGXP","YAWBRTAGYP","YAWBRTAGZP","YAWBRTAXP ", & + "YAWBRTAYP ","YAWBRTAZP ","YAWBRTDXI ","YAWBRTDXP ","YAWBRTDXT ","YAWBRTDYI ","YAWBRTDYP ", & + "YAWBRTDYT ","YAWBRTDZI ","YAWBRTDZP ","YAWBRTDZT ","YAWBRTVXP ","YAWBRTVYP ","YAWBRTVZP ", & + "YAWFRIMFP ","YAWFRIMOM ","YAWFRIMZ ","YAWPOS ","YAWPZN ","YAWPZP ","YAWRATE ", & + "YAWVZN ","YAWVZP "/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(1115) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) LSSTipPxa , PtchPMzc1 , PtchPMzc2 , PtchPMzc3 , PtchPMzc1 , PtchPMzc2 , PtchPMzc3 , & - HSShftA , HSShftV , HSSBrTq , HSShftA , HSShftPwr , HSShftTq , HSShftV , & - TipDyc1 , TipDyc2 , TipDyc3 , LSSGagAxa , LSSGagAxa , LSSGagAxa , LSShftFxa , & - LSShftFxa , LSShftFya , LSShftFys , LSShftFza , LSShftFzs , LSShftMxa , LSShftMxa , & - LSSGagMya , LSSGagMys , LSSGagMza , LSSGagMzs , LSSGagPxa , LSSGagPxa , LSSGagPxa , & - LSSGagVxa , LSSGagVxa , LSSGagVxa , LSShftFxa , LSShftFxa , LSShftFya , LSShftFys , & - LSShftFza , LSShftFzs , LSShftMxa , LSShftMxa , RotPwr , LSShftMxa , LSSTipAxa , & - LSSTipAxa , LSSTipAxa , LSSTipMya , LSSTipMys , LSSTipMza , LSSTipMzs , LSSTipPxa , & - LSSTipPxa , LSSTipPxa , LSSTipVxa , LSSTipVxa , LSSTipVxa , YawPzn , YawAzn , & - YawPzn , YawVzn , NcIMURAxs , NcIMURAys , NcIMURAzs , NcIMURVxs , NcIMURVys , & - NcIMURVzs , NcIMUTAgxs , NcIMUTAgys , NcIMUTAgzs , NcIMUTAxs , NcIMUTAys , NcIMUTAzs , & - NcIMUTVxs , NcIMUTVys , NcIMUTVzs , TipDxc1 , TipDxc2 , TipDxc3 , TipRDyb1 , & - TipRDyb2 , TipRDyb3 , PtchPMzc1 , PtchPMzc2 , PtchPMzc3 , PtchPMzc1 , PtchPMzc2 , & - PtchPMzc3 , PtfmTDzi , PtfmRDyi , PtfmRAxi , PtfmRAxt , PtfmRAyi , PtfmRAyt , & - PtfmRAzi , PtfmRAzt , PtfmRDxi , PtfmRDyi , PtfmRDzi , PtfmRDxi , PtfmRVxi , & - PtfmRVxt , PtfmRVyi , PtfmRVyt , PtfmRVzi , PtfmRVzt , PtfmTDxi , PtfmTDyi , & - PtfmTAgxi , PtfmTAgxt , PtfmTAgyi , PtfmTAgyt , PtfmTAgzi , PtfmTAgzt , PtfmTAxi , & - PtfmTAxt , PtfmTAyi , PtfmTAyt , PtfmTAzi , PtfmTAzt , PtfmTDxi , PtfmTDxt , & - PtfmTDyi , PtfmTDyt , PtfmTDzi , PtfmTDzt , PtfmTVxi , PtfmTVxt , PtfmTVyi , & - PtfmTVyt , PtfmTVzi , PtfmTVzt , PtfmRDzi , QD2_B1E1 , QD2_B1F1 , QD2_B1F2 , & - QD2_B2E1 , QD2_B2F1 , QD2_B2F2 , QD2_B3E1 , QD2_B3F1 , QD2_B3F2 , QD2_DrTr , & - QD2_GeAz , QD2_Hv , QD2_P , QD2_R , QD2_RFrl , QD2_Sg , QD2_Sw , & - QD2_Teet , QD2_TFA1 , QD2_TFA2 , QD2_TFrl , QD2_TSS1 , QD2_TSS2 , QD2_Y , & - QD2_Yaw , QD_B1E1 , QD_B1F1 , QD_B1F2 , QD_B2E1 , QD_B2F1 , QD_B2F2 , & - QD_B3E1 , QD_B3F1 , QD_B3F2 , QD_DrTr , QD_GeAz , QD_Hv , QD_P , & - QD_R , QD_RFrl , QD_Sg , QD_Sw , QD_Teet , QD_TFA1 , QD_TFA2 , & - QD_TFrl , QD_TSS1 , QD_TSS2 , QD_Y , QD_Yaw , Q_B1E1 , Q_B1F1 , & - Q_B1F2 , Q_B2E1 , Q_B2F1 , Q_B2F2 , Q_B3E1 , Q_B3F1 , Q_B3F2 , & - Q_DrTr , Q_GeAz , Q_Hv , Q_P , Q_R , Q_RFrl , Q_Sg , & - Q_Sw , Q_Teet , Q_TFA1 , Q_TFA2 , Q_TFrl , Q_TSS1 , Q_TSS2 , & - Q_Y , Q_Yaw , RFrlBrM , TipRDxb1 , TipRDxb2 , TipRDxb3 , RootFxb1 , & - RootFxb2 , RootFxb3 , RootFxc1 , RootFxc2 , RootFxc3 , RootFyb1 , RootFyb2 , & - RootFyb3 , RootFyc1 , RootFyc2 , RootFyc3 , RootFzc1 , RootFzc2 , RootFzc3 , & - RootFzc1 , RootFzc2 , RootFzc3 , RootMxb1 , RootMxb2 , RootMxb3 , RootMyb1 , & - RootMyb2 , RootMyb3 , RootMxc1 , RootMxc2 , RootMxc3 , RootMyc1 , RootMyc2 , & - RootMyc3 , RootMxb1 , RootMxb2 , RootMxb3 , RootMxc1 , RootMxc2 , RootMxc3 , & - RootMyb1 , RootMyb2 , RootMyb3 , RootMyc1 , RootMyc2 , RootMyc3 , RootMzc1 , & - RootMzc2 , RootMzc3 , RootMzc1 , RootMzc2 , RootMzc3 , LSSTipAxa , RotFurlP , & - RotFurlA , RotFurlP , RotFurlV , RotPwr , LSSTipVxa , TeetAya , TeetPya , & - TeetVya , LSShftFxa , LSShftMxa , Spn1ALgxb1 , Spn1ALgxb2 , Spn1ALgxb3 , Spn1ALgyb1 , & - Spn1ALgyb2 , Spn1ALgyb3 , Spn1ALgzb1 , Spn1ALgzb2 , Spn1ALgzb3 , Spn1ALxb1 , Spn1ALxb2 , & - Spn1ALxb3 , Spn1ALyb1 , Spn1ALyb2 , Spn1ALyb3 , Spn1ALzb1 , Spn1ALzb2 , Spn1ALzb3 , & - Spn1FLxb1 , Spn1FLxb2 , Spn1FLxb3 , Spn1FLyb1 , Spn1FLyb2 , Spn1FLyb3 , Spn1FLzb1 , & - Spn1FLzb2 , Spn1FLzb3 , Spn1MLxb1 , Spn1MLxb2 , Spn1MLxb3 , Spn1MLyb1 , Spn1MLyb2 , & - Spn1MLyb3 , Spn1MLzb1 , Spn1MLzb2 , Spn1MLzb3 , Spn1RDxb1 , Spn1RDxb2 , Spn1RDxb3 , & - Spn1RDyb1 , Spn1RDyb2 , Spn1RDyb3 , Spn1RDzb1 , Spn1RDzb2 , Spn1RDzb3 , Spn1TDxb1 , & - Spn1TDxb2 , Spn1TDxb3 , Spn1TDyb1 , Spn1TDyb2 , Spn1TDyb3 , Spn1TDzb1 , Spn1TDzb2 , & - Spn1TDzb3 , Spn2ALgxb1 , Spn2ALgxb2 , Spn2ALgxb3 , Spn2ALgyb1 , Spn2ALgyb2 , Spn2ALgyb3 , & - Spn2ALgzb1 , Spn2ALgzb2 , Spn2ALgzb3 , Spn2ALxb1 , Spn2ALxb2 , Spn2ALxb3 , Spn2ALyb1 , & - Spn2ALyb2 , Spn2ALyb3 , Spn2ALzb1 , Spn2ALzb2 , Spn2ALzb3 , Spn2FLxb1 , Spn2FLxb2 , & - Spn2FLxb3 , Spn2FLyb1 , Spn2FLyb2 , Spn2FLyb3 , Spn2FLzb1 , Spn2FLzb2 , Spn2FLzb3 , & - Spn2MLxb1 , Spn2MLxb2 , Spn2MLxb3 , Spn2MLyb1 , Spn2MLyb2 , Spn2MLyb3 , Spn2MLzb1 , & - Spn2MLzb2 , Spn2MLzb3 , Spn2RDxb1 , Spn2RDxb2 , Spn2RDxb3 , Spn2RDyb1 , Spn2RDyb2 , & - Spn2RDyb3 , Spn2RDzb1 , Spn2RDzb2 , Spn2RDzb3 , Spn2TDxb1 , Spn2TDxb2 , Spn2TDxb3 , & - Spn2TDyb1 , Spn2TDyb2 , Spn2TDyb3 , Spn2TDzb1 , Spn2TDzb2 , Spn2TDzb3 , Spn3ALgxb1 , & - Spn3ALgxb2 , Spn3ALgxb3 , Spn3ALgyb1 , Spn3ALgyb2 , Spn3ALgyb3 , Spn3ALgzb1 , Spn3ALgzb2 , & - Spn3ALgzb3 , Spn3ALxb1 , Spn3ALxb2 , Spn3ALxb3 , Spn3ALyb1 , Spn3ALyb2 , Spn3ALyb3 , & - Spn3ALzb1 , Spn3ALzb2 , Spn3ALzb3 , Spn3FLxb1 , Spn3FLxb2 , Spn3FLxb3 , Spn3FLyb1 , & - Spn3FLyb2 , Spn3FLyb3 , Spn3FLzb1 , Spn3FLzb2 , Spn3FLzb3 , Spn3MLxb1 , Spn3MLxb2 , & - Spn3MLxb3 , Spn3MLyb1 , Spn3MLyb2 , Spn3MLyb3 , Spn3MLzb1 , Spn3MLzb2 , Spn3MLzb3 , & - Spn3RDxb1 , Spn3RDxb2 , Spn3RDxb3 , Spn3RDyb1 , Spn3RDyb2 , Spn3RDyb3 , Spn3RDzb1 , & - Spn3RDzb2 , Spn3RDzb3 , Spn3TDxb1 , Spn3TDxb2 , Spn3TDxb3 , Spn3TDyb1 , Spn3TDyb2 , & - Spn3TDyb3 , Spn3TDzb1 , Spn3TDzb2 , Spn3TDzb3 , Spn4ALgxb1 , Spn4ALgxb2 , Spn4ALgxb3 , & - Spn4ALgyb1 , Spn4ALgyb2 , Spn4ALgyb3 , Spn4ALgzb1 , Spn4ALgzb2 , Spn4ALgzb3 , Spn4ALxb1 , & - Spn4ALxb2 , Spn4ALxb3 , Spn4ALyb1 , Spn4ALyb2 , Spn4ALyb3 , Spn4ALzb1 , Spn4ALzb2 , & - Spn4ALzb3 , Spn4FLxb1 , Spn4FLxb2 , Spn4FLxb3 , Spn4FLyb1 , Spn4FLyb2 , Spn4FLyb3 , & - Spn4FLzb1 , Spn4FLzb2 , Spn4FLzb3 , Spn4MLxb1 , Spn4MLxb2 , Spn4MLxb3 , Spn4MLyb1 , & - Spn4MLyb2 , Spn4MLyb3 , Spn4MLzb1 , Spn4MLzb2 , Spn4MLzb3 , Spn4RDxb1 , Spn4RDxb2 , & - Spn4RDxb3 , Spn4RDyb1 , Spn4RDyb2 , Spn4RDyb3 , Spn4RDzb1 , Spn4RDzb2 , Spn4RDzb3 , & - Spn4TDxb1 , Spn4TDxb2 , Spn4TDxb3 , Spn4TDyb1 , Spn4TDyb2 , Spn4TDyb3 , Spn4TDzb1 , & - Spn4TDzb2 , Spn4TDzb3 , Spn5ALgxb1 , Spn5ALgxb2 , Spn5ALgxb3 , Spn5ALgyb1 , Spn5ALgyb2 , & - Spn5ALgyb3 , Spn5ALgzb1 , Spn5ALgzb2 , Spn5ALgzb3 , Spn5ALxb1 , Spn5ALxb2 , Spn5ALxb3 , & - Spn5ALyb1 , Spn5ALyb2 , Spn5ALyb3 , Spn5ALzb1 , Spn5ALzb2 , Spn5ALzb3 , Spn5FLxb1 , & - Spn5FLxb2 , Spn5FLxb3 , Spn5FLyb1 , Spn5FLyb2 , Spn5FLyb3 , Spn5FLzb1 , Spn5FLzb2 , & - Spn5FLzb3 , Spn5MLxb1 , Spn5MLxb2 , Spn5MLxb3 , Spn5MLyb1 , Spn5MLyb2 , Spn5MLyb3 , & - Spn5MLzb1 , Spn5MLzb2 , Spn5MLzb3 , Spn5RDxb1 , Spn5RDxb2 , Spn5RDxb3 , Spn5RDyb1 , & - Spn5RDyb2 , Spn5RDyb3 , Spn5RDzb1 , Spn5RDzb2 , Spn5RDzb3 , Spn5TDxb1 , Spn5TDxb2 , & - Spn5TDxb3 , Spn5TDyb1 , Spn5TDyb2 , Spn5TDyb3 , Spn5TDzb1 , Spn5TDzb2 , Spn5TDzb3 , & - Spn6ALgxb1 , Spn6ALgxb2 , Spn6ALgxb3 , Spn6ALgyb1 , Spn6ALgyb2 , Spn6ALgyb3 , Spn6ALgzb1 , & - Spn6ALgzb2 , Spn6ALgzb3 , Spn6ALxb1 , Spn6ALxb2 , Spn6ALxb3 , Spn6ALyb1 , Spn6ALyb2 , & - Spn6ALyb3 , Spn6ALzb1 , Spn6ALzb2 , Spn6ALzb3 , Spn6FLxb1 , Spn6FLxb2 , Spn6FLxb3 , & - Spn6FLyb1 , Spn6FLyb2 , Spn6FLyb3 , Spn6FLzb1 , Spn6FLzb2 , Spn6FLzb3 , Spn6MLxb1 , & - Spn6MLxb2 , Spn6MLxb3 , Spn6MLyb1 , Spn6MLyb2 , Spn6MLyb3 , Spn6MLzb1 , Spn6MLzb2 , & - Spn6MLzb3 , Spn6RDxb1 , Spn6RDxb2 , Spn6RDxb3 , Spn6RDyb1 , Spn6RDyb2 , Spn6RDyb3 , & - Spn6RDzb1 , Spn6RDzb2 , Spn6RDzb3 , Spn6TDxb1 , Spn6TDxb2 , Spn6TDxb3 , Spn6TDyb1 , & - Spn6TDyb2 , Spn6TDyb3 , Spn6TDzb1 , Spn6TDzb2 , Spn6TDzb3 , Spn7ALgxb1 , Spn7ALgxb2 , & - Spn7ALgxb3 , Spn7ALgyb1 , Spn7ALgyb2 , Spn7ALgyb3 , Spn7ALgzb1 , Spn7ALgzb2 , Spn7ALgzb3 , & - Spn7ALxb1 , Spn7ALxb2 , Spn7ALxb3 , Spn7ALyb1 , Spn7ALyb2 , Spn7ALyb3 , Spn7ALzb1 , & - Spn7ALzb2 , Spn7ALzb3 , Spn7FLxb1 , Spn7FLxb2 , Spn7FLxb3 , Spn7FLyb1 , Spn7FLyb2 , & - Spn7FLyb3 , Spn7FLzb1 , Spn7FLzb2 , Spn7FLzb3 , Spn7MLxb1 , Spn7MLxb2 , Spn7MLxb3 , & - Spn7MLyb1 , Spn7MLyb2 , Spn7MLyb3 , Spn7MLzb1 , Spn7MLzb2 , Spn7MLzb3 , Spn7RDxb1 , & - Spn7RDxb2 , Spn7RDxb3 , Spn7RDyb1 , Spn7RDyb2 , Spn7RDyb3 , Spn7RDzb1 , Spn7RDzb2 , & - Spn7RDzb3 , Spn7TDxb1 , Spn7TDxb2 , Spn7TDxb3 , Spn7TDyb1 , Spn7TDyb2 , Spn7TDyb3 , & - Spn7TDzb1 , Spn7TDzb2 , Spn7TDzb3 , Spn8ALgxb1 , Spn8ALgxb2 , Spn8ALgxb3 , Spn8ALgyb1 , & - Spn8ALgyb2 , Spn8ALgyb3 , Spn8ALgzb1 , Spn8ALgzb2 , Spn8ALgzb3 , Spn8ALxb1 , Spn8ALxb2 , & - Spn8ALxb3 , Spn8ALyb1 , Spn8ALyb2 , Spn8ALyb3 , Spn8ALzb1 , Spn8ALzb2 , Spn8ALzb3 , & - Spn8FLxb1 , Spn8FLxb2 , Spn8FLxb3 , Spn8FLyb1 , Spn8FLyb2 , Spn8FLyb3 , Spn8FLzb1 , & - Spn8FLzb2 , Spn8FLzb3 , Spn8MLxb1 , Spn8MLxb2 , Spn8MLxb3 , Spn8MLyb1 , Spn8MLyb2 , & - Spn8MLyb3 , Spn8MLzb1 , Spn8MLzb2 , Spn8MLzb3 , Spn8RDxb1 , Spn8RDxb2 , Spn8RDxb3 , & - Spn8RDyb1 , Spn8RDyb2 , Spn8RDyb3 , Spn8RDzb1 , Spn8RDzb2 , Spn8RDzb3 , Spn8TDxb1 , & - Spn8TDxb2 , Spn8TDxb3 , Spn8TDyb1 , Spn8TDyb2 , Spn8TDyb3 , Spn8TDzb1 , Spn8TDzb2 , & - Spn8TDzb3 , Spn9ALgxb1 , Spn9ALgxb2 , Spn9ALgxb3 , Spn9ALgyb1 , Spn9ALgyb2 , Spn9ALgyb3 , & - Spn9ALgzb1 , Spn9ALgzb2 , Spn9ALgzb3 , Spn9ALxb1 , Spn9ALxb2 , Spn9ALxb3 , Spn9ALyb1 , & - Spn9ALyb2 , Spn9ALyb3 , Spn9ALzb1 , Spn9ALzb2 , Spn9ALzb3 , Spn9FLxb1 , Spn9FLxb2 , & - Spn9FLxb3 , Spn9FLyb1 , Spn9FLyb2 , Spn9FLyb3 , Spn9FLzb1 , Spn9FLzb2 , Spn9FLzb3 , & - Spn9MLxb1 , Spn9MLxb2 , Spn9MLxb3 , Spn9MLyb1 , Spn9MLyb2 , Spn9MLyb3 , Spn9MLzb1 , & - Spn9MLzb2 , Spn9MLzb3 , Spn9RDxb1 , Spn9RDxb2 , Spn9RDxb3 , Spn9RDyb1 , Spn9RDyb2 , & - Spn9RDyb3 , Spn9RDzb1 , Spn9RDzb2 , Spn9RDzb3 , Spn9TDxb1 , Spn9TDxb2 , Spn9TDxb3 , & - Spn9TDyb1 , Spn9TDyb2 , Spn9TDyb3 , Spn9TDzb1 , Spn9TDzb2 , Spn9TDzb3 , TailFurlP , & - TailFurlA , TailFurlP , TailFurlV , TeetAya , TeetPya , TeetPya , TeetVya , & - TFrlBrM , TipClrnc1 , TipClrnc2 , TipClrnc3 , TipALgxb1 , TipALgxb2 , TipALgxb3 , & - TipALgyb1 , TipALgyb2 , TipALgyb3 , TipALgzb1 , TipALgzb2 , TipALgzb3 , TipALxb1 , & - TipALxb2 , TipALxb3 , TipALyb1 , TipALyb2 , TipALyb3 , TipALzb1 , TipALzb2 , & - TipALzb3 , TipClrnc1 , TipClrnc2 , TipClrnc3 , TipDxb1 , TipDxb2 , TipDxb3 , & - TipDxc1 , TipDxc2 , TipDxc3 , TipDyb1 , TipDyb2 , TipDyb3 , TipDyc1 , & - TipDyc2 , TipDyc3 , TipDzc1 , TipDzc2 , TipDzc3 , TipDzc1 , TipDzc2 , & - TipDzc3 , TipRDxb1 , TipRDxb2 , TipRDxb3 , TipRDyb1 , TipRDyb2 , TipRDyb3 , & - TipRDzc1 , TipRDzc2 , TipRDzc3 , TipRDzc1 , TipRDzc2 , TipRDzc3 , YawBrTDzt , & - YawBrTDxt , YawBrRDyt , YawBrRDxt , YawBrTDyt , YawBrRDzt , TwHt1ALgxt , TwHt1ALgyt , & - TwHt1ALgzt , TwHt1ALxt , TwHt1ALyt , TwHt1ALzt , TwHt1FLxt , TwHt1FLyt , TwHt1FLzt , & - TwHt1MLxt , TwHt1MLyt , TwHt1MLzt , TwHt1RDxt , TwHt1RDyt , TwHt1RDzt , TwHt1RPxi , & - TwHt1RPyi , TwHt1RPzi , TwHt1TDxt , TwHt1TDyt , TwHt1TDzt , TwHt1TPxi , TwHt1TPyi , & - TwHt1TPzi , TwHt2ALgxt , TwHt2ALgyt , TwHt2ALgzt , TwHt2ALxt , TwHt2ALyt , TwHt2ALzt , & - TwHt2FLxt , TwHt2FLyt , TwHt2FLzt , TwHt2MLxt , TwHt2MLyt , TwHt2MLzt , TwHt2RDxt , & - TwHt2RDyt , TwHt2RDzt , TwHt2RPxi , TwHt2RPyi , TwHt2RPzi , TwHt2TDxt , TwHt2TDyt , & - TwHt2TDzt , TwHt2TPxi , TwHt2TPyi , TwHt2TPzi , TwHt3ALgxt , TwHt3ALgyt , TwHt3ALgzt , & - TwHt3ALxt , TwHt3ALyt , TwHt3ALzt , TwHt3FLxt , TwHt3FLyt , TwHt3FLzt , TwHt3MLxt , & - TwHt3MLyt , TwHt3MLzt , TwHt3RDxt , TwHt3RDyt , TwHt3RDzt , TwHt3RPxi , TwHt3RPyi , & - TwHt3RPzi , TwHt3TDxt , TwHt3TDyt , TwHt3TDzt , TwHt3TPxi , TwHt3TPyi , TwHt3TPzi , & - TwHt4ALgxt , TwHt4ALgyt , TwHt4ALgzt , TwHt4ALxt , TwHt4ALyt , TwHt4ALzt , TwHt4FLxt , & - TwHt4FLyt , TwHt4FLzt , TwHt4MLxt , TwHt4MLyt , TwHt4MLzt , TwHt4RDxt , TwHt4RDyt , & - TwHt4RDzt , TwHt4RPxi , TwHt4RPyi , TwHt4RPzi , TwHt4TDxt , TwHt4TDyt , TwHt4TDzt , & - TwHt4TPxi , TwHt4TPyi , TwHt4TPzi , TwHt5ALgxt , TwHt5ALgyt , TwHt5ALgzt , TwHt5ALxt , & - TwHt5ALyt , TwHt5ALzt , TwHt5FLxt , TwHt5FLyt , TwHt5FLzt , TwHt5MLxt , TwHt5MLyt , & - TwHt5MLzt , TwHt5RDxt , TwHt5RDyt , TwHt5RDzt , TwHt5RPxi , TwHt5RPyi , TwHt5RPzi , & - TwHt5TDxt , TwHt5TDyt , TwHt5TDzt , TwHt5TPxi , TwHt5TPyi , TwHt5TPzi , TwHt6ALgxt , & - TwHt6ALgyt , TwHt6ALgzt , TwHt6ALxt , TwHt6ALyt , TwHt6ALzt , TwHt6FLxt , TwHt6FLyt , & - TwHt6FLzt , TwHt6MLxt , TwHt6MLyt , TwHt6MLzt , TwHt6RDxt , TwHt6RDyt , TwHt6RDzt , & - TwHt6RPxi , TwHt6RPyi , TwHt6RPzi , TwHt6TDxt , TwHt6TDyt , TwHt6TDzt , TwHt6TPxi , & - TwHt6TPyi , TwHt6TPzi , TwHt7ALgxt , TwHt7ALgyt , TwHt7ALgzt , TwHt7ALxt , TwHt7ALyt , & - TwHt7ALzt , TwHt7FLxt , TwHt7FLyt , TwHt7FLzt , TwHt7MLxt , TwHt7MLyt , TwHt7MLzt , & - TwHt7RDxt , TwHt7RDyt , TwHt7RDzt , TwHt7RPxi , TwHt7RPyi , TwHt7RPzi , TwHt7TDxt , & - TwHt7TDyt , TwHt7TDzt , TwHt7TPxi , TwHt7TPyi , TwHt7TPzi , TwHt8ALgxt , TwHt8ALgyt , & - TwHt8ALgzt , TwHt8ALxt , TwHt8ALyt , TwHt8ALzt , TwHt8FLxt , TwHt8FLyt , TwHt8FLzt , & - TwHt8MLxt , TwHt8MLyt , TwHt8MLzt , TwHt8RDxt , TwHt8RDyt , TwHt8RDzt , TwHt8RPxi , & - TwHt8RPyi , TwHt8RPzi , TwHt8TDxt , TwHt8TDyt , TwHt8TDzt , TwHt8TPxi , TwHt8TPyi , & - TwHt8TPzi , TwHt9ALgxt , TwHt9ALgyt , TwHt9ALgzt , TwHt9ALxt , TwHt9ALyt , TwHt9ALzt , & - TwHt9FLxt , TwHt9FLyt , TwHt9FLzt , TwHt9MLxt , TwHt9MLyt , TwHt9MLzt , TwHt9RDxt , & - TwHt9RDyt , TwHt9RDzt , TwHt9RPxi , TwHt9RPyi , TwHt9RPzi , TwHt9TDxt , TwHt9TDyt , & - TwHt9TDzt , TwHt9TPxi , TwHt9TPyi , TwHt9TPzi , TwrBsFxt , TwrBsFyt , TwrBsFzt , & - TwrBsMxt , TwrBsMyt , TwrBsMzt , TipClrnc1 , TipClrnc2 , TipClrnc3 , TwrTpTDxi , & - TwrTpTDyi , TwrTpTDzi , TipRDzc1 , TipRDzc2 , TipRDzc3 , YawAzn , YawAzn , & - YawAzn , YawBrFxn , YawBrFxp , YawBrFyn , YawBrFyp , YawBrFzn , YawBrFzn , & - YawBrMxn , YawBrMxp , YawBrMyn , YawBrMyp , YawBrMzn , YawBrMzn , YawBrRAxp , & - YawBrRAyp , YawBrRAzp , YawBrRDxt , YawBrRDyt , YawBrRDzt , YawBrRVxp , YawBrRVyp , & - YawBrRVzp , YawBrTAgxp , YawBrTAgyp , YawBrTAgzp , YawBrTAxp , YawBrTAyp , YawBrTAzp , & - TwrTpTDxi , YawBrTDxp , YawBrTDxt , TwrTpTDyi , YawBrTDyp , YawBrTDyt , TwrTpTDzi , & - YawBrTDzp , YawBrTDzt , YawBrTVxp , YawBrTVyp , YawBrTVzp , YawPzn , YawPzn , & - YawPzn , YawVzn , YawVzn , YawVzn /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1110) = (/ & ! This lists the units corresponding to the allowed parameters + dOmegaYF , HSShftA , HSShftV , HSSBrTq , HSShftA , HSShftPwr , HSShftTq , & + HSShftV , TipDyc1 , TipDyc2 , TipDyc3 , LSSGagAxa , LSSGagAxa , LSSGagAxa , & + LSShftFxa , LSShftFxa , LSShftFya , LSShftFys , LSShftFza , LSShftFzs , LSShftMxa , & + LSShftMxa , LSSGagMya , LSSGagMys , LSSGagMza , LSSGagMzs , LSSGagPxa , LSSGagPxa , & + LSSGagPxa , LSSGagVxa , LSSGagVxa , LSSGagVxa , LSShftFxa , LSShftFxa , LSShftFya , & + LSShftFys , LSShftFza , LSShftFzs , LSShftMxa , LSShftMxa , RotPwr , LSShftMxa , & + LSSTipAxa , LSSTipAxa , LSSTipAxa , LSSTipMya , LSSTipMys , LSSTipMza , LSSTipMzs , & + LSSTipPxa , LSSTipPxa , LSSTipPxa , LSSTipVxa , LSSTipVxa , LSSTipVxa , YawPzn , & + YawAzn , YawPzn , YawVzn , NcIMURAxs , NcIMURAys , NcIMURAzs , NcIMURVxs , & + NcIMURVys , NcIMURVzs , NcIMUTAgxs , NcIMUTAgys , NcIMUTAgzs , NcIMUTAxs , NcIMUTAys , & + NcIMUTAzs , NcIMUTVxs , NcIMUTVys , NcIMUTVzs , OmegaYF , TipDxc1 , TipDxc2 , & + TipDxc3 , TipRDyb1 , TipRDyb2 , TipRDyb3 , PtchPMzc1 , PtchPMzc2 , PtchPMzc3 , & + PtchPMzc1 , PtchPMzc2 , PtchPMzc3 , PtfmTDzi , PtfmRDyi , PtfmRAxi , PtfmRAxt , & + PtfmRAyi , PtfmRAyt , PtfmRAzi , PtfmRAzt , PtfmRDxi , PtfmRDyi , PtfmRDzi , & + PtfmRDxi , PtfmRVxi , PtfmRVxt , PtfmRVyi , PtfmRVyt , PtfmRVzi , PtfmRVzt , & + PtfmTDxi , PtfmTDyi , PtfmTAgxi , PtfmTAgxt , PtfmTAgyi , PtfmTAgyt , PtfmTAgzi , & + PtfmTAgzt , PtfmTAxi , PtfmTAxt , PtfmTAyi , PtfmTAyt , PtfmTAzi , PtfmTAzt , & + PtfmTDxi , PtfmTDxt , PtfmTDyi , PtfmTDyt , PtfmTDzi , PtfmTDzt , PtfmTVxi , & + PtfmTVxt , PtfmTVyi , PtfmTVyt , PtfmTVzi , PtfmTVzt , PtfmRDzi , QD2_B1E1 , & + QD2_B1F1 , QD2_B1F2 , QD2_B2E1 , QD2_B2F1 , QD2_B2F2 , QD2_B3E1 , QD2_B3F1 , & + QD2_B3F2 , QD2_DrTr , QD2_GeAz , QD2_Hv , QD2_P , QD2_R , QD2_RFrl , & + QD2_Sg , QD2_Sw , QD2_Teet , QD2_TFA1 , QD2_TFA2 , QD2_TFrl , QD2_TSS1 , & + QD2_TSS2 , QD2_Y , QD2_Yaw , QD_B1E1 , QD_B1F1 , QD_B1F2 , QD_B2E1 , & + QD_B2F1 , QD_B2F2 , QD_B3E1 , QD_B3F1 , QD_B3F2 , QD_DrTr , QD_GeAz , & + QD_Hv , QD_P , QD_R , QD_RFrl , QD_Sg , QD_Sw , QD_Teet , & + QD_TFA1 , QD_TFA2 , QD_TFrl , QD_TSS1 , QD_TSS2 , QD_Y , QD_Yaw , & + Q_B1E1 , Q_B1F1 , Q_B1F2 , Q_B2E1 , Q_B2F1 , Q_B2F2 , Q_B3E1 , & + Q_B3F1 , Q_B3F2 , Q_DrTr , Q_GeAz , Q_Hv , Q_P , Q_R , & + Q_RFrl , Q_Sg , Q_Sw , Q_Teet , Q_TFA1 , Q_TFA2 , Q_TFrl , & + Q_TSS1 , Q_TSS2 , Q_Y , Q_Yaw , RFrlBrM , TipRDxb1 , TipRDxb2 , & + TipRDxb3 , RootFxb1 , RootFxb2 , RootFxb3 , RootFxc1 , RootFxc2 , RootFxc3 , & + RootFyb1 , RootFyb2 , RootFyb3 , RootFyc1 , RootFyc2 , RootFyc3 , RootFzc1 , & + RootFzc2 , RootFzc3 , RootFzc1 , RootFzc2 , RootFzc3 , RootMxb1 , RootMxb2 , & + RootMxb3 , RootMyb1 , RootMyb2 , RootMyb3 , RootMxc1 , RootMxc2 , RootMxc3 , & + RootMyc1 , RootMyc2 , RootMyc3 , RootMxb1 , RootMxb2 , RootMxb3 , RootMxc1 , & + RootMxc2 , RootMxc3 , RootMyb1 , RootMyb2 , RootMyb3 , RootMyc1 , RootMyc2 , & + RootMyc3 , RootMzc1 , RootMzc2 , RootMzc3 , RootMzc1 , RootMzc2 , RootMzc3 , & + LSSTipAxa , RotFurlP , RotFurlA , RotFurlP , RotFurlV , RotPwr , LSSTipVxa , & + TeetAya , TeetPya , TeetVya , LSShftFxa , LSShftMxa , Spn1ALgxb1 , Spn1ALgxb2 , & + Spn1ALgxb3 , Spn1ALgyb1 , Spn1ALgyb2 , Spn1ALgyb3 , Spn1ALgzb1 , Spn1ALgzb2 , Spn1ALgzb3 , & + Spn1ALxb1 , Spn1ALxb2 , Spn1ALxb3 , Spn1ALyb1 , Spn1ALyb2 , Spn1ALyb3 , Spn1ALzb1 , & + Spn1ALzb2 , Spn1ALzb3 , Spn1FLxb1 , Spn1FLxb2 , Spn1FLxb3 , Spn1FLyb1 , Spn1FLyb2 , & + Spn1FLyb3 , Spn1FLzb1 , Spn1FLzb2 , Spn1FLzb3 , Spn1MLxb1 , Spn1MLxb2 , Spn1MLxb3 , & + Spn1MLyb1 , Spn1MLyb2 , Spn1MLyb3 , Spn1MLzb1 , Spn1MLzb2 , Spn1MLzb3 , Spn1RDxb1 , & + Spn1RDxb2 , Spn1RDxb3 , Spn1RDyb1 , Spn1RDyb2 , Spn1RDyb3 , Spn1RDzb1 , Spn1RDzb2 , & + Spn1RDzb3 , Spn1TDxb1 , Spn1TDxb2 , Spn1TDxb3 , Spn1TDyb1 , Spn1TDyb2 , Spn1TDyb3 , & + Spn1TDzb1 , Spn1TDzb2 , Spn1TDzb3 , Spn2ALgxb1 , Spn2ALgxb2 , Spn2ALgxb3 , Spn2ALgyb1 , & + Spn2ALgyb2 , Spn2ALgyb3 , Spn2ALgzb1 , Spn2ALgzb2 , Spn2ALgzb3 , Spn2ALxb1 , Spn2ALxb2 , & + Spn2ALxb3 , Spn2ALyb1 , Spn2ALyb2 , Spn2ALyb3 , Spn2ALzb1 , Spn2ALzb2 , Spn2ALzb3 , & + Spn2FLxb1 , Spn2FLxb2 , Spn2FLxb3 , Spn2FLyb1 , Spn2FLyb2 , Spn2FLyb3 , Spn2FLzb1 , & + Spn2FLzb2 , Spn2FLzb3 , Spn2MLxb1 , Spn2MLxb2 , Spn2MLxb3 , Spn2MLyb1 , Spn2MLyb2 , & + Spn2MLyb3 , Spn2MLzb1 , Spn2MLzb2 , Spn2MLzb3 , Spn2RDxb1 , Spn2RDxb2 , Spn2RDxb3 , & + Spn2RDyb1 , Spn2RDyb2 , Spn2RDyb3 , Spn2RDzb1 , Spn2RDzb2 , Spn2RDzb3 , Spn2TDxb1 , & + Spn2TDxb2 , Spn2TDxb3 , Spn2TDyb1 , Spn2TDyb2 , Spn2TDyb3 , Spn2TDzb1 , Spn2TDzb2 , & + Spn2TDzb3 , Spn3ALgxb1 , Spn3ALgxb2 , Spn3ALgxb3 , Spn3ALgyb1 , Spn3ALgyb2 , Spn3ALgyb3 , & + Spn3ALgzb1 , Spn3ALgzb2 , Spn3ALgzb3 , Spn3ALxb1 , Spn3ALxb2 , Spn3ALxb3 , Spn3ALyb1 , & + Spn3ALyb2 , Spn3ALyb3 , Spn3ALzb1 , Spn3ALzb2 , Spn3ALzb3 , Spn3FLxb1 , Spn3FLxb2 , & + Spn3FLxb3 , Spn3FLyb1 , Spn3FLyb2 , Spn3FLyb3 , Spn3FLzb1 , Spn3FLzb2 , Spn3FLzb3 , & + Spn3MLxb1 , Spn3MLxb2 , Spn3MLxb3 , Spn3MLyb1 , Spn3MLyb2 , Spn3MLyb3 , Spn3MLzb1 , & + Spn3MLzb2 , Spn3MLzb3 , Spn3RDxb1 , Spn3RDxb2 , Spn3RDxb3 , Spn3RDyb1 , Spn3RDyb2 , & + Spn3RDyb3 , Spn3RDzb1 , Spn3RDzb2 , Spn3RDzb3 , Spn3TDxb1 , Spn3TDxb2 , Spn3TDxb3 , & + Spn3TDyb1 , Spn3TDyb2 , Spn3TDyb3 , Spn3TDzb1 , Spn3TDzb2 , Spn3TDzb3 , Spn4ALgxb1 , & + Spn4ALgxb2 , Spn4ALgxb3 , Spn4ALgyb1 , Spn4ALgyb2 , Spn4ALgyb3 , Spn4ALgzb1 , Spn4ALgzb2 , & + Spn4ALgzb3 , Spn4ALxb1 , Spn4ALxb2 , Spn4ALxb3 , Spn4ALyb1 , Spn4ALyb2 , Spn4ALyb3 , & + Spn4ALzb1 , Spn4ALzb2 , Spn4ALzb3 , Spn4FLxb1 , Spn4FLxb2 , Spn4FLxb3 , Spn4FLyb1 , & + Spn4FLyb2 , Spn4FLyb3 , Spn4FLzb1 , Spn4FLzb2 , Spn4FLzb3 , Spn4MLxb1 , Spn4MLxb2 , & + Spn4MLxb3 , Spn4MLyb1 , Spn4MLyb2 , Spn4MLyb3 , Spn4MLzb1 , Spn4MLzb2 , Spn4MLzb3 , & + Spn4RDxb1 , Spn4RDxb2 , Spn4RDxb3 , Spn4RDyb1 , Spn4RDyb2 , Spn4RDyb3 , Spn4RDzb1 , & + Spn4RDzb2 , Spn4RDzb3 , Spn4TDxb1 , Spn4TDxb2 , Spn4TDxb3 , Spn4TDyb1 , Spn4TDyb2 , & + Spn4TDyb3 , Spn4TDzb1 , Spn4TDzb2 , Spn4TDzb3 , Spn5ALgxb1 , Spn5ALgxb2 , Spn5ALgxb3 , & + Spn5ALgyb1 , Spn5ALgyb2 , Spn5ALgyb3 , Spn5ALgzb1 , Spn5ALgzb2 , Spn5ALgzb3 , Spn5ALxb1 , & + Spn5ALxb2 , Spn5ALxb3 , Spn5ALyb1 , Spn5ALyb2 , Spn5ALyb3 , Spn5ALzb1 , Spn5ALzb2 , & + Spn5ALzb3 , Spn5FLxb1 , Spn5FLxb2 , Spn5FLxb3 , Spn5FLyb1 , Spn5FLyb2 , Spn5FLyb3 , & + Spn5FLzb1 , Spn5FLzb2 , Spn5FLzb3 , Spn5MLxb1 , Spn5MLxb2 , Spn5MLxb3 , Spn5MLyb1 , & + Spn5MLyb2 , Spn5MLyb3 , Spn5MLzb1 , Spn5MLzb2 , Spn5MLzb3 , Spn5RDxb1 , Spn5RDxb2 , & + Spn5RDxb3 , Spn5RDyb1 , Spn5RDyb2 , Spn5RDyb3 , Spn5RDzb1 , Spn5RDzb2 , Spn5RDzb3 , & + Spn5TDxb1 , Spn5TDxb2 , Spn5TDxb3 , Spn5TDyb1 , Spn5TDyb2 , Spn5TDyb3 , Spn5TDzb1 , & + Spn5TDzb2 , Spn5TDzb3 , Spn6ALgxb1 , Spn6ALgxb2 , Spn6ALgxb3 , Spn6ALgyb1 , Spn6ALgyb2 , & + Spn6ALgyb3 , Spn6ALgzb1 , Spn6ALgzb2 , Spn6ALgzb3 , Spn6ALxb1 , Spn6ALxb2 , Spn6ALxb3 , & + Spn6ALyb1 , Spn6ALyb2 , Spn6ALyb3 , Spn6ALzb1 , Spn6ALzb2 , Spn6ALzb3 , Spn6FLxb1 , & + Spn6FLxb2 , Spn6FLxb3 , Spn6FLyb1 , Spn6FLyb2 , Spn6FLyb3 , Spn6FLzb1 , Spn6FLzb2 , & + Spn6FLzb3 , Spn6MLxb1 , Spn6MLxb2 , Spn6MLxb3 , Spn6MLyb1 , Spn6MLyb2 , Spn6MLyb3 , & + Spn6MLzb1 , Spn6MLzb2 , Spn6MLzb3 , Spn6RDxb1 , Spn6RDxb2 , Spn6RDxb3 , Spn6RDyb1 , & + Spn6RDyb2 , Spn6RDyb3 , Spn6RDzb1 , Spn6RDzb2 , Spn6RDzb3 , Spn6TDxb1 , Spn6TDxb2 , & + Spn6TDxb3 , Spn6TDyb1 , Spn6TDyb2 , Spn6TDyb3 , Spn6TDzb1 , Spn6TDzb2 , Spn6TDzb3 , & + Spn7ALgxb1 , Spn7ALgxb2 , Spn7ALgxb3 , Spn7ALgyb1 , Spn7ALgyb2 , Spn7ALgyb3 , Spn7ALgzb1 , & + Spn7ALgzb2 , Spn7ALgzb3 , Spn7ALxb1 , Spn7ALxb2 , Spn7ALxb3 , Spn7ALyb1 , Spn7ALyb2 , & + Spn7ALyb3 , Spn7ALzb1 , Spn7ALzb2 , Spn7ALzb3 , Spn7FLxb1 , Spn7FLxb2 , Spn7FLxb3 , & + Spn7FLyb1 , Spn7FLyb2 , Spn7FLyb3 , Spn7FLzb1 , Spn7FLzb2 , Spn7FLzb3 , Spn7MLxb1 , & + Spn7MLxb2 , Spn7MLxb3 , Spn7MLyb1 , Spn7MLyb2 , Spn7MLyb3 , Spn7MLzb1 , Spn7MLzb2 , & + Spn7MLzb3 , Spn7RDxb1 , Spn7RDxb2 , Spn7RDxb3 , Spn7RDyb1 , Spn7RDyb2 , Spn7RDyb3 , & + Spn7RDzb1 , Spn7RDzb2 , Spn7RDzb3 , Spn7TDxb1 , Spn7TDxb2 , Spn7TDxb3 , Spn7TDyb1 , & + Spn7TDyb2 , Spn7TDyb3 , Spn7TDzb1 , Spn7TDzb2 , Spn7TDzb3 , Spn8ALgxb1 , Spn8ALgxb2 , & + Spn8ALgxb3 , Spn8ALgyb1 , Spn8ALgyb2 , Spn8ALgyb3 , Spn8ALgzb1 , Spn8ALgzb2 , Spn8ALgzb3 , & + Spn8ALxb1 , Spn8ALxb2 , Spn8ALxb3 , Spn8ALyb1 , Spn8ALyb2 , Spn8ALyb3 , Spn8ALzb1 , & + Spn8ALzb2 , Spn8ALzb3 , Spn8FLxb1 , Spn8FLxb2 , Spn8FLxb3 , Spn8FLyb1 , Spn8FLyb2 , & + Spn8FLyb3 , Spn8FLzb1 , Spn8FLzb2 , Spn8FLzb3 , Spn8MLxb1 , Spn8MLxb2 , Spn8MLxb3 , & + Spn8MLyb1 , Spn8MLyb2 , Spn8MLyb3 , Spn8MLzb1 , Spn8MLzb2 , Spn8MLzb3 , Spn8RDxb1 , & + Spn8RDxb2 , Spn8RDxb3 , Spn8RDyb1 , Spn8RDyb2 , Spn8RDyb3 , Spn8RDzb1 , Spn8RDzb2 , & + Spn8RDzb3 , Spn8TDxb1 , Spn8TDxb2 , Spn8TDxb3 , Spn8TDyb1 , Spn8TDyb2 , Spn8TDyb3 , & + Spn8TDzb1 , Spn8TDzb2 , Spn8TDzb3 , Spn9ALgxb1 , Spn9ALgxb2 , Spn9ALgxb3 , Spn9ALgyb1 , & + Spn9ALgyb2 , Spn9ALgyb3 , Spn9ALgzb1 , Spn9ALgzb2 , Spn9ALgzb3 , Spn9ALxb1 , Spn9ALxb2 , & + Spn9ALxb3 , Spn9ALyb1 , Spn9ALyb2 , Spn9ALyb3 , Spn9ALzb1 , Spn9ALzb2 , Spn9ALzb3 , & + Spn9FLxb1 , Spn9FLxb2 , Spn9FLxb3 , Spn9FLyb1 , Spn9FLyb2 , Spn9FLyb3 , Spn9FLzb1 , & + Spn9FLzb2 , Spn9FLzb3 , Spn9MLxb1 , Spn9MLxb2 , Spn9MLxb3 , Spn9MLyb1 , Spn9MLyb2 , & + Spn9MLyb3 , Spn9MLzb1 , Spn9MLzb2 , Spn9MLzb3 , Spn9RDxb1 , Spn9RDxb2 , Spn9RDxb3 , & + Spn9RDyb1 , Spn9RDyb2 , Spn9RDyb3 , Spn9RDzb1 , Spn9RDzb2 , Spn9RDzb3 , Spn9TDxb1 , & + Spn9TDxb2 , Spn9TDxb3 , Spn9TDyb1 , Spn9TDyb2 , Spn9TDyb3 , Spn9TDzb1 , Spn9TDzb2 , & + Spn9TDzb3 , TailFurlP , TailFurlA , TailFurlP , TailFurlV , TeetAya , TeetPya , & + TeetPya , TeetVya , TFrlBrM , TipClrnc1 , TipClrnc2 , TipClrnc3 , TipALgxb1 , & + TipALgxb2 , TipALgxb3 , TipALgyb1 , TipALgyb2 , TipALgyb3 , TipALgzb1 , TipALgzb2 , & + TipALgzb3 , TipALxb1 , TipALxb2 , TipALxb3 , TipALyb1 , TipALyb2 , TipALyb3 , & + TipALzb1 , TipALzb2 , TipALzb3 , TipClrnc1 , TipClrnc2 , TipClrnc3 , TipDxb1 , & + TipDxb2 , TipDxb3 , TipDxc1 , TipDxc2 , TipDxc3 , TipDyb1 , TipDyb2 , & + TipDyb3 , TipDyc1 , TipDyc2 , TipDyc3 , TipDzc1 , TipDzc2 , TipDzc3 , & + TipDzc1 , TipDzc2 , TipDzc3 , TipRDxb1 , TipRDxb2 , TipRDxb3 , TipRDyb1 , & + TipRDyb2 , TipRDyb3 , TipRDzc1 , TipRDzc2 , TipRDzc3 , TipRDzc1 , TipRDzc2 , & + TipRDzc3 , YawBrTDzt , YawBrTDxt , YawBrRDyt , YawBrRDxt , YawBrTDyt , YawBrRDzt , & + TwHt1ALgxt , TwHt1ALgyt , TwHt1ALgzt , TwHt1ALxt , TwHt1ALyt , TwHt1ALzt , TwHt1FLxt , & + TwHt1FLyt , TwHt1FLzt , TwHt1MLxt , TwHt1MLyt , TwHt1MLzt , TwHt1RDxt , TwHt1RDyt , & + TwHt1RDzt , TwHt1RPxi , TwHt1RPyi , TwHt1RPzi , TwHt1TDxt , TwHt1TDyt , TwHt1TDzt , & + TwHt1TPxi , TwHt1TPyi , TwHt1TPzi , TwHt2ALgxt , TwHt2ALgyt , TwHt2ALgzt , TwHt2ALxt , & + TwHt2ALyt , TwHt2ALzt , TwHt2FLxt , TwHt2FLyt , TwHt2FLzt , TwHt2MLxt , TwHt2MLyt , & + TwHt2MLzt , TwHt2RDxt , TwHt2RDyt , TwHt2RDzt , TwHt2RPxi , TwHt2RPyi , TwHt2RPzi , & + TwHt2TDxt , TwHt2TDyt , TwHt2TDzt , TwHt2TPxi , TwHt2TPyi , TwHt2TPzi , TwHt3ALgxt , & + TwHt3ALgyt , TwHt3ALgzt , TwHt3ALxt , TwHt3ALyt , TwHt3ALzt , TwHt3FLxt , TwHt3FLyt , & + TwHt3FLzt , TwHt3MLxt , TwHt3MLyt , TwHt3MLzt , TwHt3RDxt , TwHt3RDyt , TwHt3RDzt , & + TwHt3RPxi , TwHt3RPyi , TwHt3RPzi , TwHt3TDxt , TwHt3TDyt , TwHt3TDzt , TwHt3TPxi , & + TwHt3TPyi , TwHt3TPzi , TwHt4ALgxt , TwHt4ALgyt , TwHt4ALgzt , TwHt4ALxt , TwHt4ALyt , & + TwHt4ALzt , TwHt4FLxt , TwHt4FLyt , TwHt4FLzt , TwHt4MLxt , TwHt4MLyt , TwHt4MLzt , & + TwHt4RDxt , TwHt4RDyt , TwHt4RDzt , TwHt4RPxi , TwHt4RPyi , TwHt4RPzi , TwHt4TDxt , & + TwHt4TDyt , TwHt4TDzt , TwHt4TPxi , TwHt4TPyi , TwHt4TPzi , TwHt5ALgxt , TwHt5ALgyt , & + TwHt5ALgzt , TwHt5ALxt , TwHt5ALyt , TwHt5ALzt , TwHt5FLxt , TwHt5FLyt , TwHt5FLzt , & + TwHt5MLxt , TwHt5MLyt , TwHt5MLzt , TwHt5RDxt , TwHt5RDyt , TwHt5RDzt , TwHt5RPxi , & + TwHt5RPyi , TwHt5RPzi , TwHt5TDxt , TwHt5TDyt , TwHt5TDzt , TwHt5TPxi , TwHt5TPyi , & + TwHt5TPzi , TwHt6ALgxt , TwHt6ALgyt , TwHt6ALgzt , TwHt6ALxt , TwHt6ALyt , TwHt6ALzt , & + TwHt6FLxt , TwHt6FLyt , TwHt6FLzt , TwHt6MLxt , TwHt6MLyt , TwHt6MLzt , TwHt6RDxt , & + TwHt6RDyt , TwHt6RDzt , TwHt6RPxi , TwHt6RPyi , TwHt6RPzi , TwHt6TDxt , TwHt6TDyt , & + TwHt6TDzt , TwHt6TPxi , TwHt6TPyi , TwHt6TPzi , TwHt7ALgxt , TwHt7ALgyt , TwHt7ALgzt , & + TwHt7ALxt , TwHt7ALyt , TwHt7ALzt , TwHt7FLxt , TwHt7FLyt , TwHt7FLzt , TwHt7MLxt , & + TwHt7MLyt , TwHt7MLzt , TwHt7RDxt , TwHt7RDyt , TwHt7RDzt , TwHt7RPxi , TwHt7RPyi , & + TwHt7RPzi , TwHt7TDxt , TwHt7TDyt , TwHt7TDzt , TwHt7TPxi , TwHt7TPyi , TwHt7TPzi , & + TwHt8ALgxt , TwHt8ALgyt , TwHt8ALgzt , TwHt8ALxt , TwHt8ALyt , TwHt8ALzt , TwHt8FLxt , & + TwHt8FLyt , TwHt8FLzt , TwHt8MLxt , TwHt8MLyt , TwHt8MLzt , TwHt8RDxt , TwHt8RDyt , & + TwHt8RDzt , TwHt8RPxi , TwHt8RPyi , TwHt8RPzi , TwHt8TDxt , TwHt8TDyt , TwHt8TDzt , & + TwHt8TPxi , TwHt8TPyi , TwHt8TPzi , TwHt9ALgxt , TwHt9ALgyt , TwHt9ALgzt , TwHt9ALxt , & + TwHt9ALyt , TwHt9ALzt , TwHt9FLxt , TwHt9FLyt , TwHt9FLzt , TwHt9MLxt , TwHt9MLyt , & + TwHt9MLzt , TwHt9RDxt , TwHt9RDyt , TwHt9RDzt , TwHt9RPxi , TwHt9RPyi , TwHt9RPzi , & + TwHt9TDxt , TwHt9TDyt , TwHt9TDzt , TwHt9TPxi , TwHt9TPyi , TwHt9TPzi , TwrBsFxt , & + TwrBsFyt , TwrBsFzt , TwrBsMxt , TwrBsMyt , TwrBsMzt , TipClrnc1 , TipClrnc2 , & + TipClrnc3 , TwrTpTDxi , TwrTpTDyi , TwrTpTDzi , TipRDzc1 , TipRDzc2 , TipRDzc3 , & + YawAzn , YawAzn , YawAzn , YawBrFxn , YawBrFxp , YawBrFyn , YawBrFyp , & + YawBrFzn , YawBrFzn , YawBrMxn , YawBrMxp , YawBrMyn , YawBrMyp , YawBrMzn , & + YawBrMzn , YawBrRAxp , YawBrRAyp , YawBrRAzp , YawBrRDxt , YawBrRDyt , YawBrRDzt , & + YawBrRVxp , YawBrRVyp , YawBrRVzp , YawBrTAgxp , YawBrTAgyp , YawBrTAgzp , YawBrTAxp , & + YawBrTAyp , YawBrTAzp , TwrTpTDxi , YawBrTDxp , YawBrTDxt , TwrTpTDyi , YawBrTDyp , & + YawBrTDyt , TwrTpTDzi , YawBrTDzp , YawBrTDzt , YawBrTVxp , YawBrTVyp , YawBrTVzp , & + YawFriMfp , YawFriMom , YawFriMz , YawPzn , YawPzn , YawPzn , YawVzn , & + YawVzn , YawVzn /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1115) = (/ character(ChanLen) :: & ! This lists the units corresponding to the allowed parameters "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg/s^2)","(rpm) ","(kN-m) ","(deg/s^2)","(kW) ","(kN-m) ","(rpm) ", & - "(m) ","(m) ","(m) ","(deg/s^2)","(deg/s^2)","(deg/s^2)","(kN) ", & - "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ", & - "(rpm) ","(rpm) ","(rpm) ","(kN) ","(kN) ","(kN) ","(kN) ", & - "(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kW) ","(kN-m) ","(deg/s^2)", & - "(deg/s^2)","(deg/s^2)","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ", & - "(deg) ","(deg) ","(rpm) ","(rpm) ","(rpm) ","(deg) ","(deg/s^2)", & - "(deg) ","(deg/s) ","(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg/s) ","(deg/s) ", & - "(deg/s) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s) ","(m/s) ","(m/s) ","(m) ","(m) ","(m) ","(deg) ", & - "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg) ","(m) ","(deg) ","(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg/s^2)", & - "(deg/s^2)","(deg/s^2)","(deg) ","(deg) ","(deg) ","(deg) ","(deg/s) ", & - "(deg/s) ","(deg/s) ","(deg/s) ","(deg/s) ","(deg/s) ","(m) ","(m) ", & + "(deg/s^2)","(deg/s^2)","(rpm) ","(kN-m) ","(deg/s^2)","(kW) ","(kN-m) ", & + "(rpm) ","(m) ","(m) ","(m) ","(deg/s^2)","(deg/s^2)","(deg/s^2)", & + "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN-m) ", & + "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ", & + "(deg) ","(rpm) ","(rpm) ","(rpm) ","(kN) ","(kN) ","(kN) ", & + "(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kW) ","(kN-m) ", & + "(deg/s^2)","(deg/s^2)","(deg/s^2)","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & + "(deg) ","(deg) ","(deg) ","(rpm) ","(rpm) ","(rpm) ","(deg) ", & + "(deg/s^2)","(deg) ","(deg/s) ","(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg/s) ", & + "(deg/s) ","(deg/s) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s) ","(m/s) ","(m/s) ","(deg/s) ","(m) ","(m) ", & + "(m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(deg) ","(deg) ","(deg) ","(m) ","(deg) ","(deg/s^2)","(deg/s^2)", & + "(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg) ","(deg) ","(deg) ", & + "(deg) ","(deg/s) ","(deg/s) ","(deg/s) ","(deg/s) ","(deg/s) ","(deg/s) ", & + "(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m) ","(m) ", & - "(m) ","(m) ","(m) ","(m) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(rad/s^2)", & - "(rad/s^2)","(m/s^2) ","(rad/s^2)","(rad/s^2)","(rad/s^2)","(m/s^2) ","(m/s^2) ", & - "(rad/s^2)","(m/s^2) ","(m/s^2) ","(rad/s^2)","(m/s^2) ","(m/s^2) ","(rad/s^2)", & - "(rad/s^2)","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(rad/s) ","(rad/s) ","(m/s) ","(rad/s) ", & - "(rad/s) ","(rad/s) ","(m/s) ","(m/s) ","(rad/s) ","(m/s) ","(m/s) ", & - "(rad/s) ","(m/s) ","(m/s) ","(rad/s) ","(rad/s) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(rad/s^2)","(rad/s^2)","(m/s^2) ","(rad/s^2)","(rad/s^2)","(rad/s^2)", & + "(m/s^2) ","(m/s^2) ","(rad/s^2)","(m/s^2) ","(m/s^2) ","(rad/s^2)","(m/s^2) ", & + "(m/s^2) ","(rad/s^2)","(rad/s^2)","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(rad/s) ","(rad/s) ", & + "(m/s) ","(rad/s) ","(rad/s) ","(rad/s) ","(m/s) ","(m/s) ","(rad/s) ", & + "(m/s) ","(m/s) ","(rad/s) ","(m/s) ","(m/s) ","(rad/s) ","(rad/s) ", & "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & - "(rad) ","(rad) ","(m) ","(rad) ","(rad) ","(rad) ","(m) ", & - "(m) ","(rad) ","(m) ","(m) ","(rad) ","(m) ","(m) ", & - "(rad) ","(rad) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(kN) ", & - "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & + "(m) ","(m) ","(rad) ","(rad) ","(m) ","(rad) ","(rad) ", & + "(rad) ","(m) ","(m) ","(rad) ","(m) ","(m) ","(rad) ", & + "(m) ","(m) ","(rad) ","(rad) ","(kN-m) ","(deg) ","(deg) ", & + "(deg) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & - "(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & + "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ", & "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg/s^2)","(deg) ", & - "(deg/s^2)","(deg) ","(deg/s) ","(kW) ","(rpm) ","(deg/s^2)","(deg) ", & - "(deg/s) ","(kN) ","(kN-m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & + "(deg/s^2)","(deg) ","(deg/s^2)","(deg) ","(deg/s) ","(kW) ","(rpm) ", & + "(deg/s^2)","(deg) ","(deg/s) ","(kN) ","(kN-m) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & + "(kN) ","(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ", & + "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ", & + "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(deg) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & @@ -4373,34 +4404,16 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ", & "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(m) ", & "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & - "(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m) ","(deg) ","(deg/s^2)","(deg) ","(deg/s) ","(deg/s^2)","(deg) ", & + "(deg) ","(deg/s) ","(kN-m) ","(m) ","(m) ","(m) ","(m/s^2) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ","(kN) ", & - "(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & - "(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg) ","(deg) ","(deg) ","(deg) ","(m) ","(m) ","(m) ", & - "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(deg) ", & - "(deg/s^2)","(deg) ","(deg/s) ","(deg/s^2)","(deg) ","(deg) ","(deg/s) ", & - "(kN-m) ","(m) ","(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m) ","(m) ","(m) ","(m) ", & "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & - "(m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(m) ", & - "(m) ","(deg) ","(deg) ","(m) ","(deg) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ","(kN) ","(kN) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg) ","(deg) ","(m) ","(m) ","(m) ","(m) ","(m) ", & - "(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ", & - "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(m) ","(m) ", & - "(m) ","(m) ","(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ","(kN) ","(kN) ","(kN-m) ", & - "(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & - "(deg) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(deg) ","(m) ","(m) ","(deg) ","(deg) ","(m) ","(deg) ", & "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ", & "(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ", & "(deg) ","(deg) ","(deg) ","(deg) ","(m) ","(m) ","(m) ", & @@ -4421,16 +4434,27 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) "(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & "(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ", & "(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(m) ","(m) ", & - "(m) ","(m) ","(m) ","(m) ","(kN) ","(kN) ","(kN) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(m) ","(m) ","(m) ","(m) ", & - "(m) ","(m) ","(deg) ","(deg) ","(deg) ","(deg/s^2)","(deg/s^2)", & - "(deg/s^2)","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ","(kN) ", & - "(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg/s^2)", & - "(deg/s^2)","(deg/s^2)","(deg) ","(deg) ","(deg) ","(deg/s) ","(deg/s) ", & - "(deg/s) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & - "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & - "(m) ","(m) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(deg) ", & - "(deg) ","(deg/s) ","(deg/s) ","(deg/s) "/) + "(m) ","(m) ","(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ","(kN) ","(kN) ","(kN-m) ", & + "(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(deg) ","(m) ","(m) ","(m) ","(m) ","(m) ","(m) ", & + "(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(kN) ", & + "(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ", & + "(deg) ","(deg) ","(deg) ","(deg) ","(m) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(kN) ","(kN) ","(kN) ","(kN-m) ","(kN-m) ", & + "(kN-m) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ","(deg) ", & + "(m) ","(m) ","(m) ","(m) ","(m) ","(m) ","(kN) ", & + "(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(m) ","(deg) ","(deg) ","(deg) ", & + "(deg/s^2)","(deg/s^2)","(deg/s^2)","(kN) ","(kN) ","(kN) ","(kN) ", & + "(kN) ","(kN) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ","(kN-m) ", & + "(kN-m) ","(deg/s^2)","(deg/s^2)","(deg/s^2)","(deg) ","(deg) ","(deg) ", & + "(deg/s) ","(deg/s) ","(deg/s) ","(m/s^2) ","(m/s^2) ","(m/s^2) ","(m/s^2) ", & + "(m/s^2) ","(m/s^2) ","(m) ","(m) ","(m) ","(m) ","(m) ", & + "(m) ","(m) ","(m) ","(m) ","(m/s) ","(m/s) ","(m/s) ", & + "(kN-m) ","(kN-m) ","(kN-m) ","(deg) ","(deg) ","(deg) ","(deg/s) ", & + "(deg/s) ","(deg/s) "/) ! Initialize values @@ -4704,17 +4728,18 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) 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 - + CALL SetErrStat(ErrID_Fatal, TRIM(p%OutParam(I)%Name)//" is not an available output channel.",ErrStat,ErrMsg,RoutineName) END IF - + END DO - + RETURN END SUBROUTINE SetOutParam !---------------------------------------------------------------------------------------------------------------------------------- !End of code generated by Matlab script !********************************************************************************************************************************** + !> This routine is used to compute rotor (blade and hub) properties: !! KBF(), KBE(), CBF(), CBE(), FreqBF(), FreqBE(), AxRedBld(), !! TwistedSF(), BldMass(), FirstMom(), SecondMom(), BldCG(), @@ -6591,6 +6616,62 @@ SUBROUTINE Teeter( t, p, TeetDef, TeetRate, TeetMom ) RETURN END SUBROUTINE Teeter !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine computes the Yaw Friction Torque due to yaw rate and acceleration. +SUBROUTINE YawFriction( t, p, Fz, Mzz, Omg, OmgDot, YawFriMf ) +!.................................................................................................................................. + + ! Passed Variables: + REAL(DbKi), INTENT(IN) :: t !< simulation time + TYPE(ED_ParameterType), INTENT(IN) :: p !< parameters from the structural dynamics module + REAL(R8Ki), INTENT(IN ) :: Fz, Mzz !< Effective yaw bearing force and external yaw bearing torque + REAL(R8Ki), INTENT(IN ) :: Omg !< The yaw rate (rotational speed), x%QDT(DOF_Yaw). + REAL(R8Ki), INTENT(IN ) :: OmgDot !< The yaw acceleration (derivative of rotational speed), x%QD2T(DOF_Yaw). + + REAL(ReKi), INTENT(OUT) :: YawFriMf !< The total friction torque (Coulomb + viscous). + + ! Local variables: + REAL(ReKi) :: temp ! It takes teh value of Fz or -1. + + + SELECT CASE ( p%YawFrctMod ) + ! Yaw-friction model {0: none, 1: does not use Fz at yaw bearing, 2: does, 3: user defined model} (switch) + + CASE ( 0_IntKi ) ! None! + + + YawFriMf = 0.0_ReKi + + + CASE ( 1_IntKi, 2_IntKi ) ! 1= no Fz use. 2=Fz used + + temp = -1.0_ReKi !In the case of YawFrctMod=1 + + IF (p%YawFrctMod .EQ. 2) THEN + temp = MIN(0.0_R8Ki, Fz) !In the case of YawFrctMod=2 + ENDIF + + IF (EqualRealNos( Omg, 0.0_R8Ki ) )THEN + YawFriMf = -MIN(real(p%M_CD,ReKi) * ABS(temp), ABS(real(Mzz,ReKi))) * SIGN(1.0_ReKi, real(Mzz,ReKi)) + IF (EqualRealNos( OmgDot, 0.0_R8Ki )) THEN + YawFriMf = -MIN(real(p%M_CSmax,ReKi) * ABS(temp), ABS(real(Mzz,ReKi))) * SIGN(1.0_ReKi, real(Mzz,ReKi)) + ENDIF + ELSE + YawFriMf = real(p%M_CD,ReKi) * temp * sign(1.0_ReKi, real(Omg,ReKi)) - real(p%sig_v,ReKi) * real(Omg,ReKi) + ENDIF + + + CASE ( 3_IntKi ) ! User-defined YawFriMf model. >>>> NOT IMPLEMENTED YET + + + CALL UserYawFrict ( t, Fz, Mzz, Omg, OmgDot, p%RootName, YawFriMf ) + + + END SELECT + + + RETURN +END SUBROUTINE YawFriction +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine computes the tail-furl moment due to tail-furl deflection and rate. SUBROUTINE TFurling( t, p, TFrlDef, TFrlRate, TFrlMom ) ! Passed Variables: @@ -8463,7 +8544,7 @@ SUBROUTINE FillAugMat( p, x, CoordSys, u, HSSBrTrq, RtHSdat, AugMat ) AugMat(p%DOFs%SrtPS(I),DOF_Yaw ) = -DOT_PRODUCT( RtHSdat%PAngVelEN(DOF_Yaw ,0,:), RtHSdat%PMomBNcRt(:,p%DOFs%SrtPS(I)) ) ! [C(q,t)]N + [C(q,t)]R + [C(q,t)]G + [C(q,t)]H + [C(q,t)]B + [C(q,t)]A ENDDO ! I - All active (enabled) DOFs on or below the diagonal AugMat(DOF_Yaw , p%NAug) = DOT_PRODUCT( RtHSdat%PAngVelEN(DOF_Yaw ,0,:), RtHSdat%MomBNcRtt ) & ! {-f(qd,q,t)}N + {-f(qd,q,t)}GravN + {-f(qd,q,t)}R + {-f(qd,q,t)}GravR + {-f(qd,q,t)}G + {-f(qd,q,t)}H + {-f(qd,q,t)}GravH + {-f(qd,q,t)}B + {-f(qd,q,t)}GravB + {-f(qd,q,t)}AeroB + {-f(qd,q,t)}A + {-f(qd,q,t)}GravA + {-f(qd,q,t)}AeroA - + u%YawMom ! + {-f(qd,q,t)}SpringYaw + {-f(qd,q,t)}DampYaw; NOTE: The neutral yaw rate, YawRateNeut, defaults to zero. It is only used for yaw control. + + u%YawMom + RtHSdat%YawFriMom ! + {-f(qd,q,t)}SpringYaw + {-f(qd,q,t)}DampYaw; NOTE: The neutral yaw rate, YawRateNeut, defaults to zero. It is only used for yaw control. ENDIF @@ -9659,6 +9740,8 @@ SUBROUTINE ED_AB4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg END IF OtherState%HSSBrTrq = OtherState%HSSBrTrqC OtherState%SgnPrvLSTQ = OtherState%SgnLSTQ(OtherState%IC(2)) + OtherState%OmegaTn = x%QDT(DOF_Yaw) !this is equal to x%QDT(DOF_Yaw) + OtherState%OmegaDotTn = m%QD2T(DOF_Yaw) !this is equal to m%QD2T(DOF_Yaw) CALL ED_CalcContStateDeriv( t, u_interp, p, x, xd, z, OtherState, m, xdot, ErrStat2, ErrMsg2 ) CALL CheckError(ErrStat2,ErrMsg2) @@ -9693,6 +9776,11 @@ SUBROUTINE ED_AB4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg CALL FixHSSBrTq ( 'P', p, x, OtherState, m, ErrStat2, ErrMsg2 ) CALL CheckError(ErrStat2,ErrMsg2) IF ( ErrStat >= AbortErrLev ) RETURN + + CALL FixYawFric ( 'P', p, x, OtherState, m, ErrStat2, ErrMsg2 ) !KBF Make sure YawFric will not reverse nacelle direction x%qdt(dof_yaw) = OtherState%xdot(OtherState%IC(1))%qt(DOF_Yaw ) + CALL CheckError(ErrStat2,ErrMsg2) + IF ( ErrStat >= AbortErrLev ) RETURN + endif @@ -9852,6 +9940,11 @@ SUBROUTINE ED_ABM4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg CALL FixHSSBrTq ( 'C', p, x, OtherState, m, ErrStat2, ErrMsg2 ) CALL CheckError(ErrStat2,ErrMsg2) IF ( ErrStat >= AbortErrLev ) RETURN + + CALL FixYawFric ( 'C', p, x, OtherState, m, ErrStat2, ErrMsg2 ) !KBF Make sure YawFric will not reverse nacelle direction x%qdt(dof_yaw) = OtherState%xdot(OtherState%IC(1))%qt(DOF_Yaw ) + CALL CheckError(ErrStat2,ErrMsg2) + IF ( ErrStat >= AbortErrLev ) RETURN + OtherState%SgnPrvLSTQ = SignLSSTrq(p, m) OtherState%SgnLSTQ(OtherState%IC(1)) = OtherState%SgnPrvLSTQ @@ -10330,6 +10423,201 @@ SUBROUTINE FixHSSBrTq ( Integrator, p, x, OtherState, m, ErrStat, ErrMsg ) RETURN END SUBROUTINE FixHSSBrTq +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine is used to adjust the YawFricMom value for unphysicalities. +SUBROUTINE FixYawFric ( Integrator, p, x, OtherState, m, ErrStat, ErrMsg ) + + ! Passed variables: + + TYPE(ED_ParameterType), INTENT(IN ) :: p !< Parameters of the structural dynamics module + TYPE(ED_OtherStateType), INTENT(INOUT) :: OtherState !< Other states of the structural dynamics module + TYPE(ED_MiscVarType), INTENT(INOUT) :: m !< misc (optimization) variables + TYPE(ED_ContinuousStateType),INTENT(INOUT) :: x !< Continuous states of the structural dynamics module at n+1 + CHARACTER(1), INTENT(IN ) :: Integrator !< A string holding the current integrator being used. + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + + ! Local variables: + + REAL(ReKi) :: RqdFrcYaw ! The force term required to produce RqdQD2Yaw. + REAL(ReKi) :: RqdQD2Yaw ! The required QD2T(DOF_Yaw) to cause the yaw bearing to stop rotating. + + INTEGER :: I ! Loops through all DOFs. + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FixYawFric' + + + + ErrStat = ErrID_None + ErrMsg = "" + + IF ( .NOT. p%DOF_Flag(DOF_Yaw) .OR. EqualRealNos(m%RtHS%YawFriMom, 0.0_ReKi ) ) RETURN + + + ! The absolute magnitude of the yaw friction must have been too great + ! that the yaw speed sign was reversed. What should have happened + ! is that the yaw system should have stopped rotating. In other words, + ! QD(DOF_Yaw,IC(NMX)) should equal zero! Determining what + ! QD2T(DOF_Yaw) will make QD(DOF_Yaw,IC(NMX)) = 0, depends on + ! which integrator we are using. + + + SELECT CASE (Integrator) + + CASE ('C') ! Corrector + + ! Find the required QD2T(DOF_Yaw) to cause the yaw system to stop rotating (RqdQD2Yaw). + ! This is found by solving the corrector formula for QD2(DOF_Yaw,IC(NMX)) + ! when QD(DOF_Yaw,IC(NMX)) equals zero. + + RqdQD2Yaw = ( - OtherState%xdot(OtherState%IC(1))%qt(DOF_Yaw)/ p%DT24 & + - 19.0*OtherState%xdot(OtherState%IC(1))%qdt(DOF_Yaw) & + + 5.0*OtherState%xdot(OtherState%IC(2))%qdt(DOF_Yaw) & + - OtherState%xdot(OtherState%IC(3))%qdt(DOF_Yaw) ) / 9.0 + + CASE ('P') ! Predictor + + ! Find the required QD2T(DOF_Yaw) to cause the yaw system to stop rotating (RqdQD2Yaw). + ! This is found by solving the predictor formula for QD2(DOF_Yaw,IC(1)) + ! when QD(DOF_Yaw,IC(NMX)) equals zero. + + RqdQD2Yaw = ( - OtherState%xdot(OtherState%IC(1))%qt( DOF_Yaw) / p%DT24 & + + 59.0*OtherState%xdot(OtherState%IC(2))%qdt(DOF_Yaw) & + - 37.0*OtherState%xdot(OtherState%IC(3))%qdt(DOF_Yaw) & + + 9.0*OtherState%xdot(OtherState%IC(4))%qdt(DOF_Yaw) )/55.0 + + END SELECT + + + ! Rearrange the augmented matrix of equations of motion to account + ! for the known acceleration of the yaw DOF. To + ! do this, make the known inertia like an applied force to the + ! system. Then set force QD2T(DOF_Yaw) to equal the known + ! acceleration in the augmented matrix of equations of motion: + ! Here is how the new equations are derived. First partition the + ! augmented matrix as follows, where Qa are the unknown + ! accelerations, Qb are the known accelerations, Fa are the + ! known forces, and Fb are the unknown forces: + ! [Caa Cab]{Qa}={Fa} + ! [Cba Cbb]{Qb}={Fb} + ! By rearranging, the equations for the unknown and known + ! accelerations are as follows: + ! [Caa]{Qa}={Fa}-[Cab]{Qb} and [I]{Qb}={Qb} + ! Combining these two sets of equations into one set yields: + ! [Caa 0]{Qa}={{Fa}-[Cab]{Qb}} + ! [ 0 I]{Qb}={ {Qb}} + ! Once this equation is solved, the unknown force can be found from: + ! {Fb}=[Cba]{Qa}+[Cbb]{Qb} + + m%OgnlYawRow = m%AugMat(DOF_Yaw,:) ! copy this row before modifying the old matrix + + + DO I = 1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs + + m%AugMat(p%DOFs%SrtPS(I), p%NAUG) = m%AugMat(p%DOFs%SrtPS(I),p%NAUG) & + - m%AugMat(p%DOFs%SrtPS(I),DOF_Yaw)*RqdQD2Yaw ! {{Fa}-[Cab]{Qb}} + m%AugMat(p%DOFs%SrtPS(I),DOF_Yaw) = 0.0 ! [0] + m%AugMat(DOF_Yaw, p%DOFs%SrtPS(I)) = 0.0 ! [0] + + ENDDO ! I - All active (enabled) DOFs + + m%AugMat(DOF_Yaw,DOF_Yaw) = 1.0 ! [I]{Qb}={Qb} + m%AugMat(DOF_Yaw, p%NAUG) = RqdQD2Yaw ! + + + ! Invert the matrix to solve for the new (updated) accelerations. Like in + ! CalcContStateDeriv(), the accelerations are returned by Gauss() in the first NActvDOF + ! elements of the solution vector, SolnVec(). These are transfered to the + ! proper index locations of the acceleration vector QD2T() using the + ! vector subscript array SrtPS(), after Gauss() has been called: + + ! Invert the matrix to solve for the accelerations. The accelerations are returned by Gauss() in the first NActvDOF elements + ! of the solution vector, SolnVec(). These are transfered to the proper index locations of the acceleration vector QD2T() + ! using the vector subscript array SrtPS(), after Gauss() has been called: + + m%AugMat_factor = m%AugMat( p%DOFs%SrtPS( 1:p%DOFs%NActvDOF ), p%DOFs%SrtPSNAUG(1:p%DOFs%NActvDOF) ) + m%SolnVec = m%AugMat( p%DOFs%SrtPS( 1:p%DOFs%NActvDOF ), p%DOFs%SrtPSNAUG(1+p%DOFs%NActvDOF) ) + + CALL LAPACK_getrf( M=p%DOFs%NActvDOF, N=p%DOFs%NActvDOF, A=m%AugMat_factor, IPIV=m%AugMat_pivot, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + CALL LAPACK_getrs( TRANS='N',N=p%DOFs%NActvDOF, A=m%AugMat_factor,IPIV=m%AugMat_pivot, B=m%SolnVec, ErrStat=ErrStat2, ErrMsg=ErrMsg2) + + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + + + ! Find the force required to produce RqdQD2Yaw from the equations of + ! motion using the new accelerations: + + RqdFrcYaw = 0.0 + DO I = 1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs + ! bjj: use m%SolnVec(I) instead of m%QD2T(p%DOFs%SrtPS(I)) here; then update m%QD2T(p%DOFs%SrtPS(I)) + ! later if necessary + RqdFrcYaw = RqdFrcYaw + m%OgnlYawRow(p%DOFs%SrtPS(I))*m%SolnVec(I) ! {Fb}=[Cba]{Qa}+[Cbb]{Qb} (note that [Cba , Cbb] is the old row, and [Qa;Qb] is a single vector SolVec; %Note this is supposedly= YawFriMz+YawFriMf+DeltaM + ENDDO ! I - All active (enabled) DOFs + + ! Find the YawFriMfp necessary to bring about this force, i.e. to stop the yaw: + + OtherState%YawFriMfp = m%RtHs%YawFriMom - ( m%OgnlYawRow(p%NAUG) - RqdFrcYaw ) !This should return YawFriMf - (YawFriMz + YawFriMf - (YawFriMz + YawFriMf + deltaM)) = YawFriMf+DeltaM =YawFriMfp + + OtherState%Mfhat = ABS(OtherState%YawFriMfp) * SIGN(1.0_ReKi, real(m%RtHs%YawFriMom,ReKi)) !Mfhat should have same sign as YawFriMom (YawFriMf) + +!Now check if YawFriMfp is unphysical (i.e., it turned out aligned with omega), and then pick the minimum between YawFriMf and YawFriMfp + + IF ( ABS( OtherState%YawFriMfp ) > ABS( m%RtHs%YawFriMom )) THEN + + OtherState%Mfhat = m%RtHs%YawFriMom !OtherState%HSSBrTrqC = SIGN( u%HSSBrTrqC, x%QDT(DOF_GeAz) ) KBF CHECK THIS, does YawFriMfp need to be OtherState? + + ELSE + + ! overwrite QD2T with the new values + m%QD2T = 0.0 + DO I = 1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs + m%QD2T(p%DOFs%SrtPS(I)) = m%SolnVec(I) + ENDDO ! I - All active (enabled) DOFs + + + ! Use the new accelerations to update the DOF values. Again, this + ! depends on the integrator type: + + SELECT CASE (Integrator) + + CASE ('C') ! Corrector + + ! Update QD and QD2 with the new accelerations using the corrector. + ! This will make QD(DOF_Yaw,IC(NMX)) equal to zero and adjust all + ! of the other QDs as necessary. + ! The Q's are unnaffected by this change. + + x%qdt = OtherState%xdot(OtherState%IC(1))%qt & ! qd at n + + p%DT24 * ( 9. * m%QD2T & ! the value we just changed + + 19. * OtherState%xdot(OtherState%IC(1))%qdt & + - 5. * OtherState%xdot(OtherState%IC(2))%qdt & + + 1. * OtherState%xdot(OtherState%IC(3))%qdt ) + + CASE ('P') ! Predictor + + ! Update QD and QD2 with the new accelerations using predictor. + + x%qdt = OtherState%xdot(OtherState%IC(1))%qt + & ! qd at n + p%DT24 * ( 55.*m%QD2T & ! the value we just changed + - 59.*OtherState%xdot(OtherState%IC(2))%qdt & + + 37.*OtherState%xdot(OtherState%IC(3))%qdt & + - 9.*OtherState%xdot(OtherState%IC(4))%qdt ) + + OtherState%xdot ( OtherState%IC(1) )%qdt = m%QD2T ! fix the history + + END SELECT + + ENDIF + + RETURN +END SUBROUTINE FixYawFric + !---------------------------------------------------------------------------------------------------------------------------------- !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/modules/elastodyn/src/ElastoDyn_IO.f90 b/modules/elastodyn/src/ElastoDyn_IO.f90 index e2be81b8a3..5a92da55b8 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -101,7 +101,13 @@ MODULE ElastoDyn_Parameters ! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these ! lines should be modified in the Matlab script and/or Excel worksheet as necessary. ! =================================================================================================== -! This code was generated by Write_ChckOutLst.m at 25-Jan-2021 13:23:51. +! This code was generated by "Write_ChckOutLst.m". +!MODULE ElastoDyn_IO_Params +! +! USE NWTC_Library +! USE ElastoDyn_Types +! +! IMPLICIT NONE ! Indices for computing output channels: @@ -111,7 +117,7 @@ MODULE ElastoDyn_Parameters ! Time: - INTEGER(IntKi), PARAMETER :: Time = 0 + INTEGER(IntKi), PARAMETER :: Time = 0 ! Blade 1 Tip Motions: @@ -1083,159 +1089,167 @@ MODULE ElastoDyn_Parameters INTEGER(IntKi), PARAMETER :: YawBrMyp = 857 + ! Yaw Friction: + + INTEGER(IntKi), PARAMETER :: YawFriMom = 858 + INTEGER(IntKi), PARAMETER :: YawFriMfp = 859 + INTEGER(IntKi), PARAMETER :: YawFriMz = 860 + INTEGER(IntKi), PARAMETER :: OmegaYF = 861 + INTEGER(IntKi), PARAMETER :: dOmegaYF = 862 + + ! Tower Base Loads: - INTEGER(IntKi), PARAMETER :: TwrBsFxt = 858 - INTEGER(IntKi), PARAMETER :: TwrBsFyt = 859 - INTEGER(IntKi), PARAMETER :: TwrBsFzt = 860 - INTEGER(IntKi), PARAMETER :: TwrBsMxt = 861 - INTEGER(IntKi), PARAMETER :: TwrBsMyt = 862 - INTEGER(IntKi), PARAMETER :: TwrBsMzt = 863 + INTEGER(IntKi), PARAMETER :: TwrBsFxt = 863 + INTEGER(IntKi), PARAMETER :: TwrBsFyt = 864 + INTEGER(IntKi), PARAMETER :: TwrBsFzt = 865 + INTEGER(IntKi), PARAMETER :: TwrBsMxt = 866 + INTEGER(IntKi), PARAMETER :: TwrBsMyt = 867 + INTEGER(IntKi), PARAMETER :: TwrBsMzt = 868 ! Local Tower Loads: - INTEGER(IntKi), PARAMETER :: TwHt1MLxt = 864 - INTEGER(IntKi), PARAMETER :: TwHt1MLyt = 865 - INTEGER(IntKi), PARAMETER :: TwHt1MLzt = 866 - INTEGER(IntKi), PARAMETER :: TwHt2MLxt = 867 - INTEGER(IntKi), PARAMETER :: TwHt2MLyt = 868 - INTEGER(IntKi), PARAMETER :: TwHt2MLzt = 869 - INTEGER(IntKi), PARAMETER :: TwHt3MLxt = 870 - INTEGER(IntKi), PARAMETER :: TwHt3MLyt = 871 - INTEGER(IntKi), PARAMETER :: TwHt3MLzt = 872 - INTEGER(IntKi), PARAMETER :: TwHt4MLxt = 873 - INTEGER(IntKi), PARAMETER :: TwHt4MLyt = 874 - INTEGER(IntKi), PARAMETER :: TwHt4MLzt = 875 - INTEGER(IntKi), PARAMETER :: TwHt5MLxt = 876 - INTEGER(IntKi), PARAMETER :: TwHt5MLyt = 877 - INTEGER(IntKi), PARAMETER :: TwHt5MLzt = 878 - INTEGER(IntKi), PARAMETER :: TwHt6MLxt = 879 - INTEGER(IntKi), PARAMETER :: TwHt6MLyt = 880 - INTEGER(IntKi), PARAMETER :: TwHt6MLzt = 881 - INTEGER(IntKi), PARAMETER :: TwHt7MLxt = 882 - INTEGER(IntKi), PARAMETER :: TwHt7MLyt = 883 - INTEGER(IntKi), PARAMETER :: TwHt7MLzt = 884 - INTEGER(IntKi), PARAMETER :: TwHt8MLxt = 885 - INTEGER(IntKi), PARAMETER :: TwHt8MLyt = 886 - INTEGER(IntKi), PARAMETER :: TwHt8MLzt = 887 - INTEGER(IntKi), PARAMETER :: TwHt9MLxt = 888 - INTEGER(IntKi), PARAMETER :: TwHt9MLyt = 889 - INTEGER(IntKi), PARAMETER :: TwHt9MLzt = 890 - INTEGER(IntKi), PARAMETER :: TwHt1FLxt = 891 - INTEGER(IntKi), PARAMETER :: TwHt1FLyt = 892 - INTEGER(IntKi), PARAMETER :: TwHt1FLzt = 893 - INTEGER(IntKi), PARAMETER :: TwHt2FLxt = 894 - INTEGER(IntKi), PARAMETER :: TwHt2FLyt = 895 - INTEGER(IntKi), PARAMETER :: TwHt2FLzt = 896 - INTEGER(IntKi), PARAMETER :: TwHt3FLxt = 897 - INTEGER(IntKi), PARAMETER :: TwHt3FLyt = 898 - INTEGER(IntKi), PARAMETER :: TwHt3FLzt = 899 - INTEGER(IntKi), PARAMETER :: TwHt4FLxt = 900 - INTEGER(IntKi), PARAMETER :: TwHt4FLyt = 901 - INTEGER(IntKi), PARAMETER :: TwHt4FLzt = 902 - INTEGER(IntKi), PARAMETER :: TwHt5FLxt = 903 - INTEGER(IntKi), PARAMETER :: TwHt5FLyt = 904 - INTEGER(IntKi), PARAMETER :: TwHt5FLzt = 905 - INTEGER(IntKi), PARAMETER :: TwHt6FLxt = 906 - INTEGER(IntKi), PARAMETER :: TwHt6FLyt = 907 - INTEGER(IntKi), PARAMETER :: TwHt6FLzt = 908 - INTEGER(IntKi), PARAMETER :: TwHt7FLxt = 909 - INTEGER(IntKi), PARAMETER :: TwHt7FLyt = 910 - INTEGER(IntKi), PARAMETER :: TwHt7FLzt = 911 - INTEGER(IntKi), PARAMETER :: TwHt8FLxt = 912 - INTEGER(IntKi), PARAMETER :: TwHt8FLyt = 913 - INTEGER(IntKi), PARAMETER :: TwHt8FLzt = 914 - INTEGER(IntKi), PARAMETER :: TwHt9FLxt = 915 - INTEGER(IntKi), PARAMETER :: TwHt9FLyt = 916 - INTEGER(IntKi), PARAMETER :: TwHt9FLzt = 917 + INTEGER(IntKi), PARAMETER :: TwHt1MLxt = 869 + INTEGER(IntKi), PARAMETER :: TwHt1MLyt = 870 + INTEGER(IntKi), PARAMETER :: TwHt1MLzt = 871 + INTEGER(IntKi), PARAMETER :: TwHt2MLxt = 872 + INTEGER(IntKi), PARAMETER :: TwHt2MLyt = 873 + INTEGER(IntKi), PARAMETER :: TwHt2MLzt = 874 + INTEGER(IntKi), PARAMETER :: TwHt3MLxt = 875 + INTEGER(IntKi), PARAMETER :: TwHt3MLyt = 876 + INTEGER(IntKi), PARAMETER :: TwHt3MLzt = 877 + INTEGER(IntKi), PARAMETER :: TwHt4MLxt = 878 + INTEGER(IntKi), PARAMETER :: TwHt4MLyt = 879 + INTEGER(IntKi), PARAMETER :: TwHt4MLzt = 880 + INTEGER(IntKi), PARAMETER :: TwHt5MLxt = 881 + INTEGER(IntKi), PARAMETER :: TwHt5MLyt = 882 + INTEGER(IntKi), PARAMETER :: TwHt5MLzt = 883 + INTEGER(IntKi), PARAMETER :: TwHt6MLxt = 884 + INTEGER(IntKi), PARAMETER :: TwHt6MLyt = 885 + INTEGER(IntKi), PARAMETER :: TwHt6MLzt = 886 + INTEGER(IntKi), PARAMETER :: TwHt7MLxt = 887 + INTEGER(IntKi), PARAMETER :: TwHt7MLyt = 888 + INTEGER(IntKi), PARAMETER :: TwHt7MLzt = 889 + INTEGER(IntKi), PARAMETER :: TwHt8MLxt = 890 + INTEGER(IntKi), PARAMETER :: TwHt8MLyt = 891 + INTEGER(IntKi), PARAMETER :: TwHt8MLzt = 892 + INTEGER(IntKi), PARAMETER :: TwHt9MLxt = 893 + INTEGER(IntKi), PARAMETER :: TwHt9MLyt = 894 + INTEGER(IntKi), PARAMETER :: TwHt9MLzt = 895 + INTEGER(IntKi), PARAMETER :: TwHt1FLxt = 896 + INTEGER(IntKi), PARAMETER :: TwHt1FLyt = 897 + INTEGER(IntKi), PARAMETER :: TwHt1FLzt = 898 + INTEGER(IntKi), PARAMETER :: TwHt2FLxt = 899 + INTEGER(IntKi), PARAMETER :: TwHt2FLyt = 900 + INTEGER(IntKi), PARAMETER :: TwHt2FLzt = 901 + INTEGER(IntKi), PARAMETER :: TwHt3FLxt = 902 + INTEGER(IntKi), PARAMETER :: TwHt3FLyt = 903 + INTEGER(IntKi), PARAMETER :: TwHt3FLzt = 904 + INTEGER(IntKi), PARAMETER :: TwHt4FLxt = 905 + INTEGER(IntKi), PARAMETER :: TwHt4FLyt = 906 + INTEGER(IntKi), PARAMETER :: TwHt4FLzt = 907 + INTEGER(IntKi), PARAMETER :: TwHt5FLxt = 908 + INTEGER(IntKi), PARAMETER :: TwHt5FLyt = 909 + INTEGER(IntKi), PARAMETER :: TwHt5FLzt = 910 + INTEGER(IntKi), PARAMETER :: TwHt6FLxt = 911 + INTEGER(IntKi), PARAMETER :: TwHt6FLyt = 912 + INTEGER(IntKi), PARAMETER :: TwHt6FLzt = 913 + INTEGER(IntKi), PARAMETER :: TwHt7FLxt = 914 + INTEGER(IntKi), PARAMETER :: TwHt7FLyt = 915 + INTEGER(IntKi), PARAMETER :: TwHt7FLzt = 916 + INTEGER(IntKi), PARAMETER :: TwHt8FLxt = 917 + INTEGER(IntKi), PARAMETER :: TwHt8FLyt = 918 + INTEGER(IntKi), PARAMETER :: TwHt8FLzt = 919 + INTEGER(IntKi), PARAMETER :: TwHt9FLxt = 920 + INTEGER(IntKi), PARAMETER :: TwHt9FLyt = 921 + INTEGER(IntKi), PARAMETER :: TwHt9FLzt = 922 ! Internal Degrees of Freedom: - INTEGER(IntKi), PARAMETER :: Q_B1E1 = 918 - INTEGER(IntKi), PARAMETER :: Q_B2E1 = 919 - INTEGER(IntKi), PARAMETER :: Q_B3E1 = 920 - INTEGER(IntKi), PARAMETER :: Q_B1F1 = 921 - INTEGER(IntKi), PARAMETER :: Q_B2F1 = 922 - INTEGER(IntKi), PARAMETER :: Q_B3F1 = 923 - INTEGER(IntKi), PARAMETER :: Q_B1F2 = 924 - INTEGER(IntKi), PARAMETER :: Q_B2F2 = 925 - INTEGER(IntKi), PARAMETER :: Q_B3F2 = 926 - INTEGER(IntKi), PARAMETER :: Q_Teet = 927 - INTEGER(IntKi), PARAMETER :: Q_DrTr = 928 - INTEGER(IntKi), PARAMETER :: Q_GeAz = 929 - INTEGER(IntKi), PARAMETER :: Q_RFrl = 930 - INTEGER(IntKi), PARAMETER :: Q_TFrl = 931 - INTEGER(IntKi), PARAMETER :: Q_Yaw = 932 - INTEGER(IntKi), PARAMETER :: Q_TFA1 = 933 - INTEGER(IntKi), PARAMETER :: Q_TSS1 = 934 - INTEGER(IntKi), PARAMETER :: Q_TFA2 = 935 - INTEGER(IntKi), PARAMETER :: Q_TSS2 = 936 - INTEGER(IntKi), PARAMETER :: Q_Sg = 937 - INTEGER(IntKi), PARAMETER :: Q_Sw = 938 - INTEGER(IntKi), PARAMETER :: Q_Hv = 939 - INTEGER(IntKi), PARAMETER :: Q_R = 940 - INTEGER(IntKi), PARAMETER :: Q_P = 941 - INTEGER(IntKi), PARAMETER :: Q_Y = 942 - INTEGER(IntKi), PARAMETER :: QD_B1E1 = 943 - INTEGER(IntKi), PARAMETER :: QD_B2E1 = 944 - INTEGER(IntKi), PARAMETER :: QD_B3E1 = 945 - INTEGER(IntKi), PARAMETER :: QD_B1F1 = 946 - INTEGER(IntKi), PARAMETER :: QD_B2F1 = 947 - INTEGER(IntKi), PARAMETER :: QD_B3F1 = 948 - INTEGER(IntKi), PARAMETER :: QD_B1F2 = 949 - INTEGER(IntKi), PARAMETER :: QD_B2F2 = 950 - INTEGER(IntKi), PARAMETER :: QD_B3F2 = 951 - INTEGER(IntKi), PARAMETER :: QD_Teet = 952 - INTEGER(IntKi), PARAMETER :: QD_DrTr = 953 - INTEGER(IntKi), PARAMETER :: QD_GeAz = 954 - INTEGER(IntKi), PARAMETER :: QD_RFrl = 955 - INTEGER(IntKi), PARAMETER :: QD_TFrl = 956 - INTEGER(IntKi), PARAMETER :: QD_Yaw = 957 - INTEGER(IntKi), PARAMETER :: QD_TFA1 = 958 - INTEGER(IntKi), PARAMETER :: QD_TSS1 = 959 - INTEGER(IntKi), PARAMETER :: QD_TFA2 = 960 - INTEGER(IntKi), PARAMETER :: QD_TSS2 = 961 - INTEGER(IntKi), PARAMETER :: QD_Sg = 962 - INTEGER(IntKi), PARAMETER :: QD_Sw = 963 - INTEGER(IntKi), PARAMETER :: QD_Hv = 964 - INTEGER(IntKi), PARAMETER :: QD_R = 965 - INTEGER(IntKi), PARAMETER :: QD_P = 966 - INTEGER(IntKi), PARAMETER :: QD_Y = 967 - INTEGER(IntKi), PARAMETER :: QD2_B1E1 = 968 - INTEGER(IntKi), PARAMETER :: QD2_B2E1 = 969 - INTEGER(IntKi), PARAMETER :: QD2_B3E1 = 970 - INTEGER(IntKi), PARAMETER :: QD2_B1F1 = 971 - INTEGER(IntKi), PARAMETER :: QD2_B2F1 = 972 - INTEGER(IntKi), PARAMETER :: QD2_B3F1 = 973 - INTEGER(IntKi), PARAMETER :: QD2_B1F2 = 974 - INTEGER(IntKi), PARAMETER :: QD2_B2F2 = 975 - INTEGER(IntKi), PARAMETER :: QD2_B3F2 = 976 - INTEGER(IntKi), PARAMETER :: QD2_Teet = 977 - INTEGER(IntKi), PARAMETER :: QD2_DrTr = 978 - INTEGER(IntKi), PARAMETER :: QD2_GeAz = 979 - INTEGER(IntKi), PARAMETER :: QD2_RFrl = 980 - INTEGER(IntKi), PARAMETER :: QD2_TFrl = 981 - INTEGER(IntKi), PARAMETER :: QD2_Yaw = 982 - INTEGER(IntKi), PARAMETER :: QD2_TFA1 = 983 - INTEGER(IntKi), PARAMETER :: QD2_TSS1 = 984 - INTEGER(IntKi), PARAMETER :: QD2_TFA2 = 985 - INTEGER(IntKi), PARAMETER :: QD2_TSS2 = 986 - INTEGER(IntKi), PARAMETER :: QD2_Sg = 987 - INTEGER(IntKi), PARAMETER :: QD2_Sw = 988 - INTEGER(IntKi), PARAMETER :: QD2_Hv = 989 - INTEGER(IntKi), PARAMETER :: QD2_R = 990 - INTEGER(IntKi), PARAMETER :: QD2_P = 991 - INTEGER(IntKi), PARAMETER :: QD2_Y = 992 + INTEGER(IntKi), PARAMETER :: Q_B1E1 = 923 + INTEGER(IntKi), PARAMETER :: Q_B2E1 = 924 + INTEGER(IntKi), PARAMETER :: Q_B3E1 = 925 + INTEGER(IntKi), PARAMETER :: Q_B1F1 = 926 + INTEGER(IntKi), PARAMETER :: Q_B2F1 = 927 + INTEGER(IntKi), PARAMETER :: Q_B3F1 = 928 + INTEGER(IntKi), PARAMETER :: Q_B1F2 = 929 + INTEGER(IntKi), PARAMETER :: Q_B2F2 = 930 + INTEGER(IntKi), PARAMETER :: Q_B3F2 = 931 + INTEGER(IntKi), PARAMETER :: Q_Teet = 932 + INTEGER(IntKi), PARAMETER :: Q_DrTr = 933 + INTEGER(IntKi), PARAMETER :: Q_GeAz = 934 + INTEGER(IntKi), PARAMETER :: Q_RFrl = 935 + INTEGER(IntKi), PARAMETER :: Q_TFrl = 936 + INTEGER(IntKi), PARAMETER :: Q_Yaw = 937 + INTEGER(IntKi), PARAMETER :: Q_TFA1 = 938 + INTEGER(IntKi), PARAMETER :: Q_TSS1 = 939 + INTEGER(IntKi), PARAMETER :: Q_TFA2 = 940 + INTEGER(IntKi), PARAMETER :: Q_TSS2 = 941 + INTEGER(IntKi), PARAMETER :: Q_Sg = 942 + INTEGER(IntKi), PARAMETER :: Q_Sw = 943 + INTEGER(IntKi), PARAMETER :: Q_Hv = 944 + INTEGER(IntKi), PARAMETER :: Q_R = 945 + INTEGER(IntKi), PARAMETER :: Q_P = 946 + INTEGER(IntKi), PARAMETER :: Q_Y = 947 + INTEGER(IntKi), PARAMETER :: QD_B1E1 = 948 + INTEGER(IntKi), PARAMETER :: QD_B2E1 = 949 + INTEGER(IntKi), PARAMETER :: QD_B3E1 = 950 + INTEGER(IntKi), PARAMETER :: QD_B1F1 = 951 + INTEGER(IntKi), PARAMETER :: QD_B2F1 = 952 + INTEGER(IntKi), PARAMETER :: QD_B3F1 = 953 + INTEGER(IntKi), PARAMETER :: QD_B1F2 = 954 + INTEGER(IntKi), PARAMETER :: QD_B2F2 = 955 + INTEGER(IntKi), PARAMETER :: QD_B3F2 = 956 + INTEGER(IntKi), PARAMETER :: QD_Teet = 957 + INTEGER(IntKi), PARAMETER :: QD_DrTr = 958 + INTEGER(IntKi), PARAMETER :: QD_GeAz = 959 + INTEGER(IntKi), PARAMETER :: QD_RFrl = 960 + INTEGER(IntKi), PARAMETER :: QD_TFrl = 961 + INTEGER(IntKi), PARAMETER :: QD_Yaw = 962 + INTEGER(IntKi), PARAMETER :: QD_TFA1 = 963 + INTEGER(IntKi), PARAMETER :: QD_TSS1 = 964 + INTEGER(IntKi), PARAMETER :: QD_TFA2 = 965 + INTEGER(IntKi), PARAMETER :: QD_TSS2 = 966 + INTEGER(IntKi), PARAMETER :: QD_Sg = 967 + INTEGER(IntKi), PARAMETER :: QD_Sw = 968 + INTEGER(IntKi), PARAMETER :: QD_Hv = 969 + INTEGER(IntKi), PARAMETER :: QD_R = 970 + INTEGER(IntKi), PARAMETER :: QD_P = 971 + INTEGER(IntKi), PARAMETER :: QD_Y = 972 + INTEGER(IntKi), PARAMETER :: QD2_B1E1 = 973 + INTEGER(IntKi), PARAMETER :: QD2_B2E1 = 974 + INTEGER(IntKi), PARAMETER :: QD2_B3E1 = 975 + INTEGER(IntKi), PARAMETER :: QD2_B1F1 = 976 + INTEGER(IntKi), PARAMETER :: QD2_B2F1 = 977 + INTEGER(IntKi), PARAMETER :: QD2_B3F1 = 978 + INTEGER(IntKi), PARAMETER :: QD2_B1F2 = 979 + INTEGER(IntKi), PARAMETER :: QD2_B2F2 = 980 + INTEGER(IntKi), PARAMETER :: QD2_B3F2 = 981 + INTEGER(IntKi), PARAMETER :: QD2_Teet = 982 + INTEGER(IntKi), PARAMETER :: QD2_DrTr = 983 + INTEGER(IntKi), PARAMETER :: QD2_GeAz = 984 + INTEGER(IntKi), PARAMETER :: QD2_RFrl = 985 + INTEGER(IntKi), PARAMETER :: QD2_TFrl = 986 + INTEGER(IntKi), PARAMETER :: QD2_Yaw = 987 + INTEGER(IntKi), PARAMETER :: QD2_TFA1 = 988 + INTEGER(IntKi), PARAMETER :: QD2_TSS1 = 989 + INTEGER(IntKi), PARAMETER :: QD2_TFA2 = 990 + INTEGER(IntKi), PARAMETER :: QD2_TSS2 = 991 + INTEGER(IntKi), PARAMETER :: QD2_Sg = 992 + INTEGER(IntKi), PARAMETER :: QD2_Sw = 993 + INTEGER(IntKi), PARAMETER :: QD2_Hv = 994 + INTEGER(IntKi), PARAMETER :: QD2_R = 995 + INTEGER(IntKi), PARAMETER :: QD2_P = 996 + INTEGER(IntKi), PARAMETER :: QD2_Y = 997 ! The maximum number of output channels which can be output by the code. - INTEGER(IntKi), PARAMETER :: MaxOutPts = 992 + INTEGER(IntKi), PARAMETER :: MaxOutPts = 997 -!End of code generated by Matlab script +!End of code generated by Matlab script Write_ChckOutLst ! =================================================================================================== - INTEGER, PARAMETER :: TipDxc( 3) = (/TipDxc1, TipDxc2, TipDxc3/) INTEGER, PARAMETER :: TipDyc( 3) = (/TipDyc1, TipDyc2, TipDyc3/) INTEGER, PARAMETER :: TipDzc( 3) = (/TipDzc1, TipDzc2, TipDzc3/) @@ -3505,6 +3519,47 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile RETURN END IF + !---------------------- YAW-FRICTION -------------------------------------------- + CALL ReadCom( UnIn, InputFile, 'Section Header: Yaw-Friction', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + ! YawFrctMod - Yaw-friction model switch (-): + CALL ReadVar( UnIn, InputFile, InputFileData%YawFrctMod, "YawFrctMod", "Yaw-friction model switch (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + ! M_CSmax - Maximum Coulomb friction torque (N-m): + CALL ReadVar( UnIn, InputFile, InputFileData%M_CSmax, "M_CSmax", "Maximum Coulomb friction torque (N-m)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + ! M_CD - Dynamic friction moment at null yaw rate (N-m): + CALL ReadVar( UnIn, InputFile, InputFileData%M_CD, "M_CD", "Dynamic friction moment at null yaw rate (N-m)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + ! sig_v - Viscous friction coefficiant (N-m s/rad): + CALL ReadVar( UnIn, InputFile, InputFileData%sig_v, "sig_v", "Viscous friction coefficient (N-m/(rad/s))", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + !---------------------- DRIVETRAIN ---------------------------------------------- CALL ReadCom( UnIn, InputFile, 'Section Header: Drivetrain', ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -4533,6 +4588,14 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta END IF + !Yaw-Friction User input checks + IF ( ( InputFileData%YawFrctMod /= 0_IntKi ) .AND. ( InputFileData%YawFrctMod /= 1_IntKi ) .AND. & + ( InputFileData%YawFrctMod /= 2_IntKi ) .AND. ( InputFileData%YawFrctMod /= 3_IntKi )) & + CALL SetErrStat( ErrID_Fatal, 'YawFrctMod must be 0, 1, 2, or 3',ErrStat,ErrMsg,RoutineName) + IF ( InputFileData%M_CD < 0_R8Ki ) CALL SetErrStat( ErrID_Fatal, 'M_CD must be greater than or equal to 0.',ErrStat,ErrMsg,RoutineName ) + IF ( InputFileData%M_CSmax < 0_R8Ki ) CALL SetErrStat( ErrID_Fatal, 'M_CSmax must be greater than or equal to 0.',ErrStat,ErrMsg,RoutineName ) + IF ( InputFileData%sig_v < 0_R8Ki ) CALL SetErrStat( ErrID_Fatal, 'sig_v must be greater than or equal to 0.',ErrStat,ErrMsg,RoutineName ) + !bjj: since ED doesn't actually use OutFmt at this point, I'm going to remove this check and warning message !!!! ! Check that InputFileData%OutFmt is a valid format specifier and will fit over the column headings !!!!CALL ChkRealFmtStr( InputFileData%OutFmt, 'OutFmt', FmtWidth, ErrStat2, ErrMsg2 ) diff --git a/modules/elastodyn/src/ElastoDyn_Registry.txt b/modules/elastodyn/src/ElastoDyn_Registry.txt index 935d2ccc46..c8bdd12b08 100644 --- a/modules/elastodyn/src/ElastoDyn_Registry.txt +++ b/modules/elastodyn/src/ElastoDyn_Registry.txt @@ -164,6 +164,10 @@ typedef ^ ED_InputFile ReKi TeetSStP - - - "Rotor-teeter soft-stop position" rad typedef ^ ED_InputFile ReKi TeetHStP - - - "Rotor-teeter hard-stop position" radians typedef ^ ED_InputFile ReKi TeetSSSp - - - "Rotor-teeter soft-stop linear-spring constant" N-m/rad typedef ^ ED_InputFile ReKi TeetHSSp - - - "Rotor-teeter hard-stop linear-spring constant" N-m/rad +typedef ^ ED_InputFile IntKi YawFrctMod - - - "Identifier for YawFrctMod (0 [no friction], 1 [does not use Fz at bearing], 2 [does use Fz at bearing], or 3 [user defined model]" - +typedef ^ ED_InputFile R8Ki M_CD - - - "Dynamic friction moment at null yaw rate" N-m +typedef ^ ED_InputFile R8Ki M_CSMAX - - - "Maximum Coulomb friction torque" N-m +typedef ^ ED_InputFile R8Ki sig_v - - - "Viscous friction coefficient" N-m/(rad/s) typedef ^ ED_InputFile ReKi GBoxEff - - - "Gearbox efficiency" % typedef ^ ED_InputFile ReKi GBRatio - - - "Gearbox ratio" - typedef ^ ED_InputFile ReKi DTTorSpr - - - "Drivetrain torsional spring" N-m/rad @@ -492,6 +496,7 @@ typedef ^ ED_RtHndSide ReKi TFrlMom - - - "The total tail-furl spring and damper typedef ^ ED_RtHndSide ReKi RFrlMom - - - "The total rotor-furl spring and damper moment" typedef ^ ED_RtHndSide ReKi GBoxEffFac - - - "The factor used to apply the gearbox efficiency effects to the equation associated with the generator DOF" typedef ^ ED_RtHndSide ReKi rSAerCen {:}{:}{:} - - "aerodynamic pitching moment arm (i.e., the position vector from point S on the blade to the aerodynamic center of the element)" +typedef ^ ED_RtHndSide ReKi YawFriMom - - - "Yaw Friction Moment" kN-m # ..... States .................................................................................................................... # Define continuous (differentiable) states here: @@ -512,6 +517,10 @@ typedef ^ OtherStateType ReKi HSSBrTrq - - - "HSSBrTrq from update states; a hac typedef ^ OtherStateType ReKi HSSBrTrqC - - - "Commanded HSS brake torque (adjusted for sign)" N-m typedef ^ OtherStateType IntKi SgnPrvLSTQ - - - "The sign of the low-speed shaft torque from the previous call to RtHS(). This is calculated at the end of RtHS(). NOTE: The low-speed shaft torque is assumed to be positive at the beginning of the run!" - typedef ^ OtherStateType IntKi SgnLSTQ {ED_NMX} - - "history of sign of LSTQ" +typedef ^ OtherStateType ReKi Mfhat - - - "Final Yaw Friction Torque" N-m +typedef ^ OtherStateType ReKi YawFriMfp - - - "Yaw Friction Torque to bring yaw system to a stop at current time step" N-m +typedef ^ OtherStateType R8Ki OmegaTn - - - "Yaw rate at t_n used to calculate friction torque and yaw rate at t_n+1" rad/s +typedef ^ OtherStateType R8Ki OmegaDotTn - - - "Yaw acceleration at t_n used to calculate friction torque and yaw rate at t_n+1" rad/s^2 # ..... Misc Vars ................................................................................................................ typedef ^ MiscVarType ED_CoordSys CoordSys - - - "Coordinate systems in the FAST framework" - @@ -524,6 +533,9 @@ typedef ^ MiscVarType IntKi AugMat_pivot {:} - - "Pivot column for AugMat in LAP typedef ^ MiscVarType ReKi OgnlGeAzRo {:} - - "Original DOF_GeAz row in AugMat" - typedef ^ MiscVarType R8Ki QD2T {:} - - "Solution (acceleration) vector; the first time derivative of QDT" typedef ^ MiscVarType Logical IgnoreMod - - - "whether to ignore the modulo in ED outputs (necessary for linearization perturbations)" - +typedef ^ MiscVarType ReKi OgnlYawRow {:} - - "Original DOF_Yaw row in AugMat" - +typedef ^ MiscVarType ReKi FrcONcRt - - - "Fz acting on yaw bearing including inertial contributions" N +typedef ^ MiscVarType ReKi YawFriMz - - - "External loading on yaw bearing not including inertial contributions" N-m # ..... Parameters ................................................................................................................ # Define parameters here: @@ -740,6 +752,13 @@ typedef ^ ParameterType ReKi PtfmCMxt - - - "Downwind distance from the ground l typedef ^ ParameterType ReKi PtfmCMyt - - - "Lateral distance from the ground level [onshore], MSL [offshore wind or floating MHK], or seabed [fixed MHK] to the platform CM" meters typedef ^ ParameterType LOGICAL BD4Blades - - - "flag to determine if BeamDyn is computing blade loads (true) or ElastoDyn is (false)" - typedef ^ ParameterType LOGICAL UseAD14 - - - "flag to determine if AeroDyn14 is being used. Will remove this later when we've replaced AD14." - +typedef ^ ParameterType IntKi YawFrctMod - - - "Identifier for YawFrctMod (0 [no friction], 1 [does not use Fz at bearing], or 2 [does use Fz at bearing]" - +typedef ^ ParameterType R8Ki M_CD - - - "Dynamic friction moment at null yaw rate" N-m +typedef ^ ParameterType R8Ki M_CSMAX - - - "Maximum Coulomb friction torque" N-m +typedef ^ ParameterType R8Ki sig_v - - - "Viscous friction coefficient" N-m/(rad/s) +#typedef ^ ParameterType R8Ki thr_omg - - - "Yaw rate stiction threshold" rad/s +#typedef ^ ParameterType R8Ki thr_omgdot - - - "Yaw acceleration stiction threshold" rad/s^2 + # .... ED_AllBlNds option ........................................................................................................ typedef ^ ParameterType IntKi BldNd_NumOuts - - - "Number of requested output channels per blade node (ED_AllBldNdOuts)" - typedef ^ ParameterType IntKi BldNd_TotNumOuts - - - "Total number of requested output channels of blade node information (BldNd_NumOuts * BldNd_BlOutNd * BldNd_BladesOut -- ED_AllBldNdOuts)" - diff --git a/modules/elastodyn/src/ElastoDyn_Types.f90 b/modules/elastodyn/src/ElastoDyn_Types.f90 index c80a1c72ca..99c18e3276 100644 --- a/modules/elastodyn/src/ElastoDyn_Types.f90 +++ b/modules/elastodyn/src/ElastoDyn_Types.f90 @@ -186,6 +186,10 @@ MODULE ElastoDyn_Types REAL(ReKi) :: TeetHStP = 0.0_ReKi !< Rotor-teeter hard-stop position [radians] REAL(ReKi) :: TeetSSSp = 0.0_ReKi !< Rotor-teeter soft-stop linear-spring constant [N-m/rad] REAL(ReKi) :: TeetHSSp = 0.0_ReKi !< Rotor-teeter hard-stop linear-spring constant [N-m/rad] + INTEGER(IntKi) :: YawFrctMod = 0_IntKi !< Identifier for YawFrctMod (0 [no friction], 1 [does not use Fz at bearing], 2 [does use Fz at bearing], or 3 [user defined model] [-] + REAL(R8Ki) :: M_CD = 0.0_R8Ki !< Dynamic friction moment at null yaw rate [N-m] + REAL(R8Ki) :: M_CSMAX = 0.0_R8Ki !< Maximum Coulomb friction torque [N-m] + REAL(R8Ki) :: sig_v = 0.0_R8Ki !< Viscous friction coefficient [N-m/(rad/s)] REAL(ReKi) :: GBoxEff = 0.0_ReKi !< Gearbox efficiency [%] REAL(ReKi) :: GBRatio = 0.0_ReKi !< Gearbox ratio [-] REAL(ReKi) :: DTTorSpr = 0.0_ReKi !< Drivetrain torsional spring [N-m/rad] @@ -492,6 +496,7 @@ MODULE ElastoDyn_Types REAL(ReKi) :: RFrlMom = 0.0_ReKi !< The total rotor-furl spring and damper moment [-] REAL(ReKi) :: GBoxEffFac = 0.0_ReKi !< The factor used to apply the gearbox efficiency effects to the equation associated with the generator DOF [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: rSAerCen !< aerodynamic pitching moment arm (i.e., the position vector from point S on the blade to the aerodynamic center of the element) [-] + REAL(ReKi) :: YawFriMom = 0.0_ReKi !< Yaw Friction Moment [kN-m] END TYPE ED_RtHndSide ! ======================= ! ========= ED_ContinuousStateType ======= @@ -519,6 +524,10 @@ MODULE ElastoDyn_Types REAL(ReKi) :: HSSBrTrqC = 0.0_ReKi !< Commanded HSS brake torque (adjusted for sign) [N-m] INTEGER(IntKi) :: SgnPrvLSTQ = 0_IntKi !< The sign of the low-speed shaft torque from the previous call to RtHS(). This is calculated at the end of RtHS(). NOTE: The low-speed shaft torque is assumed to be positive at the beginning of the run! [-] INTEGER(IntKi) , DIMENSION(1:ED_NMX) :: SgnLSTQ = 0_IntKi !< history of sign of LSTQ [-] + REAL(ReKi) :: Mfhat = 0.0_ReKi !< Final Yaw Friction Torque [N-m] + REAL(ReKi) :: YawFriMfp = 0.0_ReKi !< Yaw Friction Torque to bring yaw system to a stop at current time step [N-m] + REAL(R8Ki) :: OmegaTn = 0.0_R8Ki !< Yaw rate at t_n used to calculate friction torque and yaw rate at t_n+1 [rad/s] + REAL(R8Ki) :: OmegaDotTn = 0.0_R8Ki !< Yaw acceleration at t_n used to calculate friction torque and yaw rate at t_n+1 [rad/s^2] END TYPE ED_OtherStateType ! ======================= ! ========= ED_MiscVarType ======= @@ -533,6 +542,9 @@ MODULE ElastoDyn_Types REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: OgnlGeAzRo !< Original DOF_GeAz row in AugMat [-] REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: QD2T !< Solution (acceleration) vector; the first time derivative of QDT [-] LOGICAL :: IgnoreMod = .false. !< whether to ignore the modulo in ED outputs (necessary for linearization perturbations) [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: OgnlYawRow !< Original DOF_Yaw row in AugMat [-] + REAL(ReKi) :: FrcONcRt = 0.0_ReKi !< Fz acting on yaw bearing including inertial contributions [N] + REAL(ReKi) :: YawFriMz = 0.0_ReKi !< External loading on yaw bearing not including inertial contributions [N-m] END TYPE ED_MiscVarType ! ======================= ! ========= ED_ParameterType ======= @@ -747,6 +759,10 @@ MODULE ElastoDyn_Types REAL(ReKi) :: PtfmCMyt = 0.0_ReKi !< Lateral distance from the ground level [onshore], MSL [offshore wind or floating MHK], or seabed [fixed MHK] to the platform CM [meters] LOGICAL :: BD4Blades = .false. !< flag to determine if BeamDyn is computing blade loads (true) or ElastoDyn is (false) [-] LOGICAL :: UseAD14 = .false. !< flag to determine if AeroDyn14 is being used. Will remove this later when we've replaced AD14. [-] + INTEGER(IntKi) :: YawFrctMod = 0_IntKi !< Identifier for YawFrctMod (0 [no friction], 1 [does not use Fz at bearing], or 2 [does use Fz at bearing] [-] + REAL(R8Ki) :: M_CD = 0.0_R8Ki !< Dynamic friction moment at null yaw rate [N-m] + REAL(R8Ki) :: M_CSMAX = 0.0_R8Ki !< Maximum Coulomb friction torque [N-m] + REAL(R8Ki) :: sig_v = 0.0_R8Ki !< Viscous friction coefficient [N-m/(rad/s)] INTEGER(IntKi) :: BldNd_NumOuts = 0_IntKi !< Number of requested output channels per blade node (ED_AllBldNdOuts) [-] INTEGER(IntKi) :: BldNd_TotNumOuts = 0_IntKi !< Total number of requested output channels of blade node information (BldNd_NumOuts * BldNd_BlOutNd * BldNd_BladesOut -- ED_AllBldNdOuts) [-] TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: BldNd_OutParam !< Names and units (and other characteristics) of all requested output parameters [-] @@ -1656,6 +1672,10 @@ subroutine ED_CopyInputFile(SrcInputFileData, DstInputFileData, CtrlCode, ErrSta DstInputFileData%TeetHStP = SrcInputFileData%TeetHStP DstInputFileData%TeetSSSp = SrcInputFileData%TeetSSSp DstInputFileData%TeetHSSp = SrcInputFileData%TeetHSSp + DstInputFileData%YawFrctMod = SrcInputFileData%YawFrctMod + DstInputFileData%M_CD = SrcInputFileData%M_CD + DstInputFileData%M_CSMAX = SrcInputFileData%M_CSMAX + DstInputFileData%sig_v = SrcInputFileData%sig_v DstInputFileData%GBoxEff = SrcInputFileData%GBoxEff DstInputFileData%GBRatio = SrcInputFileData%GBRatio DstInputFileData%DTTorSpr = SrcInputFileData%DTTorSpr @@ -2018,6 +2038,10 @@ subroutine ED_PackInputFile(RF, Indata) call RegPack(RF, InData%TeetHStP) call RegPack(RF, InData%TeetSSSp) call RegPack(RF, InData%TeetHSSp) + call RegPack(RF, InData%YawFrctMod) + call RegPack(RF, InData%M_CD) + call RegPack(RF, InData%M_CSMAX) + call RegPack(RF, InData%sig_v) call RegPack(RF, InData%GBoxEff) call RegPack(RF, InData%GBRatio) call RegPack(RF, InData%DTTorSpr) @@ -2211,6 +2235,10 @@ subroutine ED_UnPackInputFile(RF, OutData) call RegUnpack(RF, OutData%TeetHStP); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TeetSSSp); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TeetHSSp); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YawFrctMod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%M_CD); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%M_CSMAX); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%sig_v); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GBoxEff); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GBRatio); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%DTTorSpr); if (RegCheckErr(RF, RoutineName)) return @@ -3965,6 +3993,7 @@ subroutine ED_CopyRtHndSide(SrcRtHndSideData, DstRtHndSideData, CtrlCode, ErrSta end if DstRtHndSideData%rSAerCen = SrcRtHndSideData%rSAerCen end if + DstRtHndSideData%YawFriMom = SrcRtHndSideData%YawFriMom end subroutine subroutine ED_DestroyRtHndSide(RtHndSideData, ErrStat, ErrMsg) @@ -4331,6 +4360,7 @@ subroutine ED_PackRtHndSide(RF, Indata) call RegPack(RF, InData%RFrlMom) call RegPack(RF, InData%GBoxEffFac) call RegPackAlloc(RF, InData%rSAerCen) + call RegPack(RF, InData%YawFriMom) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4485,6 +4515,7 @@ subroutine ED_UnPackRtHndSide(RF, OutData) call RegUnpack(RF, OutData%RFrlMom); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GBoxEffFac); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%rSAerCen); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YawFriMom); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine ED_CopyContState(SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg) @@ -4674,6 +4705,10 @@ subroutine ED_CopyOtherState(SrcOtherStateData, DstOtherStateData, CtrlCode, Err DstOtherStateData%HSSBrTrqC = SrcOtherStateData%HSSBrTrqC DstOtherStateData%SgnPrvLSTQ = SrcOtherStateData%SgnPrvLSTQ DstOtherStateData%SgnLSTQ = SrcOtherStateData%SgnLSTQ + DstOtherStateData%Mfhat = SrcOtherStateData%Mfhat + DstOtherStateData%YawFriMfp = SrcOtherStateData%YawFriMfp + DstOtherStateData%OmegaTn = SrcOtherStateData%OmegaTn + DstOtherStateData%OmegaDotTn = SrcOtherStateData%OmegaDotTn end subroutine subroutine ED_DestroyOtherState(OtherStateData, ErrStat, ErrMsg) @@ -4716,6 +4751,10 @@ subroutine ED_PackOtherState(RF, Indata) call RegPack(RF, InData%HSSBrTrqC) call RegPack(RF, InData%SgnPrvLSTQ) call RegPack(RF, InData%SgnLSTQ) + call RegPack(RF, InData%Mfhat) + call RegPack(RF, InData%YawFriMfp) + call RegPack(RF, InData%OmegaTn) + call RegPack(RF, InData%OmegaDotTn) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4739,6 +4778,10 @@ subroutine ED_UnPackOtherState(RF, OutData) call RegUnpack(RF, OutData%HSSBrTrqC); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%SgnPrvLSTQ); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%SgnLSTQ); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Mfhat); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YawFriMfp); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%OmegaTn); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%OmegaDotTn); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine ED_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) @@ -4844,6 +4887,20 @@ subroutine ED_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) DstMiscData%QD2T = SrcMiscData%QD2T end if DstMiscData%IgnoreMod = SrcMiscData%IgnoreMod + if (allocated(SrcMiscData%OgnlYawRow)) then + LB(1:1) = lbound(SrcMiscData%OgnlYawRow, kind=B8Ki) + UB(1:1) = ubound(SrcMiscData%OgnlYawRow, kind=B8Ki) + if (.not. allocated(DstMiscData%OgnlYawRow)) then + allocate(DstMiscData%OgnlYawRow(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%OgnlYawRow.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstMiscData%OgnlYawRow = SrcMiscData%OgnlYawRow + end if + DstMiscData%FrcONcRt = SrcMiscData%FrcONcRt + DstMiscData%YawFriMz = SrcMiscData%YawFriMz end subroutine subroutine ED_DestroyMisc(MiscData, ErrStat, ErrMsg) @@ -4880,6 +4937,9 @@ subroutine ED_DestroyMisc(MiscData, ErrStat, ErrMsg) if (allocated(MiscData%QD2T)) then deallocate(MiscData%QD2T) end if + if (allocated(MiscData%OgnlYawRow)) then + deallocate(MiscData%OgnlYawRow) + end if end subroutine subroutine ED_PackMisc(RF, Indata) @@ -4897,6 +4957,9 @@ subroutine ED_PackMisc(RF, Indata) call RegPackAlloc(RF, InData%OgnlGeAzRo) call RegPackAlloc(RF, InData%QD2T) call RegPack(RF, InData%IgnoreMod) + call RegPackAlloc(RF, InData%OgnlYawRow) + call RegPack(RF, InData%FrcONcRt) + call RegPack(RF, InData%YawFriMz) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4918,6 +4981,9 @@ subroutine ED_UnPackMisc(RF, OutData) call RegUnpackAlloc(RF, OutData%OgnlGeAzRo); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%QD2T); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%IgnoreMod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%OgnlYawRow); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%FrcONcRt); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YawFriMz); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine ED_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) @@ -5743,6 +5809,10 @@ subroutine ED_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%PtfmCMyt = SrcParamData%PtfmCMyt DstParamData%BD4Blades = SrcParamData%BD4Blades DstParamData%UseAD14 = SrcParamData%UseAD14 + DstParamData%YawFrctMod = SrcParamData%YawFrctMod + DstParamData%M_CD = SrcParamData%M_CD + DstParamData%M_CSMAX = SrcParamData%M_CSMAX + DstParamData%sig_v = SrcParamData%sig_v DstParamData%BldNd_NumOuts = SrcParamData%BldNd_NumOuts DstParamData%BldNd_TotNumOuts = SrcParamData%BldNd_TotNumOuts if (allocated(SrcParamData%BldNd_OutParam)) then @@ -6233,6 +6303,10 @@ subroutine ED_PackParam(RF, Indata) call RegPack(RF, InData%PtfmCMyt) call RegPack(RF, InData%BD4Blades) call RegPack(RF, InData%UseAD14) + call RegPack(RF, InData%YawFrctMod) + call RegPack(RF, InData%M_CD) + call RegPack(RF, InData%M_CSMAX) + call RegPack(RF, InData%sig_v) call RegPack(RF, InData%BldNd_NumOuts) call RegPack(RF, InData%BldNd_TotNumOuts) call RegPack(RF, allocated(InData%BldNd_OutParam)) @@ -6489,6 +6563,10 @@ subroutine ED_UnPackParam(RF, OutData) call RegUnpack(RF, OutData%PtfmCMyt); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%BD4Blades); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%UseAD14); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YawFrctMod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%M_CD); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%M_CSMAX); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%sig_v); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%BldNd_NumOuts); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%BldNd_TotNumOuts); if (RegCheckErr(RF, RoutineName)) return if (allocated(OutData%BldNd_OutParam)) deallocate(OutData%BldNd_OutParam) diff --git a/modules/extloads/CMakeLists.txt b/modules/extloads/CMakeLists.txt index b649f69557..43baa634f6 100644 --- a/modules/extloads/CMakeLists.txt +++ b/modules/extloads/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(extloadslib STATIC target_include_directories(extloadslib PUBLIC $ ) -target_link_libraries(extloadslib beamdynlib nwtclibs versioninfolib) +target_link_libraries(extloadslib beamdynlib nwtclibs versioninfolib ifwlib) set_target_properties(extloadslib PROPERTIES PUBLIC_HEADER "src/ExtLoadsDX_Types.h") install(TARGETS extloadslib diff --git a/modules/extloads/src/ExtLoads.f90 b/modules/extloads/src/ExtLoads.f90 index 86ae0c85d3..03b4404407 100644 --- a/modules/extloads/src/ExtLoads.f90 +++ b/modules/extloads/src/ExtLoads.f90 @@ -26,7 +26,10 @@ module ExtLoads use NWTC_Library use ExtLoads_Types - + use IfW_FlowField + use InflowWind_IO_Types + use InflowWind_IO + implicit none private @@ -40,7 +43,7 @@ module ExtLoads public :: ExtLd_CalcOutput ! Routine for computing outputs public :: ExtLd_ConvertOpDataForOpenFAST ! Routine to convert Output data for OpenFAST public :: ExtLd_ConvertInpDataForExtProg ! Routine to convert Input data for external programs - + contains !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets the initialization output data structure, which contains data to be returned to the calling program (e.g., @@ -86,21 +89,21 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM type(ExtLd_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated; type(ExtLd_MiscVarType), intent( out) :: m !< Miscellaneous variables type(ExtLd_ParameterType), intent( out) :: p !< Parameter variables - !! only the output mesh is initialized) - real(DbKi), intent(inout) :: interval !< Coupling interval in seconds: the rate that - !! (1) ExtLd_UpdateStates() is called in loose coupling & - !! (2) ExtLd_UpdateDiscState() is called in tight coupling. - !! Input is the suggested time from the glue code; - !! Output is the actual coupling interval that will be used - !! by the glue code. + !! only the output mesh is initialized) + real(DbKi), intent(inout) :: interval !< Coupling interval in seconds: the rate that + !! (1) ExtLd_UpdateStates() is called in loose coupling & + !! (2) ExtLd_UpdateDiscState() is called in tight coupling. + !! Input is the suggested time from the glue code; + !! Output is the actual coupling interval that will be used + !! by the glue code. type(ExtLd_InitOutputType), intent( out) :: 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 + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None ! Local variables integer(IntKi) :: i ! loop counter - + type(Points_InitInputType) :: Points_InitInput integer(IntKi) :: errStat2 ! temporary error status of the operation character(ErrMsgLen) :: errMsg2 ! temporary error message @@ -118,10 +121,7 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM p%NumBlds = InitInp%NumBlades call AllocAry(p%NumBldNds, p%NumBlds, 'NumBldNds', ErrStat2,ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return p%NumBldNds(:) = InitInp%NumBldNodes(:) p%nTotBldNds = sum(p%NumBldNds(:)) p%NumTwrNds = InitInp%NumTwrNds @@ -142,10 +142,7 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM call Init_u( u, p, InitInp, errStat2, errMsg2 ) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return ! Initialize discrete states @@ -159,11 +156,27 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM !............................................................................................ call Init_y(y, u, m, p, errStat2, errMsg2) ! do this after input meshes have been initialized call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return + !............................................................................................ + ! Initialize InflowWind FlowField + !............................................................................................ + if (associated(m%FlowField)) deallocate(m%FlowField) + allocate(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 + m%FlowField%FieldType = Point_FieldType + Points_InitInput%NumWindPoints = InitInp%nNodesVel + call IfW_Points_Init(Points_InitInput, m%FlowField%Points, ErrStat2, ErrMsg2); if (Failed()) return + + ! Set pointer to flow field in InitOut + InitOut%FlowField => m%FlowField + + write(*,*) 'Initializing InitOut ' !............................................................................................ @@ -172,13 +185,13 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM call ExtLd_SetInitOut(p, InitOut, errStat2, errMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - call Cleanup() contains - subroutine Cleanup() - - end subroutine Cleanup - + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + end subroutine ExtLd_Init !---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes ExtLoads meshes and output array variables for use during the simulation. diff --git a/modules/extloads/src/ExtLoads_Registry.txt b/modules/extloads/src/ExtLoads_Registry.txt index d70ba74433..5f3af5384d 100644 --- a/modules/extloads/src/ExtLoads_Registry.txt +++ b/modules/extloads/src/ExtLoads_Registry.txt @@ -15,6 +15,7 @@ ################################################################################################################################### # ...... Include files (definitions from NWTC Library) ............................................................................ include Registry_NWTC_Library.txt +include IfW_FlowField.txt usefrom ExtLoadsDX_Registry.txt # ..... Initialization data ....................................................................................................... @@ -43,12 +44,14 @@ typedef ^ InitInputType ReKi BldChord {:}{:} typedef ^ InitInputType ReKi BldRloc {:}{:} - - "Radial location of each node along the blade" m typedef ^ InitInputType ReKi TwrDia {:} - - "Tower diameter (NumTwrNodes)" m typedef ^ InitInputType ReKi TwrHloc {:} - - "Height location of each node along the tower" m +typedef ^ InitInputType IntKi nNodesVel - - - "Number of nodes velocity data is needed from (for sizing array)" - # Define outputs from the initialization routine here: typedef ^ 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 ReKi AirDens - - - "Air density" kg/m^3 +typedef ^ InitOutputType FlowFieldType *FlowField - - - "Pointer of flow field data type" - # ..... States .................................................................................................................... # Define continuous (differentiable) states here: @@ -58,8 +61,9 @@ typedef ^ ContinuousStateType ReKi blah - - - "Someth typedef ^ DiscreteStateType ReKi blah - - - "Something" - #Defin misc variables here -typedef ^ MiscVarType ReKi az - - - "Current azimuth" - -typedef ^ MiscVarType ReKi phi_cfd - - - "Blending ratio of load from external driver [0-1]" - +typedef ^ MiscVarType ReKi az - - - "Current azimuth" - +typedef ^ MiscVarType ReKi phi_cfd - - - "Blending ratio of load from external driver [0-1]" - +typedef ^ MiscVarType FlowFieldType &FlowField - - - "Flow field data type" - # Define constraint states here: typedef ^ ConstraintStateType ReKi blah - - - "Something" - diff --git a/modules/extloads/src/ExtLoads_Types.f90 b/modules/extloads/src/ExtLoads_Types.f90 index 1a7e775232..dcb14a5afe 100644 --- a/modules/extloads/src/ExtLoads_Types.f90 +++ b/modules/extloads/src/ExtLoads_Types.f90 @@ -31,6 +31,7 @@ !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. MODULE ExtLoads_Types !--------------------------------------------------------------------------------------------------------------------------------- +USE IfW_FlowField_Types USE ExtLoadsDX_Types USE NWTC_Library IMPLICIT NONE @@ -60,6 +61,7 @@ MODULE ExtLoads_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BldRloc !< Radial location of each node along the blade [m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrDia !< Tower diameter (NumTwrNodes) [m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrHloc !< Height location of each node along the tower [m] + INTEGER(IntKi) :: nNodesVel = 0_IntKi !< Number of nodes velocity data is needed from (for sizing array) [-] END TYPE ExtLd_InitInputType ! ======================= ! ========= ExtLd_InitOutputType ======= @@ -68,6 +70,7 @@ MODULE ExtLoads_Types CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Units of the output-to-file channels [-] TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] REAL(ReKi) :: AirDens = 0.0_ReKi !< Air density [kg/m^3] + TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Pointer of flow field data type [-] END TYPE ExtLd_InitOutputType ! ======================= ! ========= ExtLd_ContinuousStateType ======= @@ -84,6 +87,7 @@ MODULE ExtLoads_Types TYPE, PUBLIC :: ExtLd_MiscVarType REAL(ReKi) :: az = 0.0_ReKi !< Current azimuth [-] REAL(ReKi) :: phi_cfd = 0.0_ReKi !< Blending ratio of load from external driver [0-1] [-] + TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Flow field data type [-] END TYPE ExtLd_MiscVarType ! ======================= ! ========= ExtLd_ConstraintStateType ======= @@ -290,6 +294,7 @@ subroutine ExtLd_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, Err end if DstInitInputData%TwrHloc = SrcInitInputData%TwrHloc end if + DstInitInputData%nNodesVel = SrcInitInputData%nNodesVel end subroutine subroutine ExtLd_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -363,6 +368,7 @@ subroutine ExtLd_PackInitInput(RF, Indata) call RegPackAlloc(RF, InData%BldRloc) call RegPackAlloc(RF, InData%TwrDia) call RegPackAlloc(RF, InData%TwrHloc) + call RegPack(RF, InData%nNodesVel) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -398,6 +404,7 @@ subroutine ExtLd_UnPackInitInput(RF, OutData) call RegUnpackAlloc(RF, OutData%BldRloc); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%TwrDia); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%TwrHloc); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%nNodesVel); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine ExtLd_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) @@ -440,6 +447,7 @@ subroutine ExtLd_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return DstInitOutputData%AirDens = SrcInitOutputData%AirDens + DstInitOutputData%FlowField => SrcInitOutputData%FlowField end subroutine subroutine ExtLd_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) @@ -459,17 +467,26 @@ subroutine ExtLd_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) end if call NWTC_Library_DestroyProgDesc(InitOutputData%Ver, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + nullify(InitOutputData%FlowField) end subroutine subroutine ExtLd_PackInitOutput(RF, Indata) type(RegFile), intent(inout) :: RF type(ExtLd_InitOutputType), intent(in) :: InData character(*), parameter :: RoutineName = 'ExtLd_PackInitOutput' + logical :: PtrInIndex if (RF%ErrStat >= AbortErrLev) return call RegPackAlloc(RF, InData%WriteOutputHdr) call RegPackAlloc(RF, InData%WriteOutputUnt) call NWTC_Library_PackProgDesc(RF, InData%Ver) call RegPack(RF, InData%AirDens) + call RegPack(RF, associated(InData%FlowField)) + if (associated(InData%FlowField)) then + call RegPackPointer(RF, c_loc(InData%FlowField), PtrInIndex) + if (.not. PtrInIndex) then + call IfW_FlowField_PackFlowFieldType(RF, InData%FlowField) + end if + end if if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -480,11 +497,31 @@ subroutine ExtLd_UnPackInitOutput(RF, OutData) integer(B8Ki) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc + integer(B8Ki) :: PtrIdx + type(c_ptr) :: Ptr if (RF%ErrStat /= ErrID_None) return call RegUnpackAlloc(RF, OutData%WriteOutputHdr); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%WriteOutputUnt); if (RegCheckErr(RF, RoutineName)) return call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver call RegUnpack(RF, OutData%AirDens); if (RegCheckErr(RF, RoutineName)) return + if (associated(OutData%FlowField)) deallocate(OutData%FlowField) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackPointer(RF, Ptr, PtrIdx); if (RegCheckErr(RF, RoutineName)) return + if (c_associated(Ptr)) then + call c_f_pointer(Ptr, OutData%FlowField) + else + allocate(OutData%FlowField,stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%FlowField.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + RF%Pointers(PtrIdx) = c_loc(OutData%FlowField) + call IfW_FlowField_UnpackFlowFieldType(RF, OutData%FlowField) ! FlowField + end if + else + OutData%FlowField => null() + end if end subroutine subroutine ExtLd_CopyContState(SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg) @@ -569,29 +606,60 @@ subroutine ExtLd_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(0), UB(0) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'ExtLd_CopyMisc' ErrStat = ErrID_None ErrMsg = '' DstMiscData%az = SrcMiscData%az DstMiscData%phi_cfd = SrcMiscData%phi_cfd + if (associated(SrcMiscData%FlowField)) then + if (.not. associated(DstMiscData%FlowField)) then + allocate(DstMiscData%FlowField, stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%FlowField.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + call IfW_FlowField_CopyFlowFieldType(SrcMiscData%FlowField, DstMiscData%FlowField, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end if end subroutine subroutine ExtLd_DestroyMisc(MiscData, ErrStat, ErrMsg) type(ExtLd_MiscVarType), intent(inout) :: MiscData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'ExtLd_DestroyMisc' ErrStat = ErrID_None ErrMsg = '' + if (associated(MiscData%FlowField)) then + call IfW_FlowField_DestroyFlowFieldType(MiscData%FlowField, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + deallocate(MiscData%FlowField) + MiscData%FlowField => null() + end if end subroutine subroutine ExtLd_PackMisc(RF, Indata) type(RegFile), intent(inout) :: RF type(ExtLd_MiscVarType), intent(in) :: InData character(*), parameter :: RoutineName = 'ExtLd_PackMisc' + logical :: PtrInIndex if (RF%ErrStat >= AbortErrLev) return call RegPack(RF, InData%az) call RegPack(RF, InData%phi_cfd) + call RegPack(RF, associated(InData%FlowField)) + if (associated(InData%FlowField)) then + call RegPackPointer(RF, c_loc(InData%FlowField), PtrInIndex) + if (.not. PtrInIndex) then + call IfW_FlowField_PackFlowFieldType(RF, InData%FlowField) + end if + end if if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -599,9 +667,32 @@ subroutine ExtLd_UnPackMisc(RF, OutData) type(RegFile), intent(inout) :: RF type(ExtLd_MiscVarType), intent(inout) :: OutData character(*), parameter :: RoutineName = 'ExtLd_UnPackMisc' + integer(B8Ki) :: LB(0), UB(0) + integer(IntKi) :: stat + logical :: IsAllocAssoc + integer(B8Ki) :: PtrIdx + type(c_ptr) :: Ptr if (RF%ErrStat /= ErrID_None) return call RegUnpack(RF, OutData%az); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%phi_cfd); if (RegCheckErr(RF, RoutineName)) return + if (associated(OutData%FlowField)) deallocate(OutData%FlowField) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackPointer(RF, Ptr, PtrIdx); if (RegCheckErr(RF, RoutineName)) return + if (c_associated(Ptr)) then + call c_f_pointer(Ptr, OutData%FlowField) + else + allocate(OutData%FlowField,stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%FlowField.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + RF%Pointers(PtrIdx) = c_loc(OutData%FlowField) + call IfW_FlowField_UnpackFlowFieldType(RF, OutData%FlowField) ! FlowField + end if + else + OutData%FlowField => null() + end if end subroutine subroutine ExtLd_CopyConstrState(SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/hydrodyn/src/HydroDyn.f90 b/modules/hydrodyn/src/HydroDyn.f90 index 459277e42c..45ac59bf48 100644 --- a/modules/hydrodyn/src/HydroDyn.f90 +++ b/modules/hydrodyn/src/HydroDyn.f90 @@ -2619,39 +2619,35 @@ SUBROUTINE HD_Perturb_x( p, n, perturb_sign, x, dx ) ! local variables - integer(intKi) :: i, offset1, offset2, n2 + integer(intKi) :: i, j, k if ( p%totalStates == 0 ) return !Note: All excitation states for all bodies are stored 1st, then all radiation states dx = p%dx(n) - offset1 = 1 - if ( n <= p%totalExctnStates ) then - - ! Find body index for exctn states - do i=1,p%nWAMITObj - offset2 = offset1 + p%WAMIT(i)%SS_Exctn%numStates - if ( n >= offset1 .and. n < offset2) then - n2 = n - offset1 + 1 - x%WAMIT(i)%SS_Exctn%x( n2 ) = x%WAMIT(i)%SS_Exctn%x( n2 ) + dx * perturb_sign - exit + k = 1 + + ! Find body index for exctn states + do i = 1, p%nWAMITObj + do j = 1, p%WAMIT(i)%SS_Exctn%numStates + if (n == k) then + x%WAMIT(i)%SS_Exctn%x(j) = x%WAMIT(i)%SS_Exctn%x(j) + dx * perturb_sign + return end if - offset1 = offset2 + k = k + 1 end do + end do - else - offset1 = p%totalExctnStates + 1 - ! Find body index for rdtn states - do i=1,p%nWAMITObj - offset2 = offset1 + p%WAMIT(i)%SS_Exctn%numStates - if ( n >= offset1 .and. n < offset2) then - n2 = n - offset1 + 1 - x%WAMIT(i)%SS_Rdtn%x( n2 ) = x%WAMIT(i)%SS_Rdtn%x( n2 ) + dx * perturb_sign - exit + ! Find body index for rdtn states + do i = 1, p%nWAMITObj + do j = 1, p%WAMIT(i)%SS_Rdtn%numStates + if (n == k) then + x%WAMIT(i)%SS_Rdtn%x(j) = x%WAMIT(i)%SS_Rdtn%x(j) + dx * perturb_sign + return end if - offset1 = offset2 + k = k + 1 end do - end if + end do END SUBROUTINE HD_Perturb_x diff --git a/modules/hydrodyn/src/HydroDyn_Input.f90 b/modules/hydrodyn/src/HydroDyn_Input.f90 index f7fc6b9b5a..4e4800c3ea 100644 --- a/modules/hydrodyn/src/HydroDyn_Input.f90 +++ b/modules/hydrodyn/src/HydroDyn_Input.f90 @@ -364,9 +364,19 @@ SUBROUTINE HydroDyn_ParseInput( InputFileName, OutRootName, FileInfo_In, InputFi END IF DO I = 1,InputFileData%Morison%NAxCoefs - ! read the table entries AxCoefID CdAx CaAx in the HydroDyn input file + ! read the table entries AxCoefID, AxCd, AxCa, AxCp, AxFdMod, AxVnCOff, AxFDLoFSc in the HydroDyn input file + ! Try reading in 7 entries first call ParseAry( FileInfo_In, CurLine, ' axial coefficients line '//trim( Int2LStr(I)), tmpReArray, size(tmpReArray), ErrStat2, ErrMsg2, UnEc ) - if (Failed()) return; + if ( ErrStat2 /= 0 ) then ! Try reading in 5 entries + tmpReArray(6) = -1.0 ! AxVnCoff + tmpReArray(7) = 1.0 ! AxFDLoFSc + call ParseAry( FileInfo_In, CurLine, ' axial coefficients line '//trim( Int2LStr(I)), tmpReArray(1:5), 5, ErrStat2, ErrMsg2, UnEc ) + if ( ErrStat2 /= 0 ) then ! Try reading in 4 entries + tmpReArray(5) = 0.0 ! AxFdMod + call ParseAry( FileInfo_In, CurLine, ' axial coefficients line '//trim( Int2LStr(I)), tmpReArray(1:4), 4, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return; + end if + end if InputFileData%Morison%AxialCoefs(I)%AxCoefID = NINT(tmpReArray(1)) InputFileData%Morison%AxialCoefs(I)%AxCd = tmpReArray(2) InputFileData%Morison%AxialCoefs(I)%AxCa = tmpReArray(3) diff --git a/modules/hydrodyn/src/Morison.f90 b/modules/hydrodyn/src/Morison.f90 index 57bb88f075..b192582519 100644 --- a/modules/hydrodyn/src/Morison.f90 +++ b/modules/hydrodyn/src/Morison.f90 @@ -23,7 +23,6 @@ MODULE Morison USE Waves USE Morison_Types USE Morison_Output - USE SeaState_Interp USE SeaSt_WaveField ! USE HydroDyn_Output_Types USE NWTC_Library @@ -2603,7 +2602,7 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, !=============================================================================================== ! Calculate the fluid kinematics at all mesh nodes and store for use in the equations below - CALL WaveField_GetWaveKin( p%WaveField, m%SeaSt_Interp_m, Time, m%DispNodePosHdn, .FALSE., m%nodeInWater, m%WaveElev1, m%WaveElev2, m%WaveElev, m%FDynP, m%FV, m%FA, m%FAMCF, ErrStat2, ErrMsg2 ) + CALL WaveField_GetWaveKin( p%WaveField, m%WaveField_m, Time, m%DispNodePosHdn, .FALSE., m%nodeInWater, m%WaveElev1, m%WaveElev2, m%WaveElev, m%FDynP, m%FV, m%FA, m%FAMCF, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! Compute fluid velocity relative to the structure DO j = 1, p%NNodes @@ -2716,9 +2715,10 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, ! lower node Ioffset = mem%h_cmg_l(i)*mem%h_cmg_l(i)*mem%m_mg_l(i) + Imat = 0.0_ReKi Imat(1,1) = mem%I_rmg_l(i) - Ioffset Imat(2,2) = mem%I_rmg_l(i) - Ioffset - Imat(3,3) = mem%I_lmg_l(i) - Ioffset + Imat(3,3) = mem%I_lmg_l(i) Imat = matmul(matmul(CMatrix, Imat), CTrans) iArm = mem%h_cmg_l(i) * k_hat iTerm = ( -a_s1 - cross_product(omega_s1, cross_product(omega_s1,iArm )) - cross_product(alpha_s1,iArm) ) * mem%m_mg_l(i) @@ -2731,9 +2731,10 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, ! upper node Ioffset = mem%h_cmg_u(i)*mem%h_cmg_u(i)*mem%m_mg_u(i) + Imat = 0.0_ReKi Imat(1,1) = mem%I_rmg_u(i) - Ioffset Imat(2,2) = mem%I_rmg_u(i) - Ioffset - Imat(3,3) = mem%I_lmg_u(i) - Ioffset + Imat(3,3) = mem%I_lmg_u(i) Imat = matmul(matmul(CMatrix, Imat), CTrans) iArm = mem%h_cmg_u(i) * k_hat iTerm = ( -a_s2 - cross_product(omega_s2, cross_product(omega_s2,iArm )) - cross_product(alpha_s2,iArm) ) * mem%m_mg_u(i) @@ -2829,9 +2830,11 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, ! ------------------ flooded ballast inertia: sides: Section 6.1.1 : Always compute regardless of PropPot setting --------------------- ! lower node Ioffset = mem%h_cfb_l(i)*mem%h_cfb_l(i)*mem%m_fb_l(i) + Imat = 0.0_ReKi Imat(1,1) = mem%I_rfb_l(i) - Ioffset Imat(2,2) = mem%I_rfb_l(i) - Ioffset - Imat(3,3) = mem%I_lfb_l(i) - Ioffset + Imat(3,3) = mem%I_lfb_l(i) + Imat = matmul(matmul(CMatrix, Imat), CTrans) iArm = mem%h_cfb_l(i) * k_hat iTerm = ( -a_s1 - cross_product(omega_s1, cross_product(omega_s1,iArm )) - cross_product(alpha_s1,iArm) ) * mem%m_fb_l(i) F_If(1:3) = iTerm @@ -2843,9 +2846,11 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, ! upper node Ioffset = mem%h_cfb_u(i)*mem%h_cfb_u(i)*mem%m_fb_u(i) + Imat = 0.0_ReKi Imat(1,1) = mem%I_rfb_u(i) - Ioffset Imat(2,2) = mem%I_rfb_u(i) - Ioffset - Imat(3,3) = mem%I_lfb_u(i) - Ioffset + Imat(3,3) = mem%I_lfb_u(i) + Imat = matmul(matmul(CMatrix, Imat), CTrans) iArm = mem%h_cfb_u(i) * k_hat iTerm = ( -a_s2 - cross_product(omega_s2, cross_product(omega_s2,iArm )) - cross_product(alpha_s2,iArm) ) * mem%m_fb_u(i) F_If(1:3) = iTerm @@ -3037,7 +3042,7 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, ! Compute the distributed loads at the point of intersection between the member and the free surface ! !----------------------------------------------------------------------------------------------------! ! Get wave kinematics at the free-surface intersection. Set forceNodeInWater=.TRUE. to guarantee the free-surface intersection is in water. - CALL WaveField_GetNodeWaveKin( p%WaveField, m%SeaSt_Interp_m, Time, FSInt, .TRUE., nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat2, ErrMsg2 ) + CALL WaveField_GetNodeWaveKin( p%WaveField, m%WaveField_m, Time, FSInt, .TRUE., nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) FDynPFSInt = REAL(FDynP,ReKi) FVFSInt = REAL(FV, ReKi) @@ -3579,7 +3584,7 @@ SUBROUTINE GetTotalWaveElev( Time, pos, Zeta, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - Zeta = WaveField_GetNodeTotalWaveElev( p%WaveField, m%SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) + Zeta = WaveField_GetNodeTotalWaveElev( p%WaveField, m%WaveField_m, Time, pos, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END SUBROUTINE GetTotalWaveElev @@ -3597,7 +3602,7 @@ SUBROUTINE GetFreeSurfaceNormal( Time, pos, r, n, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = "" - CALL WaveField_GetNodeWaveNormal( p%WaveField, m%SeaSt_Interp_m, Time, pos, r, n, ErrStat2, ErrMsg2 ) + CALL WaveField_GetNodeWaveNormal( p%WaveField, m%WaveField_m, Time, pos, r, n, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END SUBROUTINE GetFreeSurfaceNormal @@ -4212,7 +4217,7 @@ SUBROUTINE Morison_UpdateDiscState( Time, u, p, x, xd, z, OtherState, m, errStat END IF ! Get fluid velocity at the joint - CALL WaveField_GetNodeWaveVel( p%WaveField, m%SeaSt_Interp_m, Time, pos, .FALSE., nodeInWater, FVTmp, ErrStat2, ErrMsg2 ) + CALL WaveField_GetNodeWaveVel( p%WaveField, m%WaveField_m, Time, pos, .FALSE., nodeInWater, FVTmp, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) FV = REAL(FVTmp, ReKi) vrel = ( FV - u%Mesh%TranslationVel(:,J) ) * nodeInWater diff --git a/modules/hydrodyn/src/Morison.txt b/modules/hydrodyn/src/Morison.txt index e47b40c867..43ff0ab18c 100644 --- a/modules/hydrodyn/src/Morison.txt +++ b/modules/hydrodyn/src/Morison.txt @@ -13,7 +13,6 @@ # ...... Include files (definitions from NWTC Library) ............................................................................ # make sure that the file name does not have any trailing white spaces! include Registry_NWTC_Library.txt -usefrom SeaState_Interp.txt usefrom SeaSt_WaveField.txt # # @@ -323,7 +322,7 @@ typedef ^ ^ ReKi typedef ^ ^ ReKi V_rel_n {:} - - "Normal relative flow velocity at joints" m/s typedef ^ ^ ReKi V_rel_n_HiPass {:} - - "High-pass filtered normal relative flow velocity at joints" m/s typedef ^ ^ MeshMapType VisMeshMap - - - "Mesh mapping for visualization mesh" - -typedef ^ ^ SeaSt_Interp_MiscVarType SeaSt_Interp_m - - - "misc var information from the SeaState Interpolation module" - +typedef ^ ^ SeaSt_WaveField_MiscVarType WaveField_m - - - "misc var information from the SeaState Interpolation module" - # ..... Parameters ................................................................................................................ # Define parameters here: diff --git a/modules/hydrodyn/src/Morison_Types.f90 b/modules/hydrodyn/src/Morison_Types.f90 index d63aaef883..c68757261d 100644 --- a/modules/hydrodyn/src/Morison_Types.f90 +++ b/modules/hydrodyn/src/Morison_Types.f90 @@ -31,7 +31,6 @@ !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. MODULE Morison_Types !--------------------------------------------------------------------------------------------------------------------------------- -USE SeaState_Interp_Types USE SeaSt_WaveField_Types USE NWTC_Library IMPLICIT NONE @@ -386,7 +385,7 @@ MODULE Morison_Types REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: V_rel_n !< Normal relative flow velocity at joints [m/s] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: V_rel_n_HiPass !< High-pass filtered normal relative flow velocity at joints [m/s] TYPE(MeshMapType) :: VisMeshMap !< Mesh mapping for visualization mesh [-] - TYPE(SeaSt_Interp_MiscVarType) :: SeaSt_Interp_m !< misc var information from the SeaState Interpolation module [-] + TYPE(SeaSt_WaveField_MiscVarType) :: WaveField_m !< misc var information from the SeaState Interpolation module [-] END TYPE Morison_MiscVarType ! ======================= ! ========= Morison_ParameterType ======= @@ -3570,7 +3569,7 @@ subroutine Morison_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) call NWTC_Library_CopyMeshMapType(SrcMiscData%VisMeshMap, DstMiscData%VisMeshMap, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call SeaSt_Interp_CopyMisc(SrcMiscData%SeaSt_Interp_m, DstMiscData%SeaSt_Interp_m, CtrlCode, ErrStat2, ErrMsg2) + call SeaSt_WaveField_CopyMisc(SrcMiscData%WaveField_m, DstMiscData%WaveField_m, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end subroutine @@ -3654,7 +3653,7 @@ subroutine Morison_DestroyMisc(MiscData, ErrStat, ErrMsg) end if call NWTC_Library_DestroyMeshMapType(MiscData%VisMeshMap, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call SeaSt_Interp_DestroyMisc(MiscData%SeaSt_Interp_m, ErrStat2, ErrMsg2) + call SeaSt_WaveField_DestroyMisc(MiscData%WaveField_m, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine @@ -3694,7 +3693,7 @@ subroutine Morison_PackMisc(RF, Indata) call RegPackAlloc(RF, InData%V_rel_n) call RegPackAlloc(RF, InData%V_rel_n_HiPass) call NWTC_Library_PackMeshMapType(RF, InData%VisMeshMap) - call SeaSt_Interp_PackMisc(RF, InData%SeaSt_Interp_m) + call SeaSt_WaveField_PackMisc(RF, InData%WaveField_m) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -3740,7 +3739,7 @@ subroutine Morison_UnPackMisc(RF, OutData) call RegUnpackAlloc(RF, OutData%V_rel_n); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%V_rel_n_HiPass); if (RegCheckErr(RF, RoutineName)) return call NWTC_Library_UnpackMeshMapType(RF, OutData%VisMeshMap) ! VisMeshMap - call SeaSt_Interp_UnpackMisc(RF, OutData%SeaSt_Interp_m) ! SeaSt_Interp_m + call SeaSt_WaveField_UnpackMisc(RF, OutData%WaveField_m) ! WaveField_m end subroutine subroutine Morison_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/hydrodyn/src/SS_Excitation.f90 b/modules/hydrodyn/src/SS_Excitation.f90 index 9cc0bf72ff..125217fb3e 100644 --- a/modules/hydrodyn/src/SS_Excitation.f90 +++ b/modules/hydrodyn/src/SS_Excitation.f90 @@ -20,8 +20,8 @@ ! !********************************************************************************************************************************** MODULE SS_Excitation - USE SeaState_Interp - USE SS_Excitation_Types + USE SS_Excitation_Types + use SeaSt_WaveField, only: WaveField_GetNodeTotalWaveElev USE NWTC_Library IMPLICIT NONE @@ -110,8 +110,9 @@ function GetWaveElevation ( time, u_in, t_in, p, m, ErrStat, ErrMsg ) call SS_Exc_Input_ExtrapInterp(u_in, t_in, u_out, time, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - do iBody = 1, p%NBody - GetWaveElevation(iBody) = SeaSt_Interp_3D( time, u_out%PtfmPos(1:2,iBody), p%WaveField%WaveElev1, p%WaveField%SeaSt_interp_p, m%SeaSt_Interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) + do iBody = 1, p%NBody +!FIXME: this is the total wave elevation. Should it include second order, or should it only include first order? + GetWaveElevation(iBody) = WaveField_GetNodeTotalWaveElev(p%WaveField, m%WaveField_m, time, u_out%PtfmPos(1:2,iBody), ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end do diff --git a/modules/hydrodyn/src/SS_Excitation.txt b/modules/hydrodyn/src/SS_Excitation.txt index f5b9311d60..1372e9a823 100644 --- a/modules/hydrodyn/src/SS_Excitation.txt +++ b/modules/hydrodyn/src/SS_Excitation.txt @@ -14,7 +14,6 @@ # (File) Revision #: $Rev$ # URL: $HeadURL$ ################################################################################################################################### -usefrom SeaState_Interp.txt usefrom SeaSt_WaveField.txt typedef SS_Excitation/SS_Exc InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - @@ -24,14 +23,14 @@ typedef ^ ^ R8Ki typedef ^ ^ SeaSt_WaveFieldType *WaveField - - - "Pointer to SeaState wave field" - - + typedef ^ InitOutputType CHARACTER(10) WriteOutputHdr {:} - - "Header of the output" - typedef ^ InitOutputType CHARACTER(10) WriteOutputUnt {:} - - "Units of the output" - - + typedef ^ ContinuousStateType R8Ki x {:} - - "Continuous States" - - + typedef ^ DiscreteStateType SiKi DummyDiscState - - - "" - - + # Define constraint states here: typedef ^ ConstraintStateType SiKi DummyConstrState - - - "" - @@ -44,7 +43,7 @@ typedef ^ ^ SS_Exc_ContinuousStateType # Define any data that are used only for efficiency purposes (these variables are not associated with time): # e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. typedef ^ MiscVarType INTEGER LastIndWave - 1 - "last used index in the WaveTime array" - -typedef ^ ^ SeaSt_Interp_MiscVarType SeaSt_Interp_m - - - "misc var information from the SeaState Interpolation module" - +typedef ^ ^ SeaSt_WaveField_MiscVarType WaveField_m - - - "misc var information from the SeaState Interpolation module" - # ..... Parameters ......................... diff --git a/modules/hydrodyn/src/SS_Excitation_Types.f90 b/modules/hydrodyn/src/SS_Excitation_Types.f90 index 08bfc7e05f..3e7179fe5a 100644 --- a/modules/hydrodyn/src/SS_Excitation_Types.f90 +++ b/modules/hydrodyn/src/SS_Excitation_Types.f90 @@ -31,7 +31,6 @@ !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. MODULE SS_Excitation_Types !--------------------------------------------------------------------------------------------------------------------------------- -USE SeaState_Interp_Types USE SeaSt_WaveField_Types USE NWTC_Library IMPLICIT NONE @@ -74,7 +73,7 @@ MODULE SS_Excitation_Types ! ========= SS_Exc_MiscVarType ======= TYPE, PUBLIC :: SS_Exc_MiscVarType INTEGER(IntKi) :: LastIndWave = 1 !< last used index in the WaveTime array [-] - TYPE(SeaSt_Interp_MiscVarType) :: SeaSt_Interp_m !< misc var information from the SeaState Interpolation module [-] + TYPE(SeaSt_WaveField_MiscVarType) :: WaveField_m !< misc var information from the SeaState Interpolation module [-] END TYPE SS_Exc_MiscVarType ! ======================= ! ========= SS_Exc_ParameterType ======= @@ -495,7 +494,7 @@ subroutine SS_Exc_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = '' DstMiscData%LastIndWave = SrcMiscData%LastIndWave - call SeaSt_Interp_CopyMisc(SrcMiscData%SeaSt_Interp_m, DstMiscData%SeaSt_Interp_m, CtrlCode, ErrStat2, ErrMsg2) + call SeaSt_WaveField_CopyMisc(SrcMiscData%WaveField_m, DstMiscData%WaveField_m, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end subroutine @@ -509,7 +508,7 @@ subroutine SS_Exc_DestroyMisc(MiscData, ErrStat, ErrMsg) character(*), parameter :: RoutineName = 'SS_Exc_DestroyMisc' ErrStat = ErrID_None ErrMsg = '' - call SeaSt_Interp_DestroyMisc(MiscData%SeaSt_Interp_m, ErrStat2, ErrMsg2) + call SeaSt_WaveField_DestroyMisc(MiscData%WaveField_m, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine @@ -519,7 +518,7 @@ subroutine SS_Exc_PackMisc(RF, Indata) character(*), parameter :: RoutineName = 'SS_Exc_PackMisc' if (RF%ErrStat >= AbortErrLev) return call RegPack(RF, InData%LastIndWave) - call SeaSt_Interp_PackMisc(RF, InData%SeaSt_Interp_m) + call SeaSt_WaveField_PackMisc(RF, InData%WaveField_m) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -529,7 +528,7 @@ subroutine SS_Exc_UnPackMisc(RF, OutData) character(*), parameter :: RoutineName = 'SS_Exc_UnPackMisc' if (RF%ErrStat /= ErrID_None) return call RegUnpack(RF, OutData%LastIndWave); if (RegCheckErr(RF, RoutineName)) return - call SeaSt_Interp_UnpackMisc(RF, OutData%SeaSt_Interp_m) ! SeaSt_Interp_m + call SeaSt_WaveField_UnpackMisc(RF, OutData%WaveField_m) ! WaveField_m end subroutine subroutine SS_Exc_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/hydrodyn/src/WAMIT.f90 b/modules/hydrodyn/src/WAMIT.f90 index b740b6cd35..e5049a9a8c 100644 --- a/modules/hydrodyn/src/WAMIT.f90 +++ b/modules/hydrodyn/src/WAMIT.f90 @@ -25,12 +25,10 @@ MODULE WAMIT USE WAMIT_Types USE WAMIT_Interp USE NWTC_Library - ! USE Waves_Types USE Conv_Radiation USE SS_Radiation USE SS_Excitation USE NWTC_FFTPACK - use SeaState_Interp IMPLICIT NONE @@ -191,7 +189,7 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS real(ReKi) :: WaveNmbr ! Frequency-dependent wave number COMPLEX(SiKi) :: Fxy ! Phase correction term for Wave excitation forces real(ReKi) :: tmpAngle ! Frequency and heading and platform offset dependent phase shift angle for Euler's Equation e^(-j*tmpAngle) - COMPLEX(SiKi), ALLOCATABLE :: HdroExctn_Local (:,:,:) ! Temporary Frequency- and direction-dependent complex hydrodynamic wave excitation force per unit wave amplitude vector (kg/s^2, kg-m/s^2) + REAL(ReKi) :: RotateZdegOffset ! PtfmRefZtRot converted to degrees ! Error handling CHARACTER(ErrMsgLen) :: ErrMsg2 ! Temporary error message for calls INTEGER(IntKi) :: ErrStat2 ! Temporary error status for calls @@ -956,7 +954,13 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS ! NOTE: we may end up inadvertantly aborting if the wave direction crosses ! the -Pi / Pi boundary (-180/180 degrees). - IF ( ( p%WaveField%WaveDirMin < HdroWvDir(1) ) .OR. ( p%WaveField%WaveDirMax > HdroWvDir(NInpWvDir) ) ) THEN + ! Need to account for PtfmRefZtRot if NBodyMod=2 (NBody=1 in the case) + IF ( p%NBodyMod == 2 ) THEN + RotateZdegOffset = InitInp%PtfmRefztRot(1)*R2D + ELSE + RotateZdegOffset = 0.0 + END IF + IF ( ( (p%WaveField%WaveDirMin-RotateZdegOffset) HdroWvDir(NInpWvDir) ) ) THEN ErrMsg2 = 'All Wave directions must be within the wave heading angle range available in "' & //TRIM(InitInp%WAMITFile)//'.3" (inclusive).' CALL SetErrStat( ErrID_Fatal, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -976,13 +980,13 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS END IF if (p%ExctnDisp > 0 ) then - ALLOCATE ( WaveExctnCGrid(0:p%WaveField%NStepWave2 ,p%WaveField%SeaSt_Interp_p%n(2)*p%WaveField%SeaSt_Interp_p%n(3),6*p%NBody) , STAT=ErrStat2 ) + ALLOCATE ( WaveExctnCGrid(0:p%WaveField%NStepWave2 ,p%WaveField%GridParams%n(2)*p%WaveField%GridParams%n(3),6*p%NBody) , STAT=ErrStat2 ) IF ( ErrStat2 /= 0 ) THEN CALL SetErrStat( ErrID_Fatal, 'Error allocating memory for the WaveExctnC array.', ErrStat, ErrMsg, RoutineName) CALL Cleanup() RETURN END IF - ALLOCATE ( p%WaveExctnGrid (0:p%WaveField%NStepWave,p%WaveField%SeaSt_Interp_p%n(2),p%WaveField%SeaSt_Interp_p%n(3), 6*p%NBody) , STAT=ErrStat2 ) + ALLOCATE ( p%WaveExctnGrid (0:p%WaveField%NStepWave,p%WaveField%GridParams%n(2),p%WaveField%GridParams%n(3), 6*p%NBody) , STAT=ErrStat2 ) IF ( ErrStat2 /= 0 ) THEN CALL SetErrStat( ErrID_Fatal, 'Error allocating memory for the WaveExctn array.', ErrStat, ErrMsg, RoutineName) CALL Cleanup() @@ -1005,46 +1009,35 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS if ( p%NBodyMod == 2 ) then ! Since NBodyMod = 2, then NBody = 1 for this WAMIT object (this requirement is encoded at the HydroDyn module level) - - allocate ( HdroExctn_Local(NInpFreq, NInpWvDir, 6), STAT=ErrStat2 ) - IF ( ErrStat2 /= 0 ) THEN - CALL SetErrStat( ErrID_Fatal, 'Error allocating memory for the HdroExctn_Local array.', ErrStat, ErrMsg, RoutineName) - CALL Cleanup() - RETURN - END IF - - do K = 1,6 ! Loop through all wave excitation forces and moments - do J = 1, NInpWvDir - TmpCoord(2) = HdroWvDir(J) - InitInp%PtfmRefztRot(1)*R2D ! apply locale Z rotation to heading angle (degrees) - do I = 1, NInpFreq - TmpCoord(1) = HdroFreq(I) - ! Iterpolate to find new coef - call WAMIT_Interp2D_Cplx( TmpCoord, HdroExctn(:,:,K), HdroFreq, HdroWvDir, LastInd2, HdroExctn_Local(I,J,K), ErrStat2, ErrMsg2 ) - end do - end do - end do - - ! Now apply rotation and phase shift + ! HdroWvDir from WAMIT is effectively in the body-local coordinate system. Need to offset HdroWvDir to be back in the global frame + HdroWvDir = HdroWvDir + InitInp%PtfmRefztRot(1)*R2D + ! Now apply rotation and phase shift do J = 1, NInpWvDir do I = 1, NInpFreq - ! Fxy = exp(-j * k(w) * ( X*cos(Beta(w)) + Y*sin(Beta(w)) ) + ! Fxy = exp(-j * k(w) * ( X*cos(Beta(w)) + Y*sin(Beta(w)) ) WaveNmbr = WaveNumber ( HdroFreq(I), InitInp%Gravity, p%WaveField%EffWtrDpth ) tmpAngle = WaveNmbr * ( InitInp%PtfmRefxt(1)*cos(HdroWvDir(J)*D2R) + InitInp%PtfmRefyt(1)*sin(HdroWvDir(J)*D2R) ) TmpRe = cos(tmpAngle) TmpIm = -sin(tmpAngle) Fxy = CMPLX( TmpRe, TmpIm ) - HdroExctn(I,J,1) = Fxy*( HdroExctn_Local(I,J,1)*cos(InitInp%PtfmRefztRot(1)) - HdroExctn_Local(I,J,2)*sin(InitInp%PtfmRefztRot(1)) ) - HdroExctn(I,J,2) = Fxy*( HdroExctn_Local(I,J,1)*sin(InitInp%PtfmRefztRot(1)) + HdroExctn_Local(I,J,2)*cos(InitInp%PtfmRefztRot(1)) ) - HdroExctn(I,J,3) = Fxy*( HdroExctn_Local(I,J,3) ) - HdroExctn(I,J,4) = Fxy*( HdroExctn_Local(I,J,4)*cos(InitInp%PtfmRefztRot(1)) - HdroExctn_Local(I,J,5)*sin(InitInp%PtfmRefztRot(1)) ) - HdroExctn(I,J,5) = Fxy*( HdroExctn_Local(I,J,4)*sin(InitInp%PtfmRefztRot(1)) + HdroExctn_Local(I,J,5)*cos(InitInp%PtfmRefztRot(1)) ) - HdroExctn(I,J,6) = Fxy*( HdroExctn_Local(I,J,6) ) + Ctmp1 = Fxy*( HdroExctn(I,J,1)*cos(InitInp%PtfmRefztRot(1)) - HdroExctn(I,J,2)*sin(InitInp%PtfmRefztRot(1)) ) + Ctmp2 = Fxy*( HdroExctn(I,J,1)*sin(InitInp%PtfmRefztRot(1)) + HdroExctn(I,J,2)*cos(InitInp%PtfmRefztRot(1)) ) + Ctmp4 = Fxy*( HdroExctn(I,J,4)*cos(InitInp%PtfmRefztRot(1)) - HdroExctn(I,J,5)*sin(InitInp%PtfmRefztRot(1)) ) + Ctmp5 = Fxy*( HdroExctn(I,J,4)*sin(InitInp%PtfmRefztRot(1)) + HdroExctn(I,J,5)*cos(InitInp%PtfmRefztRot(1)) ) + + HdroExctn(I,J,1) = Ctmp1 + HdroExctn(I,J,2) = Ctmp2 + HdroExctn(I,J,4) = Ctmp4 + HdroExctn(I,J,5) = Ctmp5 + + HdroExctn(I,J,3) = Fxy*( HdroExctn(I,J,3) ) + HdroExctn(I,J,6) = Fxy*( HdroExctn(I,J,6) ) end do end do - deallocate(HdroExctn_Local) + else ! Apply rotation only for NBodyMod = 1,3 @@ -1141,7 +1134,7 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS CALL Cleanup() RETURN END IF - do iGrid = 1, p%WaveField%SeaSt_Interp_p%n(2)*p%WaveField%SeaSt_Interp_p%n(3) + do iGrid = 1, p%WaveField%GridParams%n(2)*p%WaveField%GridParams%n(3) WaveExctnCGrid(I,iGrid,J) = WaveExctnC(I,J) * CMPLX(p%WaveField%WaveElevC(1,I,iGrid), p%WaveField%WaveElevC(2,I,iGrid)) end do END DO ! J - All wave excitation forces and moments @@ -1158,9 +1151,9 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS END IF DO J = 1,6*p%NBody ! Loop through all wave excitation forces and moments - do iGrid = 1, p%WaveField%SeaSt_Interp_p%n(2)*p%WaveField%SeaSt_Interp_p%n(3) - iX = mod(iGrid-1, p%WaveField%SeaSt_Interp_p%n(2)) + 1 ! 1st n index is time - iY = (iGrid-1) / p%WaveField%SeaSt_Interp_p%n(2) + 1 + do iGrid = 1, p%WaveField%GridParams%n(2)*p%WaveField%GridParams%n(3) + iX = mod(iGrid-1, p%WaveField%GridParams%n(2)) + 1 ! 1st n index is time + iY = (iGrid-1) / p%WaveField%GridParams%n(2) + 1 CALL ApplyFFT_cx ( p%WaveExctnGrid(0:p%WaveField%NStepWave-1,iX,iY,J), WaveExctnCGrid(:,iGrid,J), FFT_Data, ErrStat2 ) CALL SetErrStat( ErrStat2, ' An error occured while applying an FFT to WaveExctnC.', ErrStat, ErrMsg, RoutineName) IF ( ErrStat >= AbortErrLev) THEN @@ -1206,23 +1199,18 @@ SUBROUTINE WAMIT_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, ErrS ! Now apply the phase shift in the frequency space - do J = 1, NInpWvDir - do I = 0,p%WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transform + do I = 0,p%WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transform - ! Compute the frequency of this component: + ! Compute the phase shift of this component, Fxy = exp(-j * k(w) * ( X*cos(Beta(w)) + Y*sin(Beta(w)) ): + Omega = I*p%WaveField%WaveDOmega + WaveNmbr = WaveNumber ( Omega, InitInp%Gravity, p%WaveField%EffWtrDpth ) + tmpAngle = WaveNmbr * ( InitInp%PtfmRefxt(1)*cos(p%WaveField%WaveDirArr(I)*D2R) + InitInp%PtfmRefyt(1)*sin(p%WaveField%WaveDirArr(I)*D2R) ) + TmpRe = cos(tmpAngle) + TmpIm = -sin(tmpAngle) + Fxy = CMPLX( TmpRe, TmpIm ) - Omega = I*p%WaveField%WaveDOmega - ! Fxy = exp(-j * k(w) * ( X*cos(Beta(w)) + Y*sin(Beta(w)) ) - WaveNmbr = WaveNumber ( Omega, InitInp%Gravity, p%WaveField%EffWtrDpth ) - tmpAngle = WaveNmbr * ( InitInp%PtfmRefxt(1)*cos(HdroWvDir(J)*D2R) + InitInp%PtfmRefyt(1)*sin(HdroWvDir(J)*D2R) ) - TmpRe = cos(tmpAngle) - TmpIm = -sin(tmpAngle) - Fxy = CMPLX( TmpRe, TmpIm ) - - tmpComplexArr(I) = Fxy*CMPLX(p%WaveField%WaveElevC0(1,I), p%WaveField%WaveElevC0(2,I)) - - - end do + ! Apply phase shift + tmpComplexArr(I) = Fxy*CMPLX(p%WaveField%WaveElevC0(1,I), p%WaveField%WaveElevC0(2,I)) end do ! Compute the inverse discrete Fourier transforms to find the time-domain @@ -1567,7 +1555,7 @@ SUBROUTINE WAMIT_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds INTEGER(IntKi), INTENT(IN ) :: n !< Current step of the simulation: t = n*Interval - TYPE(WAMIT_InputType), INTENT(IN ) :: Inputs(:) !< Inputs at InputTimes + TYPE(WAMIT_InputType), INTENT(INOUT) :: Inputs(:) !< Inputs at InputTimes REAL(DbKi), INTENT(IN ) :: InputTimes(:) !< Times in seconds associated with Inputs TYPE(WAMIT_ParameterType), INTENT(IN ) :: p !< Parameters TYPE(WAMIT_ContinuousStateType), INTENT(INOUT) :: x !< Input: Continuous states at t; @@ -1600,7 +1588,6 @@ SUBROUTINE WAMIT_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState TYPE(SS_Rad_InputType), ALLOCATABLE :: SS_Rdtn_u(:) ! Inputs TYPE(SS_Exc_InputType), ALLOCATABLE :: SS_Exctn_u(:) ! Inputs - TYPE(WAMIT_InputType), ALLOCATABLE :: WAMIT_u(:) ! Inputs TYPE(WAMIT_InputType) :: WAMIT_u_t @@ -1671,23 +1658,9 @@ SUBROUTINE WAMIT_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState END IF IF ( (p%ExctnMod>0).AND.(p%ExctnDisp==2) ) THEN - ALLOCATE( WAMIT_u(nTime), STAT = ErrStat ) - IF (ErrStat /=0) THEN - ErrMsg = ' Failed to allocate array WAMIT_u.' - RETURN - END IF - DO I=1,nTime - ALLOCATE( WAMIT_u(I)%Mesh%TranslationDisp(3,p%NBody), STAT = ErrStat ) - IF (ErrStat /=0) THEN - ErrMsg = ' Failed to allocate array WAMIT_u(I)%Mesh%TranslationDisp.' - RETURN - END IF - DO iBody=1,p%NBody - WAMIT_u(I)%Mesh%TranslationDisp(:,iBody) = Inputs(I)%Mesh%TranslationDisp(:,iBody) - END DO - END DO ! Interpolate WAMIT input at time t+dt - CALL WAMIT_Input_ExtrapInterp(WAMIT_u, InputTimes, WAMIT_u_t, t+p%dt, ErrStat, ErrMsg) + CALL WAMIT_CopyInput(Inputs(1), WAMIT_u_t, MESH_NEWCOPY, ErrStat, ErrMsg) + CALL WAMIT_Input_ExtrapInterp(Inputs, InputTimes, WAMIT_u_t, t+p%dt, ErrStat, ErrMsg) DO iBody = 1,p%NBody ! Current unfiltered body position at time t+dt bodyPosition(1) = WAMIT_u_t%Mesh%TranslationDisp(1,iBody) @@ -1699,10 +1672,6 @@ SUBROUTINE WAMIT_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState xd%BdyPosFilt(2,iBody,1) = p%ExctnFiltConst * xd%BdyPosFilt(2,iBody,1) + (1.0_ReKi - p%ExctnFiltConst) * bodyPosition(2) END DO CALL WAMIT_DestroyInput( WAMIT_u_t, ErrStat, ErrMsg) - DO I=1,nTime - CALL WAMIT_DestroyInput( WAMIT_u(I), ErrStat, ErrMsg) - END DO - DEALLOCATE(WAMIT_u) END IF IF ( p%ExctnMod == 2 ) THEN ! Update the state-space wave excitation sub-module's states @@ -1837,12 +1806,12 @@ SUBROUTINE WAMIT_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, ErrStat, Er bodyPosition(2) = u%Mesh%TranslationDisp(2,iBody) ELSE IF ( p%ExctnDisp == 2 ) THEN ! Use filtered body position - bodyPosition(1) = xd%BdyPosFilt(1,iBody,1) - bodyPosition(2) = xd%BdyPosFilt(2,iBody,1) + bodyPosition(1) = p%ExctnFiltConst * xd%BdyPosFilt(1,iBody,1) + (1.0_ReKi - p%ExctnFiltConst) * u%Mesh%TranslationDisp(1,iBody) + bodyPosition(2) = p%ExctnFiltConst * xd%BdyPosFilt(2,iBody,1) + (1.0_ReKi - p%ExctnFiltConst) * u%Mesh%TranslationDisp(2,iBody) END IF iStart = (iBody-1)*6+1 ! WaveExctnGrid dimensions are: 1st: wavetime, 2nd: X, 3rd: Y, 4th: Force component for each WAMIT Body - m%F_Waves1(iStart:iStart+5) = SeaSt_Interp_3D_Vec6( Time, bodyPosition, p%WaveExctnGrid(:,:,:,iStart:iStart+5), p%WaveField%SeaSt_interp_p, m%seast_interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) + m%F_Waves1(iStart:iStart+5) = WAMIT_ForceWaves_Interp( Time, bodyPosition, p%WaveExctnGrid(:,:,:,iStart:iStart+5), p%WaveField%GridParams, m%WaveField_m, ErrStat2, ErrMsg2 ) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'SeaState_CalcOutput' ) END DO end if @@ -1931,8 +1900,9 @@ SUBROUTINE WAMIT_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, ErrStat, Er ! Output channels will be dealt with by the HydroDyn module - END SUBROUTINE WAMIT_CalcOutput + + !---------------------------------------------------------------------------------------------------------------------------------- !> Tight coupling routine for computing derivatives of continuous states SUBROUTINE WAMIT_CalcContStateDeriv( Time, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) diff --git a/modules/hydrodyn/src/WAMIT.txt b/modules/hydrodyn/src/WAMIT.txt index 51c0294603..608afe87b4 100644 --- a/modules/hydrodyn/src/WAMIT.txt +++ b/modules/hydrodyn/src/WAMIT.txt @@ -16,7 +16,6 @@ include Registry_NWTC_Library.txt usefrom Conv_Radiation.txt usefrom SS_Radiation.txt usefrom SS_Excitation.txt -usefrom SeaState_Interp.txt usefrom SeaSt_WaveField.txt typedef WAMIT/WAMIT InitInputType INTEGER NBody - - - "[>=1; only used when PotMod=1. If NBodyMod=1, the WAMIT data contains a vector of size 6*NBody x 1 and matrices of size 6*NBody x 6*NBody; if NBodyMod>1, there are NBody sets of WAMIT data each with a vector of size 6 x 1 and matrices of size 6 x 6]" - @@ -93,7 +92,7 @@ typedef ^ ^ SS_Exc_Outp typedef ^ ^ Conv_Rdtn_MiscVarType Conv_Rdtn - - - "" - typedef ^ ^ Conv_Rdtn_InputType Conv_Rdtn_u - - - "" - typedef ^ ^ Conv_Rdtn_OutputType Conv_Rdtn_y - - - "" - -typedef ^ ^ SeaSt_Interp_MiscVarType SeaSt_Interp_m - - - "misc var information from the SeaState Interpolation module" - +typedef ^ ^ SeaSt_WaveField_MiscVarType WaveField_m - - - "misc var information from the SeaState Interpolation module" - # ..... Parameters ................................................................................................................ # Define parameters here: diff --git a/modules/hydrodyn/src/WAMIT2.f90 b/modules/hydrodyn/src/WAMIT2.f90 index 21c4f18ffc..8cbb1da71e 100644 --- a/modules/hydrodyn/src/WAMIT2.f90 +++ b/modules/hydrodyn/src/WAMIT2.f90 @@ -180,6 +180,10 @@ MODULE WAMIT2 TYPE(W2_InitData4D_Type) :: Data4D !< The 4D type from above END TYPE W2_SumData_Type + INTERFACE CheckWamit2WvHdg + MODULE PROCEDURE CheckWAMIT2WvHdgDiffData + MODULE PROCEDURE CheckWAMIT2WvHdgSumData + END INTERFACE CheckWamit2WvHdg CONTAINS !---------------------------------------------------------------------------------------------------------------------------------- @@ -819,188 +823,10 @@ SUBROUTINE MnDrift_InitCalc( InitInp, p, MnDriftData, MnDriftForce, ErrMsg, ErrS RETURN ENDIF - - - !> 2. Check the data to see if the wave frequencies are present in the QTF data. Since the mean drift term only uses - !! frequencies where \f$ \omega_1=\omega_2 \f$, the data read in from the files must contain the full range of frequencies - !! present in the waves. - - IF ( MnDriftData%DataIs3D ) THEN - - ! Check the low frequency cutoff - IF ( MINVAL( MnDriftData%Data3D%WvFreq1 ) > InitInp%WaveField%WvLowCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(MnDriftData%Data3D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( (MAXVAL(MnDriftData%Data3D%WvFreq1 ) < InitInp%WaveField%WvHiCOffD) ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(MnDriftData%Data3D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE IF ( MnDriftData%DataIs4D ) THEN ! only check if not 3D data. If there is 3D data, we default to using it for calculations - - ! Check the low frequency cutoff - IF ( MINVAL( MnDriftData%Data4D%WvFreq1 ) > InitInp%WaveField%WvLowCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(MnDriftData%Data4D%WvFreq1)))// & - ' rad/s first wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MINVAL( MnDriftData%Data4D%WvFreq2 ) > InitInp%WaveField%WvLowCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(MnDriftData%Data4D%WvFreq2)))// & - ' rad/s for second wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( (MAXVAL(MnDriftData%Data4D%WvFreq1) < InitInp%WaveField%WvHiCOffD) ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(MnDriftData%Data4D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( (MAXVAL(MnDriftData%Data4D%WvFreq2) < InitInp%WaveField%WvHiCOffD) ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(MnDriftData%Data4D%WvFreq1)))// & - ' rad/s second wave period) data in '//TRIM(MnDriftData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffD.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE - ! This is a catastrophic issue. We should not have called this routine without data that is usable for the MnDrift calculation - CALL SetErrStat( ErrID_Fatal, ' Mean drift calculation called without data.',ErrStat,ErrMsg,RoutineName) - ENDIF - + CALL CheckWAMIT2WvHdg(InitInp,MnDriftData,ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 3. Check the data to see if the wave directions are present. May need to adjust for the boundary at +/- PI - IF ( MnDriftData%DataIs3D ) THEN - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (MnDriftData%Data3D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(MnDriftData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(MnDriftData%Data3D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (MnDriftData%Data3D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(MnDriftData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(MnDriftData%Data3D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (minval(MnDriftData%data3d%WvDir1) > 150.0_SiKi) .OR. (maxval(MnDriftData%data3d%WvDir1) < -150.0_SiKi) .OR. & - (minval(MnDriftData%data3d%WvDir2) > 150.0_SiKi) .OR. (maxval(MnDriftData%data3d%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(MnDriftData%Data3D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(MnDriftData%Data3D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(MnDriftData%Data3D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(MnDriftData%Data3D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - - ELSEIF ( MnDriftData%DataIs4D ) THEN - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (MnDriftData%Data4D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(MnDriftData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(MnDriftData%Data4D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (MnDriftData%Data4D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(MnDriftData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(MnDriftData%Data4D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (MINVAL(MnDriftData%Data4D%WvDir1) > 150.0_SiKi) .OR. (MAXVAL(MnDriftData%Data4D%WvDir1) < -150.0_SiKi) .OR. & - (MINVAL(MnDriftData%Data4D%WvDir2) > 150.0_SiKi) .OR. (MAXVAL(MnDriftData%Data4D%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - ! --> FIXME: modify to allow shifting values by TwoPi before comparing - IF ( InitInp%WaveField%WaveDirMin < MINVAL(MnDriftData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(MnDriftData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(MnDriftData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(MnDriftData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(MnDriftData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - - ELSE - ! No data. This is a catastrophic issue. We should not have called this routine without data that is usable for the MnDrift calculation - CALL SetErrStat( ErrID_Fatal, ' Mean drift calculation called without data.',ErrStat,ErrMsg,RoutineName) - ENDIF - - IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 4. Check the data to see if we need to convert to 3D arrays before continuing (4D is sparse in any dimension we want and !! frequency diagonal is complete). Only check if we don't have 3D data. @@ -1105,8 +931,8 @@ SUBROUTINE MnDrift_InitCalc( InitInp, p, MnDriftData, MnDriftForce, ErrMsg, ErrS endif ! NOTE: RotateZMatrixT is the rotation from local to global. - RotateZMatrixT(:,1) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) - RotateZMatrixT(:,2) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(1,:) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(2,:) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) DO ThisDim=1,6 @@ -1220,8 +1046,9 @@ SUBROUTINE MnDrift_InitCalc( InitInp, p, MnDriftData, MnDriftForce, ErrMsg, ErrS ! Now rotate the force components with platform orientation - MnDriftForce(1:2) = MATMUL( RotateZMatrixT, MnDriftForce(1:2) ) ! Fx and Fy, rotation about z - MnDriftForce(4:5) = MATMUL( RotateZMatrixT, MnDriftForce(4:5) ) ! Mx and My, rotation about z + Idx = (IBody-1)*6 + MnDriftForce( (Idx+1):(Idx+2) ) = MATMUL( RotateZMatrixT, MnDriftForce( (Idx+1):(Idx+2) ) ) ! Fx and Fy, rotation about z + MnDriftForce( (Idx+4):(Idx+5) ) = MATMUL( RotateZMatrixT, MnDriftForce( (Idx+4):(Idx+5) ) ) ! Mx and My, rotation about z ENDDO ! IBody @@ -1344,193 +1171,10 @@ SUBROUTINE NewmanApp_InitCalc( InitInp, p, NewmanAppData, NewmanAppForce, ErrMsg ErrStat = ErrID_None ErrStatTmp = ErrID_None - - - !> 1. Check the data to see if the wave frequencies are present in the QTF data. Since Newman's approximation only uses - !! frequencies where \f$ \omega_1=\omega_2 \f$, the data read in from the files must contain the full range of frequencies - !! present in the waves. - IF ( NewmanAppData%DataIs3D ) THEN - - ! Check the low frequency cutoff - IF ( MINVAL( NewmanAppData%Data3D%WvFreq1 ) > InitInp%WaveField%WvLowCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(NewmanAppData%Data3D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( MAXVAL(NewmanAppData%Data3D%WvFreq1 ) < InitInp%WaveField%WvHiCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(NewmanAppData%Data3D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE IF ( NewmanAppData%DataIs4D ) THEN ! only check if not 3D data. If there is 3D data, we default to using it for calculations - - ! Check the low frequency cutoff - IF ( MINVAL( NewmanAppData%Data4D%WvFreq1 ) > InitInp%WaveField%WvLowCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(NewmanAppData%Data4D%WvFreq1)))// & - ' rad/s first wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MINVAL( NewmanAppData%Data4D%WvFreq2 ) > InitInp%WaveField%WvLowCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(NewmanAppData%Data4D%WvFreq2)))// & - ' rad/s for second wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( MAXVAL(NewmanAppData%Data4D%WvFreq1) < InitInp%WaveField%WvHiCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(NewmanAppData%Data4D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MAXVAL(NewmanAppData%Data4D%WvFreq2) < InitInp%WaveField%WvHiCOff ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(NewmanAppData%Data4D%WvFreq1)))// & - ' rad/s second wave period) data in '//TRIM(NewmanAppData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOff.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE - ! This is a catastrophic issue. We should not have called this routine without data that is usable for the NewmanApp calculation - CALL SetErrStat( ErrID_Fatal, ' Newman approximation calculation called without data.',ErrStat,ErrMsg,RoutineName) - ENDIF - + CALL CheckWAMIT2WvHdg(InitInp,NewmanAppData,ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 2. Check the data to see if the wave directions are present. May need to adjust for the boundary at +/- PI - IF ( NewmanAppData%DataIs3D ) THEN - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (NewmanAppData%Data3D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(NewmanAppData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(NewmanAppData%Data3D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (NewmanAppData%Data3D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(NewmanAppData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(NewmanAppData%Data3D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (minval(NewmanAppData%data3d%WvDir1) > 150.0_SiKi) .OR. (maxval(NewmanAppData%data3d%WvDir1) < -150.0_SiKi) .OR. & - (minval(NewmanAppData%data3d%WvDir2) > 150.0_SiKi) .OR. (maxval(NewmanAppData%data3d%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(NewmanAppData%Data3D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(NewmanAppData%Data3D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(NewmanAppData%Data3D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(NewmanAppData%Data3D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - - ELSEIF ( NewmanAppData%DataIs4D ) THEN - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (NewmanAppData%Data4D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(NewmanAppData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(NewmanAppData%Data4D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (NewmanAppData%Data4D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(NewmanAppData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(NewmanAppData%Data4D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (MINVAL(NewmanAppData%Data4D%WvDir1) > 150.0_SiKi) .OR. (MAXVAL(NewmanAppData%Data4D%WvDir1) < -150.0_SiKi) .OR. & - (MINVAL(NewmanAppData%Data4D%WvDir2) > 150.0_SiKi) .OR. (MAXVAL(NewmanAppData%Data4D%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - ! --> FIXME: modify to allow shifting values by TwoPi before comparing - IF ( InitInp%WaveField%WaveDirMin < MINVAL(NewmanAppData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(NewmanAppData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(NewmanAppData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(NewmanAppData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(NewmanAppData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - - ELSE - ! No data. This is a catastrophic issue. We should not have called this routine without data that is usable for the NewmanApp calculation - CALL SetErrStat( ErrID_Fatal, ' Newman approximation calculation called without data.',ErrStat,ErrMsg,RoutineName) - ENDIF - - IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 3. Check the data to see if we need to convert to 3D arrays before continuing (4D is sparse in any dimension we want and !! frequency diagonal is complete). Only check if we don't have 3D data. @@ -1804,8 +1448,8 @@ SUBROUTINE NewmanApp_InitCalc( InitInp, p, NewmanAppData, NewmanAppForce, ErrMsg ! Set rotation ! NOTE: RotateZMatrixT is the rotation from local to global. - RotateZMatrixT(:,1) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) - RotateZMatrixT(:,2) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(1,:) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(2,:) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) ! Loop through all the frequencies DO J=1,InitInp%WaveField%NStepWave2 @@ -2017,110 +1661,10 @@ SUBROUTINE DiffQTF_InitCalc( InitInp, p, DiffQTFData, DiffQTFForce, ErrMsg, ErrS ErrStat = ErrID_None ErrStatTmp = ErrID_None - - !> 1. Check the data to see if the wave frequencies are present in the QTF data. - - IF ( DiffQTFData%DataIs4D ) THEN ! We must have a 4D data set - - ! Check the low frequency cutoff - IF ( MINVAL( DiffQTFData%Data4D%WvFreq1 ) > InitInp%WaveField%WvLowCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(DiffQTFData%Data4D%WvFreq1)))// & - ' rad/s first wave period) data in '//TRIM(DiffQTFData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffD.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MINVAL( DiffQTFData%Data4D%WvFreq2 ) > InitInp%WaveField%WvLowCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(DiffQTFData%Data4D%WvFreq2)))// & - ' rad/s for second wave period) data in '//TRIM(DiffQTFData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffD.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( MAXVAL(DiffQTFData%Data4D%WvFreq1) < InitInp%WaveField%WvHiCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(DiffQTFData%Data4D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(DiffQTFData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffD.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MAXVAL(DiffQTFData%Data4D%WvFreq2) < InitInp%WaveField%WvHiCOffD ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(DiffQTFData%Data4D%WvFreq1)))// & - ' rad/s second wave period) data in '//TRIM(DiffQTFData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffD.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE - ! This is a catastrophic issue. We should not have called this routine without data that is usable for the DiffQTF calculation - CALL SetErrStat( ErrID_Fatal, ' The full Difference QTF method requires 4D data, and was not passed any.',ErrStat,ErrMsg,RoutineName) - ENDIF - - IF ( ErrStat >= AbortErrLev ) RETURN - - - - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (DiffQTFData%Data4D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(DiffQTFData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(DiffQTFData%Data4D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (DiffQTFData%Data4D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(DiffQTFData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(DiffQTFData%Data4D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (MINVAL(DiffQTFData%Data4D%WvDir1) > 150.0_SiKi) .OR. (MAXVAL(DiffQTFData%Data4D%WvDir1) < -150.0_SiKi) .OR. & - (MINVAL(DiffQTFData%Data4D%WvDir2) > 150.0_SiKi) .OR. (MAXVAL(DiffQTFData%Data4D%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - ! --> FIXME: modify to allow shifting values by TwoPi before comparing - IF ( InitInp%WaveField%WaveDirMin < MINVAL(DiffQTFData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(DiffQTFData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(DiffQTFData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(DiffQTFData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(DiffQTFData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(DiffQTFData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(DiffQTFData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(DiffQTFData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - + CALL CheckWAMIT2WvHdg(InitInp,DiffQTFData,ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 4. Now check to make sure we have data that will work. For the 4D data, it must not be sparse. !! To check this, we have to check the load components that we will use. So, we will loop through them !! and set the TmpFlag to true if there is a sparse matrix for one of them. @@ -2331,8 +1875,8 @@ SUBROUTINE DiffQTF_InitCalc( InitInp, p, DiffQTFData, DiffQTFForce, ErrMsg, ErrS ! Set rotation ! NOTE: RotateZMatrixT is the rotation from local to global. - RotateZMatrixT(:,1) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) - RotateZMatrixT(:,2) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(1,:) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(2,:) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) ! Loop through all the frequencies DO J=1,InitInp%WaveField%NStepWave2 @@ -2523,110 +2067,10 @@ SUBROUTINE SumQTF_InitCalc( InitInp, p, SumQTFData, SumQTFForce, ErrMsg, ErrStat ErrStat = ErrID_None ErrStatTmp = ErrID_None - - !> 1. Check the data to see if the wave frequencies are present in the QTF data. - - IF ( SumQTFData%DataIs4D ) THEN ! We must have a 4D data set - - ! Check the low frequency cutoff - IF ( MINVAL( SumQTFData%Data4D%WvFreq1 ) > InitInp%WaveField%WvLowCOffS ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(SumQTFData%Data4D%WvFreq1)))// & - ' rad/s first wave period) data in '//TRIM(SumQTFData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffS.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MINVAL( SumQTFData%Data4D%WvFreq2 ) > InitInp%WaveField%WvLowCOffS ) THEN - CALL SetErrStat( ErrID_Fatal,' The lowest frequency ( '//TRIM(Num2LStr(MINVAL(SumQTFData%Data4D%WvFreq2)))// & - ' rad/s for second wave period) data in '//TRIM(SumQTFData%Filename)// & - ' is above the low frequency cutoff set by WvLowCOffS.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Check the high frequency cutoff -- using the Difference high frequency cutoff. The first order high frequency - ! cutoff is typically too high for this in most cases. - IF ( MAXVAL(SumQTFData%Data4D%WvFreq1) < InitInp%WaveField%WvHiCOffS ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(SumQTFData%Data4D%WvFreq1)))// & - ' rad/s for first wave period) data in '//TRIM(SumQTFData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffS.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - IF ( MAXVAL(SumQTFData%Data4D%WvFreq2) < InitInp%WaveField%WvHiCOffS ) THEN - CALL SetErrStat( ErrID_Fatal,' The highest frequency ( '//TRIM(Num2LStr(MAXVAL(SumQTFData%Data4D%WvFreq1)))// & - ' rad/s second wave period) data in '//TRIM(SumQTFData%Filename)// & - ' is below the high frequency cutoff set by WvHiCOffS.', & - ErrStat,ErrMsg,RoutineName) - ENDIF - - ELSE - ! This is a catastrophic issue. We should not have called this routine without data that is usable for the SumQTF calculation - CALL SetErrStat( ErrID_Fatal, ' The full Sum QTF method requires 4D data, and was not passed any.',ErrStat,ErrMsg,RoutineName) - ENDIF - - IF ( ErrStat >= AbortErrLev ) RETURN - - - - - ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. - IF ( InitInp%WaveField%WaveMultiDir .AND. (SumQTFData%Data4D%NumWvDir1 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(SumQTFData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(SumQTFData%Data4D%WvDir1(1)))//' degrees (first wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE IF ( InitInp%WaveField%WaveMultiDir .AND. (SumQTFData%Data4D%NumWvDir2 == 1) ) THEN - CALL SetErrStat( ErrID_Fatal,' WAMIT output file '//TRIM(SumQTFData%Filename)//' only contains one wave '// & - 'direction at '//TRIM(Num2LStr(SumQTFData%Data4D%WvDir2(1)))//' degrees (second wave direction). '// & - 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & - ErrStat,ErrMsg,RoutineName) - ELSE - - ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For - ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves - ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), - ! we will issue a warning. - IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & - (MINVAL(SumQTFData%Data4D%WvDir1) > 150.0_SiKi) .OR. (MAXVAL(SumQTFData%Data4D%WvDir1) < -150.0_SiKi) .OR. & - (MINVAL(SumQTFData%Data4D%WvDir2) > 150.0_SiKi) .OR. (MAXVAL(SumQTFData%Data4D%WvDir2) < -150.0_SiKi) ) THEN - CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & - 'direction of interest is near the +/- 180 direction. This is a known issue with '// & - 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,RoutineName) - ENDIF - - ! Now check the limits for the first wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - ! --> FIXME: modify to allow shifting values by TwoPi before comparing - IF ( InitInp%WaveField%WaveDirMin < MINVAL(SumQTFData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(SumQTFData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(SumQTFData%Data4D%WvDir1) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(SumQTFData%Filename)//' for the first wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - - ! Now check the limits for the second wave direction - ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. - IF ( InitInp%WaveField%WaveDirMin < MINVAL(SumQTFData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' is not'//& - 'found in the WAMIT data file '//TRIM(SumQTFData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - IF ( InitInp%WaveField%WaveDirMax > MAXVAL(SumQTFData%Data4D%WvDir2) ) THEN - CALL SetErrStat( ErrID_Fatal,' Maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' is not'//& - 'found in the WAMIT data file '//TRIM(SumQTFData%Filename)//' for the second wave direction.', & - ErrStat, ErrMsg, RoutineName) - ENDIF - - ENDIF - + CALL CheckWAMIT2WvHdg(InitInp,SumQTFData,ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN - - - !> 4. Now check to make sure we have data that will work. For the 4D data, it must not be sparse. !! To check this, we have to check the load components that we will use. So, we will loop through them !! and set the TmpFlag to true if there is a sparse matrix for one of them. @@ -2931,8 +2375,8 @@ SUBROUTINE SumQTF_InitCalc( InitInp, p, SumQTFData, SumQTFForce, ErrMsg, ErrStat ! Set rotation ! NOTE: RotateZMatrixT is the rotation from local to global. - RotateZMatrixT(:,1) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) - RotateZMatrixT(:,2) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(1,:) = (/ cos(InitInp%PtfmRefztRot(IBody)), -sin(InitInp%PtfmRefztRot(IBody)) /) + RotateZMatrixT(2,:) = (/ sin(InitInp%PtfmRefztRot(IBody)), cos(InitInp%PtfmRefztRot(IBody)) /) ! Loop through all the frequencies DO J=1,InitInp%WaveField%NStepWave2 @@ -5587,6 +5031,117 @@ SUBROUTINE Destroy_InitData4D(Data4D) END SUBROUTINE Destroy_InitData4D +SUBROUTINE CheckWAMIT2WvHdgDiffData(InitInp,W2Data,ErrStat,ErrMsg) + TYPE(WAMIT2_InitInputType), INTENT(IN ) :: InitInp !< Input data for initialization routine + TYPE(W2_DiffData_Type), INTENT(IN ) :: W2Data + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + CHARACTER(*), PARAMETER :: RoutineName = 'CheckWAMIT2WvHdgDiffData' + INTEGER(IntKi) :: ErrStatTmp + CHARACTER(ErrMsgLen) :: ErrMsgTmp + + ErrStat = ErrID_None + ErrMsg = "" + + IF ( W2Data%DataIs3D ) THEN + CALL CheckWvHdg(InitInp,W2Data%Data3D%NumWvDir1,W2Data%data3d%WvDir1,'first',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + CALL CheckWvHdg(InitInp,W2Data%Data3D%NumWvDir2,W2Data%data3d%WvDir2,'second',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + ELSEIF ( W2Data%DataIs4D ) THEN + CALL CheckWvHdg(InitInp,W2Data%Data4D%NumWvDir1,W2Data%data4D%WvDir1,'first',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + CALL CheckWvHdg(InitInp,W2Data%Data4D%NumWvDir2,W2Data%data4D%WvDir2,'second',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + ELSE + ! No data. This is a catastrophic issue. We should not have called this routine without data that is usable for the MnDrift calculation + CALL SetErrStat( ErrID_Fatal, ' Second-order wave-load calculation called without data.',ErrStat,ErrMsg,RoutineName) + ENDIF + + RETURN + +END SUBROUTINE CheckWAMIT2WvHdgDiffData + +SUBROUTINE CheckWAMIT2WvHdgSumData(InitInp,W2Data,ErrStat,ErrMsg) + TYPE(WAMIT2_InitInputType), INTENT(IN ) :: InitInp !< Input data for initialization routine + TYPE(W2_SumData_Type), INTENT(IN ) :: W2Data + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + CHARACTER(*), PARAMETER :: RoutineName = 'CheckWAMIT2WvHdgSumData' + INTEGER(IntKi) :: ErrStatTmp + CHARACTER(ErrMsgLen) :: ErrMsgTmp + + ErrStat = ErrID_None + ErrMsg = "" + + IF ( W2Data%DataIs4D ) THEN + CALL CheckWvHdg(InitInp,W2Data%Data4D%NumWvDir1,W2Data%data4D%WvDir1,'first',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + CALL CheckWvHdg(InitInp,W2Data%Data4D%NumWvDir2,W2Data%data4D%WvDir2,'second',ErrStatTmp,ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,' WAMIT output file '//TRIM(W2Data%Filename)//ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + ELSE + ! No data. This is a catastrophic issue. We should not have called this routine without data that is usable for the MnDrift calculation + CALL SetErrStat( ErrID_Fatal, ' Second-order wave-load calculation called without data.',ErrStat,ErrMsg,RoutineName) + ENDIF + + RETURN + +END SUBROUTINE CheckWAMIT2WvHdgSumData + +SUBROUTINE CheckWvHdg(InitInp,NumWAMITWvDir,WAMITWvDir,WvDirName,ErrStat,ErrMsg) + TYPE(WAMIT2_InitInputType), INTENT(IN ) :: InitInp !< Input data for initialization routine + INTEGER(IntKi), INTENT(IN ) :: NumWAMITWvDir + REAL(SiKi), INTENT(IN ) :: WAMITWvDir(:) + CHARACTER(*), INTENT(IN ) :: WvDirName + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + REAL(ReKi), PARAMETER :: WvDirTol = 0.001 ! deg + REAL(ReKi) :: RotateZdegOffset + + ErrStat = ErrID_None + ErrMsg = "" + + ! If we are using multidirectional waves, then we should have more than 1 wave direction in the WAMIT file. + IF ( InitInp%WaveField%WaveMultiDir .AND. (NumWAMITWvDir == 1) ) THEN + CALL SetErrStat( ErrID_Fatal,' only contains one '//WvDirName//' wave direction at '//TRIM(Num2LStr(WAMITWvDir(1)))//' degrees'// & + 'It cannot be used with multidirectional waves. Set WaveDirMod to 0 to use this file.', & + ErrStat,ErrMsg,'') + ELSE + ! See Known Issues #1 at the top of this file. There may be problems if the data spans the +/- Pi boundary. For + ! now (since time is limited) we will issue a warning if any of the wave directions for multidirectional waves + ! or data from the WAMIT file for the wavedirections is close to the +/-pi boundary (>150 degrees, <-150 degrees), + ! we will issue a warning. + IF ( (InitInp%WaveField%WaveDirMin > 150.0_SiKi) .OR. (InitInp%WaveField%WaveDirMax < -150.0_SiKi) .OR. & + (minval(WAMITWvDir) > 150.0_SiKi) .OR. (maxval(WAMITWvDir) < -150.0_SiKi)) THEN + CALL SetErrStat( ErrID_Warn,' There may be issues with how the wave direction data is handled when the wave '// & + 'direction of interest is near the +/- 180 direction. This is a known issue with '// & + 'the WAMIT2 module that has not yet been addressed.',ErrStat,ErrMsg,'') + ENDIF + + if (InitInp%NBodyMod==2) then ! Need to account for PtfmRefztRot (the current WAMIT2 module can only contain one body in this case) + RotateZdegOffset = InitInp%PtfmRefztRot(1)*R2D + else + RotateZdegOffset = 0.0 + end if + + ! Now check the limits for the wave direction + ! --> FIXME: sometime fix this to handle the above case. See Known Issue #1 at top of file. + IF ( (InitInp%WaveField%WaveDirMin-RotateZdegOffset) < (MINVAL(WAMITWvDir)-WvDirTol) ) THEN + CALL SetErrStat( ErrID_Fatal,' does not contain the minimum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMin))//' for the '//WvDirName//' wave direction.', & + ErrStat, ErrMsg, '') + ENDIF + IF ( (InitInp%WaveField%WaveDirMax-RotateZdegOffset) > (MAXVAL(WAMITWvDir)+WvDirTol) ) THEN + CALL SetErrStat( ErrID_Fatal,' does not contain the maximum wave direction required of '//TRIM(Num2LStr(InitInp%WaveField%WaveDirMax))//' for the '//WvDirName//' wave direction.', & + ErrStat, ErrMsg, '') + ENDIF + + ENDIF + +END SUBROUTINE CheckWvHdg + !---------------------------------------------------------------------------------------------------------------------------------- END MODULE WAMIT2 diff --git a/modules/hydrodyn/src/WAMIT_Interp.f90 b/modules/hydrodyn/src/WAMIT_Interp.f90 index 7e7ce8cfaa..585867a33a 100644 --- a/modules/hydrodyn/src/WAMIT_Interp.f90 +++ b/modules/hydrodyn/src/WAMIT_Interp.f90 @@ -29,6 +29,8 @@ MODULE WAMIT_Interp USE NWTC_Library + use SeaSt_WaveField_Types, only: SeaSt_WaveField_ParameterType, SeaSt_WaveField_MiscVarType + use SeaSt_WaveField, only: WaveField_Interp_Setup3D, WaveField_Interp_Setup4D IMPLICIT NONE PRIVATE @@ -37,8 +39,16 @@ MODULE WAMIT_Interp PUBLIC :: WAMIT_Interp2D_Cplx PUBLIC :: WAMIT_Interp3D_Cplx PUBLIC :: WAMIT_Interp4D_Cplx + public :: WAMIT_ForceWaves_Interp + + ! 3D and 4D interpolations using WaveField indexing + interface WAMIT_ForceWaves_Interp + module procedure WAMIT_ForceWaves_Interp_3D_vec6 + module procedure WAMIT_ForceWaves_Interp_4D_vec6 + end interface + CONTAINS !---------------------------------------------------------------------------------------------------------------------------------- @@ -621,5 +631,80 @@ SUBROUTINE CalcIsoparCoords( InCoord, posLo, posHi, isopc ) END SUBROUTINE CalcIsoparCoords + +!> retrieve indices from the WaveField info, and do interpolation for this point. +!! NOTE: the WAMIT field passed in here through pKinXX is based on WaveField sizing, which is why we can do this. +function WAMIT_ForceWaves_Interp_3D_vec6(Time, pos, pKinXX, WF_p, WF_m, ErrStat3, ErrMsg3) + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(2) !< position + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:) !< 3D Wave excitation data (SiKi for storage space reasons) + type(SeaSt_WaveField_ParameterType), intent(in ) :: WF_p !< wavefield parameters + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WF_m !< wavefield misc/optimization variables + integer(IntKi), intent( out) :: ErrStat3 + character(*), intent( out) :: ErrMsg3 + + real(SiKi) :: WAMIT_ForceWaves_Interp_3D_vec6(6) + real(SiKi) :: u(8) + integer(IntKi) :: i + + ! get the bounding indices from the WaveField info (same indexing used in WAMIT) + call WaveField_Interp_Setup3D( Time, pos, WF_p, WF_m, ErrStat3, ErrMsg3 ) + + ! interpolate + do i = 1,6 + u(1) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), i ) + u(2) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), i ) + u(3) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), i ) + u(4) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), i ) + u(5) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), i ) + u(6) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), i ) + u(7) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), i ) + u(8) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), i ) + WAMIT_ForceWaves_Interp_3D_vec6(i) = SUM ( WF_m%N3D * u ) + end do +end function + + +!> retrieve indices from the WaveField info, and do interpolation for this point. This is for interpolating on 4D +!! NOTE: the WAMIT field passed in here through pKinXX is based on WaveField sizing, which is why we can do this. +function WAMIT_ForceWaves_Interp_4D_vec6(Time, pos, pKinXX, WF_p, WF_m, ErrStat3, ErrMsg3) + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(3) !< position + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:,:) !< 4D Wave excitation data (SiKi for storage space reasons) + type(SeaSt_WaveField_ParameterType), intent(in ) :: WF_p !< wavefield parameters + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WF_m !< wavefield misc/optimization variables + integer(IntKi), intent( out) :: ErrStat3 + character(*), intent( out) :: ErrMsg3 + + real(SiKi) :: WAMIT_ForceWaves_Interp_4D_vec6(6) + real(SiKi) :: u(16) + integer(IntKi) :: i + + ! get the bounding indices from the WaveField info (same indexing used in WAMIT) + call WaveField_Interp_Setup4D( Time, pos, WF_p, WF_m, ErrStat3, ErrMsg3 ) + + ! interpolate + do i = 1,6 + u( 1) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), WF_m%Indx_Lo(4), i ) + u( 2) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), WF_m%Indx_Hi(4), i ) + u( 3) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), WF_m%Indx_Lo(4), i ) + u( 4) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), WF_m%Indx_Hi(4), i ) + u( 5) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), WF_m%Indx_Lo(4), i ) + u( 6) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), WF_m%Indx_Hi(4), i ) + u( 7) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), WF_m%Indx_Lo(4), i ) + u( 8) = pKinXX( WF_m%Indx_Lo(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), WF_m%Indx_Hi(4), i ) + u( 9) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), WF_m%Indx_Lo(4), i ) + u(10) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Lo(3), WF_m%Indx_Hi(4), i ) + u(11) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), WF_m%Indx_Lo(4), i ) + u(12) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Lo(2), WF_m%Indx_Hi(3), WF_m%Indx_Hi(4), i ) + u(13) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), WF_m%Indx_Lo(4), i ) + u(14) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Lo(3), WF_m%Indx_Hi(4), i ) + u(15) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), WF_m%Indx_Lo(4), i ) + u(16) = pKinXX( WF_m%Indx_Hi(1), WF_m%Indx_Hi(2), WF_m%Indx_Hi(3), WF_m%Indx_Hi(4), i ) + WAMIT_ForceWaves_Interp_4D_vec6(i) = SUM ( WF_m%N4D * u ) + end do +end function + + !---------------------------------------------------------------------------------------------------------------------------------- END MODULE WAMIT_Interp diff --git a/modules/hydrodyn/src/WAMIT_Types.f90 b/modules/hydrodyn/src/WAMIT_Types.f90 index 0c82e5c2d8..1f1bbd75dd 100644 --- a/modules/hydrodyn/src/WAMIT_Types.f90 +++ b/modules/hydrodyn/src/WAMIT_Types.f90 @@ -105,7 +105,7 @@ MODULE WAMIT_Types TYPE(Conv_Rdtn_MiscVarType) :: Conv_Rdtn !< [-] TYPE(Conv_Rdtn_InputType) :: Conv_Rdtn_u !< [-] TYPE(Conv_Rdtn_OutputType) :: Conv_Rdtn_y !< [-] - TYPE(SeaSt_Interp_MiscVarType) :: SeaSt_Interp_m !< misc var information from the SeaState Interpolation module [-] + TYPE(SeaSt_WaveField_MiscVarType) :: WaveField_m !< misc var information from the SeaState Interpolation module [-] END TYPE WAMIT_MiscVarType ! ======================= ! ========= WAMIT_ParameterType ======= @@ -722,7 +722,7 @@ subroutine WAMIT_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) call Conv_Rdtn_CopyOutput(SrcMiscData%Conv_Rdtn_y, DstMiscData%Conv_Rdtn_y, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call SeaSt_Interp_CopyMisc(SrcMiscData%SeaSt_Interp_m, DstMiscData%SeaSt_Interp_m, CtrlCode, ErrStat2, ErrMsg2) + call SeaSt_WaveField_CopyMisc(SrcMiscData%WaveField_m, DstMiscData%WaveField_m, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end subroutine @@ -766,7 +766,7 @@ subroutine WAMIT_DestroyMisc(MiscData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call Conv_Rdtn_DestroyOutput(MiscData%Conv_Rdtn_y, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call SeaSt_Interp_DestroyMisc(MiscData%SeaSt_Interp_m, ErrStat2, ErrMsg2) + call SeaSt_WaveField_DestroyMisc(MiscData%WaveField_m, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine @@ -789,7 +789,7 @@ subroutine WAMIT_PackMisc(RF, Indata) call Conv_Rdtn_PackMisc(RF, InData%Conv_Rdtn) call Conv_Rdtn_PackInput(RF, InData%Conv_Rdtn_u) call Conv_Rdtn_PackOutput(RF, InData%Conv_Rdtn_y) - call SeaSt_Interp_PackMisc(RF, InData%SeaSt_Interp_m) + call SeaSt_WaveField_PackMisc(RF, InData%WaveField_m) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -815,7 +815,7 @@ subroutine WAMIT_UnPackMisc(RF, OutData) call Conv_Rdtn_UnpackMisc(RF, OutData%Conv_Rdtn) ! Conv_Rdtn call Conv_Rdtn_UnpackInput(RF, OutData%Conv_Rdtn_u) ! Conv_Rdtn_u call Conv_Rdtn_UnpackOutput(RF, OutData%Conv_Rdtn_y) ! Conv_Rdtn_y - call SeaSt_Interp_UnpackMisc(RF, OutData%SeaSt_Interp_m) ! SeaSt_Interp_m + call SeaSt_WaveField_UnpackMisc(RF, OutData%WaveField_m) ! WaveField_m end subroutine subroutine WAMIT_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/lindyn/CMakeLists.txt b/modules/lindyn/CMakeLists.txt new file mode 100644 index 0000000000..4e010d16e5 --- /dev/null +++ b/modules/lindyn/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2016 National Renewable Energy Laboratory +# +# 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. +# + +if (GENERATE_TYPES) + generate_f90_types(src/LinDyn_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/LinDyn_Types.f90) +endif() + +add_library(lindynlib + src/LinDyn.f90 + src/LinDyn_Types.f90 +) +target_link_libraries(lindynlib nwtclibs) + +install(TARGETS lindynlib + EXPORT "${CMAKE_PROJECT_NAME}Libraries" + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/modules/lindyn/README.md b/modules/lindyn/README.md new file mode 100644 index 0000000000..564ae516eb --- /dev/null +++ b/modules/lindyn/README.md @@ -0,0 +1,4 @@ +# LinDyn Module + +## Overview +A module for linear dynamics (m, c, k, f) in OpenFAST diff --git a/modules/lindyn/src/LinDyn.f90 b/modules/lindyn/src/LinDyn.f90 new file mode 100644 index 0000000000..9ae64598f4 --- /dev/null +++ b/modules/lindyn/src/LinDyn.f90 @@ -0,0 +1,938 @@ +!********************************************************************************************************************************** +!> LinDyn, module for a second order linear dynamical system with mass, stiffness and damping matrix +!! +!! The state is q = [x; xdot], of shape nq = 2*nx +!! The input is F_ext of shape nx +!! The equation of motion is: +!! +!! qdot = [xdot ] = [ 0 I ] [ x ] + [ 0 ] F_ext +!! [xddot] [-M^{-1} K -M^{-1} C ] [ xdot] + [M^{-1}] +!! +!! .................................................................................................................................. +!! ## Licensing +!! Copyright (C) 2012-2013, 2015-2016 National Renewable Energy Laboratory +!! +!! This file is part of LinDyn. +!! +!! 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 LinDyn + + use LinDyn_Types + use NWTC_Library + USE NWTC_LAPACK +! + implicit none + + type(ProgDesc), parameter :: LD_Ver = ProgDesc( 'LinDyn', '', '' ) + + private + + public :: LD_Init ! Initialization routine + public :: LD_InitInputData ! Set default values and allocations for init + public :: LD_End ! Ending routine (includes clean up) + public :: LD_UpdateStates ! Loose coupling routine for solving for constraint states, integrating continuous states, and updating discrete states + public :: LD_CalcOutput ! Routine for computing outputs + public :: LD_CalcContStateDeriv ! Tight coupling routine for computing derivatives of continuous states + public :: LD_JacobianPInput ! Jacobians of (y, x, xd, z) with respect to the inputs (u) + public :: LD_JacobianPContState ! Jacobians of (y, x, xd, z) with respect to the continuous (x) + public :: LD_GetOP ! Routine to get the operating-point values for linearization (from data structures to arrays) +! +contains + +subroutine LD_Init(InitInp, u, p, x, xd, z, OtherState, y, m, InitOut, errStat, errMsg) + type(LD_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine + type(LD_InputType), intent(out) :: u !< An initial guess for the input; input mesh must be defined + type(LD_ParameterType), intent(out) :: p !< Parameters + type(LD_ContinuousStateType), intent(out) :: x !< Initial continuous states + type(LD_DiscreteStateType), intent(out) :: xd !< Initial discrete states + type(LD_ConstraintStateType), intent(out) :: z !< Initial guess of the constraint states + type(LD_OtherStateType), intent(out) :: OtherState !< Initial other states (logical, etc) + type(LD_OutputType), intent(out) :: y !< Initial system outputs (outputs are not calculated; + type(LD_MiscVarType), intent(out) :: m !< Misc variables for optimization (not copied in glue code) + type(LD_InitOutputType), intent(out) :: 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 + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + ! Misc Init + errStat = ErrID_None + errMsg = "" + call NWTC_Init( ) ! Initialize the NWTC Subroutine Library + call DispNVD( LD_Ver ) ! Display the module information + + ! --- Setting Params from InitInp + p%nx = size(InitInp%MM,1) + p%nq = 2*p%nx + call AllocAry(p%MM , p%nx, p%nx, 'MM', errStat2, errMsg2); if(Failed()) return + call AllocAry(p%CC , p%nx, p%nx, 'CC', errStat2, errMsg2); if(Failed()) return + call AllocAry(p%KK , p%nx, p%nx, 'KK', errStat2, errMsg2); if(Failed()) return + call AllocAry(p%activeDOFs, p%nx , 'activeDOFs', errStat2, errMsg2); if(Failed()) return + p%dt = InitInp%dt + p%IntMethod = InitInp%IntMethod + p%MM = InitInp%MM + p%CC = InitInp%CC + p%KK = InitInp%KK + p%activeDOFs = InitInp%activeDOFs + ! Prescribed motion + if (len_trim(InitInp%PrescribedMotionFile)>0) then + if( count(p%activeDOFs)/=0) then + errStat2 = errID_Fatal + errMsg2 = 'Currently, prescribed motion is only allowed if all degrees of freedom are turned off' + if(Failed()) return + endif + call WrScr(' Using prescribed motion.') + call ReadDelimFile(InitInp%PrescribedMotionFile, (p%nx*3+1), p%PrescribedValues, errStat2, errMsg2); if(Failed()) return + else + if (allocated(p%PrescribedValues)) deallocate(p%PrescribedValues) + endif + call StateMatrices(p%MM, p%CC, p%KK, p%AA, p%BB, errStat2, errMsg2); if(Failed()) return + + ! --- Misc + call allocAry(m%qPrescribed, 3*p%nx, 'qPrescribed', errStat2, errMsg2); if(Failed()) return + m%qPrescribed = 0.0_ReKi ! NOTE: will be updated by LD_SetInitialConditions + + ! --- Allocate States + call AllocAry( x%q , p%nq, 'DOFs', errStat, errMsg); if(Failed()) return + call LD_SetInitialConditions(x, InitInp%x0, InitInp%xd0, p, OtherState, m, errStat, errMsg); if(Failed()) return + if ( ( p%IntMethod .eq. 2) .OR. ( p%IntMethod .eq. 3)) then !Multi-step methods + allocate( OtherState%xdot(4), STAT=errStat2); errMsg2='Error allocating OtherState%xdot' + if(Failed()) return + endif + + ! --- Guess inputs + call AllocAry(u%Fext, p%nx, 'Fext', errStat2, errMsg2); if(Failed()) return + u%Fext=0.0_ReKi + + ! --- Outputs & Write Outputs + call Init_Outputs(p, m, y, InitInp, InitOut, errStat, errMsg); if(Failed()) return + InitOut%Ver = LD_Ver + + ! --- Linearization + if (InitInp%Linearize) then + call Init_Lin(p, InitOut, errStat, errMsg); if(Failed()) return + endif +! +! ! --- Summary file +! if (InputFileData%SumPrint) then +! TODO use yaml +! print*,'' +! print*,'M',p%MM(1,:) +! print*,'M',p%MM(2,:) +! print*,'M',p%MM(3,:) +! print*,'' +! print*,'C',p%CC(1,:) +! print*,'C',p%CC(2,:) +! print*,'C',p%CC(3,:) +! print*,'' +! print*,'K',p%KK(1,:) +! print*,'K',p%KK(2,:) +! print*,'K',p%KK(3,:) +! print*,'' +! +! print*,'' +! print*,'A',p%AA(1,:) +! print*,'A',p%AA(2,:) +! print*,'A',p%AA(3,:) +! print*,'A',p%AA(4,:) +! print*,'A',p%AA(5,:) +! print*,'A',p%AA(6,:) +! print*,'' +! print*,'B',p%BB(1,:) +! print*,'B',p%BB(2,:) +! print*,'B',p%BB(3,:) +! print*,'B',p%BB(4,:) +! print*,'B',p%BB(5,:) +! print*,'B',p%BB(6,:) +! endif +! +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'LD_Init' ) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine CleanUp() + end subroutine CleanUp +end subroutine LD_Init +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine LD_SetInitialConditions(x, x0, xd0, p, OtherState, m, errStat, errMsg) + type(LD_ContinuousStateType), intent(inout) :: x !< Initial continuous states + real(ReKi), intent(in) :: x0(:) !< Values of the positions at t=0 + real(ReKi), intent(in) :: xd0(:) !< Velocity values at t=0 + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states + type(LD_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + integer :: nx + nx = int(size(x%q)/2) + errStat = ErrID_Fatal + if (size(x0)/=size(xd0)) then + errMsg ='Shape of x0 and xd0 should match when setting intial conditions'; return + endif + if (size(x0)/=nx) then + errMsg ='Shape of x0 should match nx when setting intial conditions'; return + endif + errMsg = '' + errStat = ErrID_None + + if (allocated(p%PrescribedValues)) then + call interpTimeValue(p%PrescribedValues, 0.0_DbKi, OtherState%iMotionInterpLast, m%qPrescribed(:)) + ! TODO the code below will need to be updated if a subset of the DOFs are active + x%q(1:p%nq) = m%qPrescribed(1:p%nq) + else + x%q( 1:nx) = x0 + x%q(nx+1:2*nx) = xd0 + endif +end subroutine LD_SetInitialConditions +!---------------------------------------------------------------------------------------------------------------------------------- +!> Allocate init input data for module based on number of degrees of freedom +subroutine LD_InitInputData(nx, InitInp, errStat, errMsg) + integer(IntKi), intent(in ) :: nx !< Number of degrees of freedom + type(LD_InitInputType), intent(out) :: InitInp !< Input data for initialization routine + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + integer(IntKi) :: iDOF + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + ! Initialize errStat + errStat = ErrID_None ! no error has occurred + errMsg = "" + call AllocAry(InitInp%MM , nx, nx, 'MM' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%CC , nx, nx, 'CC' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%KK , nx, nx, 'KK' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%x0 , nx , 'x0' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%xd0 , nx , 'xd0', errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%activeDOFs, nx , 'activeDOFs', errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%DOFsNames , nx , 'DOFsNames' , errStat2, errMsg2); if(Failed()) return + call AllocAry(InitInp%DOFsUnits , nx , 'DOFsUnits' , errStat2, errMsg2); if(Failed()) return + InitInp%MM = 0.0_ReKi + InitInp%CC = 0.0_ReKi + InitInp%KK = 0.0_ReKi + InitInp%x0 = 0.0_ReKi + InitInp%xd0 = 0.0_ReKi + InitInp%activeDOFs = .True. + ! Default DOFs Names and Units + do iDOF=1,nx + InitInp%DOFsNames(iDOF)='x'//trim(num2lstr(iDOF)) + InitInp%DOFsUnits(iDOF)='-' + enddo + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'LD_Init' ) + Failed = ErrStat >= AbortErrLev + end function Failed +end subroutine LD_InitInputData +!---------------------------------------------------------------------------------------------------------------------------------- +!> Compute A and B state matrices for a linear mechanical system +!! NOTE: Generic function (no derived types), keep it that way +!! A = [ 0 I ] B = [0 ] +!! [-M^{-1}K -M^{-1}C ] = [-M^{-1}] +subroutine StateMatrices(MM, CC, KK, AA, BB, errStat, errMsg) + real(ReKi), intent(in ) :: MM(:,:) + real(ReKi), intent(in ) :: CC(:,:) + real(ReKi), intent(in ) :: KK(:,:) + real(ReKi), allocatable, intent(out) :: AA(:,:) + real(ReKi), allocatable, intent(out) :: BB(:,:) + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + integer :: nx, nq, i + real(ReKi), dimension(:,:), allocatable :: MLU ! LU factorization of M matrix + real(ReKi), dimension(:,:), allocatable :: MinvX ! Tmp array to store either: M^{-1} C, M^{-1} K , or M^{-1} + real(ReKi), dimension(:) , allocatable :: WORK ! LAPACK variable + integer, allocatable :: IPIV(:) ! LAPACK variable + integer :: LWORK ! LAPACK variable + ! Initialize errStat + errStat = ErrID_None + errMsg = "" + + ! --- Init A and B matrix + nx = size(MM,1) + nq = 2*nx + call AllocAry(AA, nq, nq, 'AA', errStat2, errMsg2); if(Failed()) return + call AllocAry(BB, nq, nx, 'BB', errStat2, errMsg2); if(Failed()) return + AA(:,:) = 0.0_ReKi + BB(:,:) = 0.0_ReKi + do i=1,nx ; AA(i,i+nx)=1; enddo ! Identity matrix for upper right block + + ! --- Compute misc inverse of M and put in A and B matrices + call AllocAry(IPIV , nx , 'IPIV' , errStat2, errMsg2); if(Failed()) return + call AllocAry(MinvX , nx, nx, 'MinvX', errStat2, errMsg2); if(Failed()) return + call AllocAry(MLU , nx, nx, 'MLU' , errStat2, errMsg2); if(Failed()) return + + ! LU Factorization of M + MLU = MM ! temp copy + call LAPACK_getrf(nx, nx, MLU, IPIV, errStat2, errMsg2); if(Failed()) return + + ! M^-1 C + MinvX = CC + call LAPACK_getrs('n', nx, MLU, IPIV, MinvX, errStat2, errMsg2); if(Failed()) return + AA(nx+1:nq,nx+1:nq) = -MinvX + + ! M^-1 K + MinvX = KK + call LAPACK_getrs('n', nx, MLU, IPIV, MinvX, errStat2, errMsg2); if(Failed()) return + AA(nx+1:nq, 1:nx) = -MinvX + + ! Inverse of M + MinvX = MLU + LWORK=nx*nx ! Somehow LWORK = -1 does not work + allocate(WORK(LWORk)) + call LAPACK_getri(nx, MinvX, IPIV, WORK, LWORK, errStat2, errMsg2); if(Failed()) return + BB(nx+1:nq, : ) = -MinvX + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'StateMatrices' ) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine CleanUp() + if (allocated(MLU)) deallocate(MLU) + if (allocated(IPIV)) deallocate(IPIV) + if (allocated(WORK )) deallocate(WORK) + if (allocated(MinvX)) deallocate(MinvX) + end subroutine CleanUp +end subroutine StateMatrices +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine is called at the end of the simulation. +subroutine LD_End( u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) + type(LD_InputType), intent(inout) :: u !< System inputs + type(LD_ParameterType), intent(inout) :: p !< Parameters + type(LD_ContinuousStateType), intent(inout) :: x !< Continuous states + type(LD_DiscreteStateType), intent(inout) :: xd !< Discrete states + type(LD_ConstraintStateType), intent(inout) :: z !< Constraint states + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states + type(LD_OutputType), intent(inout) :: y !< System outputs + type(LD_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + ! Initialize errStat + errStat = ErrID_None ! no error has occurred + errMsg = "" + call LD_DestroyInput (u ,errStat,errMsg) + call LD_DestroyParam (p ,errStat,errMsg) + call LD_DestroyContState (x ,errStat,errMsg) + call LD_DestroyDiscState (xd ,errStat,errMsg) + call LD_DestroyConstrState(z ,errStat,errMsg) + call LD_DestroyOtherState (OtherState,errStat,errMsg) + call LD_DestroyOutput (y ,errStat,errMsg) + call LD_DestroyMisc (m ,errStat,errMsg) +end subroutine LD_End +!---------------------------------------------------------------------------------------------------------------------------------- +!> Fourth-order Adams-Bashforth Method (RK4) for numerically integration (see ElastoDyn.f9) +subroutine LD_AB4( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< time step number + type(LD_InputType), intent(inout) :: u(:) !< Inputs at t + real(DbKi), intent(in ) :: utimes(:) !< times of input + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(inout) :: x !< Continuous states at t on input at t + dt on output + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at t (possibly a guess) + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states at t on input at t + dt on output + type(LD_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 + type(LD_ContinuousStateType) :: xdot ! Continuous state derivs at t + type(LD_InputType) :: u_interp + ! Initialize errStat + errStat = ErrID_None + errMsg = "" + + ! need xdot at t + call LD_CopyInput(u(1), u_interp, MESH_NEWCOPY, errStat, errMsg ) ! we need to allocate input arrays/meshes before calling ExtrapInterp... + call LD_Input_ExtrapInterp(u, utimes, u_interp, t, errStat, errMsg) + call LD_CalcContStateDeriv( t, u_interp, p, x, xd, z, OtherState, m, xdot, errStat, errMsg ) ! initializes xdot + call LD_DestroyInput( u_interp, errStat, errMsg) ! we don't need this local copy anymore + if (n .le. 2) then + OtherState%n = n + call LD_CopyContState(xdot, OtherState%xdot(3-n), MESH_UPDATECOPY, errStat, errMsg ) + call LD_RK4(t, n, u, utimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + else + if (OtherState%n .lt. n) then + OtherState%n = n + call LD_CopyContState(OtherState%xdot(3), OtherState%xdot(4), MESH_UPDATECOPY, errStat, errMsg ) + call LD_CopyContState(OtherState%xdot(2), OtherState%xdot(3), MESH_UPDATECOPY, errStat, errMsg ) + call LD_CopyContState(OtherState%xdot(1), OtherState%xdot(2), MESH_UPDATECOPY, errStat, errMsg ) + elseif (OtherState%n .gt. n) then + errStat = ErrID_Fatal + errMsg = ' Backing up in time is not supported with a multistep method ' + return + endif + call LD_CopyContState( xdot, OtherState%xdot ( 1 ), MESH_UPDATECOPY, errStat, errMsg ) + !OtherState%xdot ( 1 ) = xdot ! make sure this is most up to date + x%q = x%q + (p%dt / 24._ReKi) * (55._ReKi*OtherState%xdot(1)%q - 59._ReKi*OtherState%xdot(2)%q + 37._ReKi*OtherState%xdot(3)%q - 9._ReKi * OtherState%xdot(4)%q) + endif + call LD_DestroyContState(xdot, errStat, errMsg) + call LD_DestroyInput(u_interp, errStat, errMsg) +end subroutine LD_AB4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> Fourth-order Adams-Bashforth-Moulton Method (RK4) for numerically integrating (see ElastoDyn.f90) +subroutine LD_ABM4( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< time step number + type(LD_InputType), intent(inout) :: u(:) !< Inputs at t + real(DbKi), intent(in ) :: utimes(:) !< times of input + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(inout) :: x !< Continuous states at t on input at t + dt on output ! TODO TODO TODO in + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at t (possibly a guess) + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states at t on input at t + dt on output + type(LD_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 + type(LD_InputType) :: u_interp ! Continuous states at t + type(LD_ContinuousStateType) :: x_pred ! Continuous states at t + type(LD_ContinuousStateType) :: xdot_pred ! Continuous states at t + ! Initialize errStat + errStat = ErrID_None + errMsg = "" + call LD_CopyContState(x, x_pred, MESH_NEWCOPY, errStat, errMsg) !initialize x_pred + call LD_AB4( t, n, u, utimes, p, x_pred, xd, z, OtherState, m, errStat, errMsg ) + if (n .gt. 2) then + call LD_CopyInput( u(1), u_interp, MESH_NEWCOPY, errStat, errMsg) ! make copy so that arrays/meshes get initialized/allocated for ExtrapInterp + call LD_Input_ExtrapInterp(u, utimes, u_interp, t + p%dt, errStat, errMsg) + call LD_CalcContStateDeriv(t + p%dt, u_interp, p, x_pred, xd, z, OtherState, m, xdot_pred, errStat, errMsg ) ! initializes xdot_pred + call LD_DestroyInput( u_interp, errStat, errMsg) ! local copy no longer needed + + x%q = x%q + (p%dt / 24.) * ( 9. * xdot_pred%q + 19. * OtherState%xdot(1)%q - 5. * OtherState%xdot(2)%q + 1. * OtherState%xdot(3)%q ) + call LD_DestroyContState( xdot_pred, errStat, errMsg) ! local copy no longer needed + else + x%q = x_pred%q + endif + call LD_DestroyContState( x_pred, errStat, errMsg) ! local copy no longer needed +end subroutine LD_ABM4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> Fourth-order Runge-Kutta Method (RK4) for numerically integration (see ElastoDyn.f90) +subroutine LD_RK4( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< time step number + type(LD_InputType), intent(inout) :: u(:) !< Inputs at t + real(DbKi), intent(in ) :: utimes(:) !< times of input + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(inout) :: x !< Continuous states at t on input at t + dt on output + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at t (possibly a guess) + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states at t on input at t + dt on output + type(LD_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 + type(LD_ContinuousStateType) :: xdot ! time derivatives of continuous states + type(LD_ContinuousStateType) :: k1 ! RK4 constant; see above + type(LD_ContinuousStateType) :: k2 ! RK4 constant; see above + type(LD_ContinuousStateType) :: k3 ! RK4 constant; see above + type(LD_ContinuousStateType) :: k4 ! RK4 constant; see above + type(LD_ContinuousStateType) :: x_tmp ! Holds temporary modification to x + type(LD_InputType) :: u_interp ! interpolated value of inputs + ! Initialize errStat + errStat = ErrID_None + errMsg = "" + + ! Initialize interim vars + call LD_CopyContState( x, k1, MESH_NEWCOPY, errStat, errMsg ) + call LD_CopyContState( x, k2, MESH_NEWCOPY, errStat, errMsg ) + call LD_CopyContState( x, k3, MESH_NEWCOPY, errStat, errMsg ) + call LD_CopyContState( x, k4, MESH_NEWCOPY, errStat, errMsg ) + call LD_CopyContState( x, x_tmp, MESH_NEWCOPY, errStat, errMsg ) + + ! interpolate u to find u_interp = u(t) + call LD_CopyInput(u(1), u_interp, MESH_NEWCOPY, errStat, errMsg ) ! we need to allocate input arrays/meshes before calling ExtrapInterp... + call LD_Input_ExtrapInterp( u, utimes, u_interp, t, errStat, errMsg ) + + ! find xdot at t + call LD_CalcContStateDeriv( t, u_interp, p, x, xd, z, OtherState, m, xdot, errStat, errMsg ) !initializes xdot + + k1%q = p%dt * xdot%q + x_tmp%q = x%q + 0.5_ReKi * k1%q + + ! interpolate u to find u_interp = u(t + dt/2) + call LD_Input_ExtrapInterp(u, utimes, u_interp, t+0.5_ReKi*p%dt, errStat, errMsg) + + ! find xdot at t + dt/2 + call LD_CalcContStateDeriv( t + 0.5_ReKi*p%dt, u_interp, p, x_tmp, xd, z, OtherState, m, xdot, errStat, errMsg ) + + k2%q = p%dt * xdot%q + x_tmp%q = x%q + 0.5_ReKi * k2%q + + ! find xdot at t + dt/2 + call LD_CalcContStateDeriv( t + 0.5_ReKi*p%dt, u_interp, p, x_tmp, xd, z, OtherState, m, xdot, errStat, errMsg ) + + k3%q = p%dt * xdot%q + x_tmp%q = x%q + k3%q + + ! interpolate u to find u_interp = u(t + dt) + call LD_Input_ExtrapInterp(u, utimes, u_interp, t + p%dt, errStat, errMsg) + + ! find xdot at t + dt + call LD_CalcContStateDeriv( t + p%dt, u_interp, p, x_tmp, xd, z, OtherState, m, xdot, errStat, errMsg ) + k4%q = p%dt * xdot%q + x%q = x%q + ( k1%q + 2._ReKi * k2%q + 2._ReKi * k3%q + k4%q ) / 6._ReKi + call CleanUp() +contains + subroutine CleanUp() + integer(IntKi) :: errStat3 ! The error identifier (errStat) + character(1024) :: errMsg3 ! The error message (errMsg) + call LD_DestroyContState( xdot, errStat3, errMsg3 ) + call LD_DestroyContState( k1, errStat3, errMsg3 ) + call LD_DestroyContState( k2, errStat3, errMsg3 ) + call LD_DestroyContState( k3, errStat3, errMsg3 ) + call LD_DestroyContState( k4, errStat3, errMsg3 ) + call LD_DestroyContState( x_tmp, errStat3, errMsg3 ) + call LD_DestroyInput( u_interp, errStat3, errMsg3 ) + end subroutine CleanUp +end subroutine LD_RK4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> Loose coupling routine for solving states at t+dt +subroutine LD_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< Current step of the simulation: t = n*dt + type(LD_InputType), intent(inout) :: Inputs(:) !< Inputs at InputTimes (output from this routine only + real(DbKi), intent(in ) :: InputTimes(:) !< Times in seconds associated with Inputs + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; Output: at t+dt + type(LD_DiscreteStateType), intent(inout) :: xd !< Input: Discrete states at t; Output: at t+dt + type(LD_ConstraintStateType), intent(inout) :: z !< Input: Constraint states at t; Output: at t+dt + type(LD_OtherStateType), intent(inout) :: OtherState !< Other states: Other states at t;Output: at t+dt + type(LD_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + ! Initialize variables + errStat = ErrID_None ! no error has occurred + errMsg = "" + if (allocated(p%PrescribedValues)) then + call interpTimeValue(p%PrescribedValues, t+p%dt, OtherState%iMotionInterpLast, m%qPrescribed(:)) + x%q(1:p%nq) = m%qPrescribed(1:p%nq) + endif + if ( p%nq == 0) return + if (p%IntMethod .eq. 1) then + call LD_RK4( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + elseif (p%IntMethod .eq. 2) then + call LD_AB4( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + elseif (p%IntMethod .eq. 3) then + call LD_ABM4( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, errStat, errMsg ) + else + call SeterrStat(ErrID_Fatal,'Invalid time integration method:'//Num2LStr(p%IntMethod),errStat,errMsg,'LD_UpdateState') + end if +end subroutine LD_UpdateStates +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a routine for computing outputs, used in both loose and tight coupling. +subroutine LD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(LD_InputType), intent(in ) :: u !< Inputs at t + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(LD_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(LD_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(LD_OutputType), intent(inout) :: y !< Outputs computed at t (Input only so that mesh con- + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + type(LD_ContinuousStateType) :: dxdt !< + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + errStat = ErrID_None ! no error has occurred + errMsg = "" + + ! --- Compute accelerations + if (allocated(p%PrescribedValues)) then + y%xdd(1:p%nx) = m%qPrescribed(p%nq+1:p%nq+p%nx) + else + call LD_CalcContStateDeriv(t, u, p, x, xd, z, OtherState, m, dxdt, errStat2, errMsg2) + y%xdd(1:p%nx) = dxdt%q(p%nx+1:p%nq) + endif + + !--- Computing outputs: y = Cx + Du (optional) + + ! --- Write Outputs + y%WriteOutput(1:2*p%nx) = x%q(1:p%nq) ! Positions and velocities + y%WriteOutput(2*p%nx+1:3*p%nx) = y%xdd(1:p%nx) ! Accelerations + y%WriteOutput(3*p%nx+1:4*p%nx) = u%Fext(1:p%nx) ! Forces + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'LD_CalcOutput' ) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine LD_CalcOutput +!---------------------------------------------------------------------------------------------------------------------------------- +!> Tight coupling routine for computing derivatives of continuous states. +subroutine LD_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, errStat, errMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(LD_InputType), intent(in ) :: u !< Inputs at t + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(LD_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(LD_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(LD_ContinuousStateType), intent(out) :: dxdt !< Continuous state derivatives at t + integer(IntKi), intent(out) :: errStat !< Error status of the operation + character(*), intent(out) :: errMsg !< Error message if errStat /= ErrID_None + ! Local variables + integer(IntKi) :: iDOF + integer(IntKi) :: errStat2 ! Status of error message + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + ! Initialize variables + errStat = ErrID_None ! no error has occurred + errMsg = "" + ! Allocation of output dxdt (since intent(out)) + call AllocAry(dxdt%q, p%nq, 'dxdt%q', errStat2, errMsg2); if(Failed()) return + if ( p%nq == 0 ) return + + ! --- Computation of dq + ! >>> MATMUL IMPLEMENTATION + dxdt%q = matmul(p%AA,x%q) + matmul(p%BB,u%Fext) + ! >>> BLAS IMPLEMENTATION + ! COPY( N , X , inCX, Y , inCY) + !call LAPACK_COPY(p%nCB, x%qmdot , 1 , dxdt%qm , 1 ) ! qmdot=qmdot + !! GEMV(TRS, M , N , alpha , A , LDA , X ,inCX, Beta , Y , IncY) + !call LAPACK_GEMV('n', p%nq, p%nq , 1.0_ReKi, p%AA, p%nq, x%q , 1 , 1.0_ReKi, dxdt%qmdot, 1 ) ! - K22 x2 + !call LAPACK_GEMV('n', p%nq, p%nx , 1.0_ReKi, p%BB, p%nq, u%Fext, 1 , 1.0_ReKi, dxdt%qmdot, 1 ) ! - M21 \ddot{x1} + ! --- Desactivating Constant DOFs + do iDOF = 1,p%nx + if (.not. p%activeDOFs(iDOF)) then + dxdt%q(iDOF ) = 0.0_ReKi + dxdt%q(iDOF+p%nx) = 0.0_ReKi + endif + enddo + +contains + logical function Failed() + call SetErrStat( errStat2, errMsg2, errStat, errMsg, 'LD_CalcContStateDeriv' ) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine LD_CalcContStateDeriv +!---------------------------------------------------------------------------------------------------------------------------------- +!> Setup outputs +subroutine Init_Outputs(p, m, y, InitInp, InitOut, errStat, errMsg) + ! character(ChanLen), intent(in) :: OutList(:) !< list of user-requested outputs + type(LD_ParameterType), intent(inout) :: p !< module parameters + type(LD_MiscVarType), intent(inout) :: m !< module misc + type(LD_OutputType), intent(inout) :: y !< module outputs + type(LD_InitInputType), intent(in ) :: InitInp !< module init inputs + type(LD_InitOutputType),intent(inout) :: InitOut !< module init outputs + integer(intki), intent(out) :: errStat !< error status code + character(*), intent(out) :: errMsg !< error message, if an error occurred + integer :: errStat2 ! temporary (local) error status + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + integer :: i, iOut + errStat = ErrID_None + errMsg = "" + + ! --- Regular outputs + call AllocAry(y%xdd, p%nx, 'qd', errStat2, errMsg2); if(Failed()) return + y%xdd = 0.0_ReKi + + ! --- Write Outputs + p%NumOuts = (p%nx) * (1 + 1 + 1 + 1) ! Pos, Vel, Acc, Force + + !call AllocAry(m%AllOuts, p%NumOuts, "LinDyn AllOut", errStat,errMsg ); if(Failed()) return; m%AllOuts(:) = 0.0_ReKi + call AllocAry(y%WriteOutput, p%NumOuts,'WriteOutput', errStat,errMsg); if(Failed()) return + call AllocAry(InitOut%WriteOutputHdr,p%NumOuts,'WriteOutputHdr',errStat,errMsg); if(Failed()) return + call AllocAry(InitOut%WriteOutputUnt,p%NumOuts,'WriteOutputUnt',errStat,errMsg); if(Failed()) return + y%WriteOutput(1:p%NumOuts) = 0.0 + + ! Sanity checks + if (.not. allocated(InitInp%DOFsNames)) then + errStat2 = errID_Fatal; errMsg2='DOFs Names not allocated'; if(Failed()) return + else + if(size(InitInp%DOFsNames)/=p%nx) then + errStat2 = errID_Fatal; errMsg2='Shape of DOFs Names incorrect'; if(Failed()) return + endif + if (.not.allocated(InitInp%DOFsUnits)) then + errStat2 = errID_Fatal; errMsg2='DOFs Units should be allocated if Names are provided'; if(Failed()) return + endif + if(size(InitInp%DOFsUnits)/=p%nx) then + errStat2 = errID_Fatal; errMsg2='Shape of DOFs Units incorrect'; if(Failed()) return + endif + endif + + iOut = 0 ! Cumulative counter + call SetWriteOutputsForDOFs('' ) ! Positions + call SetWriteOutputsForDOFs('d' ) ! Velocities + call SetWriteOutputsForDOFs('dd') ! Accelerations + call SetWriteOutputsForDOFs('f' ) ! Forces + + ! If using OutParam instead + !InitOut%WriteOutputHdr(1:p%NumOuts) = p%OutParam(1:p%NumOuts)%Name + !InitOut%WriteOutputUnt(1:p%NumOuts) = p%OutParam(1:p%NumOuts)%Units + ! Debug output to screen + !do i = 1,p%NumOuts + ! print*,i, InitOut%WriteOutputHdr(i), InitOut%WriteOutputUnt(i) + !enddo + +contains + subroutine SetWriteOutputsForDOFs(sPrefix) + character(len=*) :: sPrefix + do i = 1, p%nx + iOut = iOut+1 + InitOut%WriteOutputHdr(iOut) = trim(InitInp%prefix)//trim(sPrefix)//trim(InitInp%DOFsNames(i)) + ! Units + if (sPrefix == '') InitOut%WriteOutputUnt(iOut) ='('//trim(InitInp%DOFsUnits(i))//')' + if (sPrefix == 'd') InitOut%WriteOutputUnt(iOut) ='('//trim(InitInp%DOFsUnits(i))//'/s)' + if (sPrefix == 'dd') InitOut%WriteOutputUnt(iOut) ='('//trim(InitInp%DOFsUnits(i))//'/s^2)' + if (sPrefix == 'f') then + if (InitInp%DOFsUnits(i)=='m') then; InitOut%WriteOutputUnt(iOut) ='(N)' ; + elseif (InitInp%DOFsUnits(i)=='rad') then; InitOut%WriteOutputUnt(iOut) ='(Nm)' ; + else; InitOut%WriteOutputUnt(iOut) ='(-)' + endif + endif + enddo + endsubroutine + + logical function Failed() + call SetErrStat( errStat2, errMsg2, errStat, errMsg, 'Init_Outputs' ) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine Init_Outputs +!---------------------------------------------------------------------------------------------------------------------------------- +!> Setup Linearization data +subroutine Init_Lin(p, InitOut, errStat, errMsg) + type(LD_ParameterType), intent(in ) :: p !< module parameters + type(LD_InitOutputType),intent(inout) :: InitOut !< module init outputs + integer(intki), intent(out) :: errStat !< error status code + character(*), intent(out) :: errMsg !< error message, if an error occurred + integer :: errStat2 ! temporary (local) error status + character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None + integer :: i, nu + errStat = ErrID_None + errMsg = "" + nu = p%nx + +! LinNames_y {:} - - "Names of the outputs used in linearization" - +! LinNames_x {:} - - "Names of the continuous states used in linearization" - +! LinNames_u {:} - - "Names of the inputs used in linearization" - +! RotFrame_y {:} - - "Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame" - +! RotFrame_x {:} - - "Flag that tells FAST/MBC3 if the continuous states used in linearization are in the rotating frame" - +! RotFrame_u {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - +! IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - +! DerivOrder_x {:} - - "Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization" - + !Appropriate Jacobian row/column names and rotating-frame flags here: + call AllocAry(InitOut%LinNames_y , p%NumOuts , 'LinNames_y', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%RotFrame_y , p%NumOuts , 'RotFrame_y', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%LinNames_x , p%nq , 'LinNames_x', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%RotFrame_x , p%nq , 'RotFrame_x', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%DerivOrder_x, p%nq , 'DerivOrd_x', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%LinNames_u , nu , 'LinNames_u', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%RotFrame_u , nu , 'RotFrame_u', errStat, errMsg); if(Failed()) return + call AllocAry(InitOut%IsLoad_u , nu , 'IsLoad_u' , errStat, errMsg); if(Failed()) return + InitOut%DerivOrder_x(:)=2 + ! LinNames_y + do i=1, p%NumOuts + InitOut%LinNames_y(i) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) + print*,'y',i, trim(InitOut%LinNames_y(i)) + enddo + ! LinNames_u + do i=1, p%nx + InitOut%LinNames_u(i) = trim(InitOut%WriteOutputHdr(3*p%nx+ i))//', '//trim(InitOut%WriteOutputUnt(3*p%nx+i)) + print*,'u',i, trim(InitOut%LinNames_u(i)) + enddo + ! LinNames_x + do I=1,p%nq; + InitOut%LinNames_x(I) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) + print*,'x',i, trim(InitOut%LinNames_x(i)) + enddo + InitOut%RotFrame_x = .false. + InitOut%RotFrame_y = .false. + InitOut%RotFrame_u = .false. + InitOut%IsLoad_u = .true. + ! +contains + logical function Failed() + if (errStat >= AbortErrLev) errMsg = 'LD_JacobianLin:'//trim(errMsg) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine Init_Lin + +!---------------------------------------------------------------------------------------------------------------------------------- +!> Jacobians with respect to inputs (u) +subroutine LD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg, dYdu, dXdu, dXddu, dZdu) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(LD_InputType), intent(in ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(LD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(LD_OutputType), intent(in ) :: y !< Output (change to inout if a mesh copy is required); + type(LD_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 + real(R8Ki), allocatable, optional, intent(inout) :: dYdu(:,:) !< Jacobians of output functions (Y) with respect to (u) + real(R8Ki), allocatable, optional, intent(inout) :: dXdu(:,:) !< Jacobians of continuous state functions (X) with respect to (u) + real(R8Ki), allocatable, optional, intent(inout) :: dXddu(:,:) !< Jacobians of discrete state functions (Xd) with respect to (u) + real(R8Ki), allocatable, optional, intent(inout) :: dZdu(:,:) !< Jacobians of constraint state functions (Z) with respect to (u) + integer(IntKi) :: i, nu ! Loop index + ! Initialize errStat + errStat = ErrID_None + errMsg = '' + nu = p%nx + if (present(dYdu)) then + if (.not. allocated(dYdu)) then + call AllocAry(dYdu, p%NumOuts, nu, 'dYdu', errStat, errMsg); if(Failed()) return + dYdu(:,:) = 0.0_ReKi + end if + !dYdu(1 : p%nx, :) = 0.0_ReKi ! Positions + dYdu( p%nx+1 : 3*p%nx, :) = p%BB ! Velocities and accelerations + do i=1, p%nx ; dYdu(3*p%nx+i, i) = 1.0_ReKi; enddo ! Forces (which are inputs) + end if + if (present(dXdu)) then + if (.not. allocated(dXdu)) then + call AllocAry(dXdu, p%nq, nu, 'dXdu', errStat, errMsg); if(Failed()) return + dXdu(:,:) = 0.0_ReKi + end if + dXdu = p%BB + end if + if (present(dXddu)) then + end if + if (present(dZdu)) then + end if +contains + logical function Failed() + if (errStat >= AbortErrLev) errMsg = 'LD_JacobianPInput:'//trim(errMsg) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine LD_JacobianPInput +!---------------------------------------------------------------------------------------------------------------------------------- +!> Jacobians with respect to continuous states (x) +subroutine LD_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg, dYdx, dXdx, dXddx, dZdx ) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(LD_InputType), intent(in ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(LD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(LD_OutputType), intent(in ) :: y !< Output (change to inout if a mesh copy is required); + type(LD_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 + real(R8Ki), allocatable, optional, intent(inout) :: dYdx(:,:) !< Jacobians of output functions (Y) with respect to (x) + real(R8Ki), allocatable, optional, intent(inout) :: dXdx(:,:) !< Jacobians of continuous state functions (X) with respect to (x) + real(R8Ki), allocatable, optional, intent(inout) :: dXddx(:,:) !< Jacobians of discrete state functions (Xd) with respect to (x) + real(R8Ki), allocatable, optional, intent(inout) :: dZdx(:,:) !< Jacobians of constraint state functions (Z) with respect to (x) + integer(IntKi) :: i ! Loop index + ! Initialize errStat + errStat = ErrID_None + errMsg = '' + if (present(dYdx)) then + ! allocate and set dYdx + if (.not. allocated(dYdx)) then + call AllocAry(dYdx, p%NumOuts, p%nq, 'dYdx', errStat, errMsg); if(Failed()) return + dYdx(:,:) = 0.0_ReKi + end if + do i=1,p%nx; dYdx(i,i) = 1.0_ReKi; enddo ! Position + dYdx(p%nx+1:3*p%nx,: ) = p%AA ! Velocity and acceleration + !dYdx(3*p%nx+1:,:) = 0 ! Forces + end if + if (present(dXdx)) then + ! allocate and set dXdx + if (.not. allocated(dXdx)) then + call AllocAry(dXdx, p%nq, p%nq, 'dXdx', errStat, errMsg); if(Failed()) return + dXdx(:,:) = 0.0_ReKi + end if + dXdx = p%AA + end if + if (present(dXddx)) then + end if + if (present(dZdx)) then + end if +contains + logical function Failed() + if (errStat >= AbortErrLev) errMsg = 'LD_JacobianPContState:'//trim(errMsg) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine LD_JacobianPContState +!---------------------------------------------------------------------------------------------------------------------------------- +!> Routine to pack the data structures representing the operating points into arrays for linearization. +subroutine LD_GetOP( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg, u_op, y_op, x_op, dx_op, xd_op, z_op ) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(LD_InputType), intent(in ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + type(LD_ParameterType), intent(in ) :: p !< Parameters + type(LD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(LD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(LD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(LD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(LD_OutputType), intent(in ) :: y !< Output at operating point + type(LD_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 + real(ReKi), allocatable, optional, intent(inout) :: u_op(:) !< values of linearized inputs + real(ReKi), allocatable, optional, intent(inout) :: y_op(:) !< values of linearized outputs + real(ReKi), allocatable, optional, intent(inout) :: x_op(:) !< values of linearized continuous states + real(ReKi), allocatable, optional, intent(inout) :: dx_op(:) !< values of first time derivatives of linearized continuous states + 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) :: i, nu + type(LD_ContinuousStateType) :: dx !< derivative of continuous states at operating point + ! Initialize errStat + errStat = ErrID_None + errMsg = '' + nu = p%nx + + if ( present( u_op ) ) then + if (.not. allocated(u_op)) then + call AllocAry(u_op, nu, 'u_op', errStat, errMsg); if(Failed())return + endif + u_op(:) = u%Fext + end if + + if ( present( y_op ) ) then + if (.not. allocated(y_op)) then + call AllocAry(y_op, p%NumOuts, 'y_op', errStat, errMsg); if(Failed())return + endif + ! Update the output mesh + do i=1,p%NumOuts + y_op(i) = y%WriteOutput(i) + end do + end if + + if ( present( x_op ) ) then + if (.not. allocated(x_op)) then + call AllocAry(x_op, p%nq, 'x_op', errStat, errMsg); if (Failed())return + endif + x_op = x%q + end if + + if ( present( dx_op ) ) then + if (.not. allocated(dx_op)) then + call AllocAry(dx_op, p%nq, 'dx_op', errStat, errMsg); if (Failed())return + endif + call LD_CalcContStateDeriv(t, u, p, x, xd, z, OtherState, m, dx, errStat, errMsg); if(Failed()) return + dx_op = dx%q + end if + + if ( present( xd_op ) ) then + end if + + if ( present( z_op ) ) then + end if + +contains + logical function Failed() + if (errStat >= AbortErrLev) errMsg = 'LD_GetOP:'//trim(errMsg) + Failed = errStat >= AbortErrLev + end function Failed +end subroutine LD_GetOP + +end module LinDyn +!********************************************************************************************************************************** diff --git a/modules/lindyn/src/LinDyn_Registry.txt b/modules/lindyn/src/LinDyn_Registry.txt new file mode 100644 index 0000000000..6140a54fab --- /dev/null +++ b/modules/lindyn/src/LinDyn_Registry.txt @@ -0,0 +1,82 @@ +################################################################################################################################### +# Registry for Linear Dynamics Module +################################################################################################################################### +include Registry_NWTC_Library.txt + +#param ElasticSection/ES - INTEGER ES_Baseline - 1 - "UAMod = 1 [Baseline model (Original)]" - + +# ..... Initialization data ....................................................................................................... +# Initialization inputs +typedef LinDyn/LD InitInputType DbKi dt - - - "time step" s +typedef ^ ^ IntKi IntMethod - - - "Identifier for integration method (1 [RK4], 2 [AB4], or 3 [ABM4])" - +typedef ^ ^ ReKi MM {:}{:} - - "Mass matrix" - +typedef ^ ^ ReKi CC {:}{:} - - "Damping matrix" - +typedef ^ ^ ReKi KK {:}{:} - - "Stiffness matrix" - +typedef ^ ^ ReKi x0 {:} 0 - "Degrees of freedom initial conditions - shape nx" - +typedef ^ ^ ReKi xd0 {:} 0 - "Velocities initial conditions - shape nx" - +typedef ^ ^ logical activeDOFs {:} .true. - "Degrees of freedom that are active - shape nx" - +typedef ^ ^ character(8) prefix - "" - "Prefix for degrees of freedom write outputs" - +typedef ^ ^ character(8) DOFsNames {:} "" - "Names of degrees of freedom for write outputs" - +typedef ^ ^ character(8) DOFsUnits {:} "" - "Units of degrees of freedom for write outputs" - +typedef ^ ^ logical Linearize - .false. - "Flag that tells this module if the glue code wants to linearize." - +typedef ^ ^ character(2048) PrescribedMotionFile - "" - "Input file for prescribed motion" - + +# Initialization outputs +typedef LinDyn/LD InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - +typedef ^ InitOutputType character(ChanLen) WriteOutputHdr {:} - - "The is the list of all output channel header strings (includes all sub-module channels)" - +typedef ^ ^ character(ChanLen) WriteOutputUnt {:} - - "The is the list of all output channel unit strings (includes all sub-module channels)" - +typedef ^ ^ character(LinChanLen) LinNames_y {:} - - "Names of the outputs used in linearization" - +typedef ^ ^ character(LinChanLen) LinNames_x {:} - - "Names of the continuous states used in linearization" - +typedef ^ ^ character(LinChanLen) LinNames_u {:} - - "Names of the inputs used in linearization" - +typedef ^ ^ logical RotFrame_y {:} - - "Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame" - +typedef ^ ^ logical RotFrame_x {:} - - "Flag that tells FAST/MBC3 if the continuous states used in linearization are in the rotating frame" - +typedef ^ ^ logical RotFrame_u {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - +typedef ^ ^ logical IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - +typedef ^ ^ IntKi DerivOrder_x {:} - - "Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization" - + +# ..... States .................................................................................................................... +# Continuous states +typedef ^ ContinuousStateType ReKi q {:} - - "Continuous states q =(x,xdot)" "-" + +# Discrete (non-differentiable) states: +typedef ^ DiscreteStateType SiKi Dummy - - - "" - + +# Constraint states: +typedef ^ ConstraintStateType SiKi Dummy - - - "" - + +# Other states: +typedef ^ OtherStateType LD_ContinuousStateType xdot {:} - - "Previous state derivs for m-step time integrator" +typedef ^ ^ IntKi n - - - "Tracks time step for which OtherState was updated last" +typedef ^ ^ IntKi iMotionInterpLast - 1 - "Last index used to interpolate the presribed motion time series" - + +# ..... Misc/Optimization variables................................................................................................. +typedef ^ MiscVarType Logical Dummy - - - "" - +typedef ^ ^ ReKi qPrescribed {:} - - "Prescribed motion/velocity/accelerations for all degrees of freedom at a given time" - + + +# ..... Parameters ................................................................................................................ +typedef ^ ParameterType DbKi dt - - - "time step" s +typedef ^ ^ IntKi IntMethod - - - "Identifier for integration method (1 [RK4], 2 [AB4], or 3 [ABM4])" - +typedef ^ ^ IntKi nx - - - "Number of degrees of freedom (size of M)" - +typedef ^ ^ IntKi nq - - - "nq=2*nx" - +typedef ^ ^ ReKi MM {:}{:} - - "Mass Matrix - shape (nx x nx)" - +typedef ^ ^ ReKi CC {:}{:} - - "Damping Matrix - shape (nx x nx)" - +typedef ^ ^ ReKi KK {:}{:} - - "Stiffness Matrix - shape (nx x nx)" - +typedef ^ ^ ReKi Minv {:}{:} - - "Inverse of Mass matrix" - +typedef ^ ^ Logical activeDOFs {:} - - "Degrees of freedom that are active" - +typedef ^ ^ ReKi AA {:}{:} - - "State matrix A - shape (nq x nq) " - +typedef ^ ^ ReKi BB {:}{:} - - "State matrix B - shape (nq x nx) " - +typedef ^ ^ IntKi NumOuts - - - "Number of values in WriteOutput" - +typedef ^ ^ OutParmType OutParam {:} - - "Names and units (and other characteristics) of all requested output parameters" - +typedef ^ ^ IntKi OutParamLinIndx {:}{:} - - "Index into WriteOutput for linearization analysis" - +typedef ^ ^ ReKi PrescribedValues {:}{:} - - "Prescribed motion for all degrees of freedom" - + + + +# ..... Inputs .................................................................................................................... +typedef ^ InputType ReKi Fext : - - "External loads - shape nx" + +# ..... Outputs ................................................................................................................... +typedef ^ OutputType ReKi xdd {:} - "Time derivative of continuous states" - +typedef ^ ^ ReKi WriteOutput {:} - - "outputs to be written to a file" - + diff --git a/modules/lindyn/src/LinDyn_Types.f90 b/modules/lindyn/src/LinDyn_Types.f90 new file mode 100644 index 0000000000..ebaaa657a2 --- /dev/null +++ b/modules/lindyn/src/LinDyn_Types.f90 @@ -0,0 +1,1559 @@ +!STARTOFREGISTRYGENERATEDFILE 'LinDyn_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 +!********************************************************************************************************************************* +! LinDyn_Types +!................................................................................................................................. +! This file is part of LinDyn. +! +! Copyright (C) 2012-2016 National Renewable Energy Laboratory +! +! 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. +! +! +! 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 LinDyn. 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 LinDyn_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE NWTC_Library +IMPLICIT NONE +! ========= LD_InitInputType ======= + TYPE, PUBLIC :: LD_InitInputType + REAL(DbKi) :: dt = 0.0_R8Ki !< time step [s] + INTEGER(IntKi) :: IntMethod = 0_IntKi !< Identifier for integration method (1 [RK4], 2 [AB4], or 3 [ABM4]) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: MM !< Mass matrix [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: CC !< Damping matrix [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: KK !< Stiffness matrix [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: x0 !< Degrees of freedom initial conditions - shape nx [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: xd0 !< Velocities initial conditions - shape nx [-] + LOGICAL , DIMENSION(:), ALLOCATABLE :: activeDOFs !< Degrees of freedom that are active - shape nx [-] + character(8) :: prefix !< Prefix for degrees of freedom write outputs [-] + character(8) , DIMENSION(:), ALLOCATABLE :: DOFsNames !< Names of degrees of freedom for write outputs [-] + character(8) , DIMENSION(:), ALLOCATABLE :: DOFsUnits !< Units of degrees of freedom for write outputs [-] + LOGICAL :: Linearize = .false. !< Flag that tells this module if the glue code wants to linearize. [-] + character(2048) :: PrescribedMotionFile !< Input file for prescribed motion [-] + END TYPE LD_InitInputType +! ======================= +! ========= LD_InitOutputType ======= + TYPE, PUBLIC :: LD_InitOutputType + TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] + character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< The is the list of all output channel header strings (includes all sub-module channels) [-] + character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< The is the list of all output channel unit strings (includes all sub-module channels) [-] + character(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_y !< Names of the outputs used in linearization [-] + character(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_x !< Names of the continuous states used in linearization [-] + character(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_u !< Names of the inputs used in linearization [-] + LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_y !< Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame [-] + LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_x !< Flag that tells FAST/MBC3 if the continuous states used in linearization are in the rotating frame [-] + 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) , DIMENSION(:), ALLOCATABLE :: DerivOrder_x !< Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization [-] + END TYPE LD_InitOutputType +! ======================= +! ========= LD_ContinuousStateType ======= + TYPE, PUBLIC :: LD_ContinuousStateType + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: q !< Continuous states q =(x,xdot) [-] + END TYPE LD_ContinuousStateType +! ======================= +! ========= LD_DiscreteStateType ======= + TYPE, PUBLIC :: LD_DiscreteStateType + REAL(SiKi) :: Dummy = 0.0_R4Ki !< [-] + END TYPE LD_DiscreteStateType +! ======================= +! ========= LD_ConstraintStateType ======= + TYPE, PUBLIC :: LD_ConstraintStateType + REAL(SiKi) :: Dummy = 0.0_R4Ki !< [-] + END TYPE LD_ConstraintStateType +! ======================= +! ========= LD_OtherStateType ======= + TYPE, PUBLIC :: LD_OtherStateType + TYPE(LD_ContinuousStateType) , DIMENSION(:), ALLOCATABLE :: xdot !< Previous state derivs for m-step time integrator [-] + INTEGER(IntKi) :: n = 0_IntKi !< Tracks time step for which OtherState was updated last [-] + INTEGER(IntKi) :: iMotionInterpLast = 1 !< Last index used to interpolate the presribed motion time series [-] + END TYPE LD_OtherStateType +! ======================= +! ========= LD_MiscVarType ======= + TYPE, PUBLIC :: LD_MiscVarType + LOGICAL :: Dummy = .false. !< [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: qPrescribed !< Prescribed motion/velocity/accelerations for all degrees of freedom at a given time [-] + END TYPE LD_MiscVarType +! ======================= +! ========= LD_ParameterType ======= + TYPE, PUBLIC :: LD_ParameterType + REAL(DbKi) :: dt = 0.0_R8Ki !< time step [s] + INTEGER(IntKi) :: IntMethod = 0_IntKi !< Identifier for integration method (1 [RK4], 2 [AB4], or 3 [ABM4]) [-] + INTEGER(IntKi) :: nx = 0_IntKi !< Number of degrees of freedom (size of M) [-] + INTEGER(IntKi) :: nq = 0_IntKi !< nq=2*nx [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: MM !< Mass Matrix - shape (nx x nx) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: CC !< Damping Matrix - shape (nx x nx) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: KK !< Stiffness Matrix - shape (nx x nx) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Minv !< Inverse of Mass matrix [-] + LOGICAL , DIMENSION(:), ALLOCATABLE :: activeDOFs !< Degrees of freedom that are active [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AA !< State matrix A - shape (nq x nq) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BB !< State matrix B - shape (nq x nx) [-] + INTEGER(IntKi) :: NumOuts = 0_IntKi !< Number of values in WriteOutput [-] + TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: OutParam !< Names and units (and other characteristics) of all requested output parameters [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: OutParamLinIndx !< Index into WriteOutput for linearization analysis [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PrescribedValues !< Prescribed motion for all degrees of freedom [-] + END TYPE LD_ParameterType +! ======================= +! ========= LD_InputType ======= + TYPE, PUBLIC :: LD_InputType + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Fext !< External loads - shape nx [-] + END TYPE LD_InputType +! ======================= +! ========= LD_OutputType ======= + TYPE, PUBLIC :: LD_OutputType + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: xdd + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< outputs to be written to a file [-] + END TYPE LD_OutputType +! ======================= +CONTAINS + +subroutine LD_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg) + type(LD_InitInputType), intent(in) :: SrcInitInputData + type(LD_InitInputType), intent(inout) :: DstInitInputData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(2), UB(2) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'LD_CopyInitInput' + ErrStat = ErrID_None + ErrMsg = '' + DstInitInputData%dt = SrcInitInputData%dt + DstInitInputData%IntMethod = SrcInitInputData%IntMethod + if (allocated(SrcInitInputData%MM)) then + LB(1:2) = lbound(SrcInitInputData%MM, kind=B8Ki) + UB(1:2) = ubound(SrcInitInputData%MM, kind=B8Ki) + if (.not. allocated(DstInitInputData%MM)) then + allocate(DstInitInputData%MM(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%MM.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%MM = SrcInitInputData%MM + end if + if (allocated(SrcInitInputData%CC)) then + LB(1:2) = lbound(SrcInitInputData%CC, kind=B8Ki) + UB(1:2) = ubound(SrcInitInputData%CC, kind=B8Ki) + if (.not. allocated(DstInitInputData%CC)) then + allocate(DstInitInputData%CC(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%CC.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%CC = SrcInitInputData%CC + end if + if (allocated(SrcInitInputData%KK)) then + LB(1:2) = lbound(SrcInitInputData%KK, kind=B8Ki) + UB(1:2) = ubound(SrcInitInputData%KK, kind=B8Ki) + if (.not. allocated(DstInitInputData%KK)) then + allocate(DstInitInputData%KK(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%KK.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%KK = SrcInitInputData%KK + end if + if (allocated(SrcInitInputData%x0)) then + LB(1:1) = lbound(SrcInitInputData%x0, kind=B8Ki) + UB(1:1) = ubound(SrcInitInputData%x0, kind=B8Ki) + if (.not. allocated(DstInitInputData%x0)) then + allocate(DstInitInputData%x0(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%x0.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%x0 = SrcInitInputData%x0 + end if + if (allocated(SrcInitInputData%xd0)) then + LB(1:1) = lbound(SrcInitInputData%xd0, kind=B8Ki) + UB(1:1) = ubound(SrcInitInputData%xd0, kind=B8Ki) + if (.not. allocated(DstInitInputData%xd0)) then + allocate(DstInitInputData%xd0(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%xd0.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%xd0 = SrcInitInputData%xd0 + end if + if (allocated(SrcInitInputData%activeDOFs)) then + LB(1:1) = lbound(SrcInitInputData%activeDOFs, kind=B8Ki) + UB(1:1) = ubound(SrcInitInputData%activeDOFs, kind=B8Ki) + if (.not. allocated(DstInitInputData%activeDOFs)) then + allocate(DstInitInputData%activeDOFs(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%activeDOFs.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%activeDOFs = SrcInitInputData%activeDOFs + end if + DstInitInputData%prefix = SrcInitInputData%prefix + if (allocated(SrcInitInputData%DOFsNames)) then + LB(1:1) = lbound(SrcInitInputData%DOFsNames, kind=B8Ki) + UB(1:1) = ubound(SrcInitInputData%DOFsNames, kind=B8Ki) + if (.not. allocated(DstInitInputData%DOFsNames)) then + allocate(DstInitInputData%DOFsNames(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%DOFsNames.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%DOFsNames = SrcInitInputData%DOFsNames + end if + if (allocated(SrcInitInputData%DOFsUnits)) then + LB(1:1) = lbound(SrcInitInputData%DOFsUnits, kind=B8Ki) + UB(1:1) = ubound(SrcInitInputData%DOFsUnits, kind=B8Ki) + if (.not. allocated(DstInitInputData%DOFsUnits)) then + allocate(DstInitInputData%DOFsUnits(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%DOFsUnits.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitInputData%DOFsUnits = SrcInitInputData%DOFsUnits + end if + DstInitInputData%Linearize = SrcInitInputData%Linearize + DstInitInputData%PrescribedMotionFile = SrcInitInputData%PrescribedMotionFile +end subroutine + +subroutine LD_DestroyInitInput(InitInputData, ErrStat, ErrMsg) + type(LD_InitInputType), intent(inout) :: InitInputData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyInitInput' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(InitInputData%MM)) then + deallocate(InitInputData%MM) + end if + if (allocated(InitInputData%CC)) then + deallocate(InitInputData%CC) + end if + if (allocated(InitInputData%KK)) then + deallocate(InitInputData%KK) + end if + if (allocated(InitInputData%x0)) then + deallocate(InitInputData%x0) + end if + if (allocated(InitInputData%xd0)) then + deallocate(InitInputData%xd0) + end if + if (allocated(InitInputData%activeDOFs)) then + deallocate(InitInputData%activeDOFs) + end if + if (allocated(InitInputData%DOFsNames)) then + deallocate(InitInputData%DOFsNames) + end if + if (allocated(InitInputData%DOFsUnits)) then + deallocate(InitInputData%DOFsUnits) + end if +end subroutine + +subroutine LD_PackInitInput(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_InitInputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackInitInput' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%dt) + call RegPack(RF, InData%IntMethod) + call RegPackAlloc(RF, InData%MM) + call RegPackAlloc(RF, InData%CC) + call RegPackAlloc(RF, InData%KK) + call RegPackAlloc(RF, InData%x0) + call RegPackAlloc(RF, InData%xd0) + call RegPackAlloc(RF, InData%activeDOFs) + call RegPack(RF, InData%prefix) + call RegPackAlloc(RF, InData%DOFsNames) + call RegPackAlloc(RF, InData%DOFsUnits) + call RegPack(RF, InData%Linearize) + call RegPack(RF, InData%PrescribedMotionFile) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackInitInput(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_InitInputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackInitInput' + integer(B8Ki) :: LB(2), UB(2) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%dt); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%IntMethod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%MM); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%CC); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%KK); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%x0); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%xd0); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%activeDOFs); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%prefix); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%DOFsNames); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%DOFsUnits); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Linearize); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%PrescribedMotionFile); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) + type(LD_InitOutputType), intent(in) :: SrcInitOutputData + type(LD_InitOutputType), intent(inout) :: DstInitOutputData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_CopyInitOutput' + ErrStat = ErrID_None + ErrMsg = '' + call NWTC_Library_CopyProgDesc(SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + if (allocated(SrcInitOutputData%WriteOutputHdr)) then + LB(1:1) = lbound(SrcInitOutputData%WriteOutputHdr, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%WriteOutputHdr, kind=B8Ki) + if (.not. allocated(DstInitOutputData%WriteOutputHdr)) then + allocate(DstInitOutputData%WriteOutputHdr(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputHdr.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%WriteOutputHdr = SrcInitOutputData%WriteOutputHdr + end if + if (allocated(SrcInitOutputData%WriteOutputUnt)) then + LB(1:1) = lbound(SrcInitOutputData%WriteOutputUnt, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%WriteOutputUnt, kind=B8Ki) + if (.not. allocated(DstInitOutputData%WriteOutputUnt)) then + allocate(DstInitOutputData%WriteOutputUnt(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputUnt.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%WriteOutputUnt = SrcInitOutputData%WriteOutputUnt + end if + if (allocated(SrcInitOutputData%LinNames_y)) then + LB(1:1) = lbound(SrcInitOutputData%LinNames_y, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%LinNames_y, kind=B8Ki) + if (.not. allocated(DstInitOutputData%LinNames_y)) then + allocate(DstInitOutputData%LinNames_y(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%LinNames_y.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%LinNames_y = SrcInitOutputData%LinNames_y + end if + if (allocated(SrcInitOutputData%LinNames_x)) then + LB(1:1) = lbound(SrcInitOutputData%LinNames_x, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%LinNames_x, kind=B8Ki) + if (.not. allocated(DstInitOutputData%LinNames_x)) then + allocate(DstInitOutputData%LinNames_x(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%LinNames_x.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%LinNames_x = SrcInitOutputData%LinNames_x + end if + if (allocated(SrcInitOutputData%LinNames_u)) then + LB(1:1) = lbound(SrcInitOutputData%LinNames_u, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%LinNames_u, kind=B8Ki) + if (.not. allocated(DstInitOutputData%LinNames_u)) then + allocate(DstInitOutputData%LinNames_u(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%LinNames_u.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%LinNames_u = SrcInitOutputData%LinNames_u + end if + if (allocated(SrcInitOutputData%RotFrame_y)) then + LB(1:1) = lbound(SrcInitOutputData%RotFrame_y, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%RotFrame_y, kind=B8Ki) + if (.not. allocated(DstInitOutputData%RotFrame_y)) then + allocate(DstInitOutputData%RotFrame_y(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%RotFrame_y.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%RotFrame_y = SrcInitOutputData%RotFrame_y + end if + if (allocated(SrcInitOutputData%RotFrame_x)) then + LB(1:1) = lbound(SrcInitOutputData%RotFrame_x, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%RotFrame_x, kind=B8Ki) + if (.not. allocated(DstInitOutputData%RotFrame_x)) then + allocate(DstInitOutputData%RotFrame_x(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%RotFrame_x.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%RotFrame_x = SrcInitOutputData%RotFrame_x + end if + if (allocated(SrcInitOutputData%RotFrame_u)) then + LB(1:1) = lbound(SrcInitOutputData%RotFrame_u, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%RotFrame_u, kind=B8Ki) + if (.not. allocated(DstInitOutputData%RotFrame_u)) then + allocate(DstInitOutputData%RotFrame_u(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%RotFrame_u.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%RotFrame_u = SrcInitOutputData%RotFrame_u + end if + if (allocated(SrcInitOutputData%IsLoad_u)) then + LB(1:1) = lbound(SrcInitOutputData%IsLoad_u, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%IsLoad_u, kind=B8Ki) + if (.not. allocated(DstInitOutputData%IsLoad_u)) then + allocate(DstInitOutputData%IsLoad_u(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%IsLoad_u.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%IsLoad_u = SrcInitOutputData%IsLoad_u + end if + if (allocated(SrcInitOutputData%DerivOrder_x)) then + LB(1:1) = lbound(SrcInitOutputData%DerivOrder_x, kind=B8Ki) + UB(1:1) = ubound(SrcInitOutputData%DerivOrder_x, kind=B8Ki) + if (.not. allocated(DstInitOutputData%DerivOrder_x)) then + allocate(DstInitOutputData%DerivOrder_x(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%DerivOrder_x.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInitOutputData%DerivOrder_x = SrcInitOutputData%DerivOrder_x + end if +end subroutine + +subroutine LD_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) + type(LD_InitOutputType), intent(inout) :: InitOutputData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_DestroyInitOutput' + ErrStat = ErrID_None + ErrMsg = '' + call NWTC_Library_DestroyProgDesc(InitOutputData%Ver, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (allocated(InitOutputData%WriteOutputHdr)) then + deallocate(InitOutputData%WriteOutputHdr) + end if + if (allocated(InitOutputData%WriteOutputUnt)) then + deallocate(InitOutputData%WriteOutputUnt) + end if + if (allocated(InitOutputData%LinNames_y)) then + deallocate(InitOutputData%LinNames_y) + end if + if (allocated(InitOutputData%LinNames_x)) then + deallocate(InitOutputData%LinNames_x) + end if + if (allocated(InitOutputData%LinNames_u)) then + deallocate(InitOutputData%LinNames_u) + end if + if (allocated(InitOutputData%RotFrame_y)) then + deallocate(InitOutputData%RotFrame_y) + end if + if (allocated(InitOutputData%RotFrame_x)) then + deallocate(InitOutputData%RotFrame_x) + end if + if (allocated(InitOutputData%RotFrame_u)) then + deallocate(InitOutputData%RotFrame_u) + end if + if (allocated(InitOutputData%IsLoad_u)) then + deallocate(InitOutputData%IsLoad_u) + end if + if (allocated(InitOutputData%DerivOrder_x)) then + deallocate(InitOutputData%DerivOrder_x) + end if +end subroutine + +subroutine LD_PackInitOutput(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_InitOutputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackInitOutput' + if (RF%ErrStat >= AbortErrLev) return + call NWTC_Library_PackProgDesc(RF, InData%Ver) + call RegPackAlloc(RF, InData%WriteOutputHdr) + call RegPackAlloc(RF, InData%WriteOutputUnt) + call RegPackAlloc(RF, InData%LinNames_y) + call RegPackAlloc(RF, InData%LinNames_x) + call RegPackAlloc(RF, InData%LinNames_u) + call RegPackAlloc(RF, InData%RotFrame_y) + call RegPackAlloc(RF, InData%RotFrame_x) + call RegPackAlloc(RF, InData%RotFrame_u) + call RegPackAlloc(RF, InData%IsLoad_u) + call RegPackAlloc(RF, InData%DerivOrder_x) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackInitOutput(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_InitOutputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackInitOutput' + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver + call RegUnpackAlloc(RF, OutData%WriteOutputHdr); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%WriteOutputUnt); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%LinNames_y); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%LinNames_x); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%LinNames_u); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%RotFrame_y); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%RotFrame_x); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%RotFrame_u); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%IsLoad_u); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%DerivOrder_x); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyContState(SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg) + type(LD_ContinuousStateType), intent(in) :: SrcContStateData + type(LD_ContinuousStateType), intent(inout) :: DstContStateData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'LD_CopyContState' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(SrcContStateData%q)) then + LB(1:1) = lbound(SrcContStateData%q, kind=B8Ki) + UB(1:1) = ubound(SrcContStateData%q, kind=B8Ki) + if (.not. allocated(DstContStateData%q)) then + allocate(DstContStateData%q(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%q.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstContStateData%q = SrcContStateData%q + end if +end subroutine + +subroutine LD_DestroyContState(ContStateData, ErrStat, ErrMsg) + type(LD_ContinuousStateType), intent(inout) :: ContStateData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyContState' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(ContStateData%q)) then + deallocate(ContStateData%q) + end if +end subroutine + +subroutine LD_PackContState(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_ContinuousStateType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackContState' + if (RF%ErrStat >= AbortErrLev) return + call RegPackAlloc(RF, InData%q) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackContState(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_ContinuousStateType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackContState' + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpackAlloc(RF, OutData%q); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyDiscState(SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg) + type(LD_DiscreteStateType), intent(in) :: SrcDiscStateData + type(LD_DiscreteStateType), intent(inout) :: DstDiscStateData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_CopyDiscState' + ErrStat = ErrID_None + ErrMsg = '' + DstDiscStateData%Dummy = SrcDiscStateData%Dummy +end subroutine + +subroutine LD_DestroyDiscState(DiscStateData, ErrStat, ErrMsg) + type(LD_DiscreteStateType), intent(inout) :: DiscStateData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyDiscState' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine LD_PackDiscState(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_DiscreteStateType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackDiscState' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%Dummy) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackDiscState(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_DiscreteStateType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackDiscState' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%Dummy); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyConstrState(SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg) + type(LD_ConstraintStateType), intent(in) :: SrcConstrStateData + type(LD_ConstraintStateType), intent(inout) :: DstConstrStateData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_CopyConstrState' + ErrStat = ErrID_None + ErrMsg = '' + DstConstrStateData%Dummy = SrcConstrStateData%Dummy +end subroutine + +subroutine LD_DestroyConstrState(ConstrStateData, ErrStat, ErrMsg) + type(LD_ConstraintStateType), intent(inout) :: ConstrStateData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyConstrState' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine LD_PackConstrState(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_ConstraintStateType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackConstrState' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%Dummy) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackConstrState(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_ConstraintStateType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackConstrState' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%Dummy); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyOtherState(SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg) + type(LD_OtherStateType), intent(in) :: SrcOtherStateData + type(LD_OtherStateType), intent(inout) :: DstOtherStateData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: i1 + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_CopyOtherState' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(SrcOtherStateData%xdot)) then + LB(1:1) = lbound(SrcOtherStateData%xdot, kind=B8Ki) + UB(1:1) = ubound(SrcOtherStateData%xdot, kind=B8Ki) + if (.not. allocated(DstOtherStateData%xdot)) then + allocate(DstOtherStateData%xdot(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstOtherStateData%xdot.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call LD_CopyContState(SrcOtherStateData%xdot(i1), DstOtherStateData%xdot(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if + DstOtherStateData%n = SrcOtherStateData%n + DstOtherStateData%iMotionInterpLast = SrcOtherStateData%iMotionInterpLast +end subroutine + +subroutine LD_DestroyOtherState(OtherStateData, ErrStat, ErrMsg) + type(LD_OtherStateType), intent(inout) :: OtherStateData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: i1 + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_DestroyOtherState' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(OtherStateData%xdot)) then + LB(1:1) = lbound(OtherStateData%xdot, kind=B8Ki) + UB(1:1) = ubound(OtherStateData%xdot, kind=B8Ki) + do i1 = LB(1), UB(1) + call LD_DestroyContState(OtherStateData%xdot(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(OtherStateData%xdot) + end if +end subroutine + +subroutine LD_PackOtherState(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_OtherStateType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackOtherState' + integer(B8Ki) :: i1 + integer(B8Ki) :: LB(1), UB(1) + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, allocated(InData%xdot)) + if (allocated(InData%xdot)) then + call RegPackBounds(RF, 1, lbound(InData%xdot, kind=B8Ki), ubound(InData%xdot, kind=B8Ki)) + LB(1:1) = lbound(InData%xdot, kind=B8Ki) + UB(1:1) = ubound(InData%xdot, kind=B8Ki) + do i1 = LB(1), UB(1) + call LD_PackContState(RF, InData%xdot(i1)) + end do + end if + call RegPack(RF, InData%n) + call RegPack(RF, InData%iMotionInterpLast) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackOtherState(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_OtherStateType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackOtherState' + integer(B8Ki) :: i1 + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + if (allocated(OutData%xdot)) deallocate(OutData%xdot) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%xdot(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%xdot.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call LD_UnpackContState(RF, OutData%xdot(i1)) ! xdot + end do + end if + call RegUnpack(RF, OutData%n); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%iMotionInterpLast); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) + type(LD_MiscVarType), intent(in) :: SrcMiscData + type(LD_MiscVarType), intent(inout) :: DstMiscData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'LD_CopyMisc' + ErrStat = ErrID_None + ErrMsg = '' + DstMiscData%Dummy = SrcMiscData%Dummy + if (allocated(SrcMiscData%qPrescribed)) then + LB(1:1) = lbound(SrcMiscData%qPrescribed, kind=B8Ki) + UB(1:1) = ubound(SrcMiscData%qPrescribed, kind=B8Ki) + if (.not. allocated(DstMiscData%qPrescribed)) then + allocate(DstMiscData%qPrescribed(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%qPrescribed.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstMiscData%qPrescribed = SrcMiscData%qPrescribed + end if +end subroutine + +subroutine LD_DestroyMisc(MiscData, ErrStat, ErrMsg) + type(LD_MiscVarType), intent(inout) :: MiscData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyMisc' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(MiscData%qPrescribed)) then + deallocate(MiscData%qPrescribed) + end if +end subroutine + +subroutine LD_PackMisc(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_MiscVarType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackMisc' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%Dummy) + call RegPackAlloc(RF, InData%qPrescribed) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackMisc(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_MiscVarType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackMisc' + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%Dummy); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%qPrescribed); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) + type(LD_ParameterType), intent(in) :: SrcParamData + type(LD_ParameterType), intent(inout) :: DstParamData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: i1, i2 + integer(B8Ki) :: LB(2), UB(2) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_CopyParam' + ErrStat = ErrID_None + ErrMsg = '' + DstParamData%dt = SrcParamData%dt + DstParamData%IntMethod = SrcParamData%IntMethod + DstParamData%nx = SrcParamData%nx + DstParamData%nq = SrcParamData%nq + if (allocated(SrcParamData%MM)) then + LB(1:2) = lbound(SrcParamData%MM, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%MM, kind=B8Ki) + if (.not. allocated(DstParamData%MM)) then + allocate(DstParamData%MM(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%MM.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%MM = SrcParamData%MM + end if + if (allocated(SrcParamData%CC)) then + LB(1:2) = lbound(SrcParamData%CC, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%CC, kind=B8Ki) + if (.not. allocated(DstParamData%CC)) then + allocate(DstParamData%CC(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%CC.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%CC = SrcParamData%CC + end if + if (allocated(SrcParamData%KK)) then + LB(1:2) = lbound(SrcParamData%KK, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%KK, kind=B8Ki) + if (.not. allocated(DstParamData%KK)) then + allocate(DstParamData%KK(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%KK.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%KK = SrcParamData%KK + end if + if (allocated(SrcParamData%Minv)) then + LB(1:2) = lbound(SrcParamData%Minv, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%Minv, kind=B8Ki) + if (.not. allocated(DstParamData%Minv)) then + allocate(DstParamData%Minv(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Minv.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%Minv = SrcParamData%Minv + end if + if (allocated(SrcParamData%activeDOFs)) then + LB(1:1) = lbound(SrcParamData%activeDOFs, kind=B8Ki) + UB(1:1) = ubound(SrcParamData%activeDOFs, kind=B8Ki) + if (.not. allocated(DstParamData%activeDOFs)) then + allocate(DstParamData%activeDOFs(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%activeDOFs.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%activeDOFs = SrcParamData%activeDOFs + end if + if (allocated(SrcParamData%AA)) then + LB(1:2) = lbound(SrcParamData%AA, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%AA, kind=B8Ki) + if (.not. allocated(DstParamData%AA)) then + allocate(DstParamData%AA(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%AA.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%AA = SrcParamData%AA + end if + if (allocated(SrcParamData%BB)) then + LB(1:2) = lbound(SrcParamData%BB, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%BB, kind=B8Ki) + if (.not. allocated(DstParamData%BB)) then + allocate(DstParamData%BB(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%BB.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%BB = SrcParamData%BB + end if + DstParamData%NumOuts = SrcParamData%NumOuts + if (allocated(SrcParamData%OutParam)) then + LB(1:1) = lbound(SrcParamData%OutParam, kind=B8Ki) + UB(1:1) = ubound(SrcParamData%OutParam, kind=B8Ki) + if (.not. allocated(DstParamData%OutParam)) then + allocate(DstParamData%OutParam(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParam.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call NWTC_Library_CopyOutParmType(SrcParamData%OutParam(i1), DstParamData%OutParam(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if + if (allocated(SrcParamData%OutParamLinIndx)) then + LB(1:2) = lbound(SrcParamData%OutParamLinIndx, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%OutParamLinIndx, kind=B8Ki) + if (.not. allocated(DstParamData%OutParamLinIndx)) then + allocate(DstParamData%OutParamLinIndx(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParamLinIndx.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%OutParamLinIndx = SrcParamData%OutParamLinIndx + end if + if (allocated(SrcParamData%PrescribedValues)) then + LB(1:2) = lbound(SrcParamData%PrescribedValues, kind=B8Ki) + UB(1:2) = ubound(SrcParamData%PrescribedValues, kind=B8Ki) + if (.not. allocated(DstParamData%PrescribedValues)) then + allocate(DstParamData%PrescribedValues(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%PrescribedValues.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%PrescribedValues = SrcParamData%PrescribedValues + end if +end subroutine + +subroutine LD_DestroyParam(ParamData, ErrStat, ErrMsg) + type(LD_ParameterType), intent(inout) :: ParamData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: i1, i2 + integer(B8Ki) :: LB(2), UB(2) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'LD_DestroyParam' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(ParamData%MM)) then + deallocate(ParamData%MM) + end if + if (allocated(ParamData%CC)) then + deallocate(ParamData%CC) + end if + if (allocated(ParamData%KK)) then + deallocate(ParamData%KK) + end if + if (allocated(ParamData%Minv)) then + deallocate(ParamData%Minv) + end if + if (allocated(ParamData%activeDOFs)) then + deallocate(ParamData%activeDOFs) + end if + if (allocated(ParamData%AA)) then + deallocate(ParamData%AA) + end if + if (allocated(ParamData%BB)) then + deallocate(ParamData%BB) + end if + if (allocated(ParamData%OutParam)) then + LB(1:1) = lbound(ParamData%OutParam, kind=B8Ki) + UB(1:1) = ubound(ParamData%OutParam, kind=B8Ki) + do i1 = LB(1), UB(1) + call NWTC_Library_DestroyOutParmType(ParamData%OutParam(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(ParamData%OutParam) + end if + if (allocated(ParamData%OutParamLinIndx)) then + deallocate(ParamData%OutParamLinIndx) + end if + if (allocated(ParamData%PrescribedValues)) then + deallocate(ParamData%PrescribedValues) + end if +end subroutine + +subroutine LD_PackParam(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_ParameterType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackParam' + integer(B8Ki) :: i1, i2 + integer(B8Ki) :: LB(2), UB(2) + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%dt) + call RegPack(RF, InData%IntMethod) + call RegPack(RF, InData%nx) + call RegPack(RF, InData%nq) + call RegPackAlloc(RF, InData%MM) + call RegPackAlloc(RF, InData%CC) + call RegPackAlloc(RF, InData%KK) + call RegPackAlloc(RF, InData%Minv) + call RegPackAlloc(RF, InData%activeDOFs) + call RegPackAlloc(RF, InData%AA) + call RegPackAlloc(RF, InData%BB) + call RegPack(RF, InData%NumOuts) + call RegPack(RF, allocated(InData%OutParam)) + if (allocated(InData%OutParam)) then + call RegPackBounds(RF, 1, lbound(InData%OutParam, kind=B8Ki), ubound(InData%OutParam, kind=B8Ki)) + LB(1:1) = lbound(InData%OutParam, kind=B8Ki) + UB(1:1) = ubound(InData%OutParam, kind=B8Ki) + do i1 = LB(1), UB(1) + call NWTC_Library_PackOutParmType(RF, InData%OutParam(i1)) + end do + end if + call RegPackAlloc(RF, InData%OutParamLinIndx) + call RegPackAlloc(RF, InData%PrescribedValues) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackParam(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_ParameterType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackParam' + integer(B8Ki) :: i1, i2 + integer(B8Ki) :: LB(2), UB(2) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%dt); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%IntMethod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%nx); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%nq); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%MM); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%CC); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%KK); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%Minv); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%activeDOFs); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%AA); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%BB); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NumOuts); if (RegCheckErr(RF, RoutineName)) return + if (allocated(OutData%OutParam)) deallocate(OutData%OutParam) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%OutParam(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParam.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call NWTC_Library_UnpackOutParmType(RF, OutData%OutParam(i1)) ! OutParam + end do + end if + call RegUnpackAlloc(RF, OutData%OutParamLinIndx); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%PrescribedValues); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) + type(LD_InputType), intent(in) :: SrcInputData + type(LD_InputType), intent(inout) :: DstInputData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'LD_CopyInput' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(SrcInputData%Fext)) then + LB(1:1) = lbound(SrcInputData%Fext, kind=B8Ki) + UB(1:1) = ubound(SrcInputData%Fext, kind=B8Ki) + if (.not. allocated(DstInputData%Fext)) then + allocate(DstInputData%Fext(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%Fext.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstInputData%Fext = SrcInputData%Fext + end if +end subroutine + +subroutine LD_DestroyInput(InputData, ErrStat, ErrMsg) + type(LD_InputType), intent(inout) :: InputData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyInput' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(InputData%Fext)) then + deallocate(InputData%Fext) + end if +end subroutine + +subroutine LD_PackInput(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_InputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackInput' + if (RF%ErrStat >= AbortErrLev) return + call RegPackAlloc(RF, InData%Fext) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackInput(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_InputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackInput' + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpackAlloc(RF, OutData%Fext); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_CopyOutput(SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg) + type(LD_OutputType), intent(in) :: SrcOutputData + type(LD_OutputType), intent(inout) :: DstOutputData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'LD_CopyOutput' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(SrcOutputData%xdd)) then + LB(1:1) = lbound(SrcOutputData%xdd, kind=B8Ki) + UB(1:1) = ubound(SrcOutputData%xdd, kind=B8Ki) + if (.not. allocated(DstOutputData%xdd)) then + allocate(DstOutputData%xdd(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%xdd.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstOutputData%xdd = SrcOutputData%xdd + end if + if (allocated(SrcOutputData%WriteOutput)) then + LB(1:1) = lbound(SrcOutputData%WriteOutput, kind=B8Ki) + UB(1:1) = ubound(SrcOutputData%WriteOutput, kind=B8Ki) + if (.not. allocated(DstOutputData%WriteOutput)) then + allocate(DstOutputData%WriteOutput(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstOutputData%WriteOutput = SrcOutputData%WriteOutput + end if +end subroutine + +subroutine LD_DestroyOutput(OutputData, ErrStat, ErrMsg) + type(LD_OutputType), intent(inout) :: OutputData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'LD_DestroyOutput' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(OutputData%xdd)) then + deallocate(OutputData%xdd) + end if + if (allocated(OutputData%WriteOutput)) then + deallocate(OutputData%WriteOutput) + end if +end subroutine + +subroutine LD_PackOutput(RF, Indata) + type(RegFile), intent(inout) :: RF + type(LD_OutputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'LD_PackOutput' + if (RF%ErrStat >= AbortErrLev) return + call RegPackAlloc(RF, InData%xdd) + call RegPackAlloc(RF, InData%WriteOutput) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_UnPackOutput(RF, OutData) + type(RegFile), intent(inout) :: RF + type(LD_OutputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'LD_UnPackOutput' + integer(B8Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpackAlloc(RF, OutData%xdd); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%WriteOutput); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine LD_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 + ! + ! expressions below based on either + ! + ! f(t) = a + ! f(t) = a + b * t, or + ! f(t) = a + b * t + c * t**2 + ! + ! where a, b and c are determined as the solution to + ! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) + ! + !---------------------------------------------------------------------------------------------------------------------------------- + + type(LD_InputType), intent(in) :: u(:) ! Input at t1 > t2 > t3 + real(DbKi), intent(in ) :: t(:) ! Times associated with the Inputs + type(LD_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 + ! local variables + integer(IntKi) :: order ! order of polynomial fit (max 2) + integer(IntKi) :: ErrStat2 ! local errors + character(ErrMsgLen) :: ErrMsg2 ! local errors + character(*), PARAMETER :: RoutineName = 'LD_Input_ExtrapInterp' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + if (size(t) /= size(u)) then + call SetErrStat(ErrID_Fatal, 'size(t) must equal size(u)', ErrStat, ErrMsg, RoutineName) + return + endif + order = size(u) - 1 + select case (order) + case (0) + call LD_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + case (1) + call LD_Input_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + case (2) + call LD_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) + return + end select +end subroutine + +SUBROUTINE LD_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. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(LD_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 + TYPE(LD_InputType), INTENT(IN) :: u2 ! Input at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs + TYPE(LD_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 = 'LD_Input_ExtrapInterp1' + REAL(DbKi) :: a1, a2 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + ! 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) + t_out = tin_out - tin(1) + + IF (EqualRealNos(t(1), t(2))) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg, RoutineName) + RETURN + END IF + + ! Calculate weighting factors from Lagrange polynomial + a1 = -(t_out - t(2))/t(2) + a2 = t_out/t(2) + + IF (ALLOCATED(u_out%Fext) .AND. ALLOCATED(u1%Fext)) THEN + u_out%Fext = a1*u1%Fext + a2*u2%Fext + END IF ! check if allocated +END SUBROUTINE + +SUBROUTINE LD_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. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(LD_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 > t3 + TYPE(LD_InputType), INTENT(IN) :: u2 ! Input at t2 > t3 + TYPE(LD_InputType), INTENT(IN) :: u3 ! Input at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs + TYPE(LD_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(3) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: a1,a2,a3 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'LD_Input_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + ! 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) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ! Calculate Lagrange polynomial coefficients + a1 = (t_out - t(2))*(t_out - t(3))/((t(1) - t(2))*(t(1) - t(3))) + a2 = (t_out - t(1))*(t_out - t(3))/((t(2) - t(1))*(t(2) - t(3))) + a3 = (t_out - t(1))*(t_out - t(2))/((t(3) - t(1))*(t(3) - t(2))) + IF (ALLOCATED(u_out%Fext) .AND. ALLOCATED(u1%Fext)) THEN + u_out%Fext = a1*u1%Fext + a2*u2%Fext + a3*u3%Fext + END IF ! check if allocated +END SUBROUTINE + +subroutine LD_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 + ! + ! expressions below based on either + ! + ! f(t) = a + ! f(t) = a + b * t, or + ! f(t) = a + b * t + c * t**2 + ! + ! where a, b and c are determined as the solution to + ! f(t1) = y1, f(t2) = y2, f(t3) = y3 (as appropriate) + ! + !---------------------------------------------------------------------------------------------------------------------------------- + + type(LD_OutputType), intent(in) :: y(:) ! Output at t1 > t2 > t3 + real(DbKi), intent(in ) :: t(:) ! Times associated with the Outputs + type(LD_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 + ! local variables + integer(IntKi) :: order ! order of polynomial fit (max 2) + integer(IntKi) :: ErrStat2 ! local errors + character(ErrMsgLen) :: ErrMsg2 ! local errors + character(*), PARAMETER :: RoutineName = 'LD_Output_ExtrapInterp' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + if (size(t) /= size(y)) then + call SetErrStat(ErrID_Fatal, 'size(t) must equal size(y)', ErrStat, ErrMsg, RoutineName) + return + endif + order = size(y) - 1 + select case (order) + case (0) + call LD_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + case (1) + call LD_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + case (2) + call LD_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) + return + end select +end subroutine + +SUBROUTINE LD_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. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = y1, f(t2) = y2 +! +!.................................................................................................................................. + + TYPE(LD_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 + TYPE(LD_OutputType), INTENT(IN) :: y2 ! Output at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs + TYPE(LD_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 = 'LD_Output_ExtrapInterp1' + REAL(DbKi) :: a1, a2 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + ! 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) + t_out = tin_out - tin(1) + + IF (EqualRealNos(t(1), t(2))) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg, RoutineName) + RETURN + END IF + + ! Calculate weighting factors from Lagrange polynomial + a1 = -(t_out - t(2))/t(2) + a2 = t_out/t(2) + + IF (ALLOCATED(y_out%xdd) .AND. ALLOCATED(y1%xdd)) THEN + y_out%xdd = a1*y1%xdd + a2*y2%xdd + END IF ! check if allocated + IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + y_out%WriteOutput = a1*y1%WriteOutput + a2*y2%WriteOutput + END IF ! check if allocated +END SUBROUTINE + +SUBROUTINE LD_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. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 +! +!.................................................................................................................................. + + TYPE(LD_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 > t3 + TYPE(LD_OutputType), INTENT(IN) :: y2 ! Output at t2 > t3 + TYPE(LD_OutputType), INTENT(IN) :: y3 ! Output at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs + TYPE(LD_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(3) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: a1,a2,a3 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'LD_Output_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + ! 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) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ! Calculate Lagrange polynomial coefficients + a1 = (t_out - t(2))*(t_out - t(3))/((t(1) - t(2))*(t(1) - t(3))) + a2 = (t_out - t(1))*(t_out - t(3))/((t(2) - t(1))*(t(2) - t(3))) + a3 = (t_out - t(1))*(t_out - t(2))/((t(3) - t(1))*(t(3) - t(2))) + IF (ALLOCATED(y_out%xdd) .AND. ALLOCATED(y1%xdd)) THEN + y_out%xdd = a1*y1%xdd + a2*y2%xdd + a3*y3%xdd + END IF ! check if allocated + IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + y_out%WriteOutput = a1*y1%WriteOutput + a2*y2%WriteOutput + a3*y3%WriteOutput + END IF ! check if allocated +END SUBROUTINE +END MODULE LinDyn_Types +!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/map/src/mapsys.h b/modules/map/src/mapsys.h index 2f6291c4d7..e8966d6d0e 100644 --- a/modules/map/src/mapsys.h +++ b/modules/map/src/mapsys.h @@ -33,7 +33,7 @@ #if defined(_WIN32) || defined(_WIN64) -# include +# include # include #else # include diff --git a/modules/moordyn/src/MoorDyn_IO.f90 b/modules/moordyn/src/MoorDyn_IO.f90 index 245c9afa1f..5a5f319a09 100644 --- a/modules/moordyn/src/MoorDyn_IO.f90 +++ b/modules/moordyn/src/MoorDyn_IO.f90 @@ -139,7 +139,7 @@ SUBROUTINE setupBathymetry(inputString, defaultDepth, BathGrid, BathGrid_Xs, Bat INTEGER(IntKi) :: ErrStat4 CHARACTER(120) :: ErrMsg4 - CHARACTER(120) :: Line2 + CHARACTER(4096) :: Line2 CHARACTER(20) :: nGridX_string ! string to temporarily hold the nGridX string from Line2 CHARACTER(20) :: nGridY_string ! string to temporarily hold the nGridY string from Line3 @@ -182,7 +182,7 @@ SUBROUTINE setupBathymetry(inputString, defaultDepth, BathGrid, BathGrid_Xs, Bat READ(UnCoef,*,IOSTAT=ErrStat4) nGridY_string, nGridY ! read in the third line as the number of y values in the BathGrid ! Allocate the bathymetry matrix and associated grid x and y values - ALLOCATE(BathGrid(nGridX, nGridY), STAT=ErrStat4) + ALLOCATE(BathGrid(nGridY, nGridX), STAT=ErrStat4) ALLOCATE(BathGrid_Xs(nGridX), STAT=ErrStat4) ALLOCATE(BathGrid_Ys(nGridY), STAT=ErrStat4) @@ -567,7 +567,7 @@ SUBROUTINE MDIO_ProcessOutList(OutList, p, m, y, InitOut, ErrStat, ErrMsg ) END IF ! Point case - ELSE IF (let1(1:1) == 'P') THEN ! Look for P?xxx or Point?xxx + ELSE IF (let1(1:1) == 'P' .OR. let1(1:1) == 'C') THEN ! Look for P?xxx or Point?xxx (C?xxx and Con?xxx for backwards compatability) p%OutParam(I)%OType = 2 ! Point object type qVal = let2 ! quantity type string @@ -605,7 +605,7 @@ SUBROUTINE MDIO_ProcessOutList(OutList, p, m, y, InitOut, ErrStat, ErrMsg ) ! error ELSE CALL DenoteInvalidOutput(p%OutParam(I)) ! flag as invalid - CALL WrScr('Warning: invalid output specifier '//trim(OutListTmp)//'. Must start with L, C, R, or B') + CALL WrScr('Warning: invalid output specifier '//trim(OutListTmp)//'. Must start with L, R, or B') CYCLE END IF diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index 8fb91cf218..c54dea1f2e 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -885,7 +885,7 @@ SUBROUTINE getDepthFromBathymetry(BathymetryGrid, BathGrid_Xs, BathGrid_Ys, Line else dc_dx = 0.0_DbKi ! maybe this should raise an error end if - if ( dx > 0.0 ) then + if ( dy > 0.0 ) then dc_dy = (cx1-cx0)/dy else dc_dy = 0.0_DbKi ! maybe this should raise an error @@ -1300,8 +1300,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) REAL(SiKi) :: t, Frac CHARACTER(1024) :: FileName ! Name of MoorDyn input file CHARACTER(120) :: Line -! CHARACTER(120) :: Line2 - CHARACTER(120) :: entries2 + CHARACTER(4096) :: entries2 INTEGER(IntKi) :: coordtype INTEGER(IntKi) :: NStepWave ! diff --git a/modules/nwtc-library/CMakeLists.txt b/modules/nwtc-library/CMakeLists.txt index de91776fea..139d67b0ef 100644 --- a/modules/nwtc-library/CMakeLists.txt +++ b/modules/nwtc-library/CMakeLists.txt @@ -160,7 +160,6 @@ add_dependencies(nwtclibs nwtc_library_inc_subs) target_link_libraries(nwtclibs PUBLIC ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS} - ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES} ) if (USE_DLL_INTERFACE) target_compile_definitions(nwtclibs PRIVATE USE_DLL_INTERFACE) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 0408b727eb..86a34299b9 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -1850,7 +1850,7 @@ SUBROUTINE DispNVD1 ( ProgInfo, DispNWTCVer ) END IF END IF - CALL WrScr ( 'Running '//TRIM( GetNVD( ProgInfo ) )//'.' ) + CALL WrScr ( ' Running '//TRIM( GetNVD( ProgInfo ) )//'.' ) RETURN END SUBROUTINE DispNVD1 @@ -7789,5 +7789,92 @@ SUBROUTINE WrScr1 ( Str ) RETURN END SUBROUTINE WrScr1 + + !---------------------------------------------------------------------------------------------------------------------------------- + !> Read a delimited file of float with one or multiple lines of header + !! TODO: put me in a CSV.f90 file of the NWTC library + !! TODO: automatic detection of number of columns for instance using ReadCAryFromStr + !! See also the quick and dirty check introduced to read blade files that don't have Buoyancy columns + subroutine ReadDelimFile(Filename, nCol, array, errStat, errMsg, nHeaderLines, priPath) + character(len=*), intent(in) :: Filename + integer(IntKi), intent(in) :: nCol + real(ReKi), dimension(:,:), allocatable, intent(out) :: array + integer(IntKi) , intent(out) :: errStat ! Status of error message + character(*) , intent(out) :: errMsg ! Error message if errStat /= ErrID_None + integer(IntKi), optional, intent(in ) :: nHeaderLines + character(*) , optional, intent(in ) :: priPath ! Primary path, to use if filename is not absolute + integer(IntKi) :: UnIn, i, j, nLine, nHead + character(len= 2048) :: line + integer(IntKi) :: errStat2 ! local status of error message + character(ErrMsgLen) :: errMsg2 ! temporary Error message + character(len=2048) :: Filename_Loc ! filename local to this function + errStat = ErrID_None + errMsg = "" + + Filename_Loc = Filename + if (present(priPath)) then + if (PathIsRelative(Filename_Loc)) Filename_Loc = trim(PriPath)//trim(Filename) + endif + + ! Open file + call GetNewUnit(UnIn) + call OpenFInpFile(UnIn, Filename_Loc, errStat2, errMsg2); if(Failed()) return + ! Count number of lines + nLine = line_count(UnIn, errStat2, errMsg2); if(Failed()) return + if (allocated(array)) deallocate(array) + allocate(array(nLine-1, nCol), stat=errStat2); errMsg2='allocation failed'; if(Failed())return + ! Read header + nHead=1 + if (present(nHeaderLines)) nHead = nHeaderLines + do i=1,nHead + read(UnIn, *, IOSTAT=errStat2) line + errMsg2 = ' Error reading line '//trim(Num2LStr(1))//' of file: '//trim(Filename_Loc) + if(Failed()) return + enddo + ! Read data + do i = 1,nLine-1 + read (UnIn,*,IOSTAT=errStat2) (array(i,j), j=1,nCol) + errMsg2 = ' Error reading line '//trim(Num2LStr(i+1))//' of file: '//trim(Filename_Loc) + if(Failed()) return + end do + close(UnIn) + contains + logical function Failed() + CALL SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile' ) + Failed = errStat >= AbortErrLev + if (Failed) then + if ((UnIn)>0) close(UnIn) + endif + end function Failed + end subroutine ReadDelimFile + + !---------------------------------------------------------------------------------------------------------------------------------- + !> Counts number of lines in a file, do not count last line if empty + integer function line_count(iUnit, errStat, errMsg) + integer(IntKi), intent(in) :: iUnit + integer(IntKi), intent(out) :: errStat ! Error status + character(*), intent(out) :: errMsg ! Error message associated with ErrStat + character(len=2048) :: line + integer, parameter :: nline_max=100000000 ! 100 M safety for infinite loop.. + integer :: i + errStat = ErrID_None + errMsg = '' + line_count=0 + do i=1,nline_max + line='' + read(iUnit,'(A)',END=100)line + line_count=line_count+1 + enddo + if (line_count==nline_max) then + errStat = ErrID_Fatal + errMsg = 'Error: maximum number of line exceeded for line_count' + return + endif + 100 if(len(trim(line))>0) then + line_count=line_count+1 + endif + rewind(iUnit) + return + end function line_count END MODULE NWTC_IO diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 012a6f280a..66148d1e3d 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -3311,6 +3311,44 @@ SUBROUTINE InterpStpMat8( XVal, XAry, Y, Ind, AryLen, yInterp ) RETURN END SUBROUTINE InterpStpMat8 +!======================================================================= +!---------------------------------------------------------------------------------------------------------------------------------- +!> Perform linear interpolation of an array, where first column is assumed to be ascending time values +!! Similar to InterpStpMat, I think (to check), interpTimeValues=InterpStpMat( array(:,1), time, array(:,1:), iLast, AryLen, values ) +!! First value is used for times before, and last value is used for time beyond + subroutine interpTimeValue(array, time, iLast, values) + real(ReKi), dimension(:,:), intent(in) :: array !< Values, shape nt x nc, where array(:,1) is the time vector + real(DbKi), intent(in) :: time !< Time where values are to be interpolated + integer(IntKi), intent(inout) :: iLast !< previous index used (to speed up interpolation) + real(ReKi), dimension(:), intent(out) :: values !< vector of values, shape nc, at given `time` + integer :: i, nMax + real(ReKi) :: alpha + nMax = size(array, 1) + iLast = max( min(iLast, nMax), 1) ! Clip iLast between 1 and nMax + !call InterpStpMat( array(:,1), time, array(:,1:), iLast, AryLen, values ) + if (array(iLast,1) > time) then + values = array(iLast,2:) + elseif (iLast == nMax) then + values = array(iLast,2:) + else + ! Look for index + do i = iLast, nMax + if (array(i,1)<=time) then + iLast=i + else + exit + endif + enddo + if (iLast==nMax) then + values = array(iLast,2:) + else + ! Linear interpolation + alpha = (array(iLast+1,1)-time)/(array(iLast+1,1)-array(iLast,1)) + values = array(iLast,2:)*alpha + array(iLast+1,2:)*(1-alpha) + endif + endif + end subroutine interpTimeValue + !======================================================================= !< This routine linearly interpolates Dataset. It is !! set for a 2-d interpolation on x and y of the input point. @@ -4946,7 +4984,7 @@ FUNCTION RegCubicSplineInterpM ( X, XAry, YAry, DelX, Coef, ErrStat, ErrMsg ) RE RETURN END FUNCTION RegCubicSplineInterpM ! ( X, XAry, YAry, DelX, Coef, ErrStat, ErrMsg ) !======================================================================= -!> This routine is used to integrate funciton f over the interval [a, b]. This routine +!> This routine is used to integrate function f over the interval [a, b]. This routine !! is useful for sufficiently smooth (e.g., analytic) integrands, integrated over !! intervals which contain no singularities, and where the endpoints are also nonsingular. !! diff --git a/modules/openfast-library/src/FAST_Library.f90 b/modules/openfast-library/src/FAST_Library.f90 index 82a5d9d96c..ff584af59a 100644 --- a/modules/openfast-library/src/FAST_Library.f90 +++ b/modules/openfast-library/src/FAST_Library.f90 @@ -53,7 +53,7 @@ subroutine FAST_AllocateTurbines(nTurbines, ErrStat_c, ErrMsg_c) BIND (C, NAME=' call wrscr1('Proceeding anyway.') end if - allocate(Turbine(0:NumTurbines-1),Stat=ErrStat) !Allocate in C style because most of the other Turbine properties from the input file are in C style inside the C++ driver + allocate(Turbine(1:NumTurbines),Stat=ErrStat) !Allocate in F style -- all logic inside FAST_Subs is based on index 1 start, not C style index 0 if (ErrStat /= 0) then ErrStat_c = ErrID_Fatal @@ -83,13 +83,13 @@ subroutine FAST_DeallocateTurbines(ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Deal ErrMsg_c = C_NULL_CHAR end subroutine !================================================================================================================================== -subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt_out_c, tmax_c, ErrStat_c, ErrMsg_c, ChannelNames_c, TMax, InitInpAry) BIND (C, NAME='FAST_Sizes') - IMPLICIT NONE +subroutine FAST_Sizes(iTurb_c, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt_out_c, tmax_c, ErrStat_c, ErrMsg_c, ChannelNames_c, TMax, InitInpAry) BIND (C, NAME='FAST_Sizes') + IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_Sizes !GCC$ ATTRIBUTES DLLEXPORT :: FAST_Sizes #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) CHARACTER(KIND=C_CHAR), INTENT(IN ) :: InputFileName_c(IntfStrLen) INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c INTEGER(C_INT), INTENT( OUT) :: NumOuts_c @@ -106,8 +106,12 @@ subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt CHARACTER(IntfStrLen) :: InputFileName INTEGER :: i, j, k TYPE(FAST_ExternInitType) :: ExternInitData + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) - ! transfer the character array from C to a Fortran string: + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + + ! transfer the character array from C to a Fortran string: InputFileName = TRANSFER( InputFileName_c, InputFileName ) I = INDEX(InputFileName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... IF ( I > 0 ) InputFileName = InputFileName(1:I) ! remove it @@ -126,7 +130,7 @@ subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt IF (PRESENT(TMax)) THEN ExternInitData%TMax = TMax END IF - ExternInitData%TurbineID = -1 ! we're not going to use this to simulate a wind farm + ExternInitData%TurbIDforName = -1 ! we're not going to use this to simulate a wind farm ExternInitData%TurbinePos = 0.0_ReKi ! turbine position is at the origin ExternInitData%NumCtrl2SC = 0 ExternInitData%NumSC2Ctrl = 0 @@ -180,29 +184,33 @@ subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt end subroutine FAST_Sizes !================================================================================================================================== -subroutine FAST_Start(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Start') - IMPLICIT NONE +subroutine FAST_Start(iTurb_c, NumInputs_c, NumOutputs_c, InputAry, OutputAry, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Start') + IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_Start !GCC$ ATTRIBUTES DLLEXPORT :: FAST_Start #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT(IN ) :: NumInputs_c INTEGER(C_INT), INTENT(IN ) :: NumOutputs_c REAL(C_DOUBLE), INTENT(IN ) :: InputAry(NumInputs_c) REAL(C_DOUBLE), INTENT( OUT) :: OutputAry(NumOutputs_c) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) - + ! local CHARACTER(IntfStrLen) :: InputFileName INTEGER :: i REAL(ReKi) :: Outputs(NumOutputs_c-1) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) INTEGER(IntKi) :: ErrStat2 ! Error status CHARACTER(IntfStrLen-1) :: ErrMsg2 ! Error message (this needs to be static so that it will print in Matlab's mex library) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + ! initialize variables: n_t_global = 0 @@ -244,13 +252,13 @@ subroutine FAST_Start(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, Err end subroutine FAST_Start !================================================================================================================================== -subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, EndSimulationEarly, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Update') +subroutine FAST_Update(iTurb_c, NumInputs_c, NumOutputs_c, InputAry, OutputAry, EndSimulationEarly, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Update') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_Update !GCC$ ATTRIBUTES DLLEXPORT :: FAST_Update #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT(IN ) :: NumInputs_c INTEGER(C_INT), INTENT(IN ) :: NumOutputs_c REAL(C_DOUBLE), INTENT(IN ) :: InputAry(NumInputs_c) @@ -262,9 +270,14 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, En ! local variables REAL(ReKi) :: Outputs(NumOutputs_c-1) INTEGER(IntKi) :: i + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + INTEGER(IntKi) :: ErrStat2 ! Error status CHARACTER(IntfStrLen-1) :: ErrMsg2 ! Error message (this needs to be static so that it will print in Matlab's mex library) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + EndSimulationEarly = .FALSE. IF ( n_t_global > Turbine(iTurb)%p_FAST%n_TMax_m1 ) THEN !finish @@ -326,21 +339,25 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, En end subroutine FAST_Update !================================================================================================================================== ! Get the hub's absolute position, rotation velocity, and orientation DCM for the current time step -subroutine FAST_HubPosition(iTurb, AbsPosition_c, RotationalVel_c, Orientation_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_HubPosition') +subroutine FAST_HubPosition(iTurb_c, AbsPosition_c, RotationalVel_c, Orientation_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_HubPosition') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_HubPosition !GCC$ ATTRIBUTES DLLEXPORT :: FAST_HubPosition #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) REAL(C_FLOAT), INTENT( OUT) :: AbsPosition_c(3), RotationalVel_c(3) REAL(C_DOUBLE), INTENT( OUT) :: Orientation_c(9) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) ErrStat_c = ErrID_None ErrMsg = C_NULL_CHAR + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + if (iTurb > size(Turbine) ) then ErrStat_c = ErrID_Fatal ErrMsg = "iTurb is greater than the number of turbines in the simulation."//C_NULL_CHAR @@ -372,7 +389,7 @@ subroutine FAST_SetExternalInputs(iTurb, NumInputs_c, InputAry, m_FAST) IMPLICIT NONE - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(IntKi), INTENT(IN ) :: iTurb ! Turbine number, Fortran indexing (starts at 1 for first turbine) INTEGER(C_INT), INTENT(IN ) :: NumInputs_c REAL(C_DOUBLE), INTENT(IN ) :: InputAry(NumInputs_c) ! Inputs from Simulink TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST ! Miscellaneous variables @@ -399,26 +416,30 @@ subroutine FAST_SetExternalInputs(iTurb, NumInputs_c, InputAry, m_FAST) end subroutine FAST_SetExternalInputs !================================================================================================================================== -subroutine FAST_End(iTurb, StopTheProgram) BIND (C, NAME='FAST_End') +subroutine FAST_End(iTurb_c, StopTheProgram) BIND (C, NAME='FAST_End') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_End !GCC$ ATTRIBUTES DLLEXPORT :: FAST_End #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) LOGICAL(C_BOOL), INTENT(IN) :: StopTheProgram ! flag indicating if the program should end (false if there are more turbines to end) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 CALL ExitThisProgram_T( Turbine(iTurb), ErrID_None, LOGICAL(StopTheProgram)) end subroutine FAST_End !================================================================================================================================== -subroutine FAST_CreateCheckpoint(iTurb, CheckpointRootName_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CreateCheckpoint') +subroutine FAST_CreateCheckpoint(iTurb_c, CheckpointRootName_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CreateCheckpoint') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_CreateCheckpoint !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CreateCheckpoint #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CheckpointRootName_c(IntfStrLen) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) @@ -427,9 +448,12 @@ subroutine FAST_CreateCheckpoint(iTurb, CheckpointRootName_c, ErrStat_c, ErrMsg_ CHARACTER(IntfStrLen) :: CheckpointRootName INTEGER(IntKi) :: I INTEGER(IntKi) :: Unit + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 - ! transfer the character array from C to a Fortran string: + ! transfer the character array from C to a Fortran string: CheckpointRootName = TRANSFER( CheckpointRootName_c, CheckpointRootName ) I = INDEX(CheckpointRootName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... IF ( I > 0 ) CheckpointRootName = CheckpointRootName(1:I) ! remove it @@ -454,13 +478,13 @@ subroutine FAST_CreateCheckpoint(iTurb, CheckpointRootName_c, ErrStat_c, ErrMsg_ end subroutine FAST_CreateCheckpoint !================================================================================================================================== -subroutine FAST_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, NumOuts_c, dt_c, n_t_global_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Restart') +subroutine FAST_Restart(iTurb_c, CheckpointRootName_c, AbortErrLev_c, NumOuts_c, dt_c, n_t_global_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Restart') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_Restart !GCC$ ATTRIBUTES DLLEXPORT :: FAST_Restart #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CheckpointRootName_c(IntfStrLen) INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c INTEGER(C_INT), INTENT( OUT) :: NumOuts_c @@ -475,8 +499,11 @@ subroutine FAST_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, NumOuts_c, d INTEGER(IntKi) :: Unit REAL(DbKi) :: t_initial_out INTEGER(IntKi) :: NumTurbines_out - CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Restart' + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Restart' + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 ! transfer the character array from C to a Fortran string: CheckpointRootName = TRANSFER( CheckpointRootName_c, CheckpointRootName ) @@ -508,19 +535,18 @@ subroutine FAST_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, NumOuts_c, d end subroutine FAST_Restart !================================================================================================================================== -subroutine FAST_ExtLoads_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_c, TurbPosn, AbortErrLev_c, dtDriver_c, dt_c, NumBl_c, & +subroutine FAST_ExtLoads_Init(iTurb_c, TMax, InputFileName_c, TurbIDforName, OutFileRoot_c, TurbPosn, AbortErrLev_c, dtDriver_c, dt_c, NumBl_c, & az_blend_mean_c, az_blend_delta_c, vel_mean_c, wind_dir_c, z_ref_c, shear_exp_c, & ExtLd_Input_from_FAST, ExtLd_Parameter_from_FAST, ExtLd_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtLoads_Init') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_ExtLoads_Init IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtLoads_Init !GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtLoads_Init #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) 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 ) :: TurbIDforName ! Need not be same as iTurb CHARACTER(KIND=C_CHAR), INTENT( OUT) :: OutFileRoot_c(IntfStrLen) REAL(C_FLOAT), INTENT(IN ) :: TurbPosn(3) REAL(C_DOUBLE), INTENT(IN ) :: dtDriver_c @@ -546,9 +572,12 @@ subroutine FAST_ExtLoads_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_ INTEGER(C_INT) :: i TYPE(FAST_ExternInitType) :: ExternInitData INTEGER(IntKi) :: CompLoadsType - + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) CHARACTER(*), PARAMETER :: RoutineName = 'FAST_ExtLoads_Init' + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + ! transfer the character array from C to a Fortran string: InputFileName = TRANSFER( InputFileName_c, InputFileName ) I = INDEX(InputFileName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... @@ -560,7 +589,7 @@ subroutine FAST_ExtLoads_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_ ErrMsg = "" ExternInitData%TMax = TMax - ExternInitData%TurbineID = TurbID + ExternInitData%TurbIDforName = TurbIDforName ExternInitData%TurbinePos = TurbPosn ExternInitData%SensorType = SensorType_None ExternInitData%NumSC2CtrlGlob = 0 @@ -607,17 +636,19 @@ subroutine FAST_ExtLoads_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_ end subroutine FAST_ExtLoads_Init !================================================================================================================================== -subroutine FAST_ExtInfw_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_c, NumSC2CtrlGlob, NumSC2Ctrl, NumCtrl2SC, InitSCOutputsGlob, InitSCOutputsTurbine, NumActForcePtsBlade, NumActForcePtsTower, TurbPosn, AbortErrLev_c, dtDriver_c, dt_c, InflowType, NumBl_c, NumBlElem_c, NumTwrElem_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') +subroutine FAST_ExtInfw_Init(iTurb_c, TMax, InputFileName_c, TurbIDforName, OutFileRoot_c, NumSC2CtrlGlob, NumSC2Ctrl, NumCtrl2SC, & + InitSCOutputsGlob, InitSCOutputsTurbine, NumActForcePtsBlade, NumActForcePtsTower, TurbPosn, AbortErrLev_c, & + dtDriver_c, dt_c, InflowType, NumBl_c, NumBlElem_c, NumTwrElem_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_ExtInfw_Init !GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Init #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! 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 ) :: TurbIDforName ! Need not be same as iTurb_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: OutFileRoot_c(IntfStrLen) ! Root of output and restart file name INTEGER(C_INT), INTENT(IN ) :: NumSC2CtrlGlob ! Supercontroller global outputs = controller global inputs INTEGER(C_INT), INTENT(IN ) :: NumSC2Ctrl ! Supercontroller outputs = controller inputs @@ -646,9 +677,13 @@ subroutine FAST_ExtInfw_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_c CHARACTER(IntfStrLen) :: InputFileName INTEGER(C_INT) :: i TYPE(FAST_ExternInitType) :: ExternInitData + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) CHARACTER(*), PARAMETER :: RoutineName = 'FAST_ExtInfw_Init' + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + ! transfer the character array from C to a Fortran string: InputFileName = TRANSFER( InputFileName_c, InputFileName ) I = INDEX(InputFileName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... @@ -662,8 +697,15 @@ subroutine FAST_ExtInfw_Init(iTurb, TMax, InputFileName_c, TurbID, OutFileRoot_c NumBl_c = 0 ! initialize here in case of error NumBlElem_c = 0 ! initialize here in case of error + ! Check TurbIDforName -- must be 0 or larger + if (TurbIDforName < 0) then + ErrStat = ErrID_Fatal + ErrMsg = "TurbIDforName cannot be negative" + if (Failed()) return + endif + ExternInitData%TMax = TMax - ExternInitData%TurbineID = TurbID + ExternInitData%TurbIDforName = TurbIDforName ExternInitData%TurbinePos = TurbPosn ExternInitData%SensorType = SensorType_None ExternInitData%NumCtrl2SC = NumCtrl2SC @@ -783,18 +825,22 @@ END FUNCTION FAILED end subroutine !================================================================================================================================== -subroutine FAST_CFD_Solution0(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Solution0') +subroutine FAST_CFD_Solution0(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Solution0') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Solution0 !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Solution0 #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) CHARACTER(*), PARAMETER :: RoutineName = 'FAST_CFD_Solution0' + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + call FAST_Solution0_T(Turbine(iTurb), ErrStat, ErrMsg ) ! if(Turbine(iTurb)%SC_DX%p%useSC) then @@ -808,15 +854,19 @@ subroutine FAST_CFD_Solution0(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CF end subroutine FAST_CFD_Solution0 !================================================================================================================================== -subroutine FAST_CFD_InitIOarrays_SubStep(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_InitIOarrays_SubStep') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_CFD_InitIOarrays_SubStep +subroutine FAST_CFD_InitIOarrays_SubStep(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_InitIOarrays_SubStep') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_InitIOarrays_SubStep !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_InitIOarrays_SubStep #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 call FAST_InitIOarrays_SubStep_T(t_initial, Turbine(iTurb), ErrStat, ErrMsg ) @@ -827,14 +877,14 @@ subroutine FAST_CFD_InitIOarrays_SubStep(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NA end subroutine FAST_CFD_InitIOarrays_SubStep !================================================================================================================================== -subroutine FAST_ExtInfw_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c, numblades_c, numElementsPerBlade_c, numElementsTower_c, n_t_global_c, & +subroutine FAST_ExtInfw_Restart(iTurb_c, CheckpointRootName_c, AbortErrLev_c, dt_c, numblades_c, numElementsPerBlade_c, numElementsTower_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_ExtInfw_Restart !GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Restart #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CheckpointRootName_c(IntfStrLen) INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c INTEGER(C_INT), INTENT( OUT) :: numblades_c @@ -856,8 +906,12 @@ subroutine FAST_ExtInfw_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c INTEGER(IntKi) :: Unit REAL(DbKi) :: t_initial_out INTEGER(IntKi) :: NumTurbines_out + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Restart' + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + CALL NWTC_Init() ! transfer the character array from C to a Fortran string: CheckpointRootName = TRANSFER( CheckpointRootName_c, CheckpointRootName ) @@ -904,7 +958,6 @@ end subroutine FAST_ExtInfw_Restart subroutine FAST_ExtLoads_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c, numblades_c, & n_t_global_c, ExtLd_Input_from_FAST, ExtLd_Parameter_from_FAST, ExtLd_Output_to_FAST, & SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtLoads_Restart') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_ExtLoads_Restart IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtLoads_Restart @@ -1062,22 +1115,25 @@ subroutine SetExternalInflow_pointers(iTurb, ExtInfw_Input_from_FAST, ExtInfw_Ou end subroutine SetExternalInflow_pointers !================================================================================================================================== -subroutine FAST_CFD_Prework(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Prework') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_CFD_Prework +subroutine FAST_CFD_Prework(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Prework') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Prework !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Prework #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 IF ( n_t_global > Turbine(iTurb)%p_FAST%n_TMax_m1 ) THEN !finish ! we can't continue because we might over-step some arrays that are allocated to the size of the simulation - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines) then IF (n_t_global == Turbine(iTurb)%p_FAST%n_TMax_m1 + 1) THEN ! we call update an extra time in Simulink, which we can ignore until the time shift with outputs is solved n_t_global = n_t_global + 1 ErrStat_c = ErrID_None @@ -1105,22 +1161,25 @@ subroutine FAST_CFD_Prework(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_ end subroutine FAST_CFD_Prework !================================================================================================================================== -subroutine FAST_CFD_UpdateStates(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_UpdateStates') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_CFD_UpdateStates +subroutine FAST_CFD_UpdateStates(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_UpdateStates') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_UpdateStates !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_UpdateStates #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 IF ( n_t_global > Turbine(iTurb)%p_FAST%n_TMax_m1 ) THEN !finish ! we can't continue because we might over-step some arrays that are allocated to the size of the simulation - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines ) then IF (n_t_global == Turbine(iTurb)%p_FAST%n_TMax_m1 + 1) THEN ! we call update an extra time in Simulink, which we can ignore until the time shift with outputs is solved n_t_global = n_t_global + 1 ErrStat_c = ErrID_None @@ -1144,22 +1203,25 @@ subroutine FAST_CFD_UpdateStates(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST end subroutine FAST_CFD_UpdateStates !================================================================================================================================== -subroutine FAST_CFD_AdvanceToNextTimeStep(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_AdvanceToNextTimeStep') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_CFD_AdvanceToNextTimeStep +subroutine FAST_CFD_AdvanceToNextTimeStep(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_AdvanceToNextTimeStep') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_AdvanceToNextTimeStep !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_AdvanceToNextTimeStep #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 IF ( n_t_global > Turbine(iTurb)%p_FAST%n_TMax_m1 ) THEN !finish ! we can't continue because we might over-step some arrays that are allocated to the size of the simulation - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines ) then IF (n_t_global == Turbine(iTurb)%p_FAST%n_TMax_m1 + 1) THEN ! we call update an extra time in Simulink, which we can ignore until the time shift with outputs is solved n_t_global = n_t_global + 1 ErrStat_c = ErrID_None @@ -1180,7 +1242,7 @@ subroutine FAST_CFD_AdvanceToNextTimeStep(iTurb, ErrStat_c, ErrMsg_c) BIND (C, N ! CALL SC_SetInputs(Turbine(iTurb)%p_FAST, Turbine(iTurb)%SrvD%y, Turbine(iTurb)%SC, ErrStat, ErrMsg) ! end if - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines ) then n_t_global = n_t_global + 1 end if @@ -1192,36 +1254,43 @@ subroutine FAST_CFD_AdvanceToNextTimeStep(iTurb, ErrStat_c, ErrMsg_c) BIND (C, N end subroutine FAST_CFD_AdvanceToNextTimeStep !================================================================================================================================== -subroutine FAST_CFD_WriteOutput(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_WriteOutput') -!DEC$ ATTRIBUTES DLLEXPORT::FAST_CFD_WriteOutput +subroutine FAST_CFD_WriteOutput(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_WriteOutput') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_WriteOutput !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_WriteOutput #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 CALL FAST_WriteOutput_T( t_initial, n_t_global, Turbine(iTurb), ErrStat, ErrMsg ) end subroutine FAST_CFD_WriteOutput !================================================================================================================================== -subroutine FAST_CFD_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Step') +subroutine FAST_CFD_Step(iTurb_c, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Step') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT !DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Step !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Step #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 IF ( n_t_global > Turbine(iTurb)%p_FAST%n_TMax_m1 ) THEN !finish ! we can't continue because we might over-step some arrays that are allocated to the size of the simulation - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines ) then IF (n_t_global == Turbine(iTurb)%p_FAST%n_TMax_m1 + 1) THEN ! we call update an extra time in Simulink, which we can ignore until the time shift with outputs is solved n_t_global = n_t_global + 1 ErrStat_c = ErrID_None @@ -1238,7 +1307,7 @@ subroutine FAST_CFD_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Ste CALL FAST_Solution_T( t_initial, n_t_global, Turbine(iTurb), ErrStat, ErrMsg ) - if (iTurb .eq. (NumTurbines-1) ) then + if (iTurb == NumTurbines ) then n_t_global = n_t_global + 1 end if @@ -1250,47 +1319,53 @@ subroutine FAST_CFD_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Ste end subroutine FAST_CFD_Step !================================================================================================================================== -subroutine FAST_CFD_Reset_SubStep(iTurb, n_timesteps, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Reset_SubStep') - IMPLICIT NONE +subroutine FAST_CFD_Reset_SubStep(iTurb_c, n_timesteps, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Reset_SubStep') + IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT - !DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Reset_SubStep - !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Reset_SubStep +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Reset_SubStep +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Reset_SubStep #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number - INTEGER(C_INT), INTENT(IN ) :: n_timesteps ! Number of time steps to go back - INTEGER(C_INT), INTENT( OUT) :: ErrStat_c - CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) - - CALL FAST_Reset_SubStep_T(t_initial, n_t_global-n_timesteps, n_timesteps, Turbine(iTurb), ErrStat, ErrMsg ) - - if (iTurb .eq. (NumTurbines-1) ) then - n_t_global = n_t_global - n_timesteps - end if - - ErrStat_c = ErrStat - ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR - ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) - + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) + INTEGER(C_INT), INTENT(IN ) :: n_timesteps ! Number of time steps to go back + INTEGER(C_INT), INTENT( OUT) :: ErrStat_c + CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + + CALL FAST_Reset_SubStep_T(t_initial, n_t_global-n_timesteps, n_timesteps, Turbine(iTurb), ErrStat, ErrMsg ) + + if (iTurb == NumTurbines ) then + n_t_global = n_t_global - n_timesteps + end if + + ErrStat_c = ErrStat + ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR + ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) end subroutine FAST_CFD_Reset_SubStep !================================================================================================================================== -subroutine FAST_CFD_Store_SubStep(iTurb, n_t_global, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Store_SubStep') +subroutine FAST_CFD_Store_SubStep(iTurb_c, n_t_global, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_CFD_Store_SubStep') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT - !DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Store_SubStep - !GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Store_SubStep +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Store_SubStep +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_CFD_Store_SubStep #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number - INTEGER(C_INT), INTENT(IN ) :: n_t_global !< loop counter - INTEGER(C_INT), INTENT( OUT) :: ErrStat_c - CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) - - CALL FAST_Store_SubStep_T(t_initial, n_t_global, Turbine(iTurb), ErrStat, ErrMsg ) - - ErrStat_c = ErrStat - ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR - ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) - + INTEGER(C_INT), INTENT(IN ) :: iTurb_c ! Turbine number, c indexing (starts at 0 for first turbine) + INTEGER(C_INT), INTENT(IN ) :: n_t_global !< loop counter + INTEGER(C_INT), INTENT( OUT) :: ErrStat_c + CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + integer(IntKi) :: iTurb ! turbine number: Fortran indexing (starts at 1 for first turbine) + + ! transfer turbine index number from C to Fortran indexing (0 to 1 start) + iTurb = int(iTurb_c,IntKi) + 1 + + CALL FAST_Store_SubStep_T(t_initial, n_t_global, Turbine(iTurb), ErrStat, ErrMsg ) + + ErrStat_c = ErrStat + ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR + ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) end subroutine FAST_CFD_Store_SubStep !================================================================================================================================== diff --git a/modules/openfast-library/src/FAST_Library.h b/modules/openfast-library/src/FAST_Library.h index 89fbd014d2..f6b9993ba3 100644 --- a/modules/openfast-library/src/FAST_Library.h +++ b/modules/openfast-library/src/FAST_Library.h @@ -20,7 +20,7 @@ EXTERNAL_ROUTINE void FAST_ExtInfw_Restart(int * iTurb, const char *CheckpointRo int * NumBl, int * NumBlElem, int * NumTwrElem, 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, char *OutFileRoot, +EXTERNAL_ROUTINE void FAST_ExtInfw_Init(int * iTurb, double *TMax, const char *InputFileName, int * TurbIDforName, char *OutFileRoot, int * NumSC2CtrlGlob, int * NumSC2Ctrl, int * NumCtrl2SC, float * initSCInputsGlob, float * initSCInputsTurbine, int * NumActForcePtsBlade, int * NumActForcePtsTower, float * TurbinePosition, int *AbortErrLev, double * dtDriver, double * dt, int * InflowType, int * NumBl, int * NumBlElem, int * NumTwrElem, int * NodeClusterType, diff --git a/modules/openfast-library/src/FAST_Lin.f90 b/modules/openfast-library/src/FAST_Lin.f90 index dfdc7c5dba..2eb01b9eda 100644 --- a/modules/openfast-library/src/FAST_Lin.f90 +++ b/modules/openfast-library/src/FAST_Lin.f90 @@ -3187,8 +3187,8 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}) from BD root-to-ED hub load transfer: ED_Start = Indx_u_ED_Hub_Start(u_ED, y_FAST) + u_ED%HubPtLoad%NNodes*3 ! start of u_ED%HubPtLoad%Moment field (skip forces) + ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) ! start of y_ED%HubMotion%TranslationDisp field DO k=1,p_FAST%nBeams - ED_Out_Start = Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, k) ! start of y_ED%BladeRootMotion(k)%TranslationDisp field call SumBlockMatrix( dUdy, MeshMapData%BD_P_2_ED_P(k)%dM%m_ud, ED_Start, ED_Out_Start) END DO @@ -3592,8 +3592,9 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa DO k=1,p_FAST%nBeams 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) - + BD_Out_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) & ! start of BD%y(k)%BldMotion%TranslationDisp field + + BD%y(k)%ReactionForce%NNodes * 6 ! 2 fields with 3 components + 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.) END DO diff --git a/modules/openfast-library/src/FAST_Registry.txt b/modules/openfast-library/src/FAST_Registry.txt index 183353d1ec..014a148710 100644 --- a/modules/openfast-library/src/FAST_Registry.txt +++ b/modules/openfast-library/src/FAST_Registry.txt @@ -831,7 +831,7 @@ typedef ^ FAST_InitData IceD_InitOutputType OutData_IceD - - typedef ^ FAST_ExternInitType DbKi Tmax - -1 - "External code specified Tmax" s typedef ^ FAST_ExternInitType IntKi SensorType - SensorType_None - "lidar sensor type, which should not be pulsed at the moment; this input should be replaced with a section in the InflowWind input file" - typedef ^ FAST_ExternInitType LOGICAL LidRadialVel - - - "TRUE => return radial component, FALSE => return 'x' direction estimate" - -typedef ^ FAST_ExternInitType IntKi TurbineID - 0 - "ID number for turbine (used to create output file naming convention)" - +typedef ^ FAST_ExternInitType IntKi TurbIDforName - -1 - "ID number for turbine (used to create output file naming convention)" - typedef ^ FAST_ExternInitType ReKi TurbinePos {3} - - "Initial position of turbine base (origin used for graphics or in FAST.Farm)" m typedef ^ FAST_ExternInitType IntKi WaveFieldMod - - - "Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin" - typedef ^ FAST_ExternInitType IntKi NumSC2CtrlGlob - - - "number of global controller inputs [from supercontroller]" - diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 7a43ea7cc7..8154f3c2f3 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -531,9 +531,6 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_A Node = Node + 1 u_IfW%PositionXYZ(:,Node) = u_AD14%Twr_InputMarkers%TranslationDisp(:,J) + u_AD14%Twr_InputMarkers%Position(:,J) END DO - - ELSEIF (p_FAST%CompAero == MODULE_AD) THEN - END IF @@ -551,55 +548,81 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_A END SUBROUTINE IfW_InputSolve !---------------------------------------------------------------------------------------------------------------------------------- -!---------------------------------------------------------------------------------------------------------------------------------- -!FIXME: ExtLoads does needs to use the new method for setting the values in the IfW pointers -SUBROUTINE AD_InputSolve_IfW_ExtLoads( p_FAST, u_AD, p_ExtLd, ErrStat, ErrMsg ) - - type(FAST_ParameterType), intent(in) :: p_FAST !< FAST parameter data - type(AD_InputType), intent(inout) :: u_AD !< The inputs to AeroDyn - type(ExtLd_ParameterType), intent(in) :: p_ExtLd !< Parameters of ExtLoads - integer(IntKi) :: ErrStat !< Error status of the operation - character(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - !local variables - real(ReKi) :: z !< Local 'z' coordinate - real(ReKi) :: mean_vel !< Local mean velocity - real(ReKi) :: pi !< Our favorite number - integer(IntKi) :: j,k !< Local counter variables - integer(IntKi) :: NumBl !< Number of blades - integer(IntKi) :: Nnodes !< Number of nodes - - ErrStat = ErrID_None - ErrMsg = '' - -! pi = acos(-1.0) -! NumBl = size(u_AD%rotors(1)%InflowOnBlade,3) -! Nnodes = size(u_AD%rotors(1)%InflowOnBlade,2) -! -! do k=1,NumBl -! do j=1,Nnodes -! !Get position first -! z = u_AD%rotors(1)%BladeMotion(k)%Position(3,j) + u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) -! mean_vel = p_ExtLd%vel_mean * ( (z/p_ExtLd%z_ref) ** p_ExtLd%shear_exp) -! u_AD%rotors(1)%InflowOnBlade(1,j,k) = -mean_vel * sin(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnBlade(2,j,k) = -mean_vel * cos(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnBlade(3,j,k) = 0.0 -! end do -! end do -! -! if ( allocated(u_AD%rotors(1)%InflowOnTower) ) then -! Nnodes = size(u_AD%rotors(1)%InflowOnTower,2) -! do j=1,Nnodes -! !Get position first -! z = u_AD%rotors(1)%TowerMotion%Position(3,j) + u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) -! mean_vel = p_ExtLd%vel_mean * ( (z/p_ExtLd%z_ref) ** p_ExtLd%shear_exp) -! u_AD%rotors(1)%InflowOnTower(1,j) = -mean_vel * sin(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnTower(2,j) = -mean_vel * cos(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnTower(3,j) = 0.0 -! end do -! end if +SUBROUTINE ExtLd_UpdateFlowField( p_FAST, u_AD, ExtLd, ErrStat, ErrMsg ) + type(FAST_ParameterType), intent(in) :: p_FAST !< FAST parameter data + type(AD_InputType), intent(in ) :: u_AD !< The inputs to AeroDyn + type(ExtLoads_Data), intent(in ) :: ExtLd !< ExtLoads data + integer(IntKi) :: ErrStat !< Error status of the operation + character(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + !local variables + real(ReKi) :: z !< Local 'z' coordinate + real(ReKi) :: pi !< Our favorite number + integer(IntKi) :: j,k !< Local counter variables + integer(IntKi) :: NumBl !< Number of blades + integer(IntKi) :: iPt !< Point in the flow field array. Make sure this order corresponds to what AD15 uses!!!!!! + -END SUBROUTINE AD_InputSolve_IfW_ExtLoads + ErrStat = ErrID_None + ErrMsg = '' + + NumBl = size(u_AD%rotors(1)%BladeMotion) + + iPt=1 + + ! Hub + if (u_AD%rotors(1)%HubMotion%committed) then + ! height + z = u_AD%rotors(1)%HubMotion%Position(3,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + + ! Blades + do k=1,NumBl + do j=1,u_AD%rotors(1)%BladeMotion(k)%nNodes + ! height + z = u_AD%rotors(1)%BladeMotion(k)%Position(3,j) + u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + call SetWind(iPt,z); iPt = iPt + 1 + end do + end do + + ! Tower + if ( allocated(u_AD%rotors(1)%InflowOnTower) ) then + do j=1,u_AD%rotors(1)%TowerMotion%nNodes + ! height + z = u_AD%rotors(1)%TowerMotion%Position(3,j) + u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) + call SetWind(iPt,z); iPt = iPt + 1 + end do + end if + + ! Nacelle + if (u_AD%rotors(1)%NacelleMotion%committed) then + ! height + z = u_AD%rotors(1)%NacelleMotion%Position(3,1) + u_AD%rotors(1)%NacelleMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + + ! Tailfin + if (u_AD%rotors(1)%TFinMotion%committed) then + ! height + z = u_AD%rotors(1)%TFinMotion%Position(3,1) + u_AD%rotors(1)%TFinMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + +contains + function mean_vel(z_h) + real(ReKi) :: z_h !< height + real(ReKi) :: mean_vel !< mean velocity at height z_h + mean_vel = ExtLd%p%vel_mean * ( (z_h/ExtLd%p%z_ref) ** ExtLd%p%shear_exp) + end function + subroutine SetWind(i,z_h) + integer(IntKi) :: i ! point num + real(ReKi) :: z_h !< height + ExtLd%m%FlowField%Points%Vel(iPt,1) = -mean_vel(z_h) * sin(ExtLd%p%wind_dir * pi / 180.0) + ExtLd%m%FlowField%Points%Vel(iPt,2) = -mean_vel(z_h) * cos(ExtLd%p%wind_dir * pi / 180.0) + ExtLd%m%FlowField%Points%Vel(iPt,3) = 0.0 + end subroutine +END SUBROUTINE ExtLd_UpdateFlowField @@ -5143,7 +5166,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca CALL AD_InputSolve_NoIfW( p_FAST, AD%Input(1), SrvD%y, ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - CALL AD_InputSolve_IfW_ExtLoads( p_FAST, AD%Input(1), ExtLd%p, ErrStat2, ErrMsg2 ) + CALL ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL ExtLd_InputSolve_NoIfW( p_FAST, ExtLd%u, ExtLd%p, ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) @@ -5518,7 +5541,7 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data - TYPE(ExtLoads_Data), INTENT(INOUT) :: ExtLD !< ExtLoads data + TYPE(ExtLoads_Data), INTENT(INOUT) :: ExtLd !< ExtLoads data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5569,6 +5592,12 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, CALL AD14_InputSolve_IfW( p_FAST, AD14%Input(1), IfW%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ELSE IF (p_FAST%CompAero == Module_ExtLd ) THEN + + ! The outputs from ExternalInflow need to be transfered to the FlowField for use by AeroDyn, this seems like the right place + call ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END IF @@ -5655,7 +5684,7 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, CALL SetErrStat(ErrID_Fatal,'p_FAST%CompInflow option not setup to work with ExtLoads module.',ErrStat,ErrMsg,RoutineName) ENDIF - CALL AD_InputSolve_IfW_ExtLoads( p_FAST, AD%Input(1), ExtLd%p, ErrStat2, ErrMsg2 ) + CALL ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL AD_CalcOutput( this_time, AD%Input(1), AD%p, AD%x(this_state), AD%xd(this_state), AD%z(this_state), & diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 2248343b26..d664cadaac 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -122,7 +122,6 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, 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 ExtInfw coupling logical :: CallStart REAL(R8Ki) :: theta(3) ! angles for hub orientation matrix for aeromaps @@ -167,8 +166,8 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, y_FAST%Lin%WindSpeed = 0.0_ReKi if (present(ExternInitData)) then - CallStart = .not. ExternInitData%FarmIntegration ! .and. ExternInitData%TurbineID == 1 - if (ExternInitData%TurbineID > 0) p_FAST%TDesc = 'T'//trim(num2lstr(ExternInitData%TurbineID)) + CallStart = .not. ExternInitData%FarmIntegration + if (ExternInitData%TurbIDforName >= 0) p_FAST%TDesc = 'T'//trim(num2lstr(ExternInitData%TurbIDforName)) else CallStart = .true. end if @@ -211,7 +210,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, if (ExternInitData%FarmIntegration) then ! we're integrating with FAST.Farm CALL FAST_Init( p_FAST, m_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, OverrideAbortLev=.false., RootName=ExternInitData%RootName ) else - CALL FAST_Init( p_FAST, m_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, ExternInitData%TurbineID, DTdriver=ExternInitData%DTdriver ) ! We have the name of the input file and the simulation length from somewhere else (e.g. Simulink) + CALL FAST_Init( p_FAST, m_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, ExternInitData%TurbIDforName, DTdriver=ExternInitData%DTdriver ) ! We have the name of the input file and the simulation length from somewhere else (e.g. Simulink) end if else @@ -613,6 +612,9 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AirDens = Init%OutData_ExtLd%AirDens + ! Set pointer to flowfield + IF (p_FAST%CompAero == Module_AD) AD%p%FlowField => Init%OutData_ExtLd%FlowField + END IF END IF @@ -654,13 +656,6 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, IF ( p_FAST%CompAero == Module_AD14 ) THEN Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints + NumBl * AD14%Input(1)%InputMarkers(1)%NNodes + AD14%Input(1)%Twr_InputMarkers%NNodes - ELSEIF ( p_FAST%CompAero == Module_AD ) THEN - ! Number of Wind points from AeroDyn, see AeroDyn.f90 - Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints - ! Wake -- we allow the wake positions to exceed the wind box - if (allocated(AD%OtherSt(STATE_CURR)%WakeLocationPoints)) then - Init%InData_IfW%BoxExceedAllow = .true. - endif END IF ! lidar @@ -883,7 +878,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, if (allocated(Init%OutData_SeaSt%WaveElevVisGrid)) then p_FAST%VTK_surface%NWaveElevPts(1) = size(Init%OutData_SeaSt%WaveElevVisX) - p_FAST%VTK_surface%NWaveElevPts(2) = size(Init%OutData_SeaSt%WaveElevVisX) + p_FAST%VTK_surface%NWaveElevPts(2) = size(Init%OutData_SeaSt%WaveElevVisY) else p_FAST%VTK_surface%NWaveElevPts(1) = 0 p_FAST%VTK_surface%NWaveElevPts(2) = 0 @@ -1630,7 +1625,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! Initialize data for VTK output ! ------------------------------------------------------------------------- if ( p_FAST%WrVTK > VTK_None ) then - call SetVTKParameters(p_FAST, Init%OutData_ED, Init%OutData_AD, Init%InData_SeaSt, Init%OutData_SeaSt, Init%OutData_HD, ED, BD, AD, HD, ErrStat2, ErrMsg2) + call SetVTKParameters(p_FAST, Init%OutData_ED, Init%OutData_AD, Init%OutData_SeaSt, Init%OutData_HD, ED, BD, AD, HD, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if @@ -3942,12 +3937,11 @@ end subroutine cleanup END SUBROUTINE FAST_ReadSteadyStateFile !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets up the information needed for plotting VTK surfaces. -SUBROUTINE SetVTKParameters(p_FAST, InitOutData_ED, InitOutData_AD, InitInData_SeaSt, InitOutData_SeaSt, InitOutData_HD, ED, BD, AD, HD, ErrStat, ErrMsg) +SUBROUTINE SetVTKParameters(p_FAST, InitOutData_ED, InitOutData_AD, InitOutData_SeaSt, InitOutData_HD, ED, BD, AD, HD, ErrStat, ErrMsg) TYPE(FAST_ParameterType), INTENT(INOUT) :: p_FAST !< The parameters of the glue code TYPE(ED_InitOutputType), INTENT(IN ) :: InitOutData_ED !< The initialization output from structural dynamics module TYPE(AD_InitOutputType), INTENT(INOUT) :: InitOutData_AD !< The initialization output from AeroDyn - TYPE(SeaSt_InitInputType), INTENT(INOUT) :: InitInData_SeaSt !< The initialization input to SeaState TYPE(SeaSt_InitOutputType), INTENT(INOUT) :: InitOutData_SeaSt !< The initialization output from SeaState TYPE(HydroDyn_InitOutputType),INTENT(INOUT) :: InitOutData_HD !< The initialization output from HydroDyn TYPE(ElastoDyn_Data), TARGET, INTENT(IN ) :: ED !< ElastoDyn data @@ -4157,7 +4151,6 @@ SUBROUTINE SetVTKParameters(p_FAST, InitOutData_ED, InitOutData_AD, InitInData_S !bjj: interpolate here instead of each time step? if ( allocated(InitOutData_SeaSt%WaveElevVisGrid) ) then -print*,'Storing Wave surface visualization' call move_alloc( InitOutData_SeaSt%WaveElevVisX, p_FAST%VTK_Surface%WaveElevVisX ) call move_alloc( InitOutData_SeaSt%WaveElevVisY, p_FAST%VTK_Surface%WaveElevVisY ) call move_alloc( InitOutData_SeaSt%WaveElevVisGrid,p_FAST%VTK_Surface%WaveElevVisGrid ) @@ -4525,7 +4518,7 @@ SUBROUTINE ExtLd_SetInitInput(InitInData_ExtLd, InitOutData_ED, y_ED, InitOutDat do k=1,InitInData_ExtLd%NumBlades InitInData_ExtLd%BldRloc(1,k) = 0.0 do j = 2, InitInData_ExtLd%NumBldNodes(k) - InitInData_ExtLd%BldRloc(j,k) = InitInData_ExtLd%BldRloc(j-1,k) + norm2(InitInData_ExtLd%BldPos(:,j,k) - InitInData_ExtLd%BldPos(:,j-1,k)) + InitInData_ExtLd%BldRloc(j,k) = InitInData_ExtLd%BldRloc(j-1,k) + TwoNorm(InitInData_ExtLd%BldPos(:,j,k) - InitInData_ExtLd%BldPos(:,j-1,k)) end do end do @@ -4587,7 +4580,7 @@ SUBROUTINE ExtLd_SetInitInput(InitInData_ExtLd, InitOutData_ED, y_ED, InitOutDat InitInData_ExtLd%TwrHloc(1) = 0.0 do j = 2, InitInData_ExtLd%NumTwrNds - InitInData_ExtLd%TwrHloc(j) = InitInData_ExtLd%TwrHloc(j-1) + norm2(InitInData_ExtLd%TwrPos(:,j) - InitInData_ExtLd%TwrPos(:,j-1)) + InitInData_ExtLd%TwrHloc(j) = InitInData_ExtLd%TwrHloc(j-1) + TwoNorm(InitInData_ExtLd%TwrPos(:,j) - InitInData_ExtLd%TwrPos(:,j-1)) end do END IF @@ -4665,6 +4658,10 @@ SUBROUTINE ExtLd_SetInitInput(InitInData_ExtLd, InitOutData_ED, y_ED, InitOutDat deallocate(AD_etaNodes) end if + ! Total number of nodes velocity is needed at + InitInData_ExtLd%nNodesVel = InitOutData_AD%nNodesVel + + RETURN END SUBROUTINE ExtLd_SetInitInput @@ -6205,9 +6202,6 @@ SUBROUTINE FAST_Reset_SubStep(t_initial, n_t_global, n_timesteps, p_FAST, y_FAST CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - INTEGER(IntKi) :: j_pc ! predictor-corrector loop counter - INTEGER(IntKi) :: NumCorrections ! number of corrections for this time step - INTEGER(IntKi) :: i, j, k ! generic loop counters REAL(DbKi) :: t_global ! the time to which states, inputs and outputs are reset INTEGER(IntKi) :: old_avrSwap1 ! previous value of avrSwap(1) !hack for Bladed DLL checkpoint/restore @@ -6793,9 +6787,6 @@ SUBROUTINE FAST_Store_SubStep(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - INTEGER(IntKi) :: j_pc ! predictor-corrector loop counter - INTEGER(IntKi) :: NumCorrections ! number of corrections for this time step - INTEGER(IntKi) :: i, j, k ! generic loop counters REAL(DbKi) :: t_global ! the time to which states, inputs and outputs are reset INTEGER(IntKi) :: old_avrSwap1 ! previous value of avrSwap(1) !hack for Bladed DLL checkpoint/restore @@ -7372,30 +7363,16 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - REAL(DbKi) :: t_global_next ! next simulation time (m_FAST%t_global + p_FAST%dt) INTEGER(IntKi) :: n_t_global_next ! n_t_global + 1 - INTEGER(IntKi) :: j_pc ! predictor-corrector loop counter - INTEGER(IntKi) :: NumCorrections ! number of corrections for this time step - INTEGER(IntKi), parameter :: MaxCorrections = 20 ! maximum number of corrections allowed - LOGICAL :: WriteThisStep ! Whether WriteOutput values will be printed - - INTEGER(IntKi) :: I, k ! generic loop counters - - !REAL(ReKi) :: ControlInputGuess ! value of controller inputs - INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Solution' - 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 - - y_FAST%WriteThisStep = NeedWriteOutput(n_t_global_next, t_global_next, p_FAST) !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !! ## Step 1.a: set some variables and Extrapolate Inputs @@ -7487,12 +7464,8 @@ SUBROUTINE FAST_Prework(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, S CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables + INTEGER(IntKi) :: n_t_global_next ! n_t_global + 1 REAL(DbKi) :: t_global_next ! next simulation time (m_FAST%t_global + p_FAST%dt) - INTEGER(IntKi) :: j_pc ! predictor-corrector loop counter - INTEGER(IntKi) :: NumCorrections ! number of corrections for this time step - - INTEGER(IntKi) :: I, k ! generic loop counters - INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -7502,7 +7475,11 @@ SUBROUTINE FAST_Prework(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, S ErrStat = ErrID_None ErrMsg = "" - t_global_next = t_initial + (n_t_global+1)*p_FAST%DT ! = m_FAST%t_global + p_FAST%dt + 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 + + ! set flag for writing output at time t_global_next + y_FAST%WriteThisStep = NeedWriteOutput(n_t_global_next, t_global_next, p_FAST) !! determine if the Jacobian should be calculated this time IF ( m_FAST%calcJacobian ) THEN ! this was true (possibly at initialization), so we'll advance the time for the next calculation of the Jacobian @@ -7598,8 +7575,7 @@ SUBROUTINE FAST_UpdateStates(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, INTEGER(IntKi), parameter :: MaxCorrections = 20 ! maximum number of corrections allowed LOGICAL :: WriteThisStep ! Whether WriteOutput values will be printed - INTEGER(IntKi) :: I, k ! generic loop counters - + !REAL(ReKi) :: ControlInputGuess ! value of controller inputs INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -7746,12 +7722,8 @@ SUBROUTINE FAST_AdvanceToNextTimeStep(t_initial, n_t_global, p_FAST, y_FAST, m_F ! local variables REAL(DbKi) :: t_global_next ! next simulation time (m_FAST%t_global + p_FAST%dt) - INTEGER(IntKi) :: j_pc ! predictor-corrector loop counter - INTEGER(IntKi) :: NumCorrections ! number of corrections for this time step - INTEGER(IntKi) :: I, k ! generic loop counters - INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'FAST_AdvanceToNextTimeStep' @@ -8007,7 +7979,6 @@ SUBROUTINE FAST_WriteOutput(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, B CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - INTEGER(IntKi) :: I, k ! generic loop counters REAL(DbKi) :: t_global ! this simulation time (m_FAST%t_global + p_FAST%dt) INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 diff --git a/modules/openfast-library/src/FAST_Types.f90 b/modules/openfast-library/src/FAST_Types.f90 index b04269cff9..fa01557597 100644 --- a/modules/openfast-library/src/FAST_Types.f90 +++ b/modules/openfast-library/src/FAST_Types.f90 @@ -846,7 +846,7 @@ MODULE FAST_Types REAL(DbKi) :: Tmax = -1 !< External code specified Tmax [s] INTEGER(IntKi) :: SensorType = SensorType_None !< lidar sensor type, which should not be pulsed at the moment; this input should be replaced with a section in the InflowWind input file [-] LOGICAL :: LidRadialVel = .false. !< TRUE => return radial component, FALSE => return 'x' direction estimate [-] - INTEGER(IntKi) :: TurbineID = 0 !< ID number for turbine (used to create output file naming convention) [-] + INTEGER(IntKi) :: TurbIDforName = -1 !< ID number for turbine (used to create output file naming convention) [-] REAL(ReKi) , DIMENSION(1:3) :: TurbinePos = 0.0_ReKi !< Initial position of turbine base (origin used for graphics or in FAST.Farm) [m] INTEGER(IntKi) :: WaveFieldMod = 0_IntKi !< Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin [-] INTEGER(IntKi) :: NumSC2CtrlGlob = 0_IntKi !< number of global controller inputs [from supercontroller] [-] @@ -14454,7 +14454,7 @@ subroutine FAST_CopyExternInitType(SrcExternInitTypeData, DstExternInitTypeData, DstExternInitTypeData%Tmax = SrcExternInitTypeData%Tmax DstExternInitTypeData%SensorType = SrcExternInitTypeData%SensorType DstExternInitTypeData%LidRadialVel = SrcExternInitTypeData%LidRadialVel - DstExternInitTypeData%TurbineID = SrcExternInitTypeData%TurbineID + DstExternInitTypeData%TurbIDforName = SrcExternInitTypeData%TurbIDforName DstExternInitTypeData%TurbinePos = SrcExternInitTypeData%TurbinePos DstExternInitTypeData%WaveFieldMod = SrcExternInitTypeData%WaveFieldMod DstExternInitTypeData%NumSC2CtrlGlob = SrcExternInitTypeData%NumSC2CtrlGlob @@ -14528,7 +14528,7 @@ subroutine FAST_PackExternInitType(RF, Indata) call RegPack(RF, InData%Tmax) call RegPack(RF, InData%SensorType) call RegPack(RF, InData%LidRadialVel) - call RegPack(RF, InData%TurbineID) + call RegPack(RF, InData%TurbIDforName) call RegPack(RF, InData%TurbinePos) call RegPack(RF, InData%WaveFieldMod) call RegPack(RF, InData%NumSC2CtrlGlob) @@ -14569,7 +14569,7 @@ subroutine FAST_UnPackExternInitType(RF, OutData) call RegUnpack(RF, OutData%Tmax); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%SensorType); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%LidRadialVel); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%TurbineID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TurbIDforName); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TurbinePos); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%WaveFieldMod); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NumSC2CtrlGlob); if (RegCheckErr(RF, RoutineName)) return diff --git a/modules/seastate/CMakeLists.txt b/modules/seastate/CMakeLists.txt index d30787e698..f0860e89ef 100644 --- a/modules/seastate/CMakeLists.txt +++ b/modules/seastate/CMakeLists.txt @@ -18,7 +18,6 @@ if (GENERATE_TYPES) generate_f90_types(src/Current.txt ${CMAKE_CURRENT_LIST_DIR}/src/Current_Types.f90 -noextrap) generate_f90_types(src/Waves.txt ${CMAKE_CURRENT_LIST_DIR}/src/Waves_Types.f90 -noextrap) generate_f90_types(src/Waves2.txt ${CMAKE_CURRENT_LIST_DIR}/src/Waves2_Types.f90 -noextrap) - generate_f90_types(src/SeaState_Interp.txt ${CMAKE_CURRENT_LIST_DIR}/src/SeaState_Interp_Types.f90 -noextrap) generate_f90_types(src/SeaSt_WaveField.txt ${CMAKE_CURRENT_LIST_DIR}/src/SeaSt_WaveField_Types.f90 -noextrap) generate_f90_types(src/SeaState.txt ${CMAKE_CURRENT_LIST_DIR}/src/SeaState_Types.f90 -noextrap) endif() @@ -28,7 +27,6 @@ add_library(seastlib STATIC src/Waves.f90 src/Waves2.f90 src/UserWaves.f90 - src/SeaState_Interp.f90 src/SeaSt_WaveField.f90 src/SeaState_Input.f90 src/SeaState.f90 @@ -36,7 +34,6 @@ add_library(seastlib STATIC src/Current_Types.f90 src/Waves_Types.f90 src/Waves2_Types.f90 - src/SeaState_Interp_Types.f90 src/SeaSt_WaveField_Types.f90 src/SeaState_Types.f90 ) diff --git a/modules/seastate/src/SeaSt_WaveField.f90 b/modules/seastate/src/SeaSt_WaveField.f90 index c8ffabbc84..a117d3db79 100644 --- a/modules/seastate/src/SeaSt_WaveField.f90 +++ b/modules/seastate/src/SeaSt_WaveField.f90 @@ -1,10 +1,9 @@ MODULE SeaSt_WaveField -USE SeaState_Interp USE SeaSt_WaveField_Types IMPLICIT NONE - + PRIVATE ! Public functions and subroutines @@ -17,150 +16,162 @@ MODULE SeaSt_WaveField PUBLIC WaveField_GetWaveKin +public WaveField_Interp_Setup3D, WaveField_Interp_Setup4D + CONTAINS !-------------------- Subroutine for wave elevation ------------------! -FUNCTION WaveField_GetNodeWaveElev1( WaveField, SeaSt_Interp_m, Time, pos, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - - REAL(SiKi) :: WaveField_GetNodeWaveElev1 - REAL(SiKi) :: Zeta - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeWaveElev1' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 - +function WaveField_GetNodeWaveElev1( WaveField, WaveField_m, Time, pos, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(SiKi) :: WaveField_GetNodeWaveElev1 + real(SiKi) :: Zeta + character(*), parameter :: RoutineName = 'WaveField_GetNodeWaveElev1' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 + ErrStat = ErrID_None ErrMsg = "" - + IF (ALLOCATED(WaveField%WaveElev1)) THEN - Zeta = SeaSt_Interp_3D( Time, pos(1:2), WaveField%WaveElev1, WaveField%seast_interp_p, seast_interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL WaveField_Interp_Setup3D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Zeta = WaveField_Interp_3D( WaveField%WaveElev1, WaveField_m ) ELSE Zeta = 0.0_SiKi END IF - + WaveField_GetNodeWaveElev1 = Zeta -END FUNCTION WaveField_GetNodeWaveElev1 - -FUNCTION WaveField_GetNodeWaveElev2( WaveField, SeaSt_Interp_m, Time, pos, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - - REAL(SiKi) :: WaveField_GetNodeWaveElev2 - REAL(SiKi) :: Zeta - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeWaveElev2' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 - +end function WaveField_GetNodeWaveElev1 + + +function WaveField_GetNodeWaveElev2( WaveField, WaveField_m, Time, pos, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(SiKi) :: WaveField_GetNodeWaveElev2 + real(SiKi) :: Zeta + character(*), parameter :: RoutineName = 'WaveField_GetNodeWaveElev2' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 + ErrStat = ErrID_None ErrMsg = "" - + IF (ALLOCATED(WaveField%WaveElev2)) THEN - Zeta = SeaSt_Interp_3D( Time, pos(1:2), WaveField%WaveElev2, WaveField%seast_interp_p, seast_interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL WaveField_Interp_Setup3D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Zeta = WaveField_Interp_3D( WaveField%WaveElev2, WaveField_m ) ELSE Zeta = 0.0_SiKi END IF WaveField_GetNodeWaveElev2 = Zeta -END FUNCTION WaveField_GetNodeWaveElev2 +end function WaveField_GetNodeWaveElev2 -FUNCTION WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, pos, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - REAL(SiKi) :: WaveField_GetNodeTotalWaveElev - REAL(SiKi) :: Zeta1, Zeta2 - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeTotalWaveElev' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 +FUNCTION WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, pos, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(*) ! Position at which free-surface elevation is to be calculated. Third entry ignored if present. + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(SiKi) :: WaveField_GetNodeTotalWaveElev + real(SiKi) :: Zeta1, Zeta2 + character(*), parameter :: RoutineName = 'WaveField_GetNodeTotalWaveElev' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 ErrStat = ErrID_None ErrMsg = "" - - Zeta1 = WaveField_GetNodeWaveElev1( WaveField, SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - Zeta2 = WaveField_GetNodeWaveElev2( WaveField, SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Zeta1 = WaveField_GetNodeWaveElev1( WaveField, WaveField_m, Time, pos, ErrStat2, ErrMsg2 ); if (Failed()) return; + Zeta2 = WaveField_GetNodeWaveElev2( WaveField, WaveField_m, Time, pos, ErrStat2, ErrMsg2 ); if (Failed()) return; WaveField_GetNodeTotalWaveElev = Zeta1 + Zeta2 - + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function END FUNCTION WaveField_GetNodeTotalWaveElev -SUBROUTINE WaveField_GetNodeWaveNormal( WaveField, SeaSt_Interp_m, Time, pos, r, n, ErrStat, ErrMsg ) - - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(*) ! Position at which free-surface normal is to be calculated. Third entry ignored if present. - REAL(ReKi), INTENT( IN ) :: r ! Distance for central differencing - REAL(ReKi), INTENT( OUT ) :: n(3) ! Free-surface normal vector - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - REAL(SiKi) :: ZetaP,ZetaM - REAL(ReKi) :: r1,dZetadx,dZetady - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeWaveNormal' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 + +SUBROUTINE WaveField_GetNodeWaveNormal( WaveField, WaveField_m, Time, pos, r, n, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(*) ! Position at which free-surface normal is to be calculated. Third entry ignored if present. + real(ReKi), intent(in ) :: r ! Distance for central differencing + real(ReKi), intent( out) :: n(3) ! Free-surface normal vector + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(SiKi) :: ZetaP,ZetaM + real(ReKi) :: r1,dZetadx,dZetady + character(*), parameter :: RoutineName = 'WaveField_GetNodeWaveNormal' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 + ErrStat = ErrID_None ErrMsg = "" r1 = MAX(r,real(1.0e-6,ReKi)) ! In case r is zero - ZetaP = WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, (/pos(1)+r1,pos(2)/), ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ZetaM = WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, (/pos(1)-r1,pos(2)/), ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ZetaP = WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, (/pos(1)+r1,pos(2)/), ErrStat2, ErrMsg2 ); if (Failed()) return; + ZetaM = WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, (/pos(1)-r1,pos(2)/), ErrStat2, ErrMsg2 ); if (Failed()) return; dZetadx = REAL(ZetaP-ZetaM,ReKi)/(2.0_ReKi*r1) - - ZetaP = WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, (/pos(1),pos(2)+r1/), ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ZetaM = WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, (/pos(1),pos(2)-r1/), ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ZetaP = WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, (/pos(1),pos(2)+r1/), ErrStat2, ErrMsg2 ); if (Failed()) return; + ZetaM = WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, (/pos(1),pos(2)-r1/), ErrStat2, ErrMsg2 ); if (Failed()) return; dZetady = REAL(ZetaP-ZetaM,ReKi)/(2.0_ReKi*r1) - + n = (/-dZetadx,-dZetady,1.0_ReKi/) n = n / SQRT(Dot_Product(n,n)) +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function END SUBROUTINE WaveField_GetNodeWaveNormal + !-------------------- Subroutine for full wave field kinematics --------------------! -SUBROUTINE WaveField_GetNodeWaveKin( WaveField, SeaSt_Interp_m, Time, pos, forceNodeInWater, nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT( INOUT ) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(3) - LOGICAL, INTENT( IN ) :: forceNodeInWater - REAL(SiKi), INTENT( OUT ) :: WaveElev1 - REAL(SiKi), INTENT( OUT ) :: WaveElev2 - REAL(SiKi), INTENT( OUT ) :: WaveElev - REAL(SiKi), INTENT( OUT ) :: FV(3) - REAL(SiKi), INTENT( OUT ) :: FA(3) - REAL(SiKi), INTENT( OUT ) :: FAMCF(3) - REAL(SiKi), INTENT( OUT ) :: FDynP - INTEGER(IntKi), INTENT( OUT ) :: nodeInWater - - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - - REAL(ReKi) :: posXY(2), posPrime(3), posXY0(3) - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeWaveKin' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 +SUBROUTINE WaveField_GetNodeWaveKin( WaveField, WaveField_m, Time, pos, forceNodeInWater, nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(3) + logical, intent(in ) :: forceNodeInWater + real(SiKi), intent( out) :: WaveElev1 + real(SiKi), intent( out) :: WaveElev2 + real(SiKi), intent( out) :: WaveElev + real(SiKi), intent( out) :: FV(3) + real(SiKi), intent( out) :: FA(3) + real(SiKi), intent( out) :: FAMCF(3) + real(SiKi), intent( out) :: FDynP + integer(IntKi), intent( out) :: nodeInWater + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(ReKi) :: posXY(2), posPrime(3), posXY0(3) + character(*), parameter :: RoutineName = 'WaveField_GetNodeWaveKin' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 ErrStat = ErrID_None ErrMsg = "" @@ -170,28 +181,21 @@ SUBROUTINE WaveField_GetNodeWaveKin( WaveField, SeaSt_Interp_m, Time, pos, force FAMCF(:) = 0.0 ! Wave elevation - WaveElev1 = WaveField_GetNodeWaveElev1( WaveField, SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - WaveElev2 = WaveField_GetNodeWaveElev2( WaveField, SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + WaveElev1 = WaveField_GetNodeWaveElev1( WaveField, WaveField_m, Time, pos, ErrStat2, ErrMsg2 ); if (Failed()) return; + WaveElev2 = WaveField_GetNodeWaveElev2( WaveField, WaveField_m, Time, pos, ErrStat2, ErrMsg2 ); if (Failed()) return; WaveElev = WaveElev1 + WaveElev2 - + IF (WaveField%WaveStMod == 0) THEN ! No wave stretching - + IF ( pos(3) <= 0.0_ReKi) THEN ! Node is at or below the SWL nodeInWater = 1_IntKi - ! Use location to obtain interpolated values of kinematics - CALL SeaSt_Interp_Setup( Time, pos, WaveField%seast_interp_p, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FA(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAcc, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FDynP = SeaSt_Interp_4D ( WaveField%WaveDynP, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ! Use location to obtain interpolated values of kinematics + CALL WaveField_Interp_Setup4D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) + FA(:) = WaveField_Interp_4D_Vec( WaveField%WaveAcc, WaveField_m ) + FDynP = WaveField_Interp_4D ( WaveField%WaveDynP, WaveField_m ) IF ( ALLOCATED(WaveField%WaveAccMCF) ) THEN - FAMCF(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAccMCF, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + FAMCF(:) = WaveField_Interp_4D_Vec( WaveField%WaveAccMCF, WaveField_m ) END IF ELSE ! Node is above the SWL nodeInWater = 0_IntKi @@ -200,116 +204,104 @@ SUBROUTINE WaveField_GetNodeWaveKin( WaveField, SeaSt_Interp_m, Time, pos, force FDynP = 0.0 FAMCF(:) = 0.0 END IF - + ELSE ! Wave stretching enabled - + IF ( (pos(3) <= WaveElev) .OR. forceNodeInWater ) THEN ! Node is submerged - + nodeInWater = 1_IntKi - + IF ( WaveField%WaveStMod < 3 ) THEN ! Vertical or extrapolated wave stretching - + IF ( pos(3) <= 0.0_SiKi) THEN ! Node is below the SWL - evaluate wave dynamics as usual - - ! Use location to obtain interpolated values of kinematics - CALL SeaSt_Interp_Setup( Time, pos, WaveField%seast_interp_p, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FA(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAcc, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FDynP = SeaSt_Interp_4D ( WaveField%WaveDynP, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! Use location to obtain interpolated values of kinematics + CALL WaveField_Interp_Setup4D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) + FA(:) = WaveField_Interp_4D_Vec( WaveField%WaveAcc, WaveField_m ) + FDynP = WaveField_Interp_4D ( WaveField%WaveDynP, WaveField_m ) IF ( ALLOCATED(WaveField%WaveAccMCF) ) THEN - FAMCF(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAccMCF, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + FAMCF(:) = WaveField_Interp_4D_Vec( WaveField%WaveAccMCF, WaveField_m ) END IF ELSE ! Node is above SWL - need wave stretching - + ! Vertical wave stretching - CALL SeaSt_Interp_Setup( Time, posXY0, WaveField%seast_interp_p, SeaSt_Interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FA(:) = SeaSt_Interp_4D_vec( WaveField%WaveAcc, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FDynP = SeaSt_Interp_4D ( WaveField%WaveDynP, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL WaveField_Interp_Setup4D( Time, posXY0, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_vec( WaveField%WaveVel, WaveField_m ) + FA(:) = WaveField_Interp_4D_vec( WaveField%WaveAcc, WaveField_m ) + FDynP = WaveField_Interp_4D ( WaveField%WaveDynP, WaveField_m ) IF ( ALLOCATED(WaveField%WaveAccMCF) ) THEN - FAMCF(:) = SeaSt_Interp_4D_vec( WaveField%WaveAccMCF, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + FAMCF(:) = WaveField_Interp_4D_vec( WaveField%WaveAccMCF, WaveField_m ) END IF - + ! Extrapoled wave stretching - IF (WaveField%WaveStMod == 2) THEN - FV(:) = FV(:) + SeaSt_Interp_3D_vec( Time, posXY, WaveField%PWaveVel0, WaveField%seast_interp_p, SeaSt_Interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) * pos(3) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FA(:) = FA(:) + SeaSt_Interp_3D_vec( Time, posXY, WaveField%PWaveAcc0, WaveField%seast_interp_p, SeaSt_Interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) * pos(3) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FDynP = FDynP + SeaSt_Interp_3D ( Time, posXY, WaveField%PWaveDynP0, WaveField%seast_interp_p, SeaSt_Interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) * pos(3) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (WaveField%WaveStMod == 2) THEN + CALL WaveField_Interp_Setup3D( Time, posXY, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = FV(:) + WaveField_Interp_3D_vec( WaveField%PWaveVel0, WaveField_m ) * pos(3) + FA(:) = FA(:) + WaveField_Interp_3D_vec( WaveField%PWaveAcc0, WaveField_m ) * pos(3) + FDynP = FDynP + WaveField_Interp_3D ( WaveField%PWaveDynP0, WaveField_m ) * pos(3) IF ( ALLOCATED(WaveField%WaveAccMCF) ) THEN - FAMCF(:) = FAMCF(:) + SeaSt_Interp_3D_vec( Time, posXY, WaveField%PWaveAccMCF0, WaveField%seast_interp_p, SeaSt_Interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) * pos(3) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + FAMCF(:) = FAMCF(:) + WaveField_Interp_3D_vec( WaveField%PWaveAccMCF0, WaveField_m ) * pos(3) END IF END IF - + END IF ! Node is submerged - + ELSE ! Wheeler stretching - no need to check whether the node is above or below SWL - - ! Map the node z-position linearly from [-EffWtrDpth,m%WaveElev(j)] to [-EffWtrDpth,0] + + ! Map the node z-position linearly from [-EffWtrDpth,m%WaveElev(j)] to [-EffWtrDpth,0] posPrime = pos posPrime(3) = WaveField%EffWtrDpth*(WaveField%EffWtrDpth+pos(3))/(WaveField%EffWtrDpth+WaveElev)-WaveField%EffWtrDpth - posPrime(3) = MIN( posPrime(3), 0.0_ReKi) ! Clamp z-position to zero. Needed when forceNodeInWater=.TRUE. - + posPrime(3) = MIN( posPrime(3), 0.0_ReKi) ! Clamp z-position to zero. Needed when forceNodeInWater=.TRUE. + ! Obtain the wave-field variables by interpolation with the mapped position. - CALL SeaSt_Interp_Setup( Time, posPrime, WaveField%seast_interp_p, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FA(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAcc, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FDynP = SeaSt_Interp_4D ( WaveField%WaveDynP, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL WaveField_Interp_Setup4D( Time, posPrime, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) + FA(:) = WaveField_Interp_4D_Vec( WaveField%WaveAcc, WaveField_m ) + FDynP = WaveField_Interp_4D ( WaveField%WaveDynP, WaveField_m ) IF ( ALLOCATED(WaveField%WaveAccMCF) ) THEN - FAMCF(:) = SeaSt_Interp_4D_Vec( WaveField%WaveAccMCF, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + FAMCF(:) = WaveField_Interp_4D_Vec( WaveField%WaveAccMCF, WaveField_m ) END IF END IF - + ELSE ! Node is out of water - zero-out all wave dynamics - - nodeInWater = 0_IntKi + + nodeInWater = 0_IntKi FV(:) = 0.0 FA(:) = 0.0 FDynP = 0.0 FAMCF(:) = 0.0 - + END IF ! If node is in or out of water - + END IF ! If wave stretching is on or off - + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function END SUBROUTINE WaveField_GetNodeWaveKin + !-------------------- Subroutine for wave field velocity only --------------------! -SUBROUTINE WaveField_GetNodeWaveVel( WaveField, SeaSt_Interp_m, Time, pos, forceNodeInWater, nodeInWater, FV, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(3) - LOGICAL, INTENT( IN ) :: forceNodeInWater - INTEGER(IntKi), INTENT( OUT ) :: nodeInWater - REAL(SiKi), INTENT( OUT ) :: FV(3) - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - - REAL(SiKi) :: WaveElev - REAL(ReKi) :: posXY(2), posPrime(3), posXY0(3) - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetNodeWaveVel' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 +SUBROUTINE WaveField_GetNodeWaveVel( WaveField, WaveField_m, Time, pos, forceNodeInWater, nodeInWater, FV, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(3) + logical, intent(in ) :: forceNodeInWater + integer(IntKi), intent( out) :: nodeInWater + real(SiKi), intent( out) :: FV(3) + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + real(SiKi) :: WaveElev + real(ReKi) :: posXY(2), posPrime(3), posXY0(3) + character(*), parameter :: RoutineName = 'WaveField_GetNodeWaveVel' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 ErrStat = ErrID_None ErrMsg = "" @@ -318,112 +310,109 @@ SUBROUTINE WaveField_GetNodeWaveVel( WaveField, SeaSt_Interp_m, Time, pos, force posXY0 = (/pos(1),pos(2),0.0_ReKi/) ! Wave elevation - WaveElev = WaveField_GetNodeTotalWaveElev( WaveField, SeaSt_Interp_m, Time, pos, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - + WaveElev = WaveField_GetNodeTotalWaveElev( WaveField, WaveField_m, Time, pos, ErrStat2, ErrMsg2 ); if (Failed()) return; + IF (WaveField%WaveStMod == 0) THEN ! No wave stretching - + IF ( pos(3) <= 0.0_ReKi) THEN ! Node is at or below the SWL nodeInWater = 1_IntKi - ! Use location to obtain interpolated values of kinematics - CALL SeaSt_Interp_Setup( Time, pos, WaveField%seast_interp_p, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ! Use location to obtain interpolated values of kinematics + CALL WaveField_Interp_Setup4D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) ELSE ! Node is above the SWL nodeInWater = 0_IntKi FV(:) = 0.0 END IF - + ELSE ! Wave stretching enabled - + IF ( (pos(3) <= WaveElev) .OR. forceNodeInWater ) THEN ! Node is submerged - + nodeInWater = 1_IntKi - + IF ( WaveField%WaveStMod < 3 ) THEN ! Vertical or extrapolated wave stretching - + IF ( pos(3) <= 0.0_SiKi) THEN ! Node is below the SWL - evaluate wave dynamics as usual - - ! Use location to obtain interpolated values of kinematics - CALL SeaSt_Interp_Setup( Time, pos, WaveField%seast_interp_p, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! Use location to obtain interpolated values of kinematics + CALL WaveField_Interp_Setup4D( Time, pos, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) ELSE ! Node is above SWL - need wave stretching - + ! Vertical wave stretching - CALL SeaSt_Interp_Setup( Time, posXY0, WaveField%seast_interp_p, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - + CALL WaveField_Interp_Setup4D( Time, posXY0, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_vec( WaveField%WaveVel, WaveField_m ) + ! Extrapoled wave stretching - IF (WaveField%WaveStMod == 2) THEN - FV(:) = FV(:) + SeaSt_Interp_3D_vec( Time, posXY, WaveField%PWaveVel0, WaveField%seast_interp_p, seast_interp_m%FirstWarn_Clamp, ErrStat2, ErrMsg2 ) * pos(3) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (WaveField%WaveStMod == 2) THEN + CALL WaveField_Interp_Setup3D( Time, posXY, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = FV(:) + WaveField_Interp_3D_vec( WaveField%PWaveVel0, WaveField_m ) * pos(3) END IF - + END IF ! Node is submerged - + ELSE ! Wheeler stretching - no need to check whether the node is above or below SWL - - ! Map the node z-position linearly from [-EffWtrDpth,m%WaveElev(j)] to [-EffWtrDpth,0] + + ! Map the node z-position linearly from [-EffWtrDpth,m%WaveElev(j)] to [-EffWtrDpth,0] posPrime = pos posPrime(3) = WaveField%EffWtrDpth*(WaveField%EffWtrDpth+pos(3))/(WaveField%EffWtrDpth+WaveElev)-WaveField%EffWtrDpth - posPrime(3) = MIN( posPrime(3), 0.0_ReKi) ! Clamp z-position to zero. Needed when forceNodeInWater=.TRUE. - + posPrime(3) = MIN( posPrime(3), 0.0_ReKi) ! Clamp z-position to zero. Needed when forceNodeInWater=.TRUE. + ! Obtain the wave-field variables by interpolation with the mapped position. - CALL SeaSt_Interp_Setup( Time, posPrime, WaveField%seast_interp_p, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - FV(:) = SeaSt_Interp_4D_Vec( WaveField%WaveVel, seast_interp_m, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - + CALL WaveField_Interp_Setup4D( Time, posPrime, WaveField%GridParams, WaveField_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + FV(:) = WaveField_Interp_4D_Vec( WaveField%WaveVel, WaveField_m ) + END IF - + ELSE ! Node is out of water - zero-out all wave dynamics - - nodeInWater = 0_IntKi + + nodeInWater = 0_IntKi FV(:) = 0.0 - + END IF ! If node is in or out of water - + END IF ! If wave stretching is on or off - + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function END SUBROUTINE WaveField_GetNodeWaveVel -SUBROUTINE WaveField_GetWaveKin( WaveField, SeaSt_Interp_m, Time, pos, forceNodeInWater, nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat, ErrMsg ) - TYPE(SeaSt_WaveFieldType), INTENT( IN ) :: WaveField - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: SeaSt_Interp_m - REAL(DbKi), INTENT( IN ) :: Time - REAL(ReKi), INTENT( IN ) :: pos(:,:) - LOGICAL, INTENT( IN ) :: forceNodeInWater - REAL(SiKi), INTENT( OUT ) :: WaveElev1(:) - REAL(SiKi), INTENT( OUT ) :: WaveElev2(:) - REAL(SiKi), INTENT( OUT ) :: WaveElev(:) - REAL(ReKi), INTENT( OUT ) :: FV(:,:) - REAL(ReKi), INTENT( OUT ) :: FA(:,:) - REAL(ReKi), INTENT( OUT ) :: FAMCF(:,:) - REAL(ReKi), INTENT( OUT ) :: FDynP(:) - INTEGER(IntKi), INTENT( OUT ) :: nodeInWater(:) - INTEGER(IntKi), INTENT( OUT ) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if errStat /= ErrID_None - - CHARACTER(*), PARAMETER :: RoutineName = 'WaveField_GetWaveKin' - INTEGER(IntKi) :: errStat2 - CHARACTER(ErrMsgLen) :: errMsg2 - - INTEGER(IntKi) :: NumPoints, i - REAL(SiKi) :: FDynP_node, FV_node(3), FA_node(3), FAMCF_node(3) + +SUBROUTINE WaveField_GetWaveKin( WaveField, WaveField_m, Time, pos, forceNodeInWater, nodeInWater, WaveElev1, WaveElev2, WaveElev, FDynP, FV, FA, FAMCF, ErrStat, ErrMsg ) + type(SeaSt_WaveFieldType), intent(in ) :: WaveField + type(SeaSt_WaveField_MiscVarType), intent(inout) :: WaveField_m + real(DbKi), intent(in ) :: Time + real(ReKi), intent(in ) :: pos(:,:) + logical, intent(in ) :: forceNodeInWater + real(SiKi), intent( out) :: WaveElev1(:) + real(SiKi), intent( out) :: WaveElev2(:) + real(SiKi), intent( out) :: WaveElev(:) + real(ReKi), intent( out) :: FV(:,:) + real(ReKi), intent( out) :: FA(:,:) + real(ReKi), intent( out) :: FAMCF(:,:) + real(ReKi), intent( out) :: FDynP(:) + integer(IntKi), intent( out) :: nodeInWater(:) + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + + character(*), parameter :: RoutineName = 'WaveField_GetWaveKin' + integer(IntKi) :: errStat2 + character(ErrMsgLen) :: errMsg2 + + integer(IntKi) :: NumPoints, i + real(SiKi) :: FDynP_node, FV_node(3), FA_node(3), FAMCF_node(3) ErrStat = ErrID_None ErrMsg = "" NumPoints = size(pos, dim=2) DO i = 1, NumPoints - CALL WaveField_GetNodeWaveKin( WaveField, SeaSt_Interp_m, Time, pos(:,i), forceNodeInWater, nodeInWater(i), WaveElev1(i), WaveElev2(i), WaveElev(i), FDynP_node, FV_node, FA_node, FAMCF_node, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL WaveField_GetNodeWaveKin( WaveField, WaveField_m, Time, pos(:,i), forceNodeInWater, nodeInWater(i), WaveElev1(i), WaveElev2(i), WaveElev(i), FDynP_node, FV_node, FA_node, FAMCF_node, ErrStat2, ErrMsg2 ) + if (Failed()) return; FDynP(i) = REAL(FDynP_node,ReKi) FV(:, i) = REAL(FV_node, ReKi) FA(:, i) = REAL(FA_node, ReKi) @@ -432,6 +421,461 @@ SUBROUTINE WaveField_GetWaveKin( WaveField, SeaSt_Interp_m, Time, pos, forceNode END IF END DO -END SUBROUTINE WaveField_GetWaveKin +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function +end subroutine WaveField_GetWaveKin + + +!---------------------------------------------------------------------------------------------------- +! Interpolation related functions +!---------------------------------------------------------------------------------------------------- + +subroutine SetCartesianXYIndex(p, pZero, delta, nMax, Indx_Lo, Indx_Hi, isopc, FirstWarn, ErrStat, ErrMsg) + REAL(ReKi), intent(in ) :: p + REAL(ReKi), intent(in ) :: pZero + REAL(ReKi), intent(in ) :: delta + INTEGER(IntKi), intent(in ) :: nMax + INTEGER(IntKi), intent(inout) :: Indx_Lo + INTEGER(IntKi), intent(inout) :: Indx_Hi + real(SiKi), intent(inout) :: isopc + logical, intent(inout) :: FirstWarn + INTEGER(IntKi), intent( out) :: ErrStat + CHARACTER(*), intent( out) :: ErrMsg + + real(ReKi) :: Tmp + + ErrStat = ErrID_None + ErrMsg = "" + + isopc = -1.0 + Indx_Lo = 0 + Indx_Hi = 0 + + + Tmp = (p-pZero) / delta + Indx_Lo = INT( Tmp ) + 1 ! convert REAL to INTEGER, then add one since our grid indices start at 1, not 0 + isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo - 1, ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 + + if ( Indx_Lo < 1 ) then + Indx_Lo = 1 + isopc = -1.0 + if (FirstWarn) then + call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianXYIndex') !error out if time is outside the lower bounds + FirstWarn = .false. + end if + end if + + Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, zero-based + + if ( Indx_Lo >= Indx_Hi ) then + ! Need to clamp to grid boundary + if (FirstWarn .and. Indx_Lo /= Indx_Hi) then ! don't warn if we are exactly at the boundary + call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianXYIndex') !error out if time is outside the lower bounds + FirstWarn = .false. + end if + Indx_Lo = max(Indx_Hi - 1, 1) + isopc = 1.0 + end if + + !------------------------------------------------------------------------------------------------- + ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) + !------------------------------------------------------------------------------------------------- + isopc = min( 1.0_SiKi, isopc ) + isopc = max(-1.0_SiKi, isopc ) + +end subroutine SetCartesianXYIndex + + +subroutine SetCartesianZIndex(p, z_depth, delta, nMax, Indx_Lo, Indx_Hi, isopc, FirstWarn, ErrStat, ErrMsg) + real(ReKi), intent(in ) :: p + real(ReKi), intent(in ) :: z_depth + real(ReKi), intent(in ) :: delta + integer(IntKi), intent(in ) :: nMax + integer(IntKi), intent(inout) :: Indx_Lo + integer(IntKi), intent(inout) :: Indx_Hi + real(SiKi), intent(inout) :: isopc + logical, intent(inout) :: FirstWarn + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + + real(ReKi) :: Tmp + + ErrStat = ErrID_None + ErrMsg = "" + + isopc = -1.0 + Indx_Lo = 0 + Indx_Hi = 0 + + + !Tmp = acos(-p / z_depth) / delta + Tmp = acos( max(-1.0_ReKi, min(1.0_ReKi, 1+(p / z_depth)) ) ) / delta + Tmp = nmax - 1 - Tmp + Indx_Lo = INT( Tmp ) + 1 ! convert REAL to INTEGER, then add one since our grid indices start at 1, not 0 + isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo - 1, ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 + + if ( Indx_Lo < 1 ) then + Indx_Lo = 1 + isopc = -1.0 + if (FirstWarn) then + call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianZIndex') !error out if z is outside the lower bounds + FirstWarn = .false. + end if + end if + + Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, one-based + + if ( Indx_Lo >= Indx_Hi ) then + ! Need to clamp to grid boundary + if (FirstWarn .and. Indx_Lo /= Indx_Hi) then ! don't warn if we are exactly at the boundary + call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianZIndex') !error out if z is outside the upper bounds + FirstWarn = .false. + end if + Indx_Lo = max(Indx_Hi - 1, 1) + isopc = 1.0 + end if + + !------------------------------------------------------------------------------------------------- + ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) + !------------------------------------------------------------------------------------------------- + isopc = min( 1.0_SiKi, isopc ) + isopc = max(-1.0_SiKi, isopc ) + +end subroutine SetCartesianZIndex + + +subroutine SetTimeIndex(Time, deltaT, nMax, Indx_Lo, Indx_Hi, isopc, ErrStat, ErrMsg) + real(DbKi), intent(in ) :: Time !< time from the start of the simulation + real(ReKi), intent(in ) :: deltaT + integer(IntKi), intent(in ) :: nMax + integer(IntKi), intent(inout) :: Indx_Lo + integer(IntKi), intent(inout) :: Indx_Hi + real(SiKi), intent(inout) :: isopc + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + + real(ReKi) :: Tmp + + ErrStat = ErrID_None + ErrMsg = "" + + isopc = -1.0 + Indx_Lo = 0 + Indx_Hi = 0 + if ( Time < 0.0_DbKi ) then + CALL SetErrStat(ErrID_Fatal,'Time value must be greater than or equal to zero!',ErrStat,ErrMsg,'SetTimeIndex') !error out if time is outside the lower bounds + RETURN + end if + + ! if there are no timesteps, don't proceed + if (EqualRealNos(deltaT,0.0_ReKi) .or. deltaT < 0.0_ReKi) return; + +! NOTE: nMax is the total number of time values in the grid, since this is zero-based indexing, the max index is nMax-1 +! for example: in a time grid with 11 grid points, the indices run from 0,1,2,3,4,5,6,7,8,9,10 +! for the repeating waves feature, index 10 is the same as index 0, so if Indx_Lo = 10 then we want to +! wrap it back to index 0, if Indx_Lo = 11 we want to wrap back to index 1. + + Tmp = real( (Time/ real(deltaT,DbKi)) ,ReKi) + Tmp = MOD(Tmp,real((nMax), ReKi)) + Indx_Lo = INT( Tmp ) ! convert REAL to INTEGER + + isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo , ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 + + !------------------------------------------------------------------------------------------------- + ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) + !------------------------------------------------------------------------------------------------- + isopc = min( 1.0_SiKi, isopc ) + isopc = max(-1.0_SiKi, isopc ) + + Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, zero-based + +end subroutine SetTimeIndex + + +!==================================================================================================== +!> This routine sets up interpolation of a 3-d or 4-d dataset. +!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf +subroutine WaveField_Interp_Setup4D( Time, Position, p, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: Time !< time from the start of the simulation + real(ReKi), intent(in ) :: Position(3) !< Array of XYZ coordinates, 3 + type(SeaSt_WaveField_ParameterType), intent(in ) :: p !< Parameters + type(SeaSt_WaveField_MiscVarType), intent(inout) :: m !< MiscVars + integer(IntKi), intent( out) :: ErrStat !< Error status + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + + character(*), parameter :: RoutineName = 'WaveField_Interp_Setup4D' + integer(IntKi) :: i + real(SiKi) :: isopc(4) ! isoparametric coordinates + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat = ErrID_None + ErrMsg = "" + + ! Find the bounding indices for time + call SetTimeIndex(Time, p%delta(1), p%n(1), m%Indx_Lo(1), m%Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) + if (Failed()) return; + + ! Find the bounding indices for XY position + do i=2,3 ! x and y components + call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), m%Indx_Lo(i), m%Indx_Hi(i), isopc(i), m%FirstWarn_Clamp, ErrStat2, ErrMsg2) + if (Failed()) return; + enddo + + ! Find the bounding indices for Z position + i=4 ! z component + call SetCartesianZIndex(Position(i-1), p%Z_Depth, p%delta(i), p%n(i), m%Indx_Lo(i), m%Indx_Hi(i), isopc(i), m%FirstWarn_Clamp, ErrStat2, ErrMsg2) + if (Failed()) return; + + ! compute weighting factors + m%N4D( 1) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D( 2) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D( 3) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D( 4) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D( 5) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D( 6) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D( 7) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D( 8) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D( 9) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D(10) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D(11) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D(12) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D(13) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D(14) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D(15) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) + m%N4D(16) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) + m%N4D = m%N4D / REAL( SIZE(m%N4D), SiKi ) ! normalize + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function +END Subroutine WaveField_Interp_Setup4D + + +subroutine WaveField_Interp_Setup3D( Time, Position, p, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: Time !< time from the start of the simulation + real(ReKi), intent(in ) :: Position(2) !< Array of XYZ coordinates, 3 + type(SeaSt_WaveField_ParameterType), intent(in ) :: p !< Parameters + type(SeaSt_WaveField_MiscVarType), intent(inout) :: m !< MiscVars + integer(IntKi), intent( out) :: ErrStat !< Error status + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + character(*), parameter :: RoutineName = 'WaveField_Interp_Setup3D' + integer(IntKi) :: i + real(SiKi) :: isopc(4) ! isoparametric coordinates + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat = ErrID_None + ErrMsg = "" + + ! Find the bounding indices for time + call SetTimeIndex(Time, p%delta(1), p%n(1), m%Indx_Lo(1), m%Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) + if (Failed()) return; + + ! Find the bounding indices for XY position + do i=2,3 ! x and y components + call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), m%Indx_Lo(i), m%Indx_Hi(i), isopc(i), m%FirstWarn_Clamp, ErrStat2, ErrMsg2) + if (Failed()) return; + enddo + + ! compute weighting factors + m%N3D(1) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) + m%N3D(2) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) + m%N3D(3) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) + m%N3D(4) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) + m%N3D(5) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) + m%N3D(6) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) + m%N3D(7) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) + m%N3D(8) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) + m%N3D = m%N3D / REAL( SIZE(m%N3D), ReKi ) ! normalize + +contains + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function +END Subroutine WaveField_Interp_Setup3D + + +!==================================================================================================== +!> This routine interpolates a 4-d dataset. +!! This method is described here: http://rjwagner49.com/Mathematics/WaveFieldolation.pdf +function WaveField_Interp_4D( pKinXX, m ) + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:) + type(SeaSt_WaveField_MiscVarType), intent(in ) :: m + + real(SiKi) :: WaveField_Interp_4D + real(SiKi) :: u(16) ! size 2^n + + ! interpolate + u( 1) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4) ) + u( 2) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4) ) + u( 3) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4) ) + u( 4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4) ) + u( 5) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4) ) + u( 6) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4) ) + u( 7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4) ) + u( 8) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4) ) + u( 9) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4) ) + u(10) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4) ) + u(11) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4) ) + u(12) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4) ) + u(13) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4) ) + u(14) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4) ) + u(15) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4) ) + u(16) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4) ) + WaveField_Interp_4D = SUM ( m%N4D * u ) +end function WaveField_Interp_4D + + +!==================================================================================================== +!> This routine interpolates a 4-d dataset. +!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf +function WaveField_Interp_4D_Vec( pKinXX, m) + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:,:) + type(SeaSt_WaveField_MiscVarType), intent(in ) :: m !< misc vars for interpolation + + real(SiKi) :: WaveField_Interp_4D_Vec(3) + real(SiKi) :: u(16) ! size 2^n + integer(IntKi) :: iDir + + ! interpolate + do iDir = 1,3 + u( 1) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u( 2) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u( 3) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u( 4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u( 5) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u( 6) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u( 7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u( 8) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u( 9) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u(10) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u(11) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u(12) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u(13) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u(14) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u(15) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u(16) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + WaveField_Interp_4D_Vec(iDir) = SUM ( m%N4D * u ) + end do +END FUNCTION WaveField_Interp_4D_Vec + + +!==================================================================================================== +!> This routine interpolates a 4-d dataset. +!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf +function WaveField_Interp_4D_Vec6( pKinXX, m) + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:,:) + type(SeaSt_WaveField_MiscVarType), intent(in ) :: m !< misc vars for interpolation + + real(SiKi) :: WaveField_Interp_4D_Vec6(6) + real(SiKi) :: u(16) ! size 2^n + integer(IntKi) :: iDir + + ! interpolate + do iDir = 1,6 + u( 1) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u( 2) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u( 3) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u( 4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u( 5) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u( 6) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u( 7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u( 8) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u( 9) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u(10) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u(11) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u(12) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + u(13) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) + u(14) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) + u(15) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) + u(16) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) + WaveField_Interp_4D_Vec6(iDir) = SUM ( m%N4D * u ) + end do +END FUNCTION WaveField_Interp_4D_Vec6 + + +!==================================================================================================== +!> This routine interpolates a 3-d dataset with index 1 = time (zero-based indexing), 2 = x-coordinate (1-based indexing), 3 = y-coordinate (1-based indexing) +!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf +!FIXME: do like the above and call the WaveField_Interp_Setup3D routine ahead +function WaveField_Interp_3D( pKinXX, m ) + real(SiKi), intent(in ) :: pKinXX(0:,:,:) !< 3D Wave elevation data (SiKi for storage space reasons) + type(SeaSt_WaveField_MiscVarType), intent(inout) :: m !< MiscVars + + character(*), parameter :: RoutineName = 'WaveField_Interp_3D' + real(SiKi) :: WaveField_Interp_3D + real(SiKi) :: u(8) + integer(IntKi) :: i + + ! interpolate + u(1) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3) ) + u(2) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3) ) + u(3) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3) ) + u(4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3) ) + u(5) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3) ) + u(6) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3) ) + u(7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3) ) + u(8) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3) ) + WaveField_Interp_3D = SUM ( m%N3D * u ) +end function WaveField_Interp_3D + + +FUNCTION WaveField_Interp_3D_VEC( pKinXX, m ) + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:) !< 3D Wave excitation data (SiKi for storage space reasons) + type(SeaSt_WaveField_MiscVarType), intent(inout) :: m !< MiscVars + + character(*), parameter :: RoutineName = 'WaveField_Interp_3D_VEC' + real(SiKi) :: WaveField_Interp_3D_VEC(3) + real(SiKi) :: u(8) + integer(IntKi) :: i + + ! interpolate + do i = 1,3 + u(1) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), i ) + u(2) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), i ) + u(3) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), i ) + u(4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), i ) + u(5) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), i ) + u(6) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), i ) + u(7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), i ) + u(8) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), i ) + WaveField_Interp_3D_VEC(i) = SUM ( m%N3D * u ) + end do +end function WaveField_Interp_3D_VEC + + +function Wavefield_Interp_3D_VEC6( pKinXX, m ) + real(SiKi), intent(in ) :: pKinXX(0:,:,:,:) !< 3D Wave excitation data (SiKi for storage space reasons) + type(SeaSt_WaveField_MiscVarType), intent(inout) :: m !< Miscvars + + character(*), parameter :: RoutineName = 'Wavefield_Interp_3D_VEC6' + real(SiKi) :: Wavefield_Interp_3D_VEC6(6) + real(SiKi) :: u(8) + integer(IntKi) :: i + + ! interpolate + do i = 1,6 + u(1) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), i ) + u(2) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), i ) + u(3) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), i ) + u(4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), i ) + u(5) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), i ) + u(6) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), i ) + u(7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), i ) + u(8) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), i ) + Wavefield_Interp_3D_VEC6(i) = SUM ( m%N3D * u ) + end do +end function Wavefield_Interp_3D_VEC6 + + END MODULE SeaSt_WaveField diff --git a/modules/seastate/src/SeaSt_WaveField.txt b/modules/seastate/src/SeaSt_WaveField.txt index 9d5c659752..f0b4aeaf14 100644 --- a/modules/seastate/src/SeaSt_WaveField.txt +++ b/modules/seastate/src/SeaSt_WaveField.txt @@ -1,8 +1,6 @@ #--------------------------------------------------------------------------------------------------------------------------------------------------------- # Data structures for representing wave fields. # -usefrom SeaState_Interp.txt - param SeaSt_WaveField - INTEGER WaveDirMod_None - 0 - "WaveDirMod = 0 [Directional spreading function is NONE]" - param SeaSt_WaveField - INTEGER WaveDirMod_COS2S - 1 - "WaveDirMod = 1 [Directional spreading function is COS2S]" - @@ -19,6 +17,18 @@ param SeaSt_WaveField - INTEGER WaveMod_User #--------------------------------------------------------------------------------------------------------------------------------------------------------- # #--------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef ^ ParameterType IntKi n 4 - - "number of evenly-spaced grid points in the t, x, y, and z directions" - +typedef ^ ParameterType ReKi delta 4 - - "size between 2 consecutive grid points in each grid direction" "s,m,m,m" +typedef ^ ParameterType ReKi pZero 4 - - "fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:))" "m" +typedef ^ ParameterType ReKi Z_Depth - - - "grid depth" m + +typedef ^ MiscVarType SiKi N3D {8} - - "this is the weighting function for 3-d velocity field" - +typedef ^ MiscVarType SiKi N4D {16} - - "this is the weighting function for 4-d velocity field" - +typedef ^ MiscVarType integer Indx_Lo 4 - - "this is the index into the 4-d velocity field for each wave component" - +typedef ^ MiscVarType integer Indx_Hi 4 - - "this is the index into the 4-d velocity field for each wave component" - +typedef ^ MiscVarType logical FirstWarn_Clamp - .true. - "used to avoid too many 'Position has been clamped to the grid boundary' warning messages " - + + typedef SeaSt_WaveField SeaSt_WaveFieldType SiKi WaveTime {:} - - "Time array" (s) typedef ^ ^ SiKi WaveDynP {:}{:}{:}{:} - - "Incident wave dynamic pressure" (N/m^2) typedef ^ ^ SiKi WaveAcc {:}{:}{:}{:}{:} - - "Incident wave acceleration" (m/s^2) @@ -31,7 +41,7 @@ typedef ^ ^ SiKi PWaveVel0 typedef ^ ^ SiKi WaveElev0 {:} - - "Instantaneous elevation time-series of incident waves at the platform reference point (NOTE THAT THIS CAN GET MODIFIED IN WAMIT)" (m) typedef ^ ^ SiKi WaveElev1 {:}{:}{:} - - "First order wave elevation" (m) typedef ^ ^ SiKi WaveElev2 {:}{:}{:} - - "Second order wave elevation" (m) -typedef ^ ^ SeaSt_Interp_ParameterType SeaSt_Interp_p - - - "Parameter information from the SeaState Interpolation module" (-) +typedef ^ ^ SeaSt_WaveField_ParameterType GridParams - - - "Parameters for grid spacing" (-) typedef ^ ^ IntKi WaveStMod - - - "Wave stretching model" typedef ^ ^ ReKi EffWtrDpth - - - "Water depth" (-) typedef ^ ^ ReKi MSL2SWL - - - "Vertical distance from mean sea level to still water level" (m) diff --git a/modules/seastate/src/SeaSt_WaveField_Types.f90 b/modules/seastate/src/SeaSt_WaveField_Types.f90 index 656e7f8460..869882a3aa 100644 --- a/modules/seastate/src/SeaSt_WaveField_Types.f90 +++ b/modules/seastate/src/SeaSt_WaveField_Types.f90 @@ -31,7 +31,6 @@ !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. MODULE SeaSt_WaveField_Types !--------------------------------------------------------------------------------------------------------------------------------- -USE SeaState_Interp_Types USE NWTC_Library IMPLICIT NONE INTEGER(IntKi), PUBLIC, PARAMETER :: WaveDirMod_None = 0 ! WaveDirMod = 0 [Directional spreading function is NONE] [-] @@ -45,6 +44,23 @@ MODULE SeaSt_WaveField_Types INTEGER(IntKi), PUBLIC, PARAMETER :: WaveMod_ExtElev = 5 ! WaveMod = 5 [Incident wave kinematics model: Externally generated wave-elevation time series] [-] INTEGER(IntKi), PUBLIC, PARAMETER :: WaveMod_ExtFull = 6 ! WaveMod = 6 [Incident wave kinematics model: Externally generated full wave-kinematics time series (invalid for PotMod/=0)] [-] INTEGER(IntKi), PUBLIC, PARAMETER :: WaveMod_UserFreq = 7 ! WaveMod = 7 [Incident wave kinematics model: user-defined wave frequency components] [-] +! ========= SeaSt_WaveField_ParameterType ======= + TYPE, PUBLIC :: SeaSt_WaveField_ParameterType + INTEGER(IntKi) , DIMENSION(1:4) :: n = 0_IntKi !< number of evenly-spaced grid points in the t, x, y, and z directions [-] + REAL(ReKi) , DIMENSION(1:4) :: delta = 0.0_ReKi !< size between 2 consecutive grid points in each grid direction [s,m,m,m] + REAL(ReKi) , DIMENSION(1:4) :: pZero = 0.0_ReKi !< fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:)) [m] + REAL(ReKi) :: Z_Depth = 0.0_ReKi !< grid depth [m] + END TYPE SeaSt_WaveField_ParameterType +! ======================= +! ========= SeaSt_WaveField_MiscVarType ======= + TYPE, PUBLIC :: SeaSt_WaveField_MiscVarType + REAL(SiKi) , DIMENSION(1:8) :: N3D = 0.0_R4Ki !< this is the weighting function for 3-d velocity field [-] + REAL(SiKi) , DIMENSION(1:16) :: N4D = 0.0_R4Ki !< this is the weighting function for 4-d velocity field [-] + INTEGER(IntKi) , DIMENSION(1:4) :: Indx_Lo = 0_IntKi !< this is the index into the 4-d velocity field for each wave component [-] + INTEGER(IntKi) , DIMENSION(1:4) :: Indx_Hi = 0_IntKi !< this is the index into the 4-d velocity field for each wave component [-] + LOGICAL :: FirstWarn_Clamp = .true. !< used to avoid too many 'Position has been clamped to the grid boundary' warning messages [-] + END TYPE SeaSt_WaveField_MiscVarType +! ======================= ! ========= SeaSt_WaveFieldType ======= TYPE, PUBLIC :: SeaSt_WaveFieldType REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: WaveTime !< Time array [(s)] @@ -59,7 +75,7 @@ MODULE SeaSt_WaveField_Types REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: WaveElev0 !< Instantaneous elevation time-series of incident waves at the platform reference point (NOTE THAT THIS CAN GET MODIFIED IN WAMIT) [(m)] REAL(SiKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveElev1 !< First order wave elevation [(m)] REAL(SiKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveElev2 !< Second order wave elevation [(m)] - TYPE(SeaSt_Interp_ParameterType) :: SeaSt_Interp_p !< Parameter information from the SeaState Interpolation module [(-)] + TYPE(SeaSt_WaveField_ParameterType) :: GridParams !< Parameters for grid spacing [(-)] INTEGER(IntKi) :: WaveStMod = 0_IntKi !< Wave stretching model [-] REAL(ReKi) :: EffWtrDpth = 0.0_ReKi !< Water depth [(-)] REAL(ReKi) :: MSL2SWL = 0.0_ReKi !< Vertical distance from mean sea level to still water level [(m)] @@ -88,6 +104,103 @@ MODULE SeaSt_WaveField_Types ! ======================= CONTAINS +subroutine SeaSt_WaveField_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) + type(SeaSt_WaveField_ParameterType), intent(in) :: SrcParamData + type(SeaSt_WaveField_ParameterType), intent(inout) :: DstParamData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'SeaSt_WaveField_CopyParam' + ErrStat = ErrID_None + ErrMsg = '' + DstParamData%n = SrcParamData%n + DstParamData%delta = SrcParamData%delta + DstParamData%pZero = SrcParamData%pZero + DstParamData%Z_Depth = SrcParamData%Z_Depth +end subroutine + +subroutine SeaSt_WaveField_DestroyParam(ParamData, ErrStat, ErrMsg) + type(SeaSt_WaveField_ParameterType), intent(inout) :: ParamData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'SeaSt_WaveField_DestroyParam' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine SeaSt_WaveField_PackParam(RF, Indata) + type(RegFile), intent(inout) :: RF + type(SeaSt_WaveField_ParameterType), intent(in) :: InData + character(*), parameter :: RoutineName = 'SeaSt_WaveField_PackParam' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%n) + call RegPack(RF, InData%delta) + call RegPack(RF, InData%pZero) + call RegPack(RF, InData%Z_Depth) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine SeaSt_WaveField_UnPackParam(RF, OutData) + type(RegFile), intent(inout) :: RF + type(SeaSt_WaveField_ParameterType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'SeaSt_WaveField_UnPackParam' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%n); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%delta); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%pZero); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Z_Depth); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine SeaSt_WaveField_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) + type(SeaSt_WaveField_MiscVarType), intent(in) :: SrcMiscData + type(SeaSt_WaveField_MiscVarType), intent(inout) :: DstMiscData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'SeaSt_WaveField_CopyMisc' + ErrStat = ErrID_None + ErrMsg = '' + DstMiscData%N3D = SrcMiscData%N3D + DstMiscData%N4D = SrcMiscData%N4D + DstMiscData%Indx_Lo = SrcMiscData%Indx_Lo + DstMiscData%Indx_Hi = SrcMiscData%Indx_Hi + DstMiscData%FirstWarn_Clamp = SrcMiscData%FirstWarn_Clamp +end subroutine + +subroutine SeaSt_WaveField_DestroyMisc(MiscData, ErrStat, ErrMsg) + type(SeaSt_WaveField_MiscVarType), intent(inout) :: MiscData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'SeaSt_WaveField_DestroyMisc' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine SeaSt_WaveField_PackMisc(RF, Indata) + type(RegFile), intent(inout) :: RF + type(SeaSt_WaveField_MiscVarType), intent(in) :: InData + character(*), parameter :: RoutineName = 'SeaSt_WaveField_PackMisc' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%N3D) + call RegPack(RF, InData%N4D) + call RegPack(RF, InData%Indx_Lo) + call RegPack(RF, InData%Indx_Hi) + call RegPack(RF, InData%FirstWarn_Clamp) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine SeaSt_WaveField_UnPackMisc(RF, OutData) + type(RegFile), intent(inout) :: RF + type(SeaSt_WaveField_MiscVarType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'SeaSt_WaveField_UnPackMisc' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%N3D); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%N4D); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Indx_Lo); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Indx_Hi); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%FirstWarn_Clamp); if (RegCheckErr(RF, RoutineName)) return +end subroutine + subroutine SeaSt_WaveField_CopySeaSt_WaveFieldType(SrcSeaSt_WaveFieldTypeData, DstSeaSt_WaveFieldTypeData, CtrlCode, ErrStat, ErrMsg) type(SeaSt_WaveFieldType), intent(in) :: SrcSeaSt_WaveFieldTypeData type(SeaSt_WaveFieldType), intent(inout) :: DstSeaSt_WaveFieldTypeData @@ -244,7 +357,7 @@ subroutine SeaSt_WaveField_CopySeaSt_WaveFieldType(SrcSeaSt_WaveFieldTypeData, D end if DstSeaSt_WaveFieldTypeData%WaveElev2 = SrcSeaSt_WaveFieldTypeData%WaveElev2 end if - call SeaSt_Interp_CopyParam(SrcSeaSt_WaveFieldTypeData%SeaSt_Interp_p, DstSeaSt_WaveFieldTypeData%SeaSt_Interp_p, CtrlCode, ErrStat2, ErrMsg2) + call SeaSt_WaveField_CopyParam(SrcSeaSt_WaveFieldTypeData%GridParams, DstSeaSt_WaveFieldTypeData%GridParams, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return DstSeaSt_WaveFieldTypeData%WaveStMod = SrcSeaSt_WaveFieldTypeData%WaveStMod @@ -351,7 +464,7 @@ subroutine SeaSt_WaveField_DestroySeaSt_WaveFieldType(SeaSt_WaveFieldTypeData, E if (allocated(SeaSt_WaveFieldTypeData%WaveElev2)) then deallocate(SeaSt_WaveFieldTypeData%WaveElev2) end if - call SeaSt_Interp_DestroyParam(SeaSt_WaveFieldTypeData%SeaSt_Interp_p, ErrStat2, ErrMsg2) + call SeaSt_WaveField_DestroyParam(SeaSt_WaveFieldTypeData%GridParams, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (allocated(SeaSt_WaveFieldTypeData%WaveElevC)) then deallocate(SeaSt_WaveFieldTypeData%WaveElevC) @@ -381,7 +494,7 @@ subroutine SeaSt_WaveField_PackSeaSt_WaveFieldType(RF, Indata) call RegPackAlloc(RF, InData%WaveElev0) call RegPackAlloc(RF, InData%WaveElev1) call RegPackAlloc(RF, InData%WaveElev2) - call SeaSt_Interp_PackParam(RF, InData%SeaSt_Interp_p) + call SeaSt_WaveField_PackParam(RF, InData%GridParams) call RegPack(RF, InData%WaveStMod) call RegPack(RF, InData%EffWtrDpth) call RegPack(RF, InData%MSL2SWL) @@ -429,7 +542,7 @@ subroutine SeaSt_WaveField_UnPackSeaSt_WaveFieldType(RF, OutData) call RegUnpackAlloc(RF, OutData%WaveElev0); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%WaveElev1); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%WaveElev2); if (RegCheckErr(RF, RoutineName)) return - call SeaSt_Interp_UnpackParam(RF, OutData%SeaSt_Interp_p) ! SeaSt_Interp_p + call SeaSt_WaveField_UnpackParam(RF, OutData%GridParams) ! GridParams call RegUnpack(RF, OutData%WaveStMod); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%EffWtrDpth); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%MSL2SWL); if (RegCheckErr(RF, RoutineName)) return diff --git a/modules/seastate/src/SeaState.f90 b/modules/seastate/src/SeaState.f90 index 0e3e27033d..a0d1424ac6 100644 --- a/modules/seastate/src/SeaState.f90 +++ b/modules/seastate/src/SeaState.f90 @@ -30,7 +30,6 @@ MODULE SeaState USE SeaSt_WaveField USE SeaState_Input USE SeaState_Output - use SeaState_Interp USE Current USE Waves2 @@ -90,7 +89,6 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init TYPE(FileInfoType) :: InFileInfo !< The derived type for holding the full input file for parsing -- we may pass this in the future TYPE(Waves_InitOutputType) :: Waves_InitOut ! Initialization Outputs from the Waves submodule initialization TYPE(Waves2_InitOutputType) :: Waves2_InitOut ! Initialization Outputs from the Waves2 submodule initialization - TYPE(SeaSt_Interp_InitInputType) :: SeaSt_Interp_InitInp TYPE(Current_InitOutputType) :: Current_InitOut ! Initialization Outputs from the Current module initialization INTEGER :: I ! Generic counters INTEGER :: it ! Generic counters @@ -123,103 +121,54 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init x%UnusedStates = 0.0 xd%UnusedStates = 0.0 OtherState%UnusedStates = 0.0 - m%SeaSt_Interp_m%FirstWarn_Clamp = .true. + m%WaveField_m%FirstWarn_Clamp = .true. - - ! Initialize the NWTC Subroutine Library - CALL NWTC_Init( ) - ! Display the module information - CALL DispNVD( SeaSt_ProgDesc ) - IF ( InitInp%UseInputFile ) THEN - CALL ProcessComFile( InitInp%InputFile, InFileInfo, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL Cleanup() - RETURN - ENDIF + CALL ProcessComFile( InitInp%InputFile, InFileInfo, ErrStat2, ErrMsg2 ); if(Failed()) return; ELSE - CALL NWTC_Library_CopyFileInfoType( InitInp%PassedFileData, InFileInfo, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL Cleanup() - RETURN - ENDIF + CALL NWTC_Library_CopyFileInfoType( InitInp%PassedFileData, InFileInfo, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if(Failed()) return; ENDIF ! For diagnostic purposes, the following can be used to display the contents ! of the InFileInfo data structure. ! call Print_FileInfo_Struct( CU, InFileInfo ) ! CU is the screen -- different number on different systems. - ! Parse all SeaState-related input and populate the InputFileData structure - CALL SeaSt_ParseInput( InitInp%InputFile, InitInp%OutRootName, InitInp%defWtrDens, InitInp%defWtrDpth, InitInp%defMSL2SWL, InFileInfo, InputFileData, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + CALL SeaSt_ParseInput( InitInp%InputFile, InitInp%OutRootName, InitInp%defWtrDens, InitInp%defWtrDpth, InitInp%defMSL2SWL, InFileInfo, InputFileData, ErrStat2, ErrMsg2 ); if(Failed()) return; + ! Verify all the necessary initialization data. Do this at the HydroDynInput module-level + ! because the HydroDynInput module is also responsible for parsing all this + ! initialization data from a file + CALL SeaStateInput_ProcessInitData( InitInp, p, InputFileData, ErrStat2, ErrMsg2 ); if(Failed()) return; - ! Verify all the necessary initialization data. Do this at the HydroDynInput module-level - ! because the HydroDynInput module is also responsible for parsing all this - ! initialization data from a file - - CALL SeaStateInput_ProcessInitData( InitInp, p, InputFileData, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - - - ! Now call each sub-module's *_Init subroutine - ! to fully initialize each sub-module based on the necessary initialization data + ! Now call each sub-module's *_Init subroutine + ! to fully initialize each sub-module based on the necessary initialization data - - ! Initialize Current module - - CALL Current_Init(InputFileData%Current, Current_InitOut, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + ! Initialize Current module + CALL Current_Init(InputFileData%Current, Current_InitOut, ErrStat2, ErrMsg2 ); if(Failed()) return; - ! Move initialization output data from Current module into the initialization input data for the Waves module - + ! Move initialization output data from Current module into the initialization input data for the Waves module IF (ALLOCATED(Current_InitOut%CurrVxi)) CALL Move_Alloc( Current_InitOut%CurrVxi, InputFileData%Waves%CurrVxi ) IF (ALLOCATED(Current_InitOut%CurrVyi)) CALL Move_Alloc( Current_InitOut%CurrVyi, InputFileData%Waves%CurrVyi ) InputFileData%Waves%PCurrVxiPz0 = Current_InitOut%PCurrVxiPz0 InputFileData%Waves%PCurrVyiPz0 = Current_InitOut%PCurrVyiPz0 - - - ! distribute wave field and turbine location variables as needed to submodule initInputs + ! distribute wave field and turbine location variables as needed to submodule initInputs InputFileData%Waves%WaveFieldMod = InitInp%WaveFieldMod InputFileData%Waves%PtfmLocationX = InitInp%PtfmLocationX InputFileData%Waves%PtfmLocationY = InitInp%PtfmLocationY + ! Initialize Waves module (Note that this may change InputFileData%Waves%WaveDT) + CALL Waves_Init(InputFileData%Waves, Waves_InitOut, p%WaveField, ErrStat2, ErrMsg2 ); if(Failed()) return; - ! Initialize Waves module (Note that this may change InputFileData%Waves%WaveDT) - CALL Waves_Init(InputFileData%Waves, Waves_InitOut, p%WaveField, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! note that we DO NOT RETURN on error until AFTER the pointers modified, below - - - ! check error - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - ! Copy Waves initialization output into the initialization input type for the WAMIT module p%WaveDT = InputFileData%Waves%WaveDT @@ -260,60 +209,40 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init !---------------------------------- ! Initialize Waves2 module !---------------------------------- - - IF (InputFileData%Waves2%WvDiffQTFF .OR. InputFileData%Waves2%WvSumQTFF ) THEN - CALL Waves2_Init(InputFileData%Waves2, Waves2_InitOut, p%WaveField, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + CALL Waves2_Init(InputFileData%Waves2, Waves2_InitOut, p%WaveField, ErrStat2, ErrMsg2 ); if(Failed()) return; ! The acceleration, velocity, and dynamic pressures will get added to the parts passed to the morrison module later... - ! Difference frequency results + ! Difference frequency results IF ( InputFileData%Waves2%WvDiffQTFF ) THEN + ! Dynamic pressure -- difference frequency terms ! WaveDynP = WaveDynP + WaveDynP2D + CALL AddArrays_4D(p%WaveField%WaveDynP, Waves2_InitOut%WaveDynP2D,'WaveDynP_D', ErrStat2, ErrMsg2); if(Failed()) return; - ! Dynamic pressure -- difference frequency terms - CALL AddArrays_4D(p%WaveField%WaveDynP, Waves2_InitOut%WaveDynP2D,'WaveDynP_D', ErrStat2, ErrMsg2) ! WaveDynP = WaveDynP + WaveDynP2D - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - ! Particle velocity -- difference frequency terms - CALL AddArrays_5D(p%WaveField%WaveVel, Waves2_InitOut%WaveVel2D,'WaveVel_D', ErrStat2, ErrMsg2) ! WaveVel = WaveVel + WaveVel2D - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - ! Particle acceleration -- difference frequency terms - CALL AddArrays_5D(p%WaveField%WaveAcc, Waves2_InitOut%WaveAcc2D,'WaveAcc_D', ErrStat2, ErrMsg2) ! WaveAcc = WaveAcc + WaveAcc2D - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - + ! Particle velocity -- difference frequency terms ! WaveVel = WaveVel + WaveVel2D + CALL AddArrays_5D(p%WaveField%WaveVel, Waves2_InitOut%WaveVel2D,'WaveVel_D', ErrStat2, ErrMsg2); if(Failed()) return; + ! Particle acceleration -- difference frequency terms ! WaveAcc = WaveAcc + WaveAcc2D + CALL AddArrays_5D(p%WaveField%WaveAcc, Waves2_InitOut%WaveAcc2D,'WaveAcc_D', ErrStat2, ErrMsg2); if(Failed()) return; ENDIF ! second order wave kinematics difference frequency results ! Sum frequency results IF ( InputFileData%Waves2%WvSumQTFF ) THEN + ! Dynamic pressure -- sum frequency terms ! WaveDynP = WaveDynP + WaveDynP2S + CALL AddArrays_4D(p%WaveField%WaveDynP, Waves2_InitOut%WaveDynP2S,'WaveDynP_S', ErrStat2, ErrMsg2); if(Failed()) return; - ! Dynamic pressure -- sum frequency terms - CALL AddArrays_4D(p%WaveField%WaveDynP, Waves2_InitOut%WaveDynP2S,'WaveDynP_S', ErrStat2, ErrMsg2) ! WaveDynP = WaveDynP + WaveDynP2S - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - ! Particle velocity -- sum frequency terms - CALL AddArrays_5D(p%WaveField%WaveVel, Waves2_InitOut%WaveVel2S,'WaveVel_S', ErrStat2, ErrMsg2) ! WaveVel = WaveVel + WaveVel2S - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - ! Particle acceleration -- sum frequency terms - ! Note: MacCamy-Fuchs scaled accleration should not contain second-order contributions - CALL AddArrays_5D(p%WaveField%WaveAcc, Waves2_InitOut%WaveAcc2S,'WaveAcc_S', ErrStat2, ErrMsg2) ! WaveAcc = WaveAcc + WaveAcc2S - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! Particle velocity -- sum frequency terms ! WaveVel = WaveVel + WaveVel2S + CALL AddArrays_5D(p%WaveField%WaveVel, Waves2_InitOut%WaveVel2S,'WaveVel_S', ErrStat2, ErrMsg2); if(Failed()) return; + ! Particle acceleration -- sum frequency terms ! WaveAcc = WaveAcc + WaveAcc2S + ! Note: MacCamy-Fuchs scaled accleration should not contain second-order contributions + CALL AddArrays_5D(p%WaveField%WaveAcc, Waves2_InitOut%WaveAcc2S,'WaveAcc_S', ErrStat2, ErrMsg2); if(Failed()) return; ENDIF ! second order wave kinematics sum frequency results ELSE - ! these need to be set to zero since we don't have a UseWaves2 flag: - InputFileData%Waves2%NWaveElevGrid = 0 - + ! these need to be set to zero since we don't have a UseWaves2 flag: + InputFileData%Waves2%NWaveElevGrid = 0 ENDIF ! InputFileData%Waves2%WvDiffQTFF .OR. InputFileData%Waves2%WvSumQTFF - END IF ! Check for WaveMod = 6 (WaveMod_ExtFull) ! Create the Output file if requested @@ -325,31 +254,21 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init ! Define initialization-routine output here: InitOut%Ver = SeaSt_ProgDesc - ! These three come directly from processing the inputs, and so will exist even if not using Morison elements: - CALL SeaStOut_Init( SeaSt_ProgDesc, InitInp%OutRootName, InputFileData, y, p, m, InitOut, ErrStat2, ErrMsg2 ); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - -!=============================================== + CALL SeaStOut_Init( SeaSt_ProgDesc, InitInp%OutRootName, InputFileData, y, p, m, InitOut, ErrStat2, ErrMsg2 ); if(Failed()) return; - CALL SeaStOut_WrSummaryFile(InitInp, InputFileData, p, ErrStat2, ErrMsg2) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL SeaStOut_WrSummaryFile(InitInp, InputFileData, p, ErrStat2, ErrMsg2); if(Failed()) return; ! Setup the 4D grid information for the Interpolation Module - SeaSt_Interp_InitInp%n = (/p%WaveField%NStepWave,p%nGrid(1),p%nGrid(2),p%nGrid(3)/) - SeaSt_Interp_InitInp%delta = (/real(p%WaveDT,ReKi),p%deltaGrid(1),p%deltaGrid(2),p%deltaGrid(3)/) - SeaSt_Interp_InitInp%pZero(1) = 0.0 !Time - SeaSt_Interp_InitInp%pZero(2) = -InputFileData%X_HalfWidth - SeaSt_Interp_InitInp%pZero(3) = -InputFileData%Y_HalfWidth - SeaSt_Interp_InitInp%pZero(4) = -InputFileData%Z_Depth ! zi - SeaSt_Interp_InitInp%Z_Depth = InputFileData%Z_Depth - call SeaSt_Interp_Init(SeaSt_Interp_InitInp, p%WaveField%seast_interp_p, ErrStat2, ErrMsg2) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + p%WaveField%GridParams%n = (/p%WaveField%NStepWave,p%nGrid(1),p%nGrid(2),p%nGrid(3)/) + p%WaveField%GridParams%delta = (/real(p%WaveDT,ReKi),p%deltaGrid(1),p%deltaGrid(2),p%deltaGrid(3)/) + p%WaveField%GridParams%pZero(1) = 0.0 !Time + p%WaveField%GridParams%pZero(2) = -InputFileData%X_HalfWidth + p%WaveField%GridParams%pZero(3) = -InputFileData%Y_HalfWidth + p%WaveField%GridParams%pZero(4) = -InputFileData%Z_Depth ! zi + p%WaveField%GridParams%Z_Depth = InputFileData%Z_Depth IF ( p%OutSwtch == 1 ) THEN ! Only HD-level output writing ! HACK WE can tell FAST not to write any HD outputs by simply deallocating the WriteOutputHdr array! @@ -359,22 +278,22 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init InitOut%WaveField => p%WaveField ! Tell HydroDyn if state-space wave excitation is not allowed: - InitOut%InvalidWithSSExctn = InputFileData%WaveMod == WaveMod_ExtFull .or. & !call SetErrStat( ErrID_Fatal, 'Externally generated full wave-kinematics time series cannot be used with state-space wave excitations. Set WaveMod 0, 1, 1P#, 2, 3, 4, or 5.', ErrStat, ErrMsg, RoutineName ) - InputFileData%WaveDirMod /= WaveDirMod_None .or. & !call SetErrStat( ErrID_Fatal, 'Directional spreading cannot be used with state-space wave excitations. Set WaveDirMod=0.', ErrStat, ErrMsg, RoutineName ) - InputFileData%Waves2%WvDiffQTFF .or. & !call SetErrStat( ErrID_Fatal, 'Cannot use full difference-frequency 2nd-order wave kinematics with state-space wave excitations. Set WvDiffQTF=FALSE.', ErrStat, ErrMsg, RoutineName ) - InputFileData%Waves2%WvSumQTFF !call SetErrStat( ErrID_Fatal, 'Cannot use full summation-frequency 2nd-order wave kinematics with state-space wave excitations. Set WvSumQTF=FALSE.', ErrStat, ErrMsg, RoutineName ) + InitOut%InvalidWithSSExctn = InputFileData%WaveMod == WaveMod_ExtFull .or. & ! 'Externally generated full wave-kinematics time series cannot be used with state-space wave excitations. Set WaveMod 0, 1, 1P#, 2, 3, 4, or 5.' + InputFileData%WaveDirMod /= WaveDirMod_None .or. & ! 'Directional spreading cannot be used with state-space wave excitations. Set WaveDirMod=0.' + InputFileData%Waves2%WvDiffQTFF .or. & ! 'Cannot use full difference-frequency 2nd-order wave kinematics with state-space wave excitations. Set WvDiffQTF=FALSE.' + InputFileData%Waves2%WvSumQTFF ! 'Cannot use full summation-frequency 2nd-order wave kinematics with state-space wave excitations. Set WvSumQTF=FALSE.' ! Write Wave Kinematics? if ( InputFileData%WaveMod /= WaveMod_ExtFull ) then if ( InitInp%WrWvKinMod == 2 ) then call SeaStOut_WriteWvKinFiles( InitInp%OutRootname, SeaSt_ProgDesc, p%WaveField, p%WaveDT, InputFileData%X_HalfWidth, InputFileData%Y_HalfWidth, & p%deltaGrid, p%NGrid, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if(Failed()) return; else if ( InitInp%WrWvKinMod == 1 ) then call SeaStOut_WriteWaveElev0(InitInp%OutRootname, p%WaveField%NStepWave, & p%NGrid, p%WaveField%WaveElev1, p%WaveField%WaveElev2, & p%WaveField%WaveTime, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if(Failed()) return; end if end if @@ -382,9 +301,7 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init ! If requested, output wave elevation data for VTK visualization if (InitInp%SurfaceVis) then - call SurfaceVisGenerate(ErrStat2, ErrMsg2) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) return + call SurfaceVisGenerate(ErrStat2, ErrMsg2); if(Failed()) return; endif @@ -420,6 +337,11 @@ SUBROUTINE SeaSt_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init CALL CleanUp() CONTAINS + logical function Failed() + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function !................................ SUBROUTINE CleanUp() @@ -458,15 +380,15 @@ subroutine SurfaceVisGenerate(ErrStat3, ErrMsg3) ErrMsg3 = "" ! Grid half width from the WaveField - HWidX = (real(p%WaveField%SeaSt_Interp_p%n(2)-1,SiKi)) / 2.0_SiKi * p%WaveField%SeaSt_Interp_p%delta(2) - HWidY = (real(p%WaveField%SeaSt_Interp_p%n(3)-1,SiKi)) / 2.0_SiKi * p%WaveField%SeaSt_Interp_p%delta(3) + HWidX = (real(p%WaveField%GridParams%n(2)-1,SiKi)) / 2.0_SiKi * p%WaveField%GridParams%delta(2) + HWidY = (real(p%WaveField%GridParams%n(3)-1,SiKi)) / 2.0_SiKi * p%WaveField%GridParams%delta(3) if ((InitInp%SurfaceVisNx <= 0) .or. (InitInp%SurfaceVisNy <= 0))then ! use the SeaState points exactly ! Set number of points to the number of seastate grid points in each direction - Nx = p%WaveField%SeaSt_Interp_p%n(2) - Ny = p%WaveField%SeaSt_Interp_p%n(3) - dx = p%WaveField%SeaSt_Interp_p%delta(2) - dy = p%WaveField%SeaSt_Interp_p%delta(3) + Nx = p%WaveField%GridParams%n(2) + Ny = p%WaveField%GridParams%n(3) + dx = p%WaveField%GridParams%delta(2) + dy = p%WaveField%GridParams%delta(3) call SetErrStat(ErrID_Info,"Setting wavefield visualization grid to "//trim(Num2LStr(Nx))//" x "//trim(Num2LStr(Ny))//"points",ErrStat3,ErrMsg3,RoutineName) elseif ((InitInp%SurfaceVisNx < 3) .or. (InitInp%SurfaceVisNx < 3)) then ! Set to 3 for minimum Nx = 3 @@ -500,31 +422,19 @@ subroutine SurfaceVisGenerate(ErrStat3, ErrMsg3) InitOut%WaveElevVisY(i2) = -HWidY + real(i2-1,SiKi)*dy enddo -!FIXME: calculate from the FFT of the data. + !TODO: sometime in the future, we might want larger grids than is stored in the WaveField. When + ! we want that, we will need to add a WaveField routine to generate for arbitrary points from an + ! FFT of the whole complex series. do it = 0,size(p%WaveField%WaveTime)-1 do i1 = 1, nx loc(1) = InitOut%WaveElevVisX(i1) do i2 = 1, ny loc(2) = InitOut%WaveElevVisX(i2) - InitOut%WaveElevVisGrid(it,i1,i2) = SeaSt_Interp_3D( real(p%WaveField%WaveTime(it),DbKi), real(loc,ReKi), p%WaveField%WaveElev1, p%WaveField%seast_interp_p, m%seast_interp_m%FirstWarn_Clamp, ErrStat4, ErrMsg4 ) + InitOut%WaveElevVisGrid(it,i1,i2) = WaveField_GetNodeTotalWaveElev(p%WaveField, m%WaveField_m, real(p%WaveField%WaveTime(it),DbKi), real(loc,ReKi), ErrStat4, ErrMsg4 ) call SetErrStat( ErrStat4, ErrMsg4, ErrStat3, ErrMsg3, RoutineName ) enddo end do end do - - if (allocated(p%WaveField%WaveElev2)) then - do it = 0,size(p%WaveField%WaveTime)-1 - do i1 = 1, nx - loc(1) = InitOut%WaveElevVisX(i1) - do i2 = 1, ny - loc(2) = InitOut%WaveElevVisX(i2) - TmpElev = SeaSt_Interp_3D( real(p%WaveField%WaveTime(it),DbKi), real(loc,ReKi), p%WaveField%WaveElev2, p%WaveField%seast_interp_p, m%seast_interp_m%FirstWarn_Clamp, ErrStat4, ErrMsg4 ) - call SetErrStat( ErrStat4, ErrMsg4, ErrStat3, ErrMsg3, RoutineName ) - InitOut%WaveElevVisGrid(it,i1,i2) = InitOut%WaveElevVisGrid(it,i1,i2) + TmpElev - end do - end do - end do - end if end subroutine SurfaceVisGenerate END SUBROUTINE SeaSt_Init @@ -764,7 +674,7 @@ SUBROUTINE SeaSt_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, ErrStat, Er DO i = 1, p%NWaveKin positionXYZ = (/p%WaveKinxi(i),p%WaveKinyi(i),p%WaveKinzi(i)/) - CALL WaveField_GetNodeWaveKin( p%WaveField, m%seast_interp_m, Time, positionXYZ, .FALSE., nodeInWater, zeta1, zeta2, zeta, WaveDynP(i), WaveVel(:,i), WaveAcc(:,i), WaveAccMCF(:,i), ErrStat2, ErrMsg2 ) + CALL WaveField_GetNodeWaveKin( p%WaveField, m%WaveField_m, Time, positionXYZ, .FALSE., nodeInWater, zeta1, zeta2, zeta, WaveDynP(i), WaveVel(:,i), WaveAcc(:,i), WaveAccMCF(:,i), ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END DO @@ -772,9 +682,9 @@ SUBROUTINE SeaSt_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, ErrStat, Er DO i = 1, p%NWaveElev positionXY = (/p%WaveElevxi(i),p%WaveElevyi(i)/) - WaveElev1(i) = WaveField_GetNodeWaveElev1( p%WaveField, m%SeaSt_Interp_m, Time, positionXY, ErrStat2, ErrMsg2 ) + WaveElev1(i) = WaveField_GetNodeWaveElev1( p%WaveField, m%WaveField_m, Time, positionXY, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - WaveElev2(i) = WaveField_GetNodeWaveElev2( p%WaveField, m%SeaSt_Interp_m, Time, positionXY, ErrStat2, ErrMsg2 ) + WaveElev2(i) = WaveField_GetNodeWaveElev2( p%WaveField, m%WaveField_m, Time, positionXY, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) WaveElev(i) = WaveElev1(i) + WaveElev2(i) END DO diff --git a/modules/seastate/src/SeaState.txt b/modules/seastate/src/SeaState.txt index 1ef0d93440..455938b537 100644 --- a/modules/seastate/src/SeaState.txt +++ b/modules/seastate/src/SeaState.txt @@ -17,7 +17,6 @@ include Registry_NWTC_Library.txt usefrom Current.txt usefrom Waves.txt usefrom Waves2.txt -usefrom SeaState_Interp.txt usefrom SeaSt_WaveField.txt # # @@ -92,7 +91,7 @@ typedef ^ ^ CHARACTER(ChanLen) Wri typedef ^ ^ ProgDesc Ver - - - "Version of SeaState" typedef ^ ^ LOGICAL InvalidWithSSExctn - - - "Whether SeaState configuration is invalid with HydroDyn's state-space excitation (ExctnMod=2)" (-) typedef ^ ^ SiKi WaveElevVisX {:} - - "X locations of grid output" "m,-" -typedef ^ ^ SiKi WaveElevVisY {:} - - "X locations of grid output" "m,-" +typedef ^ ^ SiKi WaveElevVisY {:} - - "Y locations of grid output" "m,-" typedef ^ ^ SiKi WaveElevVisGrid {:}{:}{:} - - "Wave elevation time-series at each of the points given by WaveElevXY. First dimension is the timestep. Second/third dimensions are the grid of points." (m) typedef ^ ^ SeaSt_WaveFieldType *WaveField - - - "Pointer to wave field" @@ -120,7 +119,7 @@ typedef ^ OtherStateType R8Ki Unu typedef ^ MiscVarType INTEGER Decimate - - - "The output decimation counter" - typedef ^ ^ DbKi LastOutTime - - - "Last time step which was written to the output file (sec)" - typedef ^ ^ INTEGER LastIndWave - - - "The last index used in the wave kinematics arrays, used to optimize interpolation" - -typedef ^ ^ SeaSt_Interp_MiscVarType SeaSt_Interp_m - - - "misc var information from the SeaState Interpolation module" - +typedef ^ ^ SeaSt_WaveField_MiscVarType WaveField_m - - - "misc var information from the SeaState Interpolation module" - # ..... Parameters ................................................................................................................ # Define parameters here: diff --git a/modules/seastate/src/SeaState_Interp.f90 b/modules/seastate/src/SeaState_Interp.f90 deleted file mode 100644 index 143ad80180..0000000000 --- a/modules/seastate/src/SeaState_Interp.f90 +++ /dev/null @@ -1,715 +0,0 @@ -!> This module is an interpolator for SeaState pointer arrays based on a 3D grid and time. -!! @note This module does not need to exactly conform to the FAST Modularization Framework standards. Three routines are required -!! though: -!! -- SeaSt_Interp_Init -- Load or create any wind data. Only called at the start of FAST. -!! -- SeaSt_Interp_CalcOutput -- This will be called at each timestep with a series of data points to give the wave kinematics. -!! -- SeaSt_Interp_End -- clear out any stored stuff. Only called at the end of FAST. -MODULE SeaState_Interp -!********************************************************************************************************************************** -! LICENSING -! Copyright (C) 2016 National Renewable Energy Laboratory -! -! This file is part of SeaState. -! -! 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. -! -!********************************************************************************************************************************** - - USE NWTC_Library - USE SeaState_Interp_Types - - IMPLICIT NONE - PRIVATE - - TYPE(ProgDesc), PARAMETER :: SeaSt_Interp_Ver = ProgDesc( 'SeaSt_Interp', '', '' ) - - PUBLIC :: SeaSt_Interp_Init - PUBLIC :: SeaSt_Interp_End - PUBLIC :: SeaSt_Interp_3D - PUBLIC :: SeaSt_Interp_3D_Vec - PUBLIC :: SeaSt_Interp_3D_Vec6 - PUBLIC :: SeaSt_Interp_4D - PUBLIC :: SeaSt_Interp_4D_Vec - PUBLIC :: SeaSt_Interp_Setup - -CONTAINS - -!==================================================================================================== - -!---------------------------------------------------------------------------------------------------- -!> A subroutine to initialize the SeaState 4D interpolator module. -!---------------------------------------------------------------------------------------------------- -SUBROUTINE SeaSt_Interp_Init(InitInp, p, ErrStat, ErrMsg) - - - IMPLICIT NONE - - ! Passed Variables - - TYPE(SeaSt_Interp_InitInputType), INTENT(IN ) :: InitInp !< Input data for initialization - TYPE(SeaSt_Interp_ParameterType), INTENT( OUT) :: p !< Parameters - ! TYPE(SeaSt_Interp_InitOutputType), INTENT( OUT) :: InitOut !< Initial output - - ! REAL(DbKi), INTENT(IN ) :: Interval !< Do not change this!! - - - - ! Error handling - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< determines if an error has been encountered - CHARACTER(*), INTENT( OUT) :: ErrMsg !< A message about the error. See NWTC_Library info for ErrID_* levels. - - ! local variables - ! Put local variables used during initializing your wind here. DO NOT USE GLOBAL VARIABLES EVER! - ! INTEGER(IntKi) :: UnitWind ! Use this unit number if you need to read in a file. - - ! Temporary variables for error handling -! INTEGER(IntKi) :: ErrStat2 ! Temp variable for the error status -! CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary error message - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_Init' - - !------------------------------------------------------------------------------------------------- - ! Set the Error handling variables - !------------------------------------------------------------------------------------------------- - - ErrStat = ErrID_None - ErrMsg = "" - - - !------------------------------------------------------------------------------------------------- - ! Copy things from the InitData to the ParamData. - !------------------------------------------------------------------------------------------------- - p%n = InitInp%n ! number of points on the evenly-spaced grid (in each direction) - p%delta = InitInp%delta ! distance between consecutive grid points in each direction (s,m,m,m) - p%pZero = InitInp%pZero ! fixed location of first time-XYZ grid point (i.e., XYZ coordinates of m%V(:,1,1,1,:)) - p%Z_Depth = InitInp%Z_Depth - - - !------------------------------------------------------------------------------------------------- - ! Set the InitOutput information. Set any outputs here. - !------------------------------------------------------------------------------------------------- - - ! InitOut%Ver = SeaSt_Interp_Ver - - RETURN - -END SUBROUTINE SeaSt_Interp_Init - -!==================================================================================================== - - -subroutine SetCartesianXYIndex(p, pZero, delta, nMax, Indx_Lo, Indx_Hi, isopc, FirstWarn, ErrStat, ErrMsg) - REAL(ReKi), INTENT(IN ) :: p !< - REAL(ReKi), INTENT(IN ) :: pZero - REAL(ReKi), INTENT(IN ) :: delta - INTEGER(IntKi), INTENT(in ) :: nMax - INTEGER(IntKi), intent(inout) :: Indx_Lo - INTEGER(IntKi), intent(inout) :: Indx_Hi - real(SiKi), intent(inout) :: isopc - logical, intent(inout) :: FirstWarn - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - real(ReKi) :: Tmp - - ErrStat = ErrID_None - ErrMsg = "" - - isopc = -1.0 - Indx_Lo = 0 - Indx_Hi = 0 - - - Tmp = (p-pZero) / delta - Indx_Lo = INT( Tmp ) + 1 ! convert REAL to INTEGER, then add one since our grid indices start at 1, not 0 - isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo - 1, ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 - - if ( Indx_Lo < 1 ) then - Indx_Lo = 1 - isopc = -1.0 - if (FirstWarn) then - call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianXYIndex') !error out if time is outside the lower bounds - FirstWarn = .false. - end if - end if - - Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, zero-based - - if ( Indx_Lo >= Indx_Hi ) then - ! Need to clamp to grid boundary - if (FirstWarn .and. Indx_Lo /= Indx_Hi) then ! don't warn if we are exactly at the boundary - call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianXYIndex') !error out if time is outside the lower bounds - FirstWarn = .false. - end if - Indx_Lo = max(Indx_Hi - 1, 1) - isopc = 1.0 - end if - - - - !------------------------------------------------------------------------------------------------- - ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) - !------------------------------------------------------------------------------------------------- - isopc = min( 1.0_SiKi, isopc ) - isopc = max(-1.0_SiKi, isopc ) - - -end subroutine SetCartesianXYIndex - -subroutine SetCartesianZIndex(p, z_depth, delta, nMax, Indx_Lo, Indx_Hi, isopc, FirstWarn, ErrStat, ErrMsg) - REAL(ReKi), INTENT(IN ) :: p !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: z_depth - REAL(ReKi), INTENT(IN ) :: delta - INTEGER(IntKi), INTENT(in ) :: nMax - INTEGER(IntKi), intent(inout) :: Indx_Lo - INTEGER(IntKi), intent(inout) :: Indx_Hi - real(SiKi), intent(inout) :: isopc - logical, intent(inout) :: FirstWarn - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - real(ReKi) :: Tmp - - ErrStat = ErrID_None - ErrMsg = "" - - isopc = -1.0 - Indx_Lo = 0 - Indx_Hi = 0 - - - !Tmp = acos(-p / z_depth) / delta - Tmp = acos( max(-1.0_ReKi, min(1.0_ReKi, 1+(p / z_depth)) ) ) / delta - Tmp = nmax - 1 - Tmp - Indx_Lo = INT( Tmp ) + 1 ! convert REAL to INTEGER, then add one since our grid indices start at 1, not 0 - isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo - 1, ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 - - if ( Indx_Lo < 1 ) then - Indx_Lo = 1 - isopc = -1.0 - if (FirstWarn) then - call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianZIndex') !error out if z is outside the lower bounds - FirstWarn = .false. - end if - end if - - Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, one-based - - if ( Indx_Lo >= Indx_Hi ) then - ! Need to clamp to grid boundary - if (FirstWarn .and. Indx_Lo /= Indx_Hi) then ! don't warn if we are exactly at the boundary - call SetErrStat(ErrID_Warn,'Position has been clamped to the grid boundary. Warning will not be repeated though condition may persist.',ErrStat,ErrMsg,'SetCartesianZIndex') !error out if z is outside the upper bounds - FirstWarn = .false. - end if - Indx_Lo = max(Indx_Hi - 1, 1) - isopc = 1.0 - end if - - - !------------------------------------------------------------------------------------------------- - ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) - !------------------------------------------------------------------------------------------------- - isopc = min( 1.0_SiKi, isopc ) - isopc = max(-1.0_SiKi, isopc ) - - -end subroutine SetCartesianZIndex - -subroutine SetTimeIndex(Time, deltaT, nMax, Indx_Lo, Indx_Hi, isopc, ErrStat, ErrMsg) - REAL(DbKi), INTENT(IN ) :: Time !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: deltaT - INTEGER(IntKi), INTENT(in ) :: nMax - INTEGER(IntKi), intent(inout) :: Indx_Lo - INTEGER(IntKi), intent(inout) :: Indx_Hi - real(SiKi), intent(inout) :: isopc - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - real(ReKi) :: Tmp - - ErrStat = ErrID_None - ErrMsg = "" - - isopc = -1.0 - Indx_Lo = 0 - Indx_Hi = 0 - if ( Time < 0.0_DbKi ) then - CALL SetErrStat(ErrID_Fatal,'Time value must be greater than or equal to zero!',ErrStat,ErrMsg,'SetTimeLoIndex') !error out if time is outside the lower bounds - RETURN - end if - -! NOTE: nMax is the total number of time values in the grid, since this is zero-based indexing, the max index is nMax-1 -! for example: in a time grid with 11 grid points, the indices run from 0,1,2,3,4,5,6,7,8,9,10 -! for the repeating waves feature, index 10 is the same as index 0, so if Indx_Lo = 10 then we want to -! wrap it back to index 0, if Indx_Lo = 11 we want to wrap back to index 1. - - Tmp = real( (Time/ real(deltaT,DbKi)) ,ReKi) - Tmp = MOD(Tmp,real((nMax), ReKi)) - Indx_Lo = INT( Tmp ) ! convert REAL to INTEGER - - isopc = 2.0_ReKi * (Tmp - REAL(Indx_Lo , ReKi)) - 1.0_ReKi ! convert to value between -1 and 1 - - !------------------------------------------------------------------------------------------------- - ! to verify that we don't extrapolate, make sure isopc is bound between -1 and 1 (effectively nearest neighbor) - !------------------------------------------------------------------------------------------------- - isopc = min( 1.0_SiKi, isopc ) - isopc = max(-1.0_SiKi, isopc ) - - Indx_Hi = min( Indx_Lo + 1, nMax ) ! make sure it's a valid index, zero-based - -end subroutine SetTimeIndex - - -!==================================================================================================== -!> This routine sets up interpolation of a 3-d or 4-d dataset. -!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf -subroutine SeaSt_Interp_Setup( Time, Position, p, m, ErrStat, ErrMsg ) - - ! I/O variables - - REAL(DbKi), INTENT(IN ) :: Time !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: Position(3) !< Array of XYZ coordinates, 3 - TYPE(SeaSt_Interp_ParameterType), INTENT(IN ) :: p !< Parameters - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: m !< MiscVars - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_Setup' - - ! Local variables - - INTEGER(IntKi) :: i ! loop counter - - REAL(SiKi) :: isopc(4) ! isoparametric coordinates - - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - - ErrStat = ErrID_None - ErrMsg = "" - - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for time - !------------------------------------------------------------------------------------------------- - call SetTimeIndex(Time, p%delta(1), p%n(1), m%Indx_Lo(1), m%Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if time is outside the bounds - if (ErrStat >= AbortErrLev ) return - - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for XY position - !------------------------------------------------------------------------------------------------- - do i=2,3 ! x and y components - call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), m%Indx_Lo(i), m%Indx_Hi(i), isopc(i), m%FirstWarn_Clamp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if x,y is outside the bounds - enddo - - - if (ErrStat >= AbortErrLev ) return - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for Z position - !------------------------------------------------------------------------------------------------- - i=4 ! z component - call SetCartesianZIndex(Position(i-1), p%Z_Depth, p%delta(i), p%n(i), m%Indx_Lo(i), m%Indx_Hi(i), isopc(i), m%FirstWarn_Clamp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if z is outside the bounds - if (ErrStat >= AbortErrLev ) return - - !------------------------------------------------------------------------------------------------- - ! compute weighting factors - !------------------------------------------------------------------------------------------------- - - m%N4D( 1) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D( 2) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D( 3) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D( 4) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D( 5) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D( 6) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D( 7) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D( 8) = ( 1.0_SiKi - isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D( 9) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D(10) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D(11) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D(12) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi - isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D(13) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D(14) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi - isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D(15) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi - isopc(4) ) - m%N4D(16) = ( 1.0_SiKi + isopc(1) ) * ( 1.0_SiKi + isopc(2) ) * ( 1.0_SiKi + isopc(3) ) * ( 1.0_SiKi + isopc(4) ) - m%N4D = m%N4D / REAL( SIZE(m%N4D), SiKi ) ! normalize - - -END Subroutine SeaSt_Interp_Setup - -!==================================================================================================== -!> This routine interpolates a 4-d dataset. -!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf -FUNCTION SeaSt_Interp_4D( pKinXX, m, ErrStat, ErrMsg ) - - ! I/O variables - - real(SiKi), intent(in ) :: pKinXX(0:,:,:,:) - TYPE(SeaSt_Interp_MiscVarType), INTENT(IN ) :: m !< Parameters - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_PointSetup' - Real(SiKi) :: SeaSt_Interp_4D - ! Local variables - - REAL(SiKi) :: u(16) ! size 2^n - - - SeaSt_Interp_4D = 0.0_SiKi - ErrStat = ErrID_None - ErrMsg = "" - - !------------------------------------------------------------------------------------------------- - ! interpolate - !------------------------------------------------------------------------------------------------- - - u( 1) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4) ) - u( 2) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4) ) - u( 3) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4) ) - u( 4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4) ) - u( 5) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4) ) - u( 6) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4) ) - u( 7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4) ) - u( 8) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4) ) - u( 9) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4) ) - u(10) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4) ) - u(11) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4) ) - u(12) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4) ) - u(13) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4) ) - u(14) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4) ) - u(15) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4) ) - u(16) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4) ) - - SeaSt_Interp_4D = SUM ( m%N4D * u ) - -END FUNCTION SeaSt_Interp_4D - -!==================================================================================================== -!> This routine interpolates a 4-d dataset. -!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf -FUNCTION SeaSt_Interp_4D_Vec( pKinXX, m, ErrStat, ErrMsg ) - - ! I/O variables - - real(SiKi), intent(in ) :: pKinXX(0:,:,:,:,:) - TYPE(SeaSt_Interp_MiscVarType), INTENT(IN ) :: m !< misc vars for interpolation - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_PointSetup' - Real(SiKi) :: SeaSt_Interp_4D_Vec(3) - ! Local variables - - REAL(SiKi) :: u(16) ! size 2^n - integer(IntKi) :: iDir - - SeaSt_Interp_4D_Vec = 0.0_SiKi - ErrStat = ErrID_None - ErrMsg = "" - - !------------------------------------------------------------------------------------------------- - ! interpolate - !------------------------------------------------------------------------------------------------- - do iDir = 1,3 - u( 1) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) - u( 2) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) - u( 3) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) - u( 4) = pKinXX( m%Indx_Lo(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) - u( 5) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) - u( 6) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) - u( 7) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) - u( 8) = pKinXX( m%Indx_Lo(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) - u( 9) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) - u(10) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) - u(11) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) - u(12) = pKinXX( m%Indx_Hi(1), m%Indx_Lo(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) - u(13) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Lo(4), iDir ) - u(14) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Lo(3), m%Indx_Hi(4), iDir ) - u(15) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Lo(4), iDir ) - u(16) = pKinXX( m%Indx_Hi(1), m%Indx_Hi(2), m%Indx_Hi(3), m%Indx_Hi(4), iDir ) - - SeaSt_Interp_4D_Vec(iDir) = SUM ( m%N4D * u ) - end do -END FUNCTION SeaSt_Interp_4D_Vec - - !==================================================================================================== -!> This routine interpolates a 3-d dataset with index 1 = time (zero-based indexing), 2 = x-coordinate (1-based indexing), 3 = y-coordinate (1-based indexing) -!! This method is described here: http://rjwagner49.com/Mathematics/Interpolation.pdf -FUNCTION SeaSt_Interp_3D( Time, Position, pKinXX, p, FirstWarn_Clamp, ErrStat, ErrMsg ) - - ! I/O variables - REAL(DbKi), INTENT(IN ) :: Time !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: Position(2) !< Array of XYZ coordinates, 3 - real(SiKi), intent(in ) :: pKinXX(0:,:,:) !< 3D Wave elevation data (SiKi for storage space reasons) - TYPE(SeaSt_Interp_ParameterType), INTENT(IN ) :: p !< Parameters - logical, INTENT(INOUT) :: FirstWarn_Clamp !< first warning - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_3D' - Real(SiKi) :: SeaSt_Interp_3D - ! Local variables - - REAL(SiKi) :: u(8) ! size 2^n - real(ReKi) :: N3D(8) - integer(IntKi) :: Indx_Lo(3), Indx_Hi(3) - INTEGER(IntKi) :: i ! loop counter - REAL(SiKi) :: isopc(3) ! isoparametric coordinates - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - - SeaSt_Interp_3D = 0.0_SiKi - ErrStat = ErrID_None - ErrMsg = "" - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for time - !------------------------------------------------------------------------------------------------- - call SetTimeIndex(Time, p%delta(1), p%n(1), Indx_Lo(1), Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if time is outside the bounds - if (ErrStat >= AbortErrLev ) return - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for XY position - !------------------------------------------------------------------------------------------------- - do i=2,3 - call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), Indx_Lo(i), Indx_Hi(i), isopc(i), FirstWarn_Clamp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if x,y is outside the bounds - end do - if (ErrStat >= AbortErrLev ) return - - - - N3D(1) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(2) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(3) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(4) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(5) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(6) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(7) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(8) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D = N3D / REAL( SIZE(N3D), ReKi ) ! normalize - - !------------------------------------------------------------------------------------------------- - ! interpolate - !------------------------------------------------------------------------------------------------- - - u(1) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Lo(3) ) - u(2) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Lo(3) ) - u(3) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Lo(3) ) - u(4) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Lo(3) ) - u(5) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Hi(3) ) - u(6) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Hi(3) ) - u(7) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Hi(3) ) - u(8) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Hi(3) ) - - SeaSt_Interp_3D = SUM ( N3D * u ) - -END FUNCTION SeaSt_Interp_3D - -FUNCTION SeaSt_Interp_3D_VEC ( Time, Position, pKinXX, p, FirstWarn_Clamp, ErrStat, ErrMsg ) - ! I/O variables - REAL(DbKi), INTENT(IN ) :: Time !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: Position(2) !< Array of XYZ coordinates, 3 - real(SiKi), INTENT(in ) :: pKinXX(0:,:,:,:) !< 3D Wave excitation data (SiKi for storage space reasons) - TYPE(SeaSt_Interp_ParameterType), INTENT(IN ) :: p !< Parameters - LOGICAL, INTENT(INOUT) :: FirstWarn_Clamp !< first warning - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_3D_VEC' - Real(SiKi) :: SeaSt_Interp_3D_VEC(3) - ! Local variables - - REAL(SiKi) :: u(8) ! size 2^n - real(ReKi) :: N3D(8) - integer(IntKi) :: Indx_Lo(3), Indx_Hi(3) - INTEGER(IntKi) :: i ! loop counter - REAL(SiKi) :: isopc(3) ! isoparametric coordinates - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - - SeaSt_Interp_3D_VEC = 0.0_SiKi - ErrStat = ErrID_None - ErrMsg = "" - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for time - !------------------------------------------------------------------------------------------------- - call SetTimeIndex(Time, p%delta(1), p%n(1), Indx_Lo(1), Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if time is outside the bounds - if (ErrStat >= AbortErrLev ) return - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for XY position - !------------------------------------------------------------------------------------------------- - do i=2,3 - call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), Indx_Lo(i), Indx_Hi(i), isopc(i), FirstWarn_Clamp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if x,y is outside the bounds - end do - if (ErrStat >= AbortErrLev ) return - - - - N3D(1) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(2) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(3) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(4) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(5) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(6) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(7) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(8) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D = N3D / REAL( SIZE(N3D), ReKi ) ! normalize - - !------------------------------------------------------------------------------------------------- - ! interpolate - !------------------------------------------------------------------------------------------------- - do i = 1,3 - u(1) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Lo(3), i ) - u(2) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Lo(3), i ) - u(3) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Lo(3), i ) - u(4) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Lo(3), i ) - u(5) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Hi(3), i ) - u(6) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Hi(3), i ) - u(7) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Hi(3), i ) - u(8) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Hi(3), i ) - - SeaSt_Interp_3D_VEC(i) = SUM ( N3D * u ) - end do -END FUNCTION SeaSt_Interp_3D_VEC - -FUNCTION SeaSt_Interp_3D_VEC6 ( Time, Position, pKinXX, p, FirstWarn_Clamp, ErrStat, ErrMsg ) - ! I/O variables - REAL(DbKi), INTENT(IN ) :: Time !< time from the start of the simulation - REAL(ReKi), INTENT(IN ) :: Position(2) !< Array of XYZ coordinates, 3 - real(SiKi), INTENT(in ) :: pKinXX(0:,:,:,:) !< 3D Wave excitation data (SiKi for storage space reasons) - TYPE(SeaSt_Interp_ParameterType), INTENT(IN ) :: p !< Parameters - LOGICAL, INTENT(INOUT) :: FirstWarn_Clamp !< first warning - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - - CHARACTER(*), PARAMETER :: RoutineName = 'SeaSt_Interp_3D' - Real(SiKi) :: SeaSt_Interp_3D_VEC6(6) - ! Local variables - - REAL(SiKi) :: u(8) ! size 2^n - real(ReKi) :: N3D(8) - integer(IntKi) :: Indx_Lo(3), Indx_Hi(3) - INTEGER(IntKi) :: i ! loop counter - REAL(SiKi) :: isopc(3) ! isoparametric coordinates - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - - SeaSt_Interp_3D_VEC6 = 0.0_SiKi - ErrStat = ErrID_None - ErrMsg = "" - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for time - !------------------------------------------------------------------------------------------------- - call SetTimeIndex(Time, p%delta(1), p%n(1), Indx_Lo(1), Indx_Hi(1), isopc(1), ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if time is outside the bounds - if (ErrStat >= AbortErrLev ) return - - !------------------------------------------------------------------------------------------------- - ! Find the bounding indices for XY position - !------------------------------------------------------------------------------------------------- - do i=2,3 - call SetCartesianXYIndex(Position(i-1), p%pZero(i), p%delta(i), p%n(i), Indx_Lo(i), Indx_Hi(i), isopc(i), FirstWarn_Clamp, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !warning if x,y is outside the bounds - end do - if (ErrStat >= AbortErrLev ) return - - - - N3D(1) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(2) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(3) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(4) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi - isopc(3) ) - N3D(5) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(6) = ( 1.0_ReKi + isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(7) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi + isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D(8) = ( 1.0_ReKi - isopc(1) )*( 1.0_ReKi - isopc(2) )*( 1.0_ReKi + isopc(3) ) - N3D = N3D / REAL( SIZE(N3D), ReKi ) ! normalize - - !------------------------------------------------------------------------------------------------- - ! interpolate - !------------------------------------------------------------------------------------------------- - do i = 1,6 - u(1) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Lo(3), i ) - u(2) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Lo(3), i ) - u(3) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Lo(3), i ) - u(4) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Lo(3), i ) - u(5) = pKinXX( Indx_Hi(1), Indx_Lo(2), Indx_Hi(3), i ) - u(6) = pKinXX( Indx_Hi(1), Indx_Hi(2), Indx_Hi(3), i ) - u(7) = pKinXX( Indx_Lo(1), Indx_Hi(2), Indx_Hi(3), i ) - u(8) = pKinXX( Indx_Lo(1), Indx_Lo(2), Indx_Hi(3), i ) - - SeaSt_Interp_3D_VEC6(i) = SUM ( N3D * u ) - end do -END FUNCTION SeaSt_Interp_3D_VEC6 -!---------------------------------------------------------------------------------------------------- -!> This routine deallocates any memory in the FDext module. -SUBROUTINE SeaSt_Interp_End( ParamData, MiscVars, ErrStat, ErrMsg) - - - IMPLICIT NONE - - CHARACTER(*), PARAMETER :: RoutineName="SeaSt_Interp_End" - - - ! Passed Variables - TYPE(SeaSt_Interp_ParameterType), INTENT(INOUT) :: ParamData !< Parameters - TYPE(SeaSt_Interp_MiscVarType), INTENT(INOUT) :: MiscVars !< Misc variables for optimization (not copied in glue code) - - - ! Error Handling - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< determines if an error has been encountered - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Message about errors - - - ! Local Variables - INTEGER(IntKi) :: TmpErrStat ! temporary error status - CHARACTER(ErrMsgLen) :: TmpErrMsg ! temporary error message - - - ErrMsg = '' - ErrStat = ErrID_None - - - - ! Destroy parameter data - - CALL SeaSt_Interp_DestroyParam( ParamData, TmpErrStat, TmpErrMsg ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - - ! Destroy the misc data - - CALL SeaSt_Interp_DestroyMisc( MiscVars, TmpErrStat, TmpErrMsg ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - -END SUBROUTINE SeaSt_Interp_End -!==================================================================================================== -END MODULE SeaState_Interp diff --git a/modules/seastate/src/SeaState_Interp.txt b/modules/seastate/src/SeaState_Interp.txt deleted file mode 100644 index 5f12cd5a6a..0000000000 --- a/modules/seastate/src/SeaState_Interp.txt +++ /dev/null @@ -1,42 +0,0 @@ -################################################################################################################################### -# Registry for SeaState_Interp, creates MODULE SeaState_Interp_Types -# Module SeaState_Interp_Types contains all of the user-defined types needed in SeaState_Interp. It also contains copy, destroy, pack, and -# unpack routines associated with each defined data types. -################################################################################################################################### -# Entries are of the form -# keyword -################################################################################################################################### - -include Registry_NWTC_Library.txt - - -######################### - -typedef SeaState_Interp/SeaSt_Interp InitInputType IntKi n 4 - - "number of grid points in the t, x, y, and z directions" - -typedef ^ InitInputType ReKi delta 4 - - "size between 2 consecutive grid points in each grid direction (time, x, y, z)" "s,m,m,m" -typedef ^ InitInputType ReKi pZero 4 - - "fixed position of the time-X-Y-Z grid (i.e., XYZ coordinates of m%V(:,1,1,1,:))" "m" -typedef ^ InitInputType ReKi Z_Depth - - - "grid depth" m - -# Init Output -typedef ^ InitOutputType ProgDesc Ver - - - "Version information of this submodule" - - - -# ..... Misc/Optimization variables................................................................................................. -# Define any data that are used only for efficiency purposes (these variables are not associated with time): -# e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. -typedef ^ MiscVarType SiKi N3D {8} - - "this is the weighting function for 3-d velocity field" - -typedef ^ MiscVarType SiKi N4D {16} - - "this is the weighting function for 4-d velocity field" - -typedef ^ MiscVarType integer Indx_Lo 4 - - "this is the index into the 4-d velocity field for each wave component" - -typedef ^ MiscVarType integer Indx_Hi 4 - - "this is the index into the 4-d velocity field for each wave component" - -typedef ^ MiscVarType logical FirstWarn_Clamp - .true. - "used to avoid too many 'Position has been clamped to the grid boundary' warning messages " - - -# ..... Parameters ................................................................................................................ -# Define parameters here: -# Time step for integration of continuous states (if a fixed-step integrator is used) and update of discrete states: -typedef ^ ParameterType IntKi n 4 - - "number of evenly-spaced grid points in the t, x, y, and z directions" - -typedef ^ ParameterType ReKi delta 4 - - "size between 2 consecutive grid points in each grid direction" "s,m,m,m" -typedef ^ ParameterType ReKi pZero 4 - - "fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:))" "m" -typedef ^ ParameterType ReKi Z_Depth - - - "grid depth" m - - - diff --git a/modules/seastate/src/SeaState_Interp_Types.f90 b/modules/seastate/src/SeaState_Interp_Types.f90 deleted file mode 100644 index 3322b030fc..0000000000 --- a/modules/seastate/src/SeaState_Interp_Types.f90 +++ /dev/null @@ -1,258 +0,0 @@ -!STARTOFREGISTRYGENERATEDFILE 'SeaState_Interp_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 -!********************************************************************************************************************************* -! SeaState_Interp_Types -!................................................................................................................................. -! This file is part of SeaState_Interp. -! -! Copyright (C) 2012-2016 National Renewable Energy Laboratory -! -! 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. -! -! -! 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 SeaState_Interp. 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 SeaState_Interp_Types -!--------------------------------------------------------------------------------------------------------------------------------- -USE NWTC_Library -IMPLICIT NONE -! ========= SeaSt_Interp_InitInputType ======= - TYPE, PUBLIC :: SeaSt_Interp_InitInputType - INTEGER(IntKi) , DIMENSION(1:4) :: n = 0_IntKi !< number of grid points in the t, x, y, and z directions [-] - REAL(ReKi) , DIMENSION(1:4) :: delta = 0.0_ReKi !< size between 2 consecutive grid points in each grid direction (time, x, y, z) [s,m,m,m] - REAL(ReKi) , DIMENSION(1:4) :: pZero = 0.0_ReKi !< fixed position of the time-X-Y-Z grid (i.e., XYZ coordinates of m%V(:,1,1,1,:)) [m] - REAL(ReKi) :: Z_Depth = 0.0_ReKi !< grid depth [m] - END TYPE SeaSt_Interp_InitInputType -! ======================= -! ========= SeaSt_Interp_InitOutputType ======= - TYPE, PUBLIC :: SeaSt_Interp_InitOutputType - TYPE(ProgDesc) :: Ver !< Version information of this submodule [-] - END TYPE SeaSt_Interp_InitOutputType -! ======================= -! ========= SeaSt_Interp_MiscVarType ======= - TYPE, PUBLIC :: SeaSt_Interp_MiscVarType - REAL(SiKi) , DIMENSION(1:8) :: N3D = 0.0_R4Ki !< this is the weighting function for 3-d velocity field [-] - REAL(SiKi) , DIMENSION(1:16) :: N4D = 0.0_R4Ki !< this is the weighting function for 4-d velocity field [-] - INTEGER(IntKi) , DIMENSION(1:4) :: Indx_Lo = 0_IntKi !< this is the index into the 4-d velocity field for each wave component [-] - INTEGER(IntKi) , DIMENSION(1:4) :: Indx_Hi = 0_IntKi !< this is the index into the 4-d velocity field for each wave component [-] - LOGICAL :: FirstWarn_Clamp = .true. !< used to avoid too many 'Position has been clamped to the grid boundary' warning messages [-] - END TYPE SeaSt_Interp_MiscVarType -! ======================= -! ========= SeaSt_Interp_ParameterType ======= - TYPE, PUBLIC :: SeaSt_Interp_ParameterType - INTEGER(IntKi) , DIMENSION(1:4) :: n = 0_IntKi !< number of evenly-spaced grid points in the t, x, y, and z directions [-] - REAL(ReKi) , DIMENSION(1:4) :: delta = 0.0_ReKi !< size between 2 consecutive grid points in each grid direction [s,m,m,m] - REAL(ReKi) , DIMENSION(1:4) :: pZero = 0.0_ReKi !< fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:)) [m] - REAL(ReKi) :: Z_Depth = 0.0_ReKi !< grid depth [m] - END TYPE SeaSt_Interp_ParameterType -! ======================= -CONTAINS - -subroutine SeaSt_Interp_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg) - type(SeaSt_Interp_InitInputType), intent(in) :: SrcInitInputData - type(SeaSt_Interp_InitInputType), intent(inout) :: DstInitInputData - integer(IntKi), intent(in ) :: CtrlCode - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_CopyInitInput' - ErrStat = ErrID_None - ErrMsg = '' - DstInitInputData%n = SrcInitInputData%n - DstInitInputData%delta = SrcInitInputData%delta - DstInitInputData%pZero = SrcInitInputData%pZero - DstInitInputData%Z_Depth = SrcInitInputData%Z_Depth -end subroutine - -subroutine SeaSt_Interp_DestroyInitInput(InitInputData, ErrStat, ErrMsg) - type(SeaSt_Interp_InitInputType), intent(inout) :: InitInputData - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_DestroyInitInput' - ErrStat = ErrID_None - ErrMsg = '' -end subroutine - -subroutine SeaSt_Interp_PackInitInput(RF, Indata) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_InitInputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'SeaSt_Interp_PackInitInput' - if (RF%ErrStat >= AbortErrLev) return - call RegPack(RF, InData%n) - call RegPack(RF, InData%delta) - call RegPack(RF, InData%pZero) - call RegPack(RF, InData%Z_Depth) - if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_UnPackInitInput(RF, OutData) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_InitInputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'SeaSt_Interp_UnPackInitInput' - if (RF%ErrStat /= ErrID_None) return - call RegUnpack(RF, OutData%n); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%delta); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%pZero); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%Z_Depth); if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) - type(SeaSt_Interp_InitOutputType), intent(in) :: SrcInitOutputData - type(SeaSt_Interp_InitOutputType), intent(inout) :: DstInitOutputData - integer(IntKi), intent(in ) :: CtrlCode - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'SeaSt_Interp_CopyInitOutput' - ErrStat = ErrID_None - ErrMsg = '' - call NWTC_Library_CopyProgDesc(SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return -end subroutine - -subroutine SeaSt_Interp_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) - type(SeaSt_Interp_InitOutputType), intent(inout) :: InitOutputData - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - integer(IntKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'SeaSt_Interp_DestroyInitOutput' - ErrStat = ErrID_None - ErrMsg = '' - call NWTC_Library_DestroyProgDesc(InitOutputData%Ver, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) -end subroutine - -subroutine SeaSt_Interp_PackInitOutput(RF, Indata) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_InitOutputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'SeaSt_Interp_PackInitOutput' - if (RF%ErrStat >= AbortErrLev) return - call NWTC_Library_PackProgDesc(RF, InData%Ver) - if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_UnPackInitOutput(RF, OutData) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_InitOutputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'SeaSt_Interp_UnPackInitOutput' - if (RF%ErrStat /= ErrID_None) return - call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver -end subroutine - -subroutine SeaSt_Interp_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) - type(SeaSt_Interp_MiscVarType), intent(in) :: SrcMiscData - type(SeaSt_Interp_MiscVarType), intent(inout) :: DstMiscData - integer(IntKi), intent(in ) :: CtrlCode - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_CopyMisc' - ErrStat = ErrID_None - ErrMsg = '' - DstMiscData%N3D = SrcMiscData%N3D - DstMiscData%N4D = SrcMiscData%N4D - DstMiscData%Indx_Lo = SrcMiscData%Indx_Lo - DstMiscData%Indx_Hi = SrcMiscData%Indx_Hi - DstMiscData%FirstWarn_Clamp = SrcMiscData%FirstWarn_Clamp -end subroutine - -subroutine SeaSt_Interp_DestroyMisc(MiscData, ErrStat, ErrMsg) - type(SeaSt_Interp_MiscVarType), intent(inout) :: MiscData - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_DestroyMisc' - ErrStat = ErrID_None - ErrMsg = '' -end subroutine - -subroutine SeaSt_Interp_PackMisc(RF, Indata) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_MiscVarType), intent(in) :: InData - character(*), parameter :: RoutineName = 'SeaSt_Interp_PackMisc' - if (RF%ErrStat >= AbortErrLev) return - call RegPack(RF, InData%N3D) - call RegPack(RF, InData%N4D) - call RegPack(RF, InData%Indx_Lo) - call RegPack(RF, InData%Indx_Hi) - call RegPack(RF, InData%FirstWarn_Clamp) - if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_UnPackMisc(RF, OutData) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_MiscVarType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'SeaSt_Interp_UnPackMisc' - if (RF%ErrStat /= ErrID_None) return - call RegUnpack(RF, OutData%N3D); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%N4D); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%Indx_Lo); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%Indx_Hi); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%FirstWarn_Clamp); if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) - type(SeaSt_Interp_ParameterType), intent(in) :: SrcParamData - type(SeaSt_Interp_ParameterType), intent(inout) :: DstParamData - integer(IntKi), intent(in ) :: CtrlCode - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_CopyParam' - ErrStat = ErrID_None - ErrMsg = '' - DstParamData%n = SrcParamData%n - DstParamData%delta = SrcParamData%delta - DstParamData%pZero = SrcParamData%pZero - DstParamData%Z_Depth = SrcParamData%Z_Depth -end subroutine - -subroutine SeaSt_Interp_DestroyParam(ParamData, ErrStat, ErrMsg) - type(SeaSt_Interp_ParameterType), intent(inout) :: ParamData - integer(IntKi), intent( out) :: ErrStat - character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'SeaSt_Interp_DestroyParam' - ErrStat = ErrID_None - ErrMsg = '' -end subroutine - -subroutine SeaSt_Interp_PackParam(RF, Indata) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_ParameterType), intent(in) :: InData - character(*), parameter :: RoutineName = 'SeaSt_Interp_PackParam' - if (RF%ErrStat >= AbortErrLev) return - call RegPack(RF, InData%n) - call RegPack(RF, InData%delta) - call RegPack(RF, InData%pZero) - call RegPack(RF, InData%Z_Depth) - if (RegCheckErr(RF, RoutineName)) return -end subroutine - -subroutine SeaSt_Interp_UnPackParam(RF, OutData) - type(RegFile), intent(inout) :: RF - type(SeaSt_Interp_ParameterType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'SeaSt_Interp_UnPackParam' - if (RF%ErrStat /= ErrID_None) return - call RegUnpack(RF, OutData%n); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%delta); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%pZero); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%Z_Depth); if (RegCheckErr(RF, RoutineName)) return -end subroutine -END MODULE SeaState_Interp_Types -!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/seastate/src/SeaState_Output.f90 b/modules/seastate/src/SeaState_Output.f90 index b18e2c2726..7e0a6d0ebd 100644 --- a/modules/seastate/src/SeaState_Output.f90 +++ b/modules/seastate/src/SeaState_Output.f90 @@ -273,7 +273,7 @@ SUBROUTINE SeaStOut_WriteWvKinFiles( Rootname, SeaSt_Prog, WaveField, WaveDT, X_ y_gridPts(i+1) = -Y_HalfWidth + deltaGrid(2)*i end do do i = 0, NGrid(3)-1 - z_gridPts(i+1) = - ( 1.0 - cos( real((NGrid(3) - 1) - i, ReKi) * deltaGrid(3) ) ) * WaveField%SeaSt_Interp_p%Z_Depth + z_gridPts(i+1) = - ( 1.0 - cos( real((NGrid(3) - 1) - i, ReKi) * deltaGrid(3) ) ) * WaveField%GridParams%Z_Depth end do ! Write the increments from [0, NStepWave] even though for OpenFAST data, NStepWave = 0, but for arbitrary user data this may not be true. @@ -428,9 +428,9 @@ subroutine SeaStOut_WriteWaveElev0( Rootname, NStepWave, NGrid, WaveElev1, WaveE CHARACTER(*), INTENT( IN ) :: Rootname ! filename including full path, minus any file extension. INTEGER, INTENT( IN ) :: NStepWave ! Number of time steps for the wave kinematics arrays INTEGER, INTENT( IN ) :: NGrid(3) ! Number of grid points for the wave kinematics arrays - REAL(SiKi), pointer, INTENT( IN ) :: WaveElev1 (:,:,: ) ! Instantaneous wave elevations at requested locations - 1st order - REAL(SiKi), pointer, INTENT( IN ) :: WaveElev2 (:,:,: ) ! Instantaneous wave elevations at requested locations - 2nd order - REAL(SiKi), pointer, INTENT( IN ) :: WaveTime (: ) ! The time values for the wave kinematics (time) + REAL(SiKi), allocatable, INTENT( IN ) :: WaveElev1 (:,:,: ) ! Instantaneous wave elevations at requested locations - 1st order + REAL(SiKi), allocatable, INTENT( IN ) :: WaveElev2 (:,:,: ) ! Instantaneous wave elevations at requested locations - 2nd order + REAL(SiKi), allocatable, INTENT( IN ) :: WaveTime (: ) ! The time values for the wave kinematics (time) INTEGER, INTENT( OUT ) :: ErrStat ! returns a non-zero value when an error occurs CHARACTER(*), INTENT( OUT ) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -459,12 +459,11 @@ subroutine SeaStOut_WriteWaveElev0( Rootname, NStepWave, NGrid, WaveElev1, WaveE ! Write the increments from [0, NStepWave] even though for OpenFAST data, NStepWave = 0, but for arbitrary user data this may not be true. ! As a result for WaveMod=5,6 we shouldn't assume periodic waves over the period WaveTMax DO m= 0,NStepWave - - if ( associated(WaveElev2) ) then - WRITE(UnWv,Frmt) WaveTime(m), WaveElev1(m,i,j) + WaveElev2(m,i,j) - else - WRITE(UnWv,Frmt) WaveTime(m), WaveElev1(m,i,j) - end if + if ( allocated(WaveElev2) ) then + WRITE(UnWv,Frmt) WaveTime(m), WaveElev1(m,i,j) + WaveElev2(m,i,j) + else + WRITE(UnWv,Frmt) WaveTime(m), WaveElev1(m,i,j) + end if END DO CLOSE( UnWv, IOSTAT=ErrStat ) diff --git a/modules/seastate/src/SeaState_Types.f90 b/modules/seastate/src/SeaState_Types.f90 index f2807fdb04..f5d01aa62e 100644 --- a/modules/seastate/src/SeaState_Types.f90 +++ b/modules/seastate/src/SeaState_Types.f90 @@ -34,7 +34,6 @@ MODULE SeaState_Types USE Current_Types USE Waves_Types USE Waves2_Types -USE SeaState_Interp_Types USE SeaSt_WaveField_Types USE NWTC_Library IMPLICIT NONE @@ -112,7 +111,7 @@ MODULE SeaState_Types TYPE(ProgDesc) :: Ver !< Version of SeaState [-] LOGICAL :: InvalidWithSSExctn = .false. !< Whether SeaState configuration is invalid with HydroDyn's state-space excitation (ExctnMod=2) [(-)] REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: WaveElevVisX !< X locations of grid output [m,-] - REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: WaveElevVisY !< X locations of grid output [m,-] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: WaveElevVisY !< Y locations of grid output [m,-] REAL(SiKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveElevVisGrid !< Wave elevation time-series at each of the points given by WaveElevXY. First dimension is the timestep. Second/third dimensions are the grid of points. [(m)] TYPE(SeaSt_WaveFieldType) , POINTER :: WaveField => NULL() !< Pointer to wave field [-] END TYPE SeaSt_InitOutputType @@ -142,7 +141,7 @@ MODULE SeaState_Types INTEGER(IntKi) :: Decimate = 0_IntKi !< The output decimation counter [-] REAL(DbKi) :: LastOutTime = 0.0_R8Ki !< Last time step which was written to the output file (sec) [-] INTEGER(IntKi) :: LastIndWave = 0_IntKi !< The last index used in the wave kinematics arrays, used to optimize interpolation [-] - TYPE(SeaSt_Interp_MiscVarType) :: SeaSt_Interp_m !< misc var information from the SeaState Interpolation module [-] + TYPE(SeaSt_WaveField_MiscVarType) :: WaveField_m !< misc var information from the SeaState Interpolation module [-] END TYPE SeaSt_MiscVarType ! ======================= ! ========= SeaSt_ParameterType ======= @@ -874,7 +873,7 @@ subroutine SeaSt_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) DstMiscData%Decimate = SrcMiscData%Decimate DstMiscData%LastOutTime = SrcMiscData%LastOutTime DstMiscData%LastIndWave = SrcMiscData%LastIndWave - call SeaSt_Interp_CopyMisc(SrcMiscData%SeaSt_Interp_m, DstMiscData%SeaSt_Interp_m, CtrlCode, ErrStat2, ErrMsg2) + call SeaSt_WaveField_CopyMisc(SrcMiscData%WaveField_m, DstMiscData%WaveField_m, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end subroutine @@ -888,7 +887,7 @@ subroutine SeaSt_DestroyMisc(MiscData, ErrStat, ErrMsg) character(*), parameter :: RoutineName = 'SeaSt_DestroyMisc' ErrStat = ErrID_None ErrMsg = '' - call SeaSt_Interp_DestroyMisc(MiscData%SeaSt_Interp_m, ErrStat2, ErrMsg2) + call SeaSt_WaveField_DestroyMisc(MiscData%WaveField_m, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine @@ -900,7 +899,7 @@ subroutine SeaSt_PackMisc(RF, Indata) call RegPack(RF, InData%Decimate) call RegPack(RF, InData%LastOutTime) call RegPack(RF, InData%LastIndWave) - call SeaSt_Interp_PackMisc(RF, InData%SeaSt_Interp_m) + call SeaSt_WaveField_PackMisc(RF, InData%WaveField_m) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -912,7 +911,7 @@ subroutine SeaSt_UnPackMisc(RF, OutData) call RegUnpack(RF, OutData%Decimate); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%LastOutTime); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%LastIndWave); if (RegCheckErr(RF, RoutineName)) return - call SeaSt_Interp_UnpackMisc(RF, OutData%SeaSt_Interp_m) ! SeaSt_Interp_m + call SeaSt_WaveField_UnpackMisc(RF, OutData%WaveField_m) ! WaveField_m end subroutine subroutine SeaSt_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/seastate/src/Waves.f90 b/modules/seastate/src/Waves.f90 index fd1efff906..15998ac18f 100644 --- a/modules/seastate/src/Waves.f90 +++ b/modules/seastate/src/Waves.f90 @@ -585,34 +585,33 @@ SUBROUTINE StillWaterWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! Initialize everything to zero: - !>>>>>> COMPUTE INITOUT SCALARS WaveField%NStepWave, WaveField%NStepWave2, InitOut%WaveTMax, and InitOut%WaveDOmega for WAVEMOD = 0 (WaveMod_None) - WaveField%NStepWave = 2 ! We must have at least two elements in order to interpolate later on - WaveField%NStepWave2 = 1 - InitOut%WaveTMax = InitInp%WaveTMax - WaveField%WaveDOmega = 0.0 - - ! >>> Allocate and initialize (set to 0) InitOut arrays - call Initial_InitOut_Arrays(InitOut, WaveField, InitInp, 1.0_DbKi, ErrStatTmp, ErrMsgTmp); CALL SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) - !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - IF ( ErrStat >= AbortErrLev ) RETURN - - - ! Add the current velocities to the wave velocities: - count = 0 - - !DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed - do k = 1, InitInp%NGrid(3) - do j = 1, InitInp%NGrid(2) - do i = 1, InitInp%NGrid(1) - count = count + 1 - WaveField%WaveVel(:,i,j,k,1) = InitInp%CurrVxi(count) ! xi-direction - WaveField%WaveVel(:,i,j,k,2) = InitInp%CurrVyi(count) ! yi-direction - end do + !>>>>>> COMPUTE INITOUT SCALARS WaveField%NStepWave, WaveField%NStepWave2, InitOut%WaveTMax, and InitOut%WaveDOmega for WAVEMOD = 0 (WaveMod_None) + WaveField%NStepWave = 2 ! We must have at least two elements in order to interpolate later on + WaveField%NStepWave2 = 1 + InitOut%WaveTMax = InitInp%WaveTMax + WaveField%WaveDOmega = 0.0 + + ! >>> Allocate and initialize (set to 0) InitOut arrays + call Initial_InitOut_Arrays(InitOut, WaveField, InitInp, 1.0_DbKi, ErrStatTmp, ErrMsgTmp) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + ! Add the current velocities to the wave velocities: + count = 0 + + !DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed + do k = 1, InitInp%NGrid(3) + do j = 1, InitInp%NGrid(2) + do i = 1, InitInp%NGrid(1) + count = count + 1 + WaveField%WaveVel(:,i,j,k,1) = InitInp%CurrVxi(count) ! xi-direction + WaveField%WaveVel(:,i,j,k,2) = InitInp%CurrVyi(count) ! yi-direction end do end do + end do - ! END DO ! J - All points where the incident wave kinematics will be computed + ! END DO ! J - All points where the incident wave kinematics will be computed END SUBROUTINE StillWaterWaves_Init @@ -629,8 +628,6 @@ SUBROUTINE VariousWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None - - ! Local Variables COMPLEX(SiKi) :: ImagOmega ! = ImagNmbr*Omega (rad/s) COMPLEX(SiKi), ALLOCATABLE :: PWaveAccC0HxiPz0(:,:) ! Partial derivative of WaveAccC0Hxi(:) with respect to zi at zi = 0 (1/s^2) @@ -714,377 +711,259 @@ SUBROUTINE VariousWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - ! Tell our users what is about to happen that may take a while: - CALL WrScr ( ' Generating incident wave kinematics and current time history.' ) + ! Tell our users what is about to happen that may take a while: + CALL WrScr ( ' Generating incident wave kinematics and current time history.' ) - ! Determine the number of, NWaveKin0Prime, and the zi-coordinates for, - ! WaveKinzi0Prime(:), points where the incident wave kinematics will be - ! computed before applying stretching to the instantaneous free surface. - ! The locations are relative to the mean see level. - - NWaveKin0Prime = 0 - DO J = 1,InitInp%NWaveKinGrid ! Loop through all mesh points where the incident wave kinematics will be computed - ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL - IF ( InitInp%WaveKinGridzi(J) >= -WaveField%EffWtrDpth .AND. InitInp%WaveKinGridzi(J) <= 0 ) THEN - NWaveKin0Prime = NWaveKin0Prime + 1 - END IF - END DO ! J - All Morison nodes where the incident wave kinematics will be computed + ! Determine the number of, NWaveKin0Prime, and the zi-coordinates for, + ! WaveKinzi0Prime(:), points where the incident wave kinematics will be + ! computed before applying stretching to the instantaneous free surface. + ! The locations are relative to the mean see level. + NWaveKin0Prime = 0 + DO J = 1,InitInp%NWaveKinGrid ! Loop through all mesh points where the incident wave kinematics will be computed + ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL + IF ( InitInp%WaveKinGridzi(J) >= -WaveField%EffWtrDpth .AND. InitInp%WaveKinGridzi(J) <= 0 ) THEN + NWaveKin0Prime = NWaveKin0Prime + 1 + END IF + END DO ! J - All Morison nodes where the incident wave kinematics will be computed - ! ALLOCATE the WaveKinzi0Prime(:) array and compute its elements here: - ALLOCATE ( WaveKinzi0Prime(NWaveKin0Prime) , STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveKinzi0Prime.',ErrStat,ErrMsg,RoutineName) + ! ALLOCATE the WaveKinzi0Prime(:) array and compute its elements here: - ALLOCATE ( WaveKinPrimeMap(NWaveKin0Prime) , STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveKinPrimeMap.',ErrStat,ErrMsg,RoutineName) - - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + ALLOCATE ( WaveKinzi0Prime(NWaveKin0Prime) , STAT=ErrStatTmp ); if (Failed0('WaveKinzi0Prime')) return; + ALLOCATE ( WaveKinPrimeMap(NWaveKin0Prime) , STAT=ErrStatTmp ); if (Failed0('WaveKinPrimeMap')) return; + IF ( ErrStat >= AbortErrLev ) THEN + CALL CleanUp() + RETURN + END IF - I = 1 - DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed without stretching - ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL - IF ( InitInp%WaveKinGridzi(J) >= -WaveField%EffWtrDpth .AND. InitInp%WaveKinGridzi(J) <= 0 ) THEN + I = 1 - WaveKinzi0Prime(I) = InitInp%WaveKinGridzi(J) - WaveKinPrimeMap(I) = J - I = I + 1 + DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed without stretching + ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL + IF ( InitInp%WaveKinGridzi(J) >= -WaveField%EffWtrDpth .AND. InitInp%WaveKinGridzi(J) <= 0 ) THEN - END IF + WaveKinzi0Prime(I) = InitInp%WaveKinGridzi(J) + WaveKinPrimeMap(I) = J + I = I + 1 - END DO ! J - All points where the incident wave kinematics will be computed without stretching + END IF + END DO ! J - All points where the incident wave kinematics will be computed without stretching - ! Perform some initialization computations including calculating the total number of frequency - ! components = total number of time steps in the incident wave, - ! calculating the frequency step, calculating the index of the frequency - ! component nearest to WaveTp, and ALLOCATing the arrays: - ! NOTE: WaveDOmega = 2*Pi/WaveTMax since, in the FFT: - ! Omega = (K-1)*WaveDOmega - ! Time = (J-1)*WaveDT - ! and therefore: - ! Omega*Time = (K-1)*(J-1)*WaveDOmega*WaveDT - ! = (K-1)*(J-1)*2*Pi/NStepWave [see NWTC_FFTPACK] - ! or: - ! WaveDOmega = 2*Pi/(NStepWave*WaveDT) - ! = 2*Pi/WaveTMax + ! Perform some initialization computations including calculating the total number of frequency + ! components = total number of time steps in the incident wave, + ! calculating the frequency step, calculating the index of the frequency + ! component nearest to WaveTp, and ALLOCATing the arrays: + ! NOTE: WaveDOmega = 2*Pi/WaveTMax since, in the FFT: + ! Omega = (K-1)*WaveDOmega + ! Time = (J-1)*WaveDT + ! and therefore: + ! Omega*Time = (K-1)*(J-1)*WaveDOmega*WaveDT + ! = (K-1)*(J-1)*2*Pi/NStepWave [see NWTC_FFTPACK] + ! or: + ! WaveDOmega = 2*Pi/(NStepWave*WaveDT) + ! = 2*Pi/WaveTMax - ! Set new value for NStepWave so that the FFT algorithms are efficient. Note that if this method is changed, the method - ! used to calculate the number of multidirectional wave directions (WaveNDir) and the UserWaveElevations_Init subroutine - ! will need to be updated. - !>>>>>> COMPUTE INITOUT SCALARS WaveField%NStepWave, WaveField%NStepWave2, InitOut%WaveTMax, and InitOut%WaveDOmega for WAVEMOD = 1,2,3,4,10 (5 and 7 also call this routine, but have been set already) - ! NOTE: For WaveMod = 5, NStepWave and several other things were already set in the UserWaveElevations_Init routine - ! using file information (an FFT was performed there, so the information was needed before now). - ! Same with WaveMod = 7 (WaveMod_UserFreq). With WaveMod = 7, WaveDirArr is also populated in UserWaveComponents_Init routine. - ! Need to make sure the wave-direction in formation is not overwritten later. - IF (WaveField%WaveMod /= WaveMod_ExtElev .AND. WaveField%WaveMod /= WaveMod_UserFreq) THEN - WaveField%NStepWave = CEILING ( InitInp%WaveTMax/InitInp%WaveDT ) ! Set NStepWave to an even integer ... - IF ( MOD(WaveField%NStepWave,2) == 1 ) WaveField%NStepWave = WaveField%NStepWave + 1 ! ... larger or equal to WaveTMax/WaveDT. - - WaveField%NStepWave2 = MAX( WaveField%NStepWave/2, 1 ) ! Make sure that NStepWave is an even product of small factors (PSF) that is - WaveField%NStepWave = 2 * PSF( WaveField%NStepWave2, 9 ) ! greater or equal to WaveTMax/WaveDT to ensure that the FFT is efficient. + ! Set new value for NStepWave so that the FFT algorithms are efficient. Note that if this method is changed, the method + ! used to calculate the number of multidirectional wave directions (WaveNDir) and the UserWaveElevations_Init subroutine + ! will need to be updated. - WaveField%NStepWave2 = WaveField%NStepWave/2 ! Update the value of NStepWave2 based on the value needed for NStepWave. - InitOut%WaveTMax = WaveField%NStepWave*InitInp%WaveDT ! Update the value of WaveTMax based on the value needed for NStepWave. - WaveField%WaveDOmega = TwoPi/InitOut%WaveTMax ! Compute the frequency step for incident wave calculations. + !>>>>>> COMPUTE INITOUT SCALARS WaveField%NStepWave, WaveField%NStepWave2, InitOut%WaveTMax, and InitOut%WaveDOmega for WAVEMOD = 1,2,3,4,10 (5 and 7 also call this routine, but have been set already) + ! NOTE: For WaveMod = 5, NStepWave and several other things were already set in the UserWaveElevations_Init routine + ! using file information (an FFT was performed there, so the information was needed before now). + ! Same with WaveMod = 7 (WaveMod_UserFreq). With WaveMod = 7, WaveDirArr is also populated in UserWaveComponents_Init routine. + ! Need to make sure the wave-direction in formation is not overwritten later. + IF (WaveField%WaveMod /= WaveMod_ExtElev .AND. WaveField%WaveMod /= WaveMod_UserFreq) THEN + WaveField%NStepWave = CEILING ( InitInp%WaveTMax/InitInp%WaveDT ) ! Set NStepWave to an even integer ... + IF ( MOD(WaveField%NStepWave,2) == 1 ) WaveField%NStepWave = WaveField%NStepWave + 1 ! ... larger or equal to WaveTMax/WaveDT. - ! >>> Allocate and initialize (set to 0) InitOut arrays - call Initial_InitOut_Arrays(InitOut, WaveField, InitInp, InitInp%WaveDT, ErrStatTmp, ErrMsgTmp); CALL SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) - ENDIF - !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - - ! Allocate all the arrays we need. - ALLOCATE ( tmpComplexArr(0:WaveField%NStepWave2 ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array tmpComplexArr.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveDynPC0 (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveDynPC0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVelC0Hxi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVelC0Hxi.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVelC0Hyi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVelC0Hyi.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVelC0V (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVelC0V.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveAccC0Hxi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0Hxi.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveAccC0Hyi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0Hyi.', ErrStat,ErrMsg,RoutineName) + WaveField%NStepWave2 = MAX( WaveField%NStepWave/2, 1 ) ! Make sure that NStepWave is an even product of small factors (PSF) that is + WaveField%NStepWave = 2 * PSF( WaveField%NStepWave2, 9 ) ! greater or equal to WaveTMax/WaveDT to ensure that the FFT is efficient. - ALLOCATE ( WaveAccC0V (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0V.', ErrStat,ErrMsg,RoutineName) - - - ALLOCATE ( WaveDynP0B (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveDynP0B.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVel0Hxi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVel0Hxi.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVel0Hyi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVel0Hyi.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveVel0V (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveVel0V.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveAcc0Hxi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0Hxi.', ErrStat,ErrMsg,RoutineName) + WaveField%NStepWave2 = WaveField%NStepWave/2 ! Update the value of NStepWave2 based on the value needed for NStepWave. + InitOut%WaveTMax = WaveField%NStepWave*InitInp%WaveDT ! Update the value of WaveTMax based on the value needed for NStepWave. + WaveField%WaveDOmega = TwoPi/InitOut%WaveTMax ! Compute the frequency step for incident wave calculations. + + ! >>> Allocate and initialize (set to 0) InitOut arrays + call Initial_InitOut_Arrays(InitOut, WaveField, InitInp, InitInp%WaveDT, ErrStatTmp, ErrMsgTmp); CALL SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) + ENDIF + + + ! Allocate all the arrays we need. + ALLOCATE ( tmpComplexArr(0:WaveField%NStepWave2 ), STAT=ErrStatTmp ); if (Failed0('tmpComplexArr')) return; + ALLOCATE ( WaveDynPC0 (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveDynPC0 ')) return; + ALLOCATE ( WaveVelC0Hxi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVelC0Hxi')) return; + ALLOCATE ( WaveVelC0Hyi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVelC0Hyi')) return; + ALLOCATE ( WaveVelC0V (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVelC0V ')) return; + ALLOCATE ( WaveAccC0Hxi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0Hxi')) return; + ALLOCATE ( WaveAccC0Hyi (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0Hyi')) return; + ALLOCATE ( WaveAccC0V (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0V ')) return; + + ALLOCATE ( WaveDynP0B (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveDynP0B ')) return; + ALLOCATE ( WaveVel0Hxi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVel0Hxi ')) return; + ALLOCATE ( WaveVel0Hyi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVel0Hyi ')) return; + ALLOCATE ( WaveVel0V (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveVel0V ')) return; + ALLOCATE ( WaveAcc0Hxi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0Hxi ')) return; + ALLOCATE ( WaveAcc0Hyi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0Hyi ')) return; + ALLOCATE ( WaveAcc0V (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0V ')) return; + + IF (WaveField%MCFD > 0.0_SiKi) THEN ! MacCamy-Fuchs model + ALLOCATE ( WaveAccC0HxiMCF(0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0HxiMCF')) return; + ALLOCATE ( WaveAccC0HyiMCF(0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0HyiMCF')) return; + ALLOCATE ( WaveAccC0VMCF (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAccC0VMCF ')) return; + ALLOCATE ( WaveAcc0HxiMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0HxiMCF ')) return; + ALLOCATE ( WaveAcc0HyiMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0HyiMCF ')) return; + ALLOCATE ( WaveAcc0VMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ); if (Failed0('WaveAcc0VMCF ')) return; + ALLOCATE ( WaveField%WaveAccMCF (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),InitInp%NGrid(3),3), STAT=ErrStatTmp ); if (Failed0('WaveField%WaveAccMCF')) return; + END IF + + + IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching + ALLOCATE ( PWaveDynPC0BPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveDynPC0BPz0 ')) return; + ALLOCATE ( PWaveVelC0HxiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVelC0HxiPz0')) return; + ALLOCATE ( PWaveVelC0HyiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVelC0HyiPz0')) return; + ALLOCATE ( PWaveVelC0VPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVelC0VPz0 ')) return; + ALLOCATE ( PWaveAccC0HxiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0HxiPz0')) return; + ALLOCATE ( PWaveAccC0HyiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0HyiPz0')) return; + ALLOCATE ( PWaveAccC0VPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0VPz0 ')) return; + ALLOCATE ( PWaveDynP0BPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveDynP0BPz0 ')) return; + ALLOCATE ( PWaveVel0HxiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVel0HxiPz0 ')) return; + ALLOCATE ( PWaveVel0HyiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVel0HyiPz0 ')) return; + ALLOCATE ( PWaveVel0VPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveVel0VPz0 ')) return; + ALLOCATE ( PWaveAcc0HxiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0HxiPz0 ')) return; + ALLOCATE ( PWaveAcc0HyiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0HyiPz0 ')) return; + ALLOCATE ( PWaveAcc0VPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0VPz0 ')) return; + ALLOCATE ( WaveField%PWaveDynP0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2) ), STAT=ErrStatTmp ); if (Failed0('WaveField%PWaveDynP0')) return; + ALLOCATE ( WaveField%PWaveVel0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ); if (Failed0('WaveField%PWaveVel0 ')) return; + ALLOCATE ( WaveField%PWaveAcc0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ); if (Failed0('WaveField%PWaveAcc0 ')) return; + IF (WaveField%MCFD > 0.0_ReKi) THEN ! MacCamy-Fuchs model + ALLOCATE ( PWaveAccC0HxiMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0HxiMCFPz0')) return; + ALLOCATE ( PWaveAccC0HyiMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0HyiMCFPz0')) return; + ALLOCATE ( PWaveAccC0VMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAccC0VMCFPz0 ')) return; + ALLOCATE ( PWaveAcc0HxiMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0HxiMCFPz0 ')) return; + ALLOCATE ( PWaveAcc0HyiMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0HyiMCFPz0 ')) return; + ALLOCATE ( PWaveAcc0VMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ); if (Failed0('PWaveAcc0VMCFPz0 ')) return; + ALLOCATE ( WaveField%PWaveAccMCF0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ); if (Failed0('WaveField%PWaveAccMCF0')) return; + END IF + END IF - ALLOCATE ( WaveAcc0Hyi (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0Hyi.', ErrStat,ErrMsg,RoutineName) - ALLOCATE ( WaveAcc0V (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0V.', ErrStat,ErrMsg,RoutineName) - - - IF (WaveField%MCFD > 0.0_SiKi) THEN ! MacCamy-Fuchs model - - ALLOCATE ( WaveAccC0HxiMCF(0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0HxiMCF.', ErrStat,ErrMsg,RoutineName) - ALLOCATE ( WaveAccC0HyiMCF(0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0HyiMCF.', ErrStat,ErrMsg,RoutineName) + ! Arrays for the Sin and Cos of the wave direction for each frequency. Used in calculating wave elevation, velocity, acceleration etc. + ALLOCATE ( CosWaveDir( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ); if (Failed0('CosWaveDir')) return; + ALLOCATE ( SinWaveDir( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ); if (Failed0('SinWaveDir')) return; + ALLOCATE ( OmegaArr( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ); if (Failed0('OmegaArr ')) return; + + ! Arrays for the constrained wave + ALLOCATE ( WaveS1SddArr( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ); if (Failed0('WaveS1SddArr')) return; - ALLOCATE ( WaveAccC0VMCF (0:WaveField%NStepWave2 ,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAccC0VMCF.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveAcc0HxiMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0HxiMCF.', ErrStat,ErrMsg,RoutineName) + ! Now check if all the allocations worked properly + IF ( ErrStat >= AbortErrLev ) THEN + CALL CleanUp() + RETURN + END IF - ALLOCATE ( WaveAcc0HyiMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0HyiMCF.', ErrStat,ErrMsg,RoutineName) - ALLOCATE ( WaveAcc0VMCF (0:WaveField%NStepWave-1,NWaveKin0Prime ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveAcc0VMCF.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveField%WaveAccMCF (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),InitInp%NGrid(3),3), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveField%WaveAccMCF.', ErrStat,ErrMsg,RoutineName) - END IF - - - IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching - ALLOCATE ( PWaveDynPC0BPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveDynPC0BPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVelC0HxiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVelC0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVelC0HyiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVelC0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVelC0VPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVelC0VPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAccC0HxiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAccC0HyiPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAccC0VPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0VPz0.', ErrStat,ErrMsg,RoutineName) + ! Compute the positive-frequency components (including zero) of the discrete + ! Fourier transforms of the wave kinematics: + DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transforms + OmegaArr(I) = I*WaveField%WaveDOmega + END DO - ALLOCATE ( PWaveDynP0BPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveDynP0BPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVel0HxiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVel0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVel0HyiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVel0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveVel0VPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveVel0Pz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAcc0HxiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAcc0HyiPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAcc0VPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0VPz0.', ErrStat,ErrMsg,RoutineName) + call Get_1Spsd_and_WaveElevC0(InitInp, InitOut, WaveField, OmegaArr, WaveS1SddArr) - ALLOCATE ( WaveField%PWaveDynP0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2) ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveField%PWaveDynP0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveField%PWaveVel0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveField%PWaveVel0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveField%PWaveAcc0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveField%PWaveAcc0.', ErrStat,ErrMsg,RoutineName) - - IF (WaveField%MCFD > 0.0_ReKi) THEN ! MacCamy-Fuchs model - - ALLOCATE ( PWaveAccC0HxiMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0HxiMCFPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAccC0HyiMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0HyiMCFPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( PWaveAccC0VMCFPz0 (0:WaveField%NStepWave2 ,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAccC0VMCFPz0.', ErrStat,ErrMsg,RoutineName) - ALLOCATE ( PWaveAcc0HxiMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0HxiMCFPz0.', ErrStat,ErrMsg,RoutineName) + !> # Multi Directional Waves + call CalculateWaveDirection(InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp); if (Failed()) return; - ALLOCATE ( PWaveAcc0HyiMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0HyiMCFPz0.', ErrStat,ErrMsg,RoutineName) + ! Store the minimum and maximum wave directions + WaveField%WaveDirMin = MINVAL(WaveField%WaveDirArr) + WaveField%WaveDirMax = MAXVAL(WaveField%WaveDirArr) - ALLOCATE ( PWaveAcc0VMCFPz0 (0:WaveField%NStepWave-1,InitInp%NWaveElevGrid), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array PWaveAcc0VMCFPz0.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( WaveField%PWaveAccMCF0 (0:WaveField%NStepWave,InitInp%NGrid(1),InitInp%NGrid(2),3), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveField%PWaveAccMCF0.', ErrStat,ErrMsg,RoutineName) - - END IF - - END IF -! END TODO SECTION + ! Set the CosWaveDir and SinWaveDir arrays + CosWaveDir=COS(D2R*WaveField%WaveDirArr) + SinWaveDir=SIN(D2R*WaveField%WaveDirArr) - - ! Arrays for the Sin and Cos of the wave direction for each frequency. Used in calculating wave elevation, velocity, acceleration etc. - ALLOCATE ( CosWaveDir( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array CosWaveDir.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( SinWaveDir( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array SinWaveDir.', ErrStat,ErrMsg,RoutineName) - - ALLOCATE ( OmegaArr( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array OmegaArr.', ErrStat,ErrMsg,RoutineName) - - - ! Arrays for the constrained wave - ALLOCATE ( WaveS1SddArr( 0:WaveField%NStepWave2 ), STAT=ErrStatTmp ) - IF (ErrStatTmp /= 0) CALL SetErrStat(ErrID_Fatal,'Cannot allocate array WaveS1SddArr.', ErrStat,ErrMsg,RoutineName) - - ! Now check if all the allocations worked properly + + ! make sure this is called before calling ConstrainedNewWaves + CALL InitFFT ( WaveField%NStepWave, FFT_Data, .TRUE., ErrStatTmp ) + CALL SetErrStat(ErrStatTmp,'Error occured while initializing the FFT.',ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) THEN CALL CleanUp() RETURN END IF - - - - ! Compute the positive-frequency components (including zero) of the discrete - ! Fourier transforms of the wave kinematics: - DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transforms - OmegaArr(I) = I*WaveField%WaveDOmega - END DO - - call Get_1Spsd_and_WaveElevC0(InitInp, InitOut, WaveField, OmegaArr, WaveS1SddArr) - - !> # Multi Directional Waves - call CalculateWaveDirection(InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp) - call SetErrStat(ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + !-------------------------------------------------------------------------------- + !=== Constrained New Waves === + ! Modify the wave components to implement the constrained wave + ! Only do this if WaveMod = 2 (JONSWAP/Pierson-Moskowitz Spectrum) and ConstWaveMod > 0 + IF ( WaveField%WaveMod == WaveMod_JONSWAP .AND. InitInp%ConstWaveMod > 0) THEN + ! adjust InitOut%WaveElevC0 for constrained wave: + call ConstrainedNewWaves(InitInp, InitOut, WaveField, OmegaArr, WaveS1SddArr, CosWaveDir, SinWaveDir, FFT_Data, ErrStatTmp, ErrMsgTmp) + call SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) then + call cleanup() + return + end if + ENDIF + ! End of Constrained Wave + + !-------------------------------------------------------------------------------- + !> ## Phase shift the discrete Fourier transform of wave elevations at the WRP + !> This changes the phasing of all wave kinematics and loads to reflect the turbine's + !! location in the larger farm, in the case of FAST.Farm simulations, based on + !! specified PtfmLocationX and PtfmLocationY. + + IF (InitInp%WaveFieldMod == 2) THEN ! case 2: adjust wave phases based on turbine offsets from farm origin + + CALL WrScr ( ' Adjusting incident wave kinematics for turbine offset from array origin.' ) + + DO I = 0,WaveField%NStepWave2 + + tmpComplex = CMPLX( WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) - ! Store the minimum and maximum wave directions - WaveField%WaveDirMin = MINVAL(WaveField%WaveDirArr) - WaveField%WaveDirMax = MAXVAL(WaveField%WaveDirArr) + ! some redundant calculations with later, but insignificant + WaveNmbr = WaveNumber ( OmegaArr(I), InitInp%Gravity, WaveField%EffWtrDpth ) + ! apply the phase shift + tmpComplex = tmpComplex * EXP( -ImagNmbr*WaveNmbr*( InitInp%PtfmLocationX*CosWaveDir(I) + InitInp%PtfmLocationY*SinWaveDir(I) )) + + ! put shifted complex amplitudes back into the array for use in the remainder of this module and other modules (Waves2, WAMIT, WAMIT2) + WaveField%WaveElevC0 (1,I) = REAL( tmpComplex) + WaveField%WaveElevC0 (2,I) = AIMAG(tmpComplex) + + END DO + END IF - ! Set the CosWaveDir and SinWaveDir arrays - CosWaveDir=COS(D2R*WaveField%WaveDirArr) - SinWaveDir=SIN(D2R*WaveField%WaveDirArr) - - - ! make sure this is called before calling ConstrainedNewWaves - CALL InitFFT ( WaveField%NStepWave, FFT_Data, .TRUE., ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while initializing the FFT.',ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - - !-------------------------------------------------------------------------------- - !=== Constrained New Waves === - ! Modify the wave components to implement the constrained wave - ! Only do this if WaveMod = 2 (JONSWAP/Pierson-Moskowitz Spectrum) and ConstWaveMod > 0 - IF ( WaveField%WaveMod == WaveMod_JONSWAP .AND. InitInp%ConstWaveMod > 0) THEN - ! adjust InitOut%WaveElevC0 for constrained wave: - call ConstrainedNewWaves(InitInp, InitOut, WaveField, OmegaArr, WaveS1SddArr, CosWaveDir, SinWaveDir, FFT_Data, ErrStatTmp, ErrMsgTmp) - call SetErrStat(ErrStatTmp,ErrMsgTmp, ErrStat,ErrMsg,RoutineName) - if (ErrStat >= AbortErrLev) then - call cleanup() - return - end if - ENDIF - ! End of Constrained Wave - - !-------------------------------------------------------------------------------- - !> ## Phase shift the discrete Fourier transform of wave elevations at the WRP - !> This changes the phasing of all wave kinematics and loads to reflect the turbine's - !! location in the larger farm, in the case of FAST.Farm simulations, based on - !! specified PtfmLocationX and PtfmLocationY. - - IF (InitInp%WaveFieldMod == 2) THEN ! case 2: adjust wave phases based on turbine offsets from farm origin - - CALL WrScr ( ' Adjusting incident wave kinematics for turbine offset from array origin.' ) - - DO I = 0,WaveField%NStepWave2 - - tmpComplex = CMPLX( WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) - - ! some redundant calculations with later, but insignificant - WaveNmbr = WaveNumber ( OmegaArr(I), InitInp%Gravity, WaveField%EffWtrDpth ) - - ! apply the phase shift - tmpComplex = tmpComplex * EXP( -ImagNmbr*WaveNmbr*( InitInp%PtfmLocationX*CosWaveDir(I) + InitInp%PtfmLocationY*SinWaveDir(I) )) - - ! put shifted complex amplitudes back into the array for use in the remainder of this module and other modules (Waves2, WAMIT, WAMIT2) - WaveField%WaveElevC0 (1,I) = REAL( tmpComplex) - WaveField%WaveElevC0 (2,I) = AIMAG(tmpComplex) - - END DO - END IF - - - !-------------------------------------------------------------------------------- - !> ## Compute IFFTs - !> Compute the discrete Fourier transform of the instantaneous elevation of - !! incident waves at each desired point on the still water level plane - !! where it can be output: - - DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transforms - - - ! Set tmpComplex to the Ith element of the WAveElevC0 array - tmpComplex = CMPLX( WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) + !-------------------------------------------------------------------------------- + !> ## Compute IFFTs + !> Compute the discrete Fourier transform of the instantaneous elevation of + !! incident waves at each desired point on the still water level plane + !! where it can be output: + DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transforms + ! Set tmpComplex to the Ith element of the WAveElevC0 array + tmpComplex = CMPLX( WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) ! Compute the frequency of this component and its imaginary value: - - ImagOmega = ImagNmbr*OmegaArr(I) + ImagOmega = ImagNmbr*OmegaArr(I) ! Compute the wavenumber: - - WaveNmbr = WaveNumber ( OmegaArr(I), InitInp%Gravity, WaveField%EffWtrDpth ) + WaveNmbr = WaveNumber ( OmegaArr(I), InitInp%Gravity, WaveField%EffWtrDpth ) ! Wavenumber-dependent acceleration scaling for MacCamy-Fuchs model MCFC = 0.0_ReKi @@ -1100,424 +979,350 @@ SUBROUTINE VariousWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! before applying stretching at the zi-coordinates for the WAMIT reference point, and all ! points where are Morison loads will be calculated. - DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching + DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching - WaveElevxiPrime0 = EXP( -ImagNmbr*WaveNmbr*( InitInp%WaveKinGridxi(WaveKinPrimeMap(J))*CosWaveDir(I) + & - InitInp%WaveKinGridyi(WaveKinPrimeMap(J))*SinWaveDir(I) )) + WaveElevxiPrime0 = EXP( -ImagNmbr*WaveNmbr*( InitInp%WaveKinGridxi(WaveKinPrimeMap(J))*CosWaveDir(I) + & + InitInp%WaveKinGridyi(WaveKinPrimeMap(J))*SinWaveDir(I) )) - WaveDynPC0 (I,J) = WaveField%RhoXg*tmpComplex*WaveElevxiPrime0 * COSHNumOvrCOSHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) + WaveDynPC0 (I,J) = WaveField%RhoXg*tmpComplex*WaveElevxiPrime0 * COSHNumOvrCOSHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) - WaveVelC0Hxi (I,J) = CosWaveDir(I)*OmegaArr(I)*tmpComplex* WaveElevxiPrime0 * COSHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) - WaveVelC0Hyi (I,J) = SinWaveDir(I)*OmegaArr(I)*tmpComplex* WaveElevxiPrime0 * COSHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) + WaveVelC0Hxi (I,J) = CosWaveDir(I)*OmegaArr(I)*tmpComplex* WaveElevxiPrime0 * COSHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) + WaveVelC0Hyi (I,J) = SinWaveDir(I)*OmegaArr(I)*tmpComplex* WaveElevxiPrime0 * COSHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) - WaveVelC0V (I,J) = ImagOmega*tmpComplex* WaveElevxiPrime0 * SINHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) - WaveAccC0Hxi (I,J) = ImagOmega* WaveVelC0Hxi (I,J) + WaveVelC0V (I,J) = ImagOmega*tmpComplex* WaveElevxiPrime0 * SINHNumOvrSINHDen ( WaveNmbr, WaveField%EffWtrDpth, WaveKinzi0Prime(J) ) + WaveAccC0Hxi (I,J) = ImagOmega* WaveVelC0Hxi (I,J) - WaveAccC0Hyi (I,J) = ImagOmega* WaveVelC0Hyi (I,J) - WaveAccC0V (I,J) = ImagOmega* WaveVelC0V (I,J) + WaveAccC0Hyi (I,J) = ImagOmega* WaveVelC0Hyi (I,J) + WaveAccC0V (I,J) = ImagOmega* WaveVelC0V (I,J) - IF (WaveField%MCFD > 0.0_SiKi) THEN - WaveAccC0HxiMCF(I,J) = WaveAccC0Hxi(I,J) * MCFC - WaveAccC0HyiMCF(I,J) = WaveAccC0Hyi(I,J) * MCFC - WaveAccC0VMCF(I,J) = WaveAccC0V(I,J) * MCFC - END IF - - - END DO ! J - All points where the incident wave kinematics will be computed without stretching + IF (WaveField%MCFD > 0.0_SiKi) THEN + WaveAccC0HxiMCF(I,J) = WaveAccC0Hxi(I,J) * MCFC + WaveAccC0HyiMCF(I,J) = WaveAccC0Hyi(I,J) * MCFC + WaveAccC0VMCF(I,J) = WaveAccC0V(I,J) * MCFC + END IF + END DO ! J - All points where the incident wave kinematics will be computed without stretching - !=================================== - IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation wave stretching - DO J = 1,InitInp%NWaveElevGrid ! Loop through all points on the SWL - WaveElevxiPrime0 = EXP( -ImagNmbr*WaveNmbr*( InitInp%WaveKinGridxi(J)*CosWaveDir(I) + & - InitInp%WaveKinGridyi(J)*SinWaveDir(I) )) - ! Partial derivatives at zi = 0 - PWaveDynPC0BPz0 (I,J) = WaveField%RhoXg* tmpComplex*WaveElevxiPrime0*WaveNmbr*TANH ( WaveNmbr*WaveField%EffWtrDpth ) - PWaveVelC0HxiPz0(I,J) = CosWaveDir(I)*OmegaArr(I)*tmpComplex*WaveElevxiPrime0*WaveNmbr - PWaveVelC0HyiPz0(I,J) = SinWaveDir(I)*OmegaArr(I)*tmpComplex*WaveElevxiPrime0*WaveNmbr + IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation wave stretching + DO J = 1,InitInp%NWaveElevGrid ! Loop through all points on the SWL + WaveElevxiPrime0 = EXP( -ImagNmbr*WaveNmbr*( InitInp%WaveKinGridxi(J)*CosWaveDir(I) + & + InitInp%WaveKinGridyi(J)*SinWaveDir(I) )) + ! Partial derivatives at zi = 0 + PWaveDynPC0BPz0 (I,J) = WaveField%RhoXg* tmpComplex*WaveElevxiPrime0*WaveNmbr*TANH ( WaveNmbr*WaveField%EffWtrDpth ) + PWaveVelC0HxiPz0(I,J) = CosWaveDir(I)*OmegaArr(I)*tmpComplex*WaveElevxiPrime0*WaveNmbr + PWaveVelC0HyiPz0(I,J) = SinWaveDir(I)*OmegaArr(I)*tmpComplex*WaveElevxiPrime0*WaveNmbr + + IF (I == 0_IntKi) THEN ! Zero frequency component - Need to avoid division by zero. + PWaveVelC0VPz0 (I,J) = 0.0_ReKi + ELSE + PWaveVelC0VPz0 (I,J) = ImagOmega*tmpComplex*WaveElevxiPrime0*WaveNmbr/TANH ( WaveNmbr*WaveField%EffWtrDpth ) + END IF + + PWaveAccC0HxiPz0(I,J) = ImagOmega*PWaveVelC0HxiPz0(I,J) + PWaveAccC0HyiPz0(I,J) = ImagOmega*PWaveVelC0HyiPz0(I,J) + PWaveAccC0VPz0 (I,J) = ImagOmega*PWaveVelC0VPz0 (I,J) - IF (I == 0_IntKi) THEN ! Zero frequency component - Need to avoid division by zero. - PWaveVelC0VPz0 (I,J) = 0.0_ReKi - ELSE - PWaveVelC0VPz0 (I,J) = ImagOmega*tmpComplex*WaveElevxiPrime0*WaveNmbr/TANH ( WaveNmbr*WaveField%EffWtrDpth ) - END IF - PWaveAccC0HxiPz0(I,J) = ImagOmega*PWaveVelC0HxiPz0(I,J) - PWaveAccC0HyiPz0(I,J) = ImagOmega*PWaveVelC0HyiPz0(I,J) - PWaveAccC0VPz0 (I,J) = ImagOmega*PWaveVelC0VPz0 (I,J) - - - IF (WaveField%MCFD > 0.0_SiKi) THEN - PWaveAccC0HxiMCFPz0(I,J) = PWaveAccC0HxiPz0(I,J) * MCFC - PWaveAccC0HyiMCFPz0(I,J) = PWaveAccC0HyiPz0(I,J) * MCFC - PWaveAccC0VMCFPz0(I,J) = PWaveAccC0VPz0(I,J) * MCFC - END IF - - END DO ! J - All points where the incident wave kinematics will be computed without stretching - END IF - !=================================== - - END DO ! I - The positive frequency components (including zero) of the discrete Fourier transforms - - ! Calculate the array of simulation times at which the instantaneous - ! elevation of, velocity of, acceleration of, and loads associated with - ! the incident waves are to be determined: - DO I = 0,WaveField%NStepWave ! Loop through all time steps - WaveField%WaveTime(I) = I*REAL(InitInp%WaveDT,SiKi) - END DO ! I - All time steps - - - DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transform - tmpComplexArr(I) = CMPLX(WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) - END DO - - ! Compute the inverse discrete Fourier transforms to find the time-domain - ! representations of the wave kinematics without stretcing: - - CALL ApplyFFT_cx ( WaveField%WaveElev0 (0:WaveField%NStepWave-1), tmpComplexArr (: ), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveElev0.',ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN + IF (WaveField%MCFD > 0.0_SiKi) THEN + PWaveAccC0HxiMCFPz0(I,J) = PWaveAccC0HxiPz0(I,J) * MCFC + PWaveAccC0HyiMCFPz0(I,J) = PWaveAccC0HyiPz0(I,J) * MCFC + PWaveAccC0VMCFPz0(I,J) = PWaveAccC0VPz0(I,J) * MCFC + END IF + + END DO ! J - All points where the incident wave kinematics will be computed without stretching END IF -!NOTE: For all grid points - DO k = 1,InitInp%NWaveElevGrid ! Loop through all points where the incident wave elevations are to be computed (normally all the XY grid points) - ! This subroutine call applies the FFT at the correct location. - i = mod(k-1, InitInp%NGrid(1)) + 1 - j = (k-1) / InitInp%NGrid(1) + 1 - ! note that this subroutine resets tmpComplexArr - CALL WaveElevTimeSeriesAtXY( InitInp%WaveKinGridxi(k), InitInp%WaveKinGridyi(k), WaveField%WaveElev1(:,i,j), WaveField%WaveElevC(:,:,k), tmpComplexArr, ErrStatTmp, ErrMsgTmp ) ! Note this sets tmpComplexArr - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveField%WaveElev1.',ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - END DO ! J - All points where the incident wave elevations can be output - - + END DO ! I - The positive frequency components (including zero) of the discrete Fourier transforms - ! User requested data points -- Do all the FFT calls first, then return if something failed. - DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching - CALL ApplyFFT_cx ( WaveDynP0B (:,J), WaveDynPC0 (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveDynP0B.', ErrStat,ErrMsg,RoutineName) + ! Calculate the array of simulation times at which the instantaneous + ! elevation of, velocity of, acceleration of, and loads associated with + ! the incident waves are to be determined: + DO I = 0,WaveField%NStepWave ! Loop through all time steps + WaveField%WaveTime(I) = I*REAL(InitInp%WaveDT,SiKi) + END DO ! I - All time steps + + + DO I = 0,WaveField%NStepWave2 ! Loop through the positive frequency components (including zero) of the discrete Fourier transform + tmpComplexArr(I) = CMPLX(WaveField%WaveElevC0(1,I), WaveField%WaveElevC0(2,I)) + END DO - CALL ApplyFFT_cx ( WaveVel0Hxi (:,J), WaveVelC0Hxi (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveVel0Hxi.', ErrStat,ErrMsg,RoutineName) + ! Compute the inverse discrete Fourier transforms to find the time-domain + ! representations of the wave kinematics without stretcing: - CALL ApplyFFT_cx ( WaveVel0Hyi (:,J), WaveVelC0Hyi (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveVel0Hyi.', ErrStat,ErrMsg,RoutineName) + CALL ApplyFFT_cx ( WaveField%WaveElev0 (0:WaveField%NStepWave-1), tmpComplexArr (: ), FFT_Data, ErrStatTmp ) + if (FailedFFT('WaveField%WaveElev0' )) return; +!NOTE: For all grid points + DO k = 1,InitInp%NWaveElevGrid ! Loop through all points where the incident wave elevations are to be computed (normally all the XY grid points) + ! This subroutine call applies the FFT at the correct location. + i = mod(k-1, InitInp%NGrid(1)) + 1 + j = (k-1) / InitInp%NGrid(1) + 1 - CALL ApplyFFT_cx ( WaveVel0V (:,J), WaveVelC0V (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveVel0V.', ErrStat,ErrMsg,RoutineName) + ! note that this subroutine resets tmpComplexArr + CALL WaveElevTimeSeriesAtXY( InitInp%WaveKinGridxi(k), InitInp%WaveKinGridyi(k), WaveField%WaveElev1(:,i,j), WaveField%WaveElevC(:,:,k), tmpComplexArr, ErrStatTmp, ErrMsgTmp ) ! Note this sets tmpComplexArr + if (FailedFFT('WaveField%WaveElev1' )) return; + END DO ! J - All points where the incident wave elevations can be output - CALL ApplyFFT_cx ( WaveAcc0Hxi (:,J), WaveAccC0Hxi (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0Hxi.', ErrStat,ErrMsg,RoutineName) - CALL ApplyFFT_cx ( WaveAcc0Hyi (:,J), WaveAccC0Hyi (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0Hyi.', ErrStat,ErrMsg,RoutineName) - CALL ApplyFFT_cx ( WaveAcc0V (:,J), WaveAccC0V (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0V.', ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + ! User requested data points -- Do all the FFT calls first, then return if something failed. + DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching + CALL ApplyFFT_cx ( WaveDynP0B (:,J), WaveDynPC0 (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveDynPC0 ')) return; + CALL ApplyFFT_cx ( WaveVel0Hxi (:,J), WaveVelC0Hxi (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveVelC0Hxi')) return; + CALL ApplyFFT_cx ( WaveVel0Hyi (:,J), WaveVelC0Hyi (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveVelC0Hyi')) return; + CALL ApplyFFT_cx ( WaveVel0V (:,J), WaveVelC0V (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveVelC0V ')) return; + CALL ApplyFFT_cx ( WaveAcc0Hxi (:,J), WaveAccC0Hxi (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAccC0Hxi')) return; + CALL ApplyFFT_cx ( WaveAcc0Hyi (:,J), WaveAccC0Hyi (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAccC0Hyi')) return; + CALL ApplyFFT_cx ( WaveAcc0V (:,J), WaveAccC0V (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAccC0V ')) return; + END DO ! J - All points where the incident wave kinematics will be computed without stretching + IF (WaveField%MCFD > 0.0_SiKi) THEN + DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching + CALL ApplyFFT_cx ( WaveAcc0HxiMCF (:,J), WaveAccC0HxiMCF (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAcc0HxiMCF')) return; + CALL ApplyFFT_cx ( WaveAcc0HyiMCF (:,J), WaveAccC0HyiMCF (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAcc0HyiMCF')) return; + CALL ApplyFFT_cx ( WaveAcc0VMCF (:,J), WaveAccC0VMCF (:,J), FFT_Data, ErrStatTmp ); if (FailedFFT('WaveAcc0VMCF ')) return; + END DO + END IF + + IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching + DO J = 1,InitInp%NWaveElevGrid ! Loop through all points on the SWL where z-partial derivatives will be computed for extrapolated stretching + ! FFT's of the partial derivatives + CALL ApplyFFT_cx ( PWaveDynP0BPz0(:,J ), PWaveDynPC0BPz0(:,J ), FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveDynP0BPz0 ')) return; + CALL ApplyFFT_cx ( PWaveVel0HxiPz0 (:,J ), PWaveVelC0HxiPz0( :,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveVel0HxiPz0')) return; + CALL ApplyFFT_cx ( PWaveVel0HyiPz0 (:,J ), PWaveVelC0HyiPz0( :,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveVel0HyiPz0')) return; + CALL ApplyFFT_cx ( PWaveVel0VPz0 (:,J ), PWaveVelC0VPz0 (:,J ), FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveVel0VPz0 ')) return; + CALL ApplyFFT_cx ( PWaveAcc0HxiPz0 (:,J ), PWaveAccC0HxiPz0(:,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0HxiPz0')) return; + CALL ApplyFFT_cx ( PWaveAcc0HyiPz0 (:,J ), PWaveAccC0HyiPz0(:,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0HyiPz0')) return; + CALL ApplyFFT_cx ( PWaveAcc0VPz0 (:,J ), PWaveAccC0VPz0( :,J ), FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0VPz0 ')) return; END DO ! J - All points where the incident wave kinematics will be computed without stretching - - IF (WaveField%MCFD > 0.0_SiKi) THEN - DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching - CALL ApplyFFT_cx ( WaveAcc0HxiMCF (:,J), WaveAccC0HxiMCF (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0HxiMCF.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( WaveAcc0HyiMCF (:,J), WaveAccC0HyiMCF (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0HyiMCF.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( WaveAcc0VMCF (:,J), WaveAccC0VMCF (:,J), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to WaveAcc0VMCF.', ErrStat,ErrMsg,RoutineName) - - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + + IF (WaveField%MCFD > 0.0_SiKi) THEN ! MacCamy-Fuchs scaled acceleration field + DO J = 1,InitInp%NWaveElevGrid + CALL ApplyFFT_cx ( PWaveAcc0HxiMCFPz0 (:,J ), PWaveAccC0HxiMCFPz0(:,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0HxiMCFPz0')) return; + CALL ApplyFFT_cx ( PWaveAcc0HyiMCFPz0 (:,J ), PWaveAccC0HyiMCFPz0(:,J ),FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0HyiMCFPz0')) return; + CALL ApplyFFT_cx ( PWaveAcc0VMCFPz0 (:,J ), PWaveAccC0VMCFPz0( :,J ), FFT_Data, ErrStatTmp ); if (FailedFFT('PWaveAcc0VMCFPz0 ')) return; END DO END IF - - !=================================== - IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching - DO J = 1,InitInp%NWaveElevGrid ! Loop through all points on the SWL where z-partial derivatives will be computed for extrapolated stretching - ! FFT's of the partial derivatives - CALL ApplyFFT_cx ( PWaveDynP0BPz0(:,J ), PWaveDynPC0BPz0(:,J ), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveDynP0BPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveVel0HxiPz0 (:,J ), PWaveVelC0HxiPz0( :,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveVel0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveVel0HyiPz0 (:,J ), PWaveVelC0HyiPz0( :,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveVel0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveVel0VPz0 (:,J ), PWaveVelC0VPz0 (:,J ), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveVel0VPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveAcc0HxiPz0 (:,J ), PWaveAccC0HxiPz0(:,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0HxiPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveAcc0HyiPz0 (:,J ), PWaveAccC0HyiPz0(:,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0HyiPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveAcc0VPz0 (:,J ), PWaveAccC0VPz0( :,J ), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0VPz0.', ErrStat,ErrMsg,RoutineName) - - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - - END DO ! J - All points where the incident wave kinematics will be computed without stretching - - IF (WaveField%MCFD > 0.0_SiKi) THEN ! MacCamy-Fuchs scaled acceleration field - DO J = 1,InitInp%NWaveElevGrid - - CALL ApplyFFT_cx ( PWaveAcc0HxiMCFPz0 (:,J ), PWaveAccC0HxiMCFPz0(:,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0HxiMCFPz0.', ErrStat,ErrMsg,RoutineName) - - CALL ApplyFFT_cx ( PWaveAcc0HyiMCFPz0 (:,J ), PWaveAccC0HyiMCFPz0(:,J ),FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0HyiMCFPz0.', ErrStat,ErrMsg,RoutineName) - CALL ApplyFFT_cx ( PWaveAcc0VMCFPz0 (:,J ), PWaveAccC0VMCFPz0( :,J ), FFT_Data, ErrStatTmp ) - CALL SetErrStat(ErrStatTmp,'Error occured while applying the FFT to PWaveAcc0VMCFPz0.', ErrStat,ErrMsg,RoutineName) - - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF - - END DO - END IF - - END IF -!=================================== + END IF + CALL ExitFFT(FFT_Data, ErrStatTmp) + CALL SetErrStat(ErrStatTmp,'Error occured while cleaning up after the FFTs.', ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) THEN + CALL CleanUp() + RETURN + END IF - CALL ExitFFT(FFT_Data, ErrStatTmp) - CALL SetErrStat(ErrStatTmp,'Error occured while cleaning up after the FFTs.', ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - END IF + ! Add the current velocities to the wave velocities: + ! NOTE: Both the horizontal velocities and the partial derivative of the + ! horizontal velocities with respect to zi at zi = 0 are found here. + ! + ! NOTE: The current module must be called prior to the waves module. If that was not done, then we + ! don't have a current to add to the wave velocity. So, check if the current velocity components + ! exist. - ! Add the current velocities to the wave velocities: - ! NOTE: Both the horizontal velocities and the partial derivative of the - ! horizontal velocities with respect to zi at zi = 0 are found here. - ! - ! NOTE: The current module must be called prior to the waves module. If that was not done, then we - ! don't have a current to add to the wave velocity. So, check if the current velocity components - ! exist. + ! If there is a current, we need to add that (the current module was called prior to calling this module - ! If there is a current, we need to add that (the current module was called prior to calling this module + IF(ALLOCATED(InitInp%CurrVxi)) THEN - IF(ALLOCATED(InitInp%CurrVxi)) THEN + DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching - DO J = 1,NWaveKin0Prime ! Loop through all points where the incident wave kinematics will be computed without stretching + WaveVel0Hxi (:,J) = WaveVel0Hxi (:,J) + InitInp%CurrVxi(WaveKinPrimeMap(J)) ! xi-direction + WaveVel0Hyi (:,J) = WaveVel0Hyi (:,J) + InitInp%CurrVyi(WaveKinPrimeMap(J)) ! yi-direction - WaveVel0Hxi (:,J) = WaveVel0Hxi (:,J) + InitInp%CurrVxi(WaveKinPrimeMap(J)) ! xi-direction - WaveVel0Hyi (:,J) = WaveVel0Hyi (:,J) + InitInp%CurrVyi(WaveKinPrimeMap(J)) ! yi-direction + END DO ! J - All points where the incident wave kinematics will be computed without stretching - END DO ! J - All points where the incident wave kinematics will be computed without stretching + ! Commented out - We do not extrapolate the current profile with extrapolated wave stretching + !PWaveVel0HxiPz0(: ) = PWaveVel0HxiPz0(: ) + InitInp%PCurrVxiPz0 ! xi-direction + !PWaveVel0HyiPz0(: ) = PWaveVel0HyiPz0(: ) + InitInp%PCurrVyiPz0 ! yi-direction - ! Commented out - We do not extrapolate the current profile with extrapolated wave stretching - !PWaveVel0HxiPz0(: ) = PWaveVel0HxiPz0(: ) + InitInp%PCurrVxiPz0 ! xi-direction - !PWaveVel0HyiPz0(: ) = PWaveVel0HyiPz0(: ) + InitInp%PCurrVyiPz0 ! yi-direction + ENDIF - ENDIF + ! Apply stretching to obtain the wave kinematics, WaveDynP0, WaveVel0, and + ! WaveAcc0, at the desired locations from the wave kinematics at + ! alternative locations, WaveDynP0B, WaveVel0Hxi, WaveVel0Hyi, WaveVel0V, + ! WaveAcc0Hxi, WaveAcc0Hyi, WaveAcc0V, if the elevation of the point defined by + ! WaveKinGridzi(J) lies between the seabed and the instantaneous free + ! surface, else set WaveDynP0, WaveVel0, and WaveAcc0 to zero. This + ! depends on which incident wave kinematics stretching method is being + ! used: - ! Apply stretching to obtain the wave kinematics, WaveDynP0, WaveVel0, and - ! WaveAcc0, at the desired locations from the wave kinematics at - ! alternative locations, WaveDynP0B, WaveVel0Hxi, WaveVel0Hyi, WaveVel0V, - ! WaveAcc0Hxi, WaveAcc0Hyi, WaveAcc0V, if the elevation of the point defined by - ! WaveKinGridzi(J) lies between the seabed and the instantaneous free - ! surface, else set WaveDynP0, WaveVel0, and WaveAcc0 to zero. This - ! depends on which incident wave kinematics stretching method is being - ! used: + ! SELECT CASE ( InitInp%WaveStMod ) ! Which model are we using to extrapolate the incident wave kinematics to the instantaneous free surface? + ! CASE ( 0 ) ! None=no stretching. - ! SELECT CASE ( InitInp%WaveStMod ) ! Which model are we using to extrapolate the incident wave kinematics to the instantaneous free surface? - ! CASE ( 0 ) ! None=no stretching. + ! Since we have no stretching, the wave kinematics between the seabed and + ! the mean sea level are left unchanged; below the seabed or above the + ! mean sea level, the wave kinematics are zero: + ! InitOut%PWaveDynP0(:,:,:,:) = 0.0 - ! Since we have no stretching, the wave kinematics between the seabed and - ! the mean sea level are left unchanged; below the seabed or above the - ! mean sea level, the wave kinematics are zero: + primeCount = 1 + count = 1 + !DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed + do k = 1, InitInp%NGrid(3) + do j = 1, InitInp%NGrid(2) + do i = 1, InitInp%NGrid(1) - ! InitOut%PWaveDynP0(:,:,:,:) = 0.0 + ! ii = mod(count-1, InitInp%NGrid(1)) + 1 + ! jj = mod( (count-1) /InitInp%NGrid(1), InitInp%NGrid(2) ) + 1 + ! kk = (count-1) / (InitInp%NGrid(1)*InitInp%NGrid(2)) + 1 + + IF ( ( InitInp%WaveKinGridzi(count) < -WaveField%EffWtrDpth ) .OR. ( InitInp%WaveKinGridzi(count) > 0.0 ) ) THEN + ! .TRUE. if the elevation of the point defined by WaveKinGridzi(J) lies below the seabed or above mean sea level (exclusive) + ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL + + WaveField%WaveDynP(:,i,j,k ) = 0.0 + WaveField%WaveVel (:,i,j,k,:) = 0.0 + WaveField%WaveAcc (:,i,j,k,:) = 0.0 + ELSE + ! The elevation of the point defined by WaveKinGridzi(J) must lie between the seabed and the mean sea level (inclusive) + + WaveField%WaveDynP(0:WaveField%NStepWave-1,i,j,k ) = WaveDynP0B( 0:WaveField%NStepWave-1,primeCount) + WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,1) = WaveVel0Hxi(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,2) = WaveVel0Hyi(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,3) = WaveVel0V( 0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,1) = WaveAcc0Hxi(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,2) = WaveAcc0Hyi(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,3) = WaveAcc0V( 0:WaveField%NStepWave-1,primeCount) + primeCount = primeCount + 1 + END IF + count = count + 1 + end do + end do + end do + + ! MacCamy-Fuchs scaled fluid acceleration + IF (WaveField%MCFD > 0.0_SiKi) THEN primeCount = 1 count = 1 - !DO J = 1,InitInp%NWaveKinGrid ! Loop through all points where the incident wave kinematics will be computed do k = 1, InitInp%NGrid(3) do j = 1, InitInp%NGrid(2) do i = 1, InitInp%NGrid(1) - - ! ii = mod(count-1, InitInp%NGrid(1)) + 1 - ! jj = mod( (count-1) /InitInp%NGrid(1), InitInp%NGrid(2) ) + 1 - ! kk = (count-1) / (InitInp%NGrid(1)*InitInp%NGrid(2)) + 1 - IF ( ( InitInp%WaveKinGridzi(count) < -WaveField%EffWtrDpth ) .OR. ( InitInp%WaveKinGridzi(count) > 0.0 ) ) THEN ! .TRUE. if the elevation of the point defined by WaveKinGridzi(J) lies below the seabed or above mean sea level (exclusive) ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL - - WaveField%WaveDynP(:,i,j,k ) = 0.0 - WaveField%WaveVel (:,i,j,k,:) = 0.0 - WaveField%WaveAcc (:,i,j,k,:) = 0.0 - + WaveField%WaveAccMCF(:,i,j,k,:) = 0.0 ELSE ! The elevation of the point defined by WaveKinGridzi(J) must lie between the seabed and the mean sea level (inclusive) - - WaveField%WaveDynP(0:WaveField%NStepWave-1,i,j,k ) = WaveDynP0B( 0:WaveField%NStepWave-1,primeCount) - WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,1) = WaveVel0Hxi(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,2) = WaveVel0Hyi(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveVel (0:WaveField%NStepWave-1,i,j,k,3) = WaveVel0V( 0:WaveField%NStepWave-1,primeCount) - WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,1) = WaveAcc0Hxi(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,2) = WaveAcc0Hyi(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveAcc (0:WaveField%NStepWave-1,i,j,k,3) = WaveAcc0V( 0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,1) = WaveAcc0HxiMCF(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,2) = WaveAcc0HyiMCF(0:WaveField%NStepWave-1,primeCount) + WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,3) = WaveAcc0VMCF( 0:WaveField%NStepWave-1,primeCount) primeCount = primeCount + 1 END IF count = count + 1 end do end do end do + END IF - ! MacCamy-Fuchs scaled fluid acceleration + IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching + + primeCount = 1 + DO j = 1, InitInp%NGrid(2) ! Loop through all points on the SWL where partial derivatives about z were computed + DO i = 1, InitInp%NGrid(1) + WaveField%PWaveDynP0(0:WaveField%NStepWave-1,i,j ) = PWaveDynP0BPz0( 0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,1) = PWaveVel0HxiPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,2) = PWaveVel0HyiPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,3) = PWaveVel0VPz0( 0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,1) = pWaveAcc0HxiPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,2) = pWaveAcc0HyiPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,3) = PWaveAcc0VPz0( 0:WaveField%NStepWave-1,primeCount) + primeCount = primeCount + 1 + END DO + END DO + IF (WaveField%MCFD > 0.0_SiKi) THEN - primeCount = 1 - count = 1 - do k = 1, InitInp%NGrid(3) - do j = 1, InitInp%NGrid(2) - do i = 1, InitInp%NGrid(1) - IF ( ( InitInp%WaveKinGridzi(count) < -WaveField%EffWtrDpth ) .OR. ( InitInp%WaveKinGridzi(count) > 0.0 ) ) THEN - ! .TRUE. if the elevation of the point defined by WaveKinGridzi(J) lies below the seabed or above mean sea level (exclusive) - ! NOTE: We test to 0 instead of MSL2SWL because the locations of WaveKinGridzi and EffWtrDpth have already been adjusted using MSL2SWL - WaveField%WaveAccMCF(:,i,j,k,:) = 0.0 - ELSE - ! The elevation of the point defined by WaveKinGridzi(J) must lie between the seabed and the mean sea level (inclusive) - WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,1) = WaveAcc0HxiMCF(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,2) = WaveAcc0HyiMCF(0:WaveField%NStepWave-1,primeCount) - WaveField%WaveAccMCF (0:WaveField%NStepWave-1,i,j,k,3) = WaveAcc0VMCF( 0:WaveField%NStepWave-1,primeCount) - primeCount = primeCount + 1 - END IF - count = count + 1 - end do - end do - end do - END IF - - IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching - primeCount = 1 DO j = 1, InitInp%NGrid(2) ! Loop through all points on the SWL where partial derivatives about z were computed DO i = 1, InitInp%NGrid(1) - WaveField%PWaveDynP0(0:WaveField%NStepWave-1,i,j ) = PWaveDynP0BPz0( 0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,1) = PWaveVel0HxiPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,2) = PWaveVel0HyiPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveVel0 (0:WaveField%NStepWave-1,i,j,3) = PWaveVel0VPz0( 0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,1) = pWaveAcc0HxiPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,2) = pWaveAcc0HyiPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveAcc0 (0:WaveField%NStepWave-1,i,j,3) = PWaveAcc0VPz0( 0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,1) = pWaveAcc0HxiMCFPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,2) = pWaveAcc0HyiMCFPz0(0:WaveField%NStepWave-1,primeCount) + WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,3) = PWaveAcc0VMCFPz0( 0:WaveField%NStepWave-1,primeCount) primeCount = primeCount + 1 END DO END DO - - IF (WaveField%MCFD > 0.0_SiKi) THEN - primeCount = 1 - DO j = 1, InitInp%NGrid(2) ! Loop through all points on the SWL where partial derivatives about z were computed - DO i = 1, InitInp%NGrid(1) - WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,1) = pWaveAcc0HxiMCFPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,2) = pWaveAcc0HyiMCFPz0(0:WaveField%NStepWave-1,primeCount) - WaveField%PWaveAccMCF0 (0:WaveField%NStepWave-1,i,j,3) = PWaveAcc0VMCFPz0( 0:WaveField%NStepWave-1,primeCount) - primeCount = primeCount + 1 - END DO - END DO - END IF - END IF + END IF - ! END DO ! J - All points where the incident wave kinematics will be computed - - ! CASE ( 1 ) ! Vertical stretching. - - - ! Vertical stretching says that the wave kinematics above the mean sea level - ! equal the wave kinematics at the mean sea level. The wave kinematics - ! below the mean sea level are left unchanged: + ! CASE ( 1 ) ! Vertical stretching. + ! Vertical stretching says that the wave kinematics above the mean sea level + ! equal the wave kinematics at the mean sea level. The wave kinematics + ! below the mean sea level are left unchanged: + ! CASE ( 2 ) ! Extrapolation stretching. + ! Extrapolation stretching uses a linear Taylor expansion of the wave + ! kinematics (and their partial derivatives with respect to z) at the mean + ! sea level to find the wave kinematics above the mean sea level. The + ! wave kinematics below the mean sea level are left unchanged: - - ! CASE ( 2 ) ! Extrapolation stretching. - - - ! Extrapolation stretching uses a linear Taylor expansion of the wave - ! kinematics (and their partial derivatives with respect to z) at the mean - ! sea level to find the wave kinematics above the mean sea level. The - ! wave kinematics below the mean sea level are left unchanged: - - - - - - ! CASE ( 3 ) ! Wheeler stretching. - - - ! Wheeler stretching says that wave kinematics calculated using Airy theory - ! at the mean sea level should actually be applied at the instantaneous - ! free surface and that Airy wave kinematics computed at locations between - ! the seabed and the mean sea level should be shifted vertically to new - ! locations in proportion to their elevation above the seabed. - ! - ! Computing the wave kinematics with Wheeler stretching requires that first - ! say that the wave kinematics we computed at the elevations defined by - ! the WaveKinzi0Prime(:) array are actual applied at the elevations found - ! by stretching the elevations in the WaveKinzi0Prime(:) array using the - ! instantaneous wave elevation--these new elevations are stored in the - ! WaveKinzi0St(:) array. Next, we interpolate the wave kinematics - ! computed without stretching to the desired elevations (defined in the - ! WaveKinGridzi(:) array) using the WaveKinzi0St(:) array: - - - - - ! ENDSELECT - - ! Set the ending timestep to the same as the first timestep - WaveField%WaveElev0 (WaveField%NStepWave) = WaveField%WaveElev0 (0 ) - WaveField%WaveDynP (WaveField%NStepWave,:,:,: ) = WaveField%WaveDynP (0,:,:,: ) - WaveField%WaveVel (WaveField%NStepWave,:,:,:,:) = WaveField%WaveVel (0,:,:,:,:) - WaveField%WaveAcc (WaveField%NStepWave,:,:,:,:) = WaveField%WaveAcc (0,:,:,:,:) + ! CASE ( 3 ) ! Wheeler stretching. + ! Wheeler stretching says that wave kinematics calculated using Airy theory + ! at the mean sea level should actually be applied at the instantaneous + ! free surface and that Airy wave kinematics computed at locations between + ! the seabed and the mean sea level should be shifted vertically to new + ! locations in proportion to their elevation above the seabed. + ! + ! Computing the wave kinematics with Wheeler stretching requires that first + ! say that the wave kinematics we computed at the elevations defined by + ! the WaveKinzi0Prime(:) array are actual applied at the elevations found + ! by stretching the elevations in the WaveKinzi0Prime(:) array using the + ! instantaneous wave elevation--these new elevations are stored in the + ! WaveKinzi0St(:) array. Next, we interpolate the wave kinematics + ! computed without stretching to the desired elevations (defined in the + ! WaveKinGridzi(:) array) using the WaveKinzi0St(:) array: + + ! ENDSELECT + + ! Set the ending timestep to the same as the first timestep + WaveField%WaveElev0 (WaveField%NStepWave) = WaveField%WaveElev0 (0 ) + WaveField%WaveDynP (WaveField%NStepWave,:,:,: ) = WaveField%WaveDynP (0,:,:,: ) + WaveField%WaveVel (WaveField%NStepWave,:,:,:,:) = WaveField%WaveVel (0,:,:,:,:) + WaveField%WaveAcc (WaveField%NStepWave,:,:,:,:) = WaveField%WaveAcc (0,:,:,:,:) + IF (WaveField%MCFD > 0.0_SiKi) THEN + WaveField%WaveAccMCF (WaveField%NStepWave,:,:,:,:) = WaveField%WaveAccMCF(0,:,:,:,:) + END IF + + IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching + WaveField%PWaveDynP0(WaveField%NStepWave,:,: ) = WaveField%PWaveDynP0(0,:,: ) + WaveField%PWaveVel0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveVel0 (0,:,:,:) + WaveField%PWaveAcc0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveAcc0 (0,:,:,:) IF (WaveField%MCFD > 0.0_SiKi) THEN - WaveField%WaveAccMCF (WaveField%NStepWave,:,:,:,:) = WaveField%WaveAccMCF(0,:,:,:,:) - END IF - - IF (WaveField%WaveStMod .EQ. 2_IntKi) THEN ! Extrapolation Wave Stretching - WaveField%PWaveDynP0(WaveField%NStepWave,:,: ) = WaveField%PWaveDynP0(0,:,: ) - WaveField%PWaveVel0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveVel0 (0,:,:,:) - WaveField%PWaveAcc0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveAcc0 (0,:,:,:) - IF (WaveField%MCFD > 0.0_SiKi) THEN - WaveField%PWaveAccMCF0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveAccMCF0(0,:,:,:) - END IF + WaveField%PWaveAccMCF0 (WaveField%NStepWave,:,:,:) = WaveField%PWaveAccMCF0(0,:,:,:) END IF + END IF CALL CleanUp ( ) CONTAINS - + logical function Failed() + CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) CALL Cleanup() + end function + logical function Failed0(TmpName) + character(*), intent(in) :: TmpName + if (ErrStatTmp /= 0) then + ErrStatTmp = ErrID_Fatal + CALL SetErrStat( ErrStatTmp, 'Error while allocating '//trim(TmpName), ErrStat, ErrMsg, RoutineName ) + endif + Failed0 = ErrStat >= AbortErrLev + if (Failed0) CALL Cleanup() + end function + logical function FailedFFT(TmpName) + character(*), intent(in) :: TmpName + CALL SetErrStat( ErrStatTmp, 'Error occured while applying the FFT to '//trim(TmpName), ErrStat, ErrMsg, RoutineName ) + FailedFFT = ErrStat >= AbortErrLev + if (FailedFFT) CALL Cleanup() + end function !-------------------------------------------------------------------------------- SUBROUTINE WaveElevTimeSeriesAtXY(Xcoord,Ycoord, WaveElevAtXY, WaveElevCAtXY, tmpComplexArr, ErrStatLcl, ErrMsgLcl ) @@ -1630,23 +1435,18 @@ END SUBROUTINE VariousWaves_Init !> This routine is called at the start of the simulation to perform initialization steps. !! The initial states and initial guess for the input are defined. SUBROUTINE Waves_Init( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) -!.................................................................................................................................. - TYPE(Waves_InitInputType), INTENT(INOUT) :: InitInp !< Input data for initialization routine !NOTE: We are making this INOUT because UserWaveComponents_Init changes the value of InitInp%WaveDT TYPE(Waves_InitOutputType), INTENT( OUT) :: InitOut !< Output for initialization routine TYPE(SeaSt_WaveFieldType), INTENT(INOUT) :: WaveField ! SeaState wave field type containing the wave field 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) :: ErrStatTmp ! Temporary error status for processing CHARACTER(ErrMsgLen) :: ErrMsgTmp ! Temporary error message for procesing ! Initialize ErrStat - ErrStat = ErrID_None ErrStatTmp = ErrID_None ErrMsg = "" @@ -1657,19 +1457,15 @@ SUBROUTINE Waves_Init( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) CALL RandNum_Init(InitInp%RNG, ErrStat, ErrMsg) IF ( ErrStat >= AbortErrLev ) RETURN - ! Define initialization-routine output here: - - - - ! Initialize the variables associated with the incident wave: + ! Initialize the variables associated with the incident wave: SELECT CASE ( WaveField%WaveMod ) ! Which incident wave kinematics model are we using? CASE ( WaveMod_None ) ! None=still water. CALL StillWaterWaves_Init( InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp ) - CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') IF ( ErrStat >= AbortErrLev ) RETURN @@ -1678,8 +1474,8 @@ SUBROUTINE Waves_Init( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! Now call the init with all the zi locations for the Morrison member nodes CALL VariousWaves_Init( InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp ) - CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') - IF ( ErrStat >= AbortErrLev ) RETURN + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') + IF ( ErrStat >= AbortErrLev ) RETURN CASE ( WaveMod_ExtElev ) ! User-supplied wave elevation time history; HD derives full wave kinematics from this elevation time series data. @@ -1691,7 +1487,7 @@ SUBROUTINE Waves_Init( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! Now call VariousWaves to continue using the wave elevation and derived frequency information from the file CALL VariousWaves_Init( InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp ) - CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') IF ( ErrStat >= AbortErrLev ) RETURN @@ -1705,12 +1501,12 @@ SUBROUTINE Waves_Init( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! Get the wave frequency information from the file (by reading in wave frequency components) CALL UserWaveComponents_Init( InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp ) - CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') IF ( ErrStat >= AbortErrLev ) RETURN ! Now call VariousWaves to continue using the wave frequency information from the file CALL VariousWaves_Init( InitInp, InitOut, WaveField, ErrStatTmp, ErrMsgTmp ) - CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'Waves_Init') IF ( ErrStat >= AbortErrLev ) RETURN ENDSELECT diff --git a/modules/servodyn/src/ServoDyn.f90 b/modules/servodyn/src/ServoDyn.f90 index a5e683526f..7fa4b05678 100644 --- a/modules/servodyn/src/ServoDyn.f90 +++ b/modules/servodyn/src/ServoDyn.f90 @@ -158,6 +158,8 @@ SUBROUTINE SrvD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO CALL DispNVD( SrvD_Ver ) CALL GetPath( InitInp%InputFile, PriPath ) ! Input files will be relative to the path where the primary input file is located. + p%PriPath = PriPath + !............................................................................................ ! Read the input file and validate the data ! (note p%NumBl and p%RootName must be set first!) @@ -1484,7 +1486,7 @@ subroutine StC_Blade_Setup(SrvD_InitInp,SrvD_p,InputFileData,SrvD_u,SrvD_y,SrvD_ ! A little bit of information about the StC location if (unsum >0) then write(UnSum, '(A24,i2)') ' Blade StC instance: ',j - write(UnSum, '(10x,A)') 'Input file: '//trim(InputFileData%NStCfiles(j)) + write(UnSum, '(10x,A)') 'Input file: '//trim(InputFileData%BStCfiles(j)) do k=1,StC_InitInp%NumMeshPts write(UnSum, '(10x,A6,I1,A29)') 'Blade ',k,' location (global/inertial): ' write(UnSum, '(20x,3(2x,ES10.3e2))') u(1,j)%Mesh(k)%Position(1:3,1) @@ -5241,7 +5243,7 @@ SUBROUTINE CalculateStandardYaw(t, u, p, m, YawPosCom, YawRateCom, YawPosComInt, CASE ( ControlMode_USER ) ! User-defined from routine UserYawCont(). - CALL UserYawCont ( u%Yaw, u%YawRate, u%WindDir, u%YawErr, p%NumBl, t, p%DT, p%RootName, YawPosCom, YawRateCom ) + CALL UserYawCont ( u%Yaw, u%YawRate, u%WindDir, u%YawErr, p%NumBl, t, p%DT, p%PriPath, YawPosCom, YawRateCom ) CASE ( ControlMode_EXTERN ) ! User-defined from Simulink or LabVIEW @@ -5380,7 +5382,7 @@ SUBROUTINE Pitch_CalcOutput( t, u, p, x, xd, z, OtherState, BlPitchCom, ElecPwr, CASE ( ControlMode_USER ) ! User-defined from routine PitchCntrl(). - CALL PitchCntrl ( u%BlPitch, ElecPwr, u%LSS_Spd, u%TwrAccel, p%NumBl, t, p%DT, p%RootName, BlPitchCom ) + CALL PitchCntrl ( u%BlPitch, ElecPwr, u%LSS_Spd, u%TwrAccel, p%NumBl, t, p%DT, p%PriPath, BlPitchCom ) CASE ( ControlMode_EXTERN ) ! User-defined from Simulink or LabVIEW. @@ -5733,7 +5735,7 @@ SUBROUTINE Torque_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM CASE ( ControlMode_USER ) ! User-defined HSS brake model. - CALL UserHSSBr ( y%GenTrq, y%ElecPwr, u%HSS_Spd, p%NumBl, t, p%DT, p%RootName, HSSBrFrac ) + CALL UserHSSBr ( y%GenTrq, y%ElecPwr, u%HSS_Spd, p%NumBl, t, p%DT, p%PriPath, HSSBrFrac ) IF ( ( HSSBrFrac < 0.0_ReKi ) .OR. ( HSSBrFrac > 1.0_ReKi ) ) THEN ! 0 (off) <= HSSBrFrac <= 1 (full); else Abort. ErrStat = ErrID_Fatal @@ -5938,8 +5940,8 @@ SUBROUTINE CalculateTorque( t, u, p, m, GenTrq, ElecPwr, ErrStat, ErrMsg ) CASE ( ControlMode_USER ) ! User-defined generator model. - ! CALL UserGen ( u%HSS_Spd, u%LSS_Spd, p%NumBl, t, DT, p%GenEff, DelGenTrq, DirRoot, GenTrq, ElecPwr ) - CALL UserGen ( u%HSS_Spd, u%LSS_Spd, p%NumBl, t, p%DT, p%GenEff, 0.0_ReKi, p%RootName, GenTrq, ElecPwr ) + CALL UserGen ( u%HSS_Spd, u%LSS_Spd, p%NumBl, t, p%DT, p%GenEff, 0.0_ReKi, p%PriPath, GenTrq, ElecPwr ) + END SELECT @@ -5974,7 +5976,7 @@ SUBROUTINE CalculateTorque( t, u, p, m, GenTrq, ElecPwr, ErrStat, ErrMsg ) CASE ( ControlMode_USER ) ! User-defined variable-speed control for routine UserVSCont(). - CALL UserVSCont ( u%HSS_Spd, u%LSS_Spd, p%NumBl, t, p%DT, p%GenEff, 0.0_ReKi, p%RootName, GenTrq, ElecPwr ) + CALL UserVSCont ( u%HSS_Spd, u%LSS_Spd, p%NumBl, t, p%DT, p%GenEff, 0.0_ReKi, p%PriPath, GenTrq, ElecPwr ) CASE ( ControlMode_DLL ) ! User-defined variable-speed control from Bladed-style DLL diff --git a/modules/servodyn/src/ServoDyn_Registry.txt b/modules/servodyn/src/ServoDyn_Registry.txt index 4f3ab877c7..30013c593f 100644 --- a/modules/servodyn/src/ServoDyn_Registry.txt +++ b/modules/servodyn/src/ServoDyn_Registry.txt @@ -439,6 +439,7 @@ typedef ^ ParameterType IntKi StCCmode - - - "Structural control control mode {0 typedef ^ ParameterType IntKi NumOuts - - - "Number of parameters in the output list (number of outputs requested)" - typedef ^ ParameterType IntKi NumOuts_DLL - - - "Number of logging channels output from the DLL (set at initialization)" - typedef ^ ParameterType CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ ParameterType CHARACTER(1024) PriPath - - - "Path of the primary SrvD input file " - typedef ^ ParameterType OutParmType OutParam {:} - - "Names and units (and other characteristics) of all requested output parameters" - typedef ^ ParameterType CHARACTER(1) Delim - - - "Column delimiter for output text files" - # parameters for Bladed Interface (dynamic-link library) diff --git a/modules/servodyn/src/ServoDyn_Types.f90 b/modules/servodyn/src/ServoDyn_Types.f90 index 9d2f6de448..806629157d 100644 --- a/modules/servodyn/src/ServoDyn_Types.f90 +++ b/modules/servodyn/src/ServoDyn_Types.f90 @@ -450,6 +450,7 @@ MODULE ServoDyn_Types INTEGER(IntKi) :: NumOuts = 0_IntKi !< Number of parameters in the output list (number of outputs requested) [-] INTEGER(IntKi) :: NumOuts_DLL = 0_IntKi !< Number of logging channels output from the DLL (set at initialization) [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] + CHARACTER(1024) :: PriPath !< Path of the primary SrvD input file [-] TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: OutParam !< Names and units (and other characteristics) of all requested output parameters [-] CHARACTER(1) :: Delim !< Column delimiter for output text files [-] LOGICAL :: UseBladedInterface = .false. !< Flag that determines if BladedInterface was used [-] @@ -4621,6 +4622,7 @@ subroutine SrvD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%NumOuts = SrcParamData%NumOuts DstParamData%NumOuts_DLL = SrcParamData%NumOuts_DLL DstParamData%RootName = SrcParamData%RootName + DstParamData%PriPath = SrcParamData%PriPath if (allocated(SrcParamData%OutParam)) then LB(1:1) = lbound(SrcParamData%OutParam, kind=B8Ki) UB(1:1) = ubound(SrcParamData%OutParam, kind=B8Ki) @@ -5141,6 +5143,7 @@ subroutine SrvD_PackParam(RF, Indata) call RegPack(RF, InData%NumOuts) call RegPack(RF, InData%NumOuts_DLL) call RegPack(RF, InData%RootName) + call RegPack(RF, InData%PriPath) call RegPack(RF, allocated(InData%OutParam)) if (allocated(InData%OutParam)) then call RegPackBounds(RF, 1, lbound(InData%OutParam, kind=B8Ki), ubound(InData%OutParam, kind=B8Ki)) @@ -5316,6 +5319,7 @@ subroutine SrvD_UnPackParam(RF, OutData) call RegUnpack(RF, OutData%NumOuts); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NumOuts_DLL); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%RootName); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%PriPath); if (RegCheckErr(RF, RoutineName)) return if (allocated(OutData%OutParam)) deallocate(OutData%OutParam) call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return if (IsAllocAssoc) then diff --git a/modules/subdyn/src/SubDyn_Driver.f90 b/modules/subdyn/src/SubDyn_Driver.f90 index de2bb6e880..0d0f1ba4f5 100644 --- a/modules/subdyn/src/SubDyn_Driver.f90 +++ b/modules/subdyn/src/SubDyn_Driver.f90 @@ -517,111 +517,5 @@ function is_int(string, x) read(string,fmt,iostat=e) x is_int = e == 0 end function is_int - - !> Read a delimited file with one line of header - subroutine ReadDelimFile(Filename, nCol, Array, errStat, errMsg, nHeaderLines, priPath) - character(len=*), intent(in) :: Filename - integer, intent(in) :: nCol - real(ReKi), dimension(:,:), allocatable, intent(out) :: Array - integer(IntKi) , intent(out) :: errStat ! Status of error message - character(*) , intent(out) :: errMsg ! Error message if ErrStat /= ErrID_None - integer(IntKi), optional, intent(in ) :: nHeaderLines - character(*) , optional, intent(in ) :: priPath ! Primary path, to use if filename is not absolute - integer :: UnIn, i, j, nLine, nHead - character(len= 2048) :: line - integer(IntKi) :: errStat2 ! local status of error message - character(ErrMsgLen) :: errMsg2 ! temporary Error message - character(len=2048) :: Filename_Loc ! filename local to this function - ErrStat = ErrID_None - ErrMsg = "" - - Filename_Loc = Filename - if (present(priPath)) then - if (PathIsRelative(Filename_Loc)) Filename_Loc = trim(PriPath)//trim(Filename) - endif - - - ! Open file - call GetNewUnit(UnIn) - call OpenFInpFile(UnIn, Filename_Loc, errStat2, errMsg2); call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile') - if (errStat >= AbortErrLev) return - ! Count number of lines - nLine = line_count(UnIn) - allocate(Array(nLine-1, nCol), stat=errStat2); errMsg2='allocation failed'; call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile') - if (errStat >= AbortErrLev) return - ! Read header - nHead=1 - if (present(nHeaderLines)) nHead = nHeaderLines - do i=1,nHead - read(UnIn, *, IOSTAT=errStat2) line - errMsg2 = ' Error reading line '//trim(Num2LStr(1))//' of file: '//trim(Filename_Loc) - call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile') - if (errStat >= AbortErrLev) return - enddo - ! Read data - do I = 1,nLine-1 - read (UnIn,*,IOSTAT=errStat2) (Array(I,J), J=1,nCol) - errMsg2 = ' Error reading line '//trim(Num2LStr(I+1))//' of file: '//trim(Filename_Loc) - call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ReadDelimFile') - if (errStat >= AbortErrLev) return - end do - close(UnIn) - end subroutine ReadDelimFile - - !> Counts number of lines in a file - integer function line_count(iunit) - integer, intent(in) :: iunit - character(len=2048) :: line - ! safety for infinite loop.. - integer :: i - integer, parameter :: nline_max=100000000 ! 100 M - line_count=0 - do i=1,nline_max - line='' - read(iunit,'(A)',END=100)line - line_count=line_count+1 - enddo - if (line_count==nline_max) then - print*,'Error: maximum number of line exceeded for line_count' - STOP - endif - 100 if(len(trim(line))>0) then - line_count=line_count+1 - endif - rewind(iunit) - return - end function - !> Perform linear interpolation of an array, where first column is assumed to be ascending time values - !! First value is used for times before, and last value is used for time beyond - subroutine interpTimeValue(array, time, iLast, values) - real(ReKi), dimension(:,:), intent(in) :: array !< vector of time steps - real(DbKi), intent(in) :: time !< time - integer, intent(inout) :: iLast - real(ReKi), dimension(:), intent(out) :: values !< vector of values at given time - integer :: i - real(ReKi) :: alpha - if (array(iLast,1)> time) then - values = array(iLast,2:) - elseif (iLast == size(array,1)) then - values = array(iLast,2:) - else - ! Look for index - do i=iLast,size(array,1) - if (array(i,1)<=time) then - iLast=i - else - exit - endif - enddo - if (iLast==size(array,1)) then - values = array(iLast,2:) - else - ! Linear interpolation - alpha = (array(iLast+1,1)-time)/(array(iLast+1,1)-array(iLast,1)) - values = array(iLast,2:)*alpha + array(iLast+1,2:)*(1-alpha) - !print*,'time', array(iLast,1), '<=', time,'<', array(iLast+1,1), 'fact', alpha - endif - endif - end subroutine interpTimeValue !---------------------------------------------------------------------------------------------------------------------------------- END PROGRAM diff --git a/modules/turbsim/src/CohStructures.f90 b/modules/turbsim/src/CohStructures.f90 index 9c1ad52141..a20ad42f18 100644 --- a/modules/turbsim/src/CohStructures.f90 +++ b/modules/turbsim/src/CohStructures.f90 @@ -766,7 +766,7 @@ SUBROUTINE CohStr_WriteEvents( RootName, p_CohStr, e_CohStr, y_CohStr, TScale, U CHARACTER(MaxMsgLen) :: ErrMsg2 ! Message describing error (local) - CHARACTER(200) :: InpFile ! Name of the input file + CHARACTER(1024) :: InpFile ! Name of the input file TYPE (Event), POINTER :: PtrCurr => NULL() ! Pointer to the current event TYPE (Event), POINTER :: PtrPrev => NULL() ! Pointer to the previous event (for deallocation purposes) diff --git a/modules/turbsim/src/Profiles.f90 b/modules/turbsim/src/Profiles.f90 index 7135b92856..36ca07fde0 100644 --- a/modules/turbsim/src/Profiles.f90 +++ b/modules/turbsim/src/Profiles.f90 @@ -122,7 +122,7 @@ SUBROUTINE GetChebCoefs(p, UJetMax_IsKnown, ErrStat, ErrMsg) ! valid only for jet WindProfileType -IMPLICIT NONE + IMPLICIT NONE TYPE(TurbSim_ParameterType),INTENT(INOUT) :: p ! TurbSim parameters LOGICAL, INTENT(IN) :: UJetMax_IsKnown diff --git a/modules/turbsim/src/TS_FileIO.f90 b/modules/turbsim/src/TS_FileIO.f90 index 70b5f91a76..d4a5814137 100644 --- a/modules/turbsim/src/TS_FileIO.f90 +++ b/modules/turbsim/src/TS_FileIO.f90 @@ -72,7 +72,7 @@ SUBROUTINE ReadInputFile(InFile, p, OtherSt_RandNum, ErrStat, ErrMsg) LOGICAL :: UseDefault ! Whether or not to use a default value LOGICAL :: IsUnusedParameter ! Whether or not this variable will be ignored - CHARACTER(200) :: Line ! An input line + CHARACTER(1024) :: Line ! An input line CHARACTER(1) :: Line1 ! The first character of an input line INTEGER(IntKi) :: ErrStat2 ! Temporary Error status diff --git a/modules/turbsim/src/TurbSim.f90 b/modules/turbsim/src/TurbSim.f90 index 5aa65491aa..768a43b859 100644 --- a/modules/turbsim/src/TurbSim.f90 +++ b/modules/turbsim/src/TurbSim.f90 @@ -82,7 +82,7 @@ PROGRAM TurbSim INTEGER(IntKi) :: ErrStat ! allocation status CHARACTER(MaxMsgLen) :: ErrMsg ! error message -CHARACTER(200) :: InFile ! Name of the TurbSim input file. +CHARACTER(1024) :: InFile ! Name of the TurbSim input file. CHARACTER(20) :: FlagArg ! flag argument from command line diff --git a/modules/turbsim/src/TurbSim_Types.f90 b/modules/turbsim/src/TurbSim_Types.f90 index c4a6071032..07a7773018 100644 --- a/modules/turbsim/src/TurbSim_Types.f90 +++ b/modules/turbsim/src/TurbSim_Types.f90 @@ -90,8 +90,8 @@ MODULE TurbSim_Types REAL(ReKi) :: DistScl ! Disturbance scale for AeroDyn coherent turbulence events - CHARACTER(200) :: CTEventPath ! String used to store the name of the coherent event definition file - CHARACTER(200) :: CTEventFile ! String used to store the name of the coherent event definition file + CHARACTER(1024) :: CTEventPath ! String used to store the name of the coherent event definition file + CHARACTER(1024) :: CTEventFile ! String used to store the name of the coherent event definition file CHARACTER( 3) :: CTExt ! String used to determine the type of coherent structures ("dns" or "les") END TYPE CohStr_ParameterType @@ -276,8 +276,8 @@ MODULE TurbSim_Types INTEGER :: US = -1 ! I/O unit for summary file. - CHARACTER(200) :: DescStr ! String used to describe the run (and the first line of the summary file) - CHARACTER(197) :: RootName ! Root name of the I/O files. + CHARACTER(1024) :: DescStr ! String used to describe the run (and the first line of the summary file) + CHARACTER(1024) :: RootName ! Root name of the I/O files. TYPE(RandNum_ParameterType) :: RNG ! parameters for random numbers p_RandNum TYPE(Grid_ParameterType) :: grid ! parameters for TurbSim (specify grid/frequency size) TYPE(Meteorology_ParameterType) :: met ! parameters for TurbSim diff --git a/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 156d28e541..9d51bb2620 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -42,7 +42,7 @@ option(CTEST_NO_RUN_FLAG "Complete the regression test comparison but do not ex # Set the OpenFAST executable configuration option and default set(CTEST_OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST executable to use in testing.") -if(BUILD_OPENFAST_CPP_DRIVER) +if(BUILD_OPENFAST_CPP_API) # Set the OpenFAST executable configuration option and default set(CTEST_OPENFASTCPP_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast-cpp/openfastcpp${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST C++ executable to use in testing.") endif() diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index bbe017d88f..cd87b2ba50 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 STEADYSTATE_FLAG TESTNAME LABEL) +function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY STEADYSTATE_FLAG TESTNAME LABEL OTHER_FLAGS) file(TO_NATIVE_PATH "${EXECUTABLE}" EXECUTABLE) file(TO_NATIVE_PATH "${TEST_SCRIPT}" TEST_SCRIPT) @@ -57,6 +57,10 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY STEA set(STEADYSTATE_FLAG "") endif() + if(OTHER_FLAGS STREQUAL " ") + set(OTHER_FLAGS "") + endif() + add_test( ${TESTNAME} ${Python_EXECUTABLE} ${TEST_SCRIPT} @@ -70,6 +74,7 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY STEA ${RUN_VERBOSE_FLAG} # empty or "-v" ${NO_RUN_FLAG} # empty or "-n" ${STEADYSTATE_FLAG} # empty or "-steadystate" + ${OTHER_FLAGS} ) # limit each test to 90 minutes: 5400s set_tests_properties(${TESTNAME} PROPERTIES TIMEOUT 5400 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" LABELS "${LABEL}") @@ -85,7 +90,7 @@ 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) @@ -94,7 +99,7 @@ function(of_aeromap_regression TESTNAME LABEL) 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}") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${STEADYSTATE_FLAG} ${TESTNAME} "${LABEL}" " ") endfunction(of_aeromap_regression) function(of_fastlib_regression TESTNAME LABEL) @@ -103,7 +108,7 @@ function(of_fastlib_regression TESTNAME LABEL) set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") # 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}) + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " "${TESTNAME}_fastlib" "${LABEL}" " " ${TESTNAME}) endfunction(of_fastlib_regression) # openfast aeroacoustic @@ -112,7 +117,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 @@ -121,16 +126,17 @@ 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 -function(of_regression_linear TESTNAME LABEL) +function(of_regression_linear TESTNAME OTHER_FLAGS LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastLinearRegressionCase.py") 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}") + set(OTHER_FLAGS "${OTHER_FLAGS}") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}" "${OTHER_FLAGS}") endfunction(of_regression_linear) # openfast C++ interface @@ -139,7 +145,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 @@ -148,7 +154,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 @@ -157,7 +163,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 @@ -166,7 +172,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) @@ -176,7 +182,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) @@ -186,7 +192,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 @@ -195,7 +201,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 @@ -204,7 +210,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 @@ -213,7 +219,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 @@ -222,7 +228,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 @@ -231,7 +237,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 @@ -240,7 +246,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 @@ -249,7 +255,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 @@ -258,7 +264,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 @@ -308,11 +314,12 @@ of_regression("StC_test_OC4Semi" "openfast;servodyn;hydrod 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_regression("Tailfin_FreeYaw1DOF_Unsteady" "openfast;elastodyn;aerodyn15") of_aeromap_regression("5MW_Land_AeroMap" "aeromap;elastodyn;aerodyn15") # OpenFAST C++ API test -if(BUILD_OPENFAST_CPP_DRIVER) +if(BUILD_OPENFAST_CPP_API) of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;fastlib;cpp") endif() @@ -336,15 +343,21 @@ 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") -of_regression_linear("5MW_Land_BD_Linear" "openfast;linear;beamdyn;servodyn") -of_regression_linear("5MW_OC4Semi_Linear" "openfast;linear;hydrodyn;servodyn") -of_regression_linear("StC_test_OC4Semi_Linear_Nac" "openfast;linear;servodyn;stc") -of_regression_linear("StC_test_OC4Semi_Linear_Tow" "openfast;linear;servodyn;stc") +of_regression_linear("Fake5MW_AeroLin_B1_UA4_DBEMT3" "-highpass=0.05" "openfast;linear;elastodyn;aerodyn") +of_regression_linear("Fake5MW_AeroLin_B3_UA6" "-highpass=0.05" "openfast;linear;elastodyn;aerodyn") +of_regression_linear("WP_Stationary_Linear" "" "openfast;linear;elastodyn") +of_regression_linear("Ideal_Beam_Fixed_Free_Linear" "-highpass=0.10" "openfast;linear;beamdyn") +of_regression_linear("Ideal_Beam_Free_Free_Linear" "-highpass=0.10" "openfast;linear;beamdyn") +#of_regression_linear("5MW_Land_Linear_Aero" "-highpass=0.05" "openfast;linear;elastodyn;servodyn;aerodyn") +of_regression_linear("5MW_Land_BD_Linear" "" "openfast;linear;beamdyn;servodyn") +#of_regression_linear("5MW_Land_BD_Linear_Aero" "-highpass=0.05" "openfast;linear;beamdyn;servodyn;aerodyn") +of_regression_linear("5MW_OC4Semi_Linear" "" "openfast;linear;hydrodyn;servodyn;map") +of_regression_linear("5MW_OC4Semi_MD_Linear" "" "openfast;linear;hydrodyn;servodyn;moordyn") +of_regression_linear("StC_test_OC4Semi_Linear_Nac" "" "openfast;linear;servodyn;stc") +of_regression_linear("StC_test_OC4Semi_Linear_Tow" "" "openfast;linear;servodyn;stc") +of_regression_linear("WP_Stationary_Linear" "" "openfast;linear;elastodyn") +of_regression_linear("5MW_OC3Spar_Linear" "" "openfast;linear;map;hydrodyn") +of_regression_linear("5MW_OC3Mnpl_Linear" "" "openfast;linear;hydrodyn;servodyn;moordyn") # FAST Farm regression tests if(BUILD_FASTFARM) @@ -388,16 +401,27 @@ bd_regression("bd_static_twisted_with_k1" "beamdyn;static") # HydroDyn regression tests hd_regression("hd_OC3tripod_offshore_fixedbottom_wavesirr" "hydrodyn;offshore") -#hd_regression("hd_5MW_ITIBarge_DLL_WTurb_WavesIrr" "hydrodyn;offshore") +#hd_regression("hd_5MW_ITIBarge_DLL_WTurb_WavesIrr" "hydrodyn;offshore") hd_regression("hd_5MW_OC3Spar_DLL_WTurb_WavesIrr" "hydrodyn;offshore") -#hd_regression("hd_5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "hydrodyn;offshore") +#hd_regression("hd_5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "hydrodyn;offshore") hd_regression("hd_5MW_OC4Semi_WSt_WavesWN" "hydrodyn;offshore") hd_regression("hd_5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "hydrodyn;offshore") hd_regression("hd_TaperCylinderPitchMoment" "hydrodyn;offshore") hd_regression("hd_NBodyMod1" "hydrodyn;offshore") hd_regression("hd_NBodyMod2" "hydrodyn;offshore") hd_regression("hd_NBodyMod3" "hydrodyn;offshore") - +hd_regression("hd_WaveStMod1" "hydrodyn;offshore") +hd_regression("hd_WaveStMod2" "hydrodyn;offshore") +hd_regression("hd_WaveStMod3" "hydrodyn;offshore") +hd_regression("hd_MHstLMod2" "hydrodyn;offshore") +hd_regression("hd_MHstLMod1_compare" "hydrodyn;offshore") +hd_regression("hd_MHstLMod2_compare" "hydrodyn;offshore") +hd_regression("hd_MCF_WaveStMod0" "hydrodyn;offshore") +hd_regression("hd_MCF_WaveStMod1" "hydrodyn;offshore") +hd_regression("hd_MCF_WaveStMod2" "hydrodyn;offshore") +hd_regression("hd_MCF_WaveStMod3" "hydrodyn;offshore") +hd_regression("hd_ExctnMod1_ExctnDisp1" "hydrodyn;offshore") +hd_regression("hd_ExctnMod1_ExctnDisp2" "hydrodyn;offshore") # Py-HydroDyn regression tests py_hd_regression("py_hd_5MW_OC4Semi_WSt_WavesWN" "hydrodyn;offshore;python") @@ -436,6 +460,11 @@ py_ifw_regression("py_ifw_turbsimff" "inflowwind;python seast_regression("seastate_1" "seastate") seast_regression("seastate_wavemod5" "seastate") seast_regression("seastate_wr_kin1" "seastate") +seast_regression("seastate_CNW1" "seastate") +seast_regression("seastate_CNW2" "seastate") +seast_regression("seastate_WaveMod7_WaveStMod1" "seastate") +seast_regression("seastate_WaveMod7_WaveStMod2" "seastate") +seast_regression("seastate_WaveMod7_WaveStMod3" "seastate") # MoorDyn regression tests md_regression("md_5MW_OC4Semi" "moordyn") diff --git a/reg_tests/executeOpenfastLinearRegressionCase.py b/reg_tests/executeOpenfastLinearRegressionCase.py index 9a721acab4..f99bb9e23c 100644 --- a/reg_tests/executeOpenfastLinearRegressionCase.py +++ b/reg_tests/executeOpenfastLinearRegressionCase.py @@ -67,6 +67,7 @@ def isclose(a, b, rtol=1e-09, atol=0.0): 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("-highpass", dest='highpass', metavar="LowPass-Filter", type=float, nargs='?', default=0.0, help="high pass filter on linearization frequencies to compare") args = parser.parse_args() @@ -79,6 +80,7 @@ def isclose(a, b, rtol=1e-09, atol=0.0): plotError = args.plot noExec = args.noExec verbose = args.verbose +highpass = args.highpass # --- Tolerances for matrix comparison # Outputs of lin matrices have 3 decimal digits leading to minimum error of 0.001 @@ -98,6 +100,10 @@ def isclose(a, b, rtol=1e-09, atol=0.0): rtol_d=1e-2 atol_d=1e-1 +# --- Filenames for frequency info +fileNameFreqRef="frequencies_ref.txt" +fileNameFreqNew="frequencies_new.txt" + CasePrefix=' Case: {}: '.format(caseName) def exitWithError(msg): @@ -120,6 +126,8 @@ def indent(msg, sindent='\t'): inputsDirectory = os.path.join(moduleDirectory, caseName) targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) +fNameFreqRef = os.path.join(testBuildDirectory, fileNameFreqRef) +fNameFreqNew = os.path.join(testBuildDirectory, fileNameFreqNew) # verify all the required directories exist if not os.path.isdir(rtest): @@ -183,7 +191,7 @@ def indent(msg, sindent='\t'): ### test for regression (compare lin files only) -def compareLin(f): +def compareLin(f,file_freq_ref,file_freq_new): Errors = [] ElemErrors = [] @@ -206,6 +214,14 @@ def newError(msg): print(msg) Errors.append(msg) + def ApplyHighPass(freq,zeta): + freqL=np.array([]) + zetaL=np.array([]) + for i in range(len(freq)): + if freq[i]>highpass: + freqL = np.append(freqL,freq[i]) + zetaL = np.append(zetaL,zeta[i]) + return freqL,zetaL @@ -244,6 +260,9 @@ def newError(msg): _, 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) + freq_bas, zeta_bas = ApplyHighPass( freq_bas, zeta_bas ) + freq_loc, zeta_loc = ApplyHighPass( freq_loc, zeta_loc ) + if len(freq_bas)==0: # We use complex eigenvalues instead of frequencies/damping # If this fails often, we should discard this test. @@ -261,12 +280,44 @@ def newError(msg): 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), '[%]') + print('\n'+errPrefix+':') + print(' Frequency (Hz) Damping (%)') + print(' ---------------------------- ----------------------------') + print(' Ref New Ref New') + + #write frequencies to file + try: + file_freq_ref.write('\n'+errPrefix+':\n') + file_freq_ref.write(' Freq (Hz) Damp (%)\n') + file_freq_new.write('\n'+errPrefix+':\n') + file_freq_new.write(' Freq (Hz) Damp (%)\n') + except Exception: + pass # ignore all writing errors + + + for j in range(min(10,max(len(freq_bas),len(freq_loc)))): + if j0: Errors += ElemErrorsLoc[:3] # Just a couple of them +freqFileClose(ff1,ff2) + + if len(Errors)>0: exitWithError('See errors below: \n'+'\n'.join(Errors)) diff --git a/reg_tests/executeUnsteadyAeroRegressionCase.py b/reg_tests/executeUnsteadyAeroRegressionCase.py index b8ca227924..ab9e5255a2 100644 --- a/reg_tests/executeUnsteadyAeroRegressionCase.py +++ b/reg_tests/executeUnsteadyAeroRegressionCase.py @@ -90,7 +90,7 @@ # create the local output directory and initialize it with input files -renameDict={'UA'+str(i)+'.UA.out':'UA'+str(i)+'.UA_ref.out' for i in [2,3,4,5,6,7]} +renameDict={'UA'+str(i)+'.outb':'UA'+str(i)+'_ref.outb' for i in [2,3,4,5,6,7]} rtl.copyTree(inputsDirectory, testBuildDirectory, renameDict=renameDict , excludeExt=['.sum']) @@ -116,8 +116,8 @@ def Error(msg): ### Compare output with for dvrf in dvrFiles: simName = os.path.splitext(os.path.basename(dvrf))[0] - localOutFile = os.path.join(testBuildDirectory, simName + '.UA.out') - baselineOutFile = os.path.join(inputsDirectory, simName + '.UA.out') + localOutFile = os.path.join(testBuildDirectory, simName + '.outb') + baselineOutFile = os.path.join(inputsDirectory, simName + '.out') # TODO TODO if not os.path.exists(localOutFile): Error('File does not exist: {}'.format(localOutFile)) diff --git a/reg_tests/lib/fast_linearization_file.py b/reg_tests/lib/fast_linearization_file.py index 3606e6699f..bda25b1ba2 100644 --- a/reg_tests/lib/fast_linearization_file.py +++ b/reg_tests/lib/fast_linearization_file.py @@ -84,17 +84,17 @@ def readOP(fid, n, name=''): OP=[] Var = {'RotatingFrame': [], 'DerivativeOrder': [], 'Description': []} colNames=fid.readline().strip() - dummy= fid.readline().strip() + fid.readline().strip() bHasDeriv= colNames.find('Derivative Order')>=0 for i, line in enumerate(fid): - sp=line.strip().split() - if sp[1].find(',')>=0: + 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])) + OP.append(np.float32(sp[1][:-1])) iRot=4 else: - OP.append(float(sp[1])) + OP.append(np.float32(sp[1])) iRot=2 Var['RotatingFrame'].append(sp[iRot]) if bHasDeriv: @@ -109,23 +109,23 @@ def readOP(fid, n, name=''): 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) + + # Read rows from file, raise exception on failure try: - vals = np.array(vals).astype(float) # This could potentially fail + vals = np.genfromtxt(fid, dtype=np.float64, max_rows=n) except: raise Exception('Failed to convert into an array of float the matrix `{}`\n\tin linfile: {}'.format(name, self.filename)) + + # Raise exception if actual matrix shape does not match expected shape 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 exceptions if any elements are NaN or infinity + if np.any(np.isnan(vals.ravel())): raise Exception('Some ill-formated/infinite values (e.g. `*******`) were found in the matrix `{}`\n\tin linflile: {}'.format(name, self.filename)) - if nNaN>0: + if np.any(np.isinf(vals.ravel())): raise Exception('Some NaN values were found in the matrix `{}`\n\tin linfile: `{}`.'.format(name, self.filename)) return vals @@ -142,15 +142,15 @@ def readMat(fid, n, m, name=''): 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:')) + self['Azimuth'] = np.float32(extractVal(self['header'],'Azimuth:')) except: self['Azimuth'] = None try: - self['RotSpeed'] = float(extractVal(self['header'],'Rotor Speed:')) # rad/s + self['RotSpeed'] = np.float32(extractVal(self['header'],'Rotor Speed:')) # rad/s except: self['RotSpeed'] = None try: - self['WindSpeed'] = float(extractVal(self['header'],'Wind Speed:')) + self['WindSpeed'] = np.float32(extractVal(self['header'],'Wind Speed:')) except: self['WindSpeed'] = None diff --git a/reg_tests/r-test b/reg_tests/r-test index de26d247b7..6ac3a141f0 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit de26d247b7b2b94134ff8bdc367a345ce4035bf3 +Subproject commit 6ac3a141f01e2d922db7441ba5d4194f4a409c2c diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..21752feaf4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# Python dependencies used for testing +numpy +vtk +Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3 \ No newline at end of file diff --git a/share/docker/Dockerfile b/share/docker/Dockerfile new file mode 100644 index 0000000000..742d6b0a59 --- /dev/null +++ b/share/docker/Dockerfile @@ -0,0 +1,73 @@ +# Copyright 2016-2024 National Renewable Energy Laboratory +# +# 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. +# +ARG BASE=ubuntu:jammy + +# Build stage 1: builds openfast. +FROM ${BASE} AS build + +# Install dependencies +# For gfortran-8 +# RUN add-apt-repository ppa:ubuntu-toolchain-r/test -y +# apt-get install gfortran-8 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y \ + software-properties-common \ + build-essential \ + cmake \ + cmake-curses-gui \ + gcc \ + gfortran \ + git \ + libopenblas-dev \ + make \ + && rm -rf /var/lib/apt/lists/* + +# Copy in the checked-out code version. +WORKDIR /openfast +COPY . . + +# Build the project. +RUN mkdir build +WORKDIR /openfast/build + +# NOTE: building with optimizations on (RELEASE or RELWITHDEBINFO), the virtual machine +# will require about 6GB of memory. Otherwise, the gfortran compiler will exit with an +# "internal error" +ENV FC=/usr/bin/gfortran +ARG CMAKE_OPTIONS="-DBUILD_TESTING=OFF -DBUILD_FASTFARM=ON -DDOUBLE_PRECISION=OFF -DCMAKE_BUILD_TYPE=RELEASE" +RUN cmake .. ${CMAKE_OPTIONS} + +ARG BUILD_CORES=4 +RUN make -j${BUILD_CORES} install + +# Build stage 2: provides built openfast in a small image. +FROM ${BASE} as production +COPY --from=build /openfast/install /openfast/install + +ARG TIMEZONE=UTC +ENV DEBIAN_FRONTEND=noninteractive TZ=${TIMEZONE} + +RUN apt-get update -qq && \ + apt-get install --no-install-recommends -y \ + libopenblas-dev \ + libgomp1 \ + nano \ + && rm -rf /var/lib/apt/lists/* + +# Make `openfast` command work. +ENV PATH=/openfast/install/bin:$PATH diff --git a/share/docker/README.md b/share/docker/README.md new file mode 100644 index 0000000000..82517f7b1f --- /dev/null +++ b/share/docker/README.md @@ -0,0 +1,42 @@ +# OpenFAST docker images + +## Summary +The `Dockerfile` in this directory can be used to reliably build OpenFAST as a docker image that can be run locally and +in the cloud without much setup. By default, it's based on Ubuntu Jammy and is optimised in size and performance for +production use. A multi-stage build is used, producing an Ubuntu image with just `libblas-dev`, `liblapack-dev`, `nano` +and `openfast` added. The image built by this `Dockerfile` can be customised at build time using build arguments. + +## Image registry +Production images of OpenFAST for the `linux/amd64` platform are available on the +[NREL docker hub](https://hub.docker.com/r/nrel/openfast). + +## Build arguments +Provide any of the following build arguments to customise the image at build time. + +| Name | Type | Allowed values | Default | Description | +| --------------- | ------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------| +| `BASE` | String | Any valid docker image URI that has the `apt` package manager installed. | `ubuntu:jammy` | The docker image to base the OpenFAST image on. | +| `CMAKE_OPTIONS` | String | Any number of valid space-separated `cmake` options in the same format they're normally passed to `cmake` directly. See the options relevant to OpenFAST [here.](https://openfast.readthedocs.io/en/main/source/install/index.html#openfast-cmake-options) | `-DBUILD_TESTING=OFF -DBUILD_FASTFARM=ON -DDOUBLE_PRECISION=OFF -DCMAKE_BUILD_TYPE=RELEASE` | Options to control how CMake is used to build OpenFAST. | +| `BUILD_CORES` | Integer | Any integer greater than 0. | `4` | The number of cores to use to build OpenFAST with `make`. | +| `TIMEZONE` | String | Any [valid timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). | `UTC` | The timezone to use when running OpenFAST. | + +For example, to build OpenFAST v3.5.3 for the `linux/amd64` platform and set `CMAKE_OPTIONS` so the testing tree is built: + +```shell +# Run from the root of this repository. +git checkout v3.5.3 +docker build -f share/docker/Dockerfile -t openfast:3.5.3 --platform=linux/amd64 --build-arg=CMAKE_OPTIONS='-DBUILD_TESTING=ON' . +``` + +**NOTE:** This version of the `Dockerfile` is only available in v3.5.3 and up of this repository. To build earlier +versions of OpenFAST, check out the code at that version and recreate the `Dockerfile` from v3.5.3 (or above) in the +checked-out repository first. + +## Building development images +Development images can be built from the production image as a base. Simply start a new `Dockerfile` with: + +```dockerfile +FROM nrel/openfast:3.5.3 +``` + +Images can be built for different platforms using the `--platform` option when building the image. diff --git a/share/docker/openfast_ubuntu/Dockerfile b/share/docker/openfast_ubuntu/Dockerfile deleted file mode 100644 index 8470e56230..0000000000 --- a/share/docker/openfast_ubuntu/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright 2016 National Renewable Energy Laboratory -# -# 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. -# - -FROM ubuntu:bionic - -# Install dependencies - -# For gfortran-8 -# RUN add-apt-repository ppa:ubuntu-toolchain-r/test -y -# apt-get install gfortran-8 - -ENV DEBIAN_FRONTEND=noninteractive TZ=America/Denver - -RUN apt update -qq && \ - apt install -y software-properties-common build-essential && \ - add-apt-repository ppa:git-core/ppa -y && \ - apt install -y python3-pip && \ - apt install -y cmake cmake-curses-gui && \ - apt install -y gcc gfortran make && \ - apt install -y libblas-dev liblapack-dev && \ - apt install -y git && \ - apt install -y nano - -RUN pip3 install numpy - -# Configure the environment -ENV FC=/usr/bin/gfortran - -# Clone the project -RUN git clone --recursive https://github.com/openfast/openfast.git openfast -WORKDIR /openfast - -# Build the project -RUN mkdir build -WORKDIR /openfast/build - -# NOTE: building with optimizations on (RELEASE or RELWITHDEBINFO), the virtual machine -# will require about 6GB of memoery. Otherwise, the gfortran compiler will exit with an -# "internal error" -RUN cmake .. -DBUILD_TESTING=ON -DDOUBLE_PRECISION=ON -DCMAKE_BUILD_TYPE=RELWITHDEBINFO -RUN make -j4 install diff --git a/vs-build/AeroDyn/AeroDyn_Driver.sln b/vs-build/AeroDyn/AeroDyn_Driver.sln index 2941d4240d..f9a1f191eb 100644 --- a/vs-build/AeroDyn/AeroDyn_Driver.sln +++ b/vs-build/AeroDyn/AeroDyn_Driver.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.33529.622 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "AeroDyn_Driver", "AeroDyn_Driver.vfproj", "{97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}" ProjectSection(ProjectDependencies) = postProject @@ -44,26 +44,26 @@ Global {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|Win32.Build.0 = Release|Win32 {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.ActiveCfg = Release|x64 {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/AeroDyn_Inflow_c_binding/AeroDyn_Inflow_c_binding.sln b/vs-build/AeroDyn_Inflow_c_binding/AeroDyn_Inflow_c_binding.sln index e9a3790633..295a6d1e8d 100644 --- a/vs-build/AeroDyn_Inflow_c_binding/AeroDyn_Inflow_c_binding.sln +++ b/vs-build/AeroDyn_Inflow_c_binding/AeroDyn_Inflow_c_binding.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.33529.622 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "AeroDyn_Inflow_c_binding", "AeroDyn_Inflow_c_binding.vfproj", "{5D991B19-D4F1-4F29-8A9D-FC36DFF07290}" ProjectSection(ProjectDependencies) = postProject @@ -44,26 +44,26 @@ Global {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|Win32.Build.0 = Release|Win32 {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|x64.ActiveCfg = Release|x64 {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/BeamDyn/BeamDyn-w-registry.sln b/vs-build/BeamDyn/BeamDyn-w-registry.sln index 0261cbdc7e..573fd9f26f 100644 --- a/vs-build/BeamDyn/BeamDyn-w-registry.sln +++ b/vs-build/BeamDyn/BeamDyn-w-registry.sln @@ -38,22 +38,22 @@ Global {815C302F-A93D-4C22-9329-7112345113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-7112345113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-7112345113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/FAST-farm/FAST-Farm.sln b/vs-build/FAST-farm/FAST-Farm.sln index b7159f95f0..bab76b0d32 100644 --- a/vs-build/FAST-farm/FAST-Farm.sln +++ b/vs-build/FAST-farm/FAST-Farm.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "FASTlib", "..\FASTlib\FASTlib.vfproj", "{1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}" ProjectSection(ProjectDependencies) = postProject @@ -55,18 +55,18 @@ Global {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|Win32.Build.0 = Release|Win32 {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.ActiveCfg = Release|x64 {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 {F47C7C94-2A7F-4CBE-B834-1BC7DD3FE692}.Debug|Win32.ActiveCfg = Debug|Win32 {F47C7C94-2A7F-4CBE-B834-1BC7DD3FE692}.Debug|Win32.Build.0 = Debug|Win32 {F47C7C94-2A7F-4CBE-B834-1BC7DD3FE692}.Debug|x64.ActiveCfg = Debug|x64 @@ -83,4 +83,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {13BD9A6C-E2B3-4423-AA37-D06CB518B5B2} + EndGlobalSection EndGlobal diff --git a/vs-build/FAST-farm/FAST-Farm.vfproj b/vs-build/FAST-farm/FAST-Farm.vfproj index e88a7fab0d..e7c3152f30 100644 --- a/vs-build/FAST-farm/FAST-Farm.vfproj +++ b/vs-build/FAST-farm/FAST-Farm.vfproj @@ -6,7 +6,7 @@ - + diff --git a/vs-build/FAST/FAST.sln b/vs-build/FAST/FAST.sln index ec3d691059..f1f08b2b9d 100644 --- a/vs-build/FAST/FAST.sln +++ b/vs-build/FAST/FAST.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27428.2043 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "FAST", "FAST.vfproj", "{18AE8067-CCC6-4479-A0DB-C4089EF9FE71}" ProjectSection(ProjectDependencies) = postProject @@ -110,30 +110,30 @@ Global {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|Win32.Build.0 = Release|Win32 {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.ActiveCfg = Release|x64 {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 {C3C93CC0-EDD7-438F-988C-1F917FAEFA67}.Debug_Double|Win32.ActiveCfg = Debug_Matlab|Win32 {C3C93CC0-EDD7-438F-988C-1F917FAEFA67}.Debug_Double|x64.ActiveCfg = Debug_Matlab|x64 {C3C93CC0-EDD7-438F-988C-1F917FAEFA67}.Debug_Matlab|Win32.ActiveCfg = Debug_Matlab|Win32 diff --git a/vs-build/FASTlib/FASTlib.vfproj b/vs-build/FASTlib/FASTlib.vfproj index 9325e85b01..4485780101 100644 --- a/vs-build/FASTlib/FASTlib.vfproj +++ b/vs-build/FASTlib/FASTlib.vfproj @@ -128,7 +128,7 @@ - + @@ -678,6 +678,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1467,45 +1547,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2039,47 +2080,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2179,44 +2179,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2306,7 +2268,6 @@ - diff --git a/vs-build/HydroDyn/HydroDynDriver.sln b/vs-build/HydroDyn/HydroDynDriver.sln index 10a8c91d84..17c738b756 100644 --- a/vs-build/HydroDyn/HydroDynDriver.sln +++ b/vs-build/HydroDyn/HydroDynDriver.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "HydroDynDriver", "HydroDynDriver.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" EndProject diff --git a/vs-build/HydroDyn/HydroDynDriver.vfproj b/vs-build/HydroDyn/HydroDynDriver.vfproj index 82488ba7a2..91a7989cbf 100644 --- a/vs-build/HydroDyn/HydroDynDriver.vfproj +++ b/vs-build/HydroDyn/HydroDynDriver.vfproj @@ -558,30 +558,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -641,7 +617,6 @@ - diff --git a/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.sln b/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.sln index 7d4579ad4f..753bece4fc 100644 --- a/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.sln +++ b/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{A2215CCC-531E-454C-A1F0-E502FB697697}") = "HydroDyn_c_binding.dll", "HydroDyn_c_binding.vfproj", "{FDA4A02B-B3A7-4D06-847C-941BE44E76FB}" +Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "HydroDyn_c_binding", "HydroDyn_c_binding.vfproj", "{FDA4A02B-B3A7-4D06-847C-941BE44E76FB}" ProjectSection(ProjectDependencies) = postProject {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} = {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} EndProjectSection @@ -38,24 +38,27 @@ Global {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release|Win32.Build.0 = Release|Win32 {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release|x64.ActiveCfg = Release|x64 {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {49DA4583-1BAB-4459-8F53-EB898075680D} + EndGlobalSection EndGlobal diff --git a/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.vfproj b/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.vfproj index 4481a2cde7..f447d872ac 100644 --- a/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.vfproj +++ b/vs-build/HydroDyn_c_binding/HydroDyn_c_binding.vfproj @@ -318,30 +318,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -401,7 +377,6 @@ - diff --git a/vs-build/InflowWind/InflowWind_driver.sln b/vs-build/InflowWind/InflowWind_driver.sln index c1f9d4753e..6bc82e29a1 100644 --- a/vs-build/InflowWind/InflowWind_driver.sln +++ b/vs-build/InflowWind/InflowWind_driver.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.33529.622 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "InflowWind_driver", "InflowWind_driver.vfproj", "{3BBE2741-5B28-47BC-9E7F-3E1D172838FB}" ProjectSection(ProjectDependencies) = postProject @@ -44,26 +44,26 @@ Global {3BBE2741-5B28-47BC-9E7F-3E1D172838FB}.Release|Win32.Build.0 = Release|Win32 {3BBE2741-5B28-47BC-9E7F-3E1D172838FB}.Release|x64.ActiveCfg = Release|x64 {3BBE2741-5B28-47BC-9E7F-3E1D172838FB}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_OpenMP|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/InflowWind_c_binding/InflowWind_c_binding.sln b/vs-build/InflowWind_c_binding/InflowWind_c_binding.sln index 03d412a05f..24fde71ef9 100644 --- a/vs-build/InflowWind_c_binding/InflowWind_c_binding.sln +++ b/vs-build/InflowWind_c_binding/InflowWind_c_binding.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "InflowWind_c_binding", "InflowWind_c_binding.vfproj", "{5D991B19-D4F1-4F29-8A9D-FC36DFF07290}" ProjectSection(ProjectDependencies) = postProject @@ -38,24 +38,27 @@ Global {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|Win32.Build.0 = Release|Win32 {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|x64.ActiveCfg = Release|x64 {5D991B19-D4F1-4F29-8A9D-FC36DFF07290}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7DBCF286-C404-4F79-A1F2-3A04C4859A09} + EndGlobalSection EndGlobal diff --git a/vs-build/MoorDyn/MoorDynDriver.sln b/vs-build/MoorDyn/MoorDynDriver.sln index 26252cc2de..29001b4108 100644 --- a/vs-build/MoorDyn/MoorDynDriver.sln +++ b/vs-build/MoorDyn/MoorDynDriver.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31613.86 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{A1373E92-2C9A-4B4D-BE47-0B46E317E1A8}") = "MoorDynDriver", "MoorDynDriver.vfproj", "{E91DED35-18F8-415F-9719-59DFBA79CB2C}" EndProject diff --git a/vs-build/MoorDyn_c_binding/MoorDyn_c_binding.sln b/vs-build/MoorDyn_c_binding/MoorDyn_c_binding.sln index fa41e081d7..d9d928b345 100644 --- a/vs-build/MoorDyn_c_binding/MoorDyn_c_binding.sln +++ b/vs-build/MoorDyn_c_binding/MoorDyn_c_binding.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31613.86 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{EBD10482-CD70-4409-938D-86A4D2DED606}") = "MoorDyn_c_binding.dll", "MoorDyn_c_binding.vfproj", "{25689C95-9A3C-41A1-B0E6-5B292B6EFBE9}" +Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "MoorDyn_c_binding", "MoorDyn_c_binding.vfproj", "{25689C95-9A3C-41A1-B0E6-5B292B6EFBE9}" ProjectSection(ProjectDependencies) = postProject {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} = {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} EndProjectSection @@ -38,22 +38,22 @@ Global {25689C95-9A3C-41A1-B0E6-5B292B6EFBE9}.Release|Win32.Build.0 = Release|Win32 {25689C95-9A3C-41A1-B0E6-5B292B6EFBE9}.Release|x64.ActiveCfg = Release|x64 {25689C95-9A3C-41A1-B0E6-5B292B6EFBE9}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/Registry/FAST_Registry.sln b/vs-build/Registry/FAST_Registry.sln index 689421c6c9..c79ad0bab2 100644 --- a/vs-build/Registry/FAST_Registry.sln +++ b/vs-build/Registry/FAST_Registry.sln @@ -1,20 +1,20 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27428.2043 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FAST_Registry", "FAST_Registry.vcxproj", "{DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Debug|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/RunRegistry.bat b/vs-build/RunRegistry.bat index adbc861f41..f56a56f29d 100644 --- a/vs-build/RunRegistry.bat +++ b/vs-build/RunRegistry.bat @@ -45,6 +45,8 @@ SET SrvD_Loc=%Modules_Loc%\servodyn\src SET BD_Loc=%Modules_Loc%\beamdyn\src SET SC_Loc=%Modules_Loc%\supercontroller\src +SET LD_Loc=%Modules_Loc%\lindyn\src + SET AWAE_Loc=%Modules_Loc%\awae\src SET WD_Loc=%Modules_Loc%\wakedynamics\src SET Farm_Loc=%Root_Loc%\glue-codes\fast-farm\src @@ -184,6 +186,12 @@ SET Output_Loc=%CURR_LOC% %REGISTRY% "%CURR_LOC%\UnsteadyAero_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" GOTO checkError +:LD +SET CURR_LOC=%LD_Loc% +SET Output_Loc=%CURR_LOC% +%REGISTRY% "%CURR_LOC%\LinDyn_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" +GOTO checkError + :FVW SET CURR_LOC=%AD_Loc% SET Output_Loc=%CURR_LOC% @@ -224,7 +232,6 @@ GOTO checkError :Current :Waves :Waves2 -:SeaState_Interp :SeaSt_WaveField SET CURR_LOC=%SEAST_Loc% diff --git a/vs-build/SC_DLL/SC_DLL.sln b/vs-build/SC_DLL/SC_DLL.sln index 54daab58ef..ce221a58ed 100644 --- a/vs-build/SC_DLL/SC_DLL.sln +++ b/vs-build/SC_DLL/SC_DLL.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "SC_DLL", "SC_DLL.vfproj", "{183CC593-AD4C-9643-81C1-7D6085A9A5ED}" EndProject diff --git a/vs-build/SeaState/SeaStateDriver.vfproj b/vs-build/SeaState/SeaStateDriver.vfproj index 208b6ce568..2d598d9e7c 100644 --- a/vs-build/SeaState/SeaStateDriver.vfproj +++ b/vs-build/SeaState/SeaStateDriver.vfproj @@ -295,29 +295,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -358,7 +335,6 @@ - diff --git a/vs-build/SubDyn/SubDyn.sln b/vs-build/SubDyn/SubDyn.sln index 817a37d8cd..fc06af462c 100644 --- a/vs-build/SubDyn/SubDyn.sln +++ b/vs-build/SubDyn/SubDyn.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.4.33205.214 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "SubDyn", "SubDyn.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" ProjectSection(ProjectDependencies) = postProject @@ -38,22 +38,22 @@ Global {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/UnsteadyAero/UnsteadyAero.sln b/vs-build/UnsteadyAero/UnsteadyAero.sln index 4daa940c63..9fbf677f9f 100644 --- a/vs-build/UnsteadyAero/UnsteadyAero.sln +++ b/vs-build/UnsteadyAero/UnsteadyAero.sln @@ -38,22 +38,22 @@ Global {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs-build/UnsteadyAero/UnsteadyAero.vfproj b/vs-build/UnsteadyAero/UnsteadyAero.vfproj index 4cb89b2f83..0903d0848b 100644 --- a/vs-build/UnsteadyAero/UnsteadyAero.vfproj +++ b/vs-build/UnsteadyAero/UnsteadyAero.vfproj @@ -5,7 +5,7 @@ - + @@ -15,7 +15,7 @@ - + @@ -25,7 +25,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -75,7 +75,7 @@ - + @@ -120,6 +120,27 @@ + + + + + + + + + + + + + + + + + + + + +