diff --git a/.gitattributes b/.gitattributes index 096b1c29a1..3cabefadce 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,4 @@ # add (semi-useful) version info to git archive CreateGitVersion.bat ident export-subst - # Declare files that will always have CRLF line endings on checkout. *.bat text eol=crlf - diff --git a/.github/actions/tests-module-aerodyn/action.yml b/.github/actions/tests-module-aerodyn/action.yml index 8759e9c58c..7dd9fb5570 100644 --- a/.github/actions/tests-module-aerodyn/action.yml +++ b/.github/actions/tests-module-aerodyn/action.yml @@ -18,7 +18,7 @@ runs: fi if [[ ${{ inputs.test-target }} == "regression" ]] || [[ ${{ inputs.test-target }} == "all" ]]; then - ctest -VV -j7 -R ad_ + ctest -VV -R ad_ # -j7 do not run these tests in parallel due to a bug in accessing shared files fi working-directory: ${{runner.workspace}}/openfast/build diff --git a/.github/actions/tests-module-hydrodyn/action.yml b/.github/actions/tests-module-hydrodyn/action.yml index 3e94eba00d..eb453ec203 100644 --- a/.github/actions/tests-module-hydrodyn/action.yml +++ b/.github/actions/tests-module-hydrodyn/action.yml @@ -4,6 +4,6 @@ author: 'Rafael Mudafort https://github.com/rafmudaf' runs: using: "composite" steps: - - run: ctest -VV -j7 -R hd_ + - run: ctest -VV -j7 -R hd_ -LE python working-directory: ${{runner.workspace}}/openfast/build shell: bash diff --git a/.github/actions/tests-module-version/action.yml b/.github/actions/tests-module-version/action.yml new file mode 100644 index 0000000000..d0ed3a723f --- /dev/null +++ b/.github/actions/tests-module-version/action.yml @@ -0,0 +1,9 @@ +name: 'VersionInfo module tests' +description: 'Run tests specific to the NWTC Library module' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: "composite" + steps: + - run: ctest -VV -R versioninfo_utest + working-directory: ${{runner.workspace}}/openfast/build + shell: bash diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 147e7fc78d..06ebebcf22 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -1,4 +1,4 @@ - + name: 'Development Pipeline' on: @@ -24,26 +24,32 @@ env: jobs: - regression-tests-release: + + ### BUILD JOBS + + + build-all-debug: + # Tests compiling in debug mode. + # TODO: NOT ENABLED Single precision compile checks that the precision types are correctly set. + # Debug more speeds up the build. runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@main with: submodules: recursive - - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.7' + python-version: '3.9' + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install numpy Bokeh==1.4 - - - name: Setup Workspace + pip install numpy Bokeh + - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure Build + - name: Configure build working-directory: ${{runner.workspace}}/openfast/build run: | cmake \ @@ -51,391 +57,700 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ + -DCMAKE_BUILD_TYPE:STRING=DEBUG \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ + -DVARIABLE_TRACKING=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ ${GITHUB_WORKSPACE} - - name: Build OpenFAST - # if: contains(github.event.head_commit.message, 'Action - Test All') || contains(github.event.pull_request.labels.*.name, 'Action - Test All') + # -DDOUBLE_PRECISION=OFF \ + - name: Build all working-directory: ${{runner.workspace}}/openfast/build - run: cmake --build . --target install -- -j ${{env.NUM_PROCS}} - - - name: Run SubDyn tests - uses: ./.github/actions/tests-module-subdyn - - name: Run AeroDyn tests - uses: ./.github/actions/tests-module-aerodyn - with: - test-target: regression - - name: Run HydroDyn tests - uses: ./.github/actions/tests-module-hydrodyn - - name: Run InflowWind tests - uses: ./.github/actions/tests-module-inflowwind - with: - test-target: regression - - name: Run BeamDyn tests - uses: ./.github/actions/tests-module-beamdyn + run: | + cmake --build . --target all -- -j ${{env.NUM_PROCS}} + - name: Cache the workspace + uses: actions/cache@v3.0.4 with: - test-target: regression - - name: Run OpenFAST tests - # if: contains(github.event.head_commit.message, 'Action - Test All') || contains(github.event.pull_request.labels.*.name, 'Action - Test All') - uses: ./.github/actions/tests-gluecode-openfast + path: ${{runner.workspace}} + key: build-all-debug-${{ github.sha }} - - name: Failing test artifacts - uses: actions/upload-artifact@v2 - if: failure() - with: - name: regression-tests-release - path: | - ${{runner.workspace}}/openfast/build/reg_tests/modules - ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline - regression-tests-debug: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: macOS-11 - FORTRAN_COMPILER: gfortran-11 - install_deps: brew install gcovr - - os: ubuntu-20.04 - FORTRAN_COMPILER: gfortran-10 - install_deps: sudo apt-get update && sudo apt-get install -y gcovr - - name: regression-test-debug-${{ matrix.os }}-${{ matrix.FORTRAN_COMPILER }} + build-drivers-release: + runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@main with: submodules: recursive - - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.7' - - name: Install Dependencies + python-version: '3.9' + cache: 'pip' + - name: Install dependencies run: | python -m pip install --upgrade pip - pip install numpy Bokeh==1.4 - ${{matrix.install_deps}} - - - name: Setup Workspace + pip install numpy Bokeh + - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure Build + - name: Configure build working-directory: ${{runner.workspace}}/openfast/build run: | cmake \ -DCMAKE_INSTALL_PREFIX:PATH=${{runner.workspace}}/openfast/install \ - -DCMAKE_Fortran_COMPILER:STRING=${{matrix.FORTRAN_COMPILER}} \ + -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ - -DCMAKE_BUILD_TYPE:STRING=Debug \ + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ + -DVARIABLE_TRACKING=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ ${GITHUB_WORKSPACE} - - - name: Build Drivers + - name: Build module drivers working-directory: ${{runner.workspace}}/openfast/build run: | - cmake --build . --target aerodyn_driver -- -j ${{env.NUM_PROCS}} - cmake --build . --target beamdyn_driver -- -j ${{env.NUM_PROCS}} - cmake --build . --target hydrodyn_driver -- -j ${{env.NUM_PROCS}} - cmake --build . --target inflowwind_driver -- -j ${{env.NUM_PROCS}} - cmake --build . --target subdyn_driver -- -j ${{env.NUM_PROCS}} - - - name: Run SubDyn tests - uses: ./.github/actions/tests-module-subdyn - - name: Run AeroDyn tests - uses: ./.github/actions/tests-module-aerodyn - with: - test-target: regression - - name: Run HydroDyn tests - uses: ./.github/actions/tests-module-hydrodyn - - name: Run InflowWind tests - uses: ./.github/actions/tests-module-inflowwind + cmake --build . --target regression_test_module_drivers -- -j ${{env.NUM_PROCS}} + - name: Cache the workspace + uses: actions/cache@v3.0.4 with: - test-target: regression - - name: Run BeamDyn tests - uses: ./.github/actions/tests-module-beamdyn - with: - test-target: regression + path: ${{runner.workspace}} + key: build-drivers-release-${{ github.sha }} - # Disabled Codecov since the dashboard and GitHub comments were buggy, - # but it may be useful to post the gcov coverage reports to GitHub Actions - # artifacts. - # Note: if reenabling Codecov, the reports must be in xml format not html. - # - name: Generate coverage report - # working-directory: ${{runner.workspace}}/openfast/build - # run: | - # find . -type f -name '*.gcno' -not -path "**tests**" -exec ${{env.GCOV_EXE}} -pb {} + - # cd .. - # gcovr -g -k -r . --html --html-details -o regressioncov.html # -v - # # cp `find . -name *.gcno` . - # # cp `find . -name *.gcda` . - # # ${{env.GCOV_EXE}} -b -l -p -c *.gcno - # - name: Success artifacts - # uses: actions/upload-artifact@v2 - # if: success() - # with: - # name: regression-tests-debug - # path: | - # ${{runner.workspace}}/openfast/regressioncov.html - - name: Failing test artifacts - uses: actions/upload-artifact@v2 - if: failure() - with: - name: regression-tests-debug - path: | - ${{runner.workspace}}/openfast/build/reg_tests/modules - fastfarm-regression-test: + build-postlib-release: runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@main with: submodules: recursive - - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.7' + python-version: '3.9' + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install numpy Bokeh==1.4 - - - name: Setup Workspace + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev # gcovr + - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure Build + - name: Configure build working-directory: ${{runner.workspace}}/openfast/build run: | cmake \ -DCMAKE_INSTALL_PREFIX:PATH=${{runner.workspace}}/openfast/install \ -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ + -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ + -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DCMAKE_BUILD_TYPE:STRING=RELWITHDEBINFO \ -DOPENMP:BOOL=ON \ + -DDOUBLE_PRECISION=ON \ + -DVARIABLE_TRACKING=OFF \ -DBUILD_FASTFARM:BOOL=ON \ - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ + -DBUILD_OPENFAST_CPP_API:BOOL=ON \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ ${GITHUB_WORKSPACE} - - name: Build FAST.Farm - # if: contains(github.event.head_commit.message, 'Action - Test All') || contains(github.event.pull_request.labels.*.name, 'Action - Test All') + - name: Build openfast-postlib + working-directory: ${{runner.workspace}}/openfast/build + run: cmake --build . --target openfast_postlib -- -j ${{env.NUM_PROCS}} + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-postlib-release-${{ github.sha }} + + + build-interfaces-release: + runs-on: ubuntu-20.04 + needs: build-postlib-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-postlib-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Build OpenFAST C-Interfaces working-directory: ${{runner.workspace}}/openfast/build run: | - cmake --build . --target FAST.Farm -- -j ${{env.NUM_PROCS}} - cmake --build . --target regression_tests -- -j ${{env.NUM_PROCS}} + cmake --build . --target openfastlib -- -j ${{env.NUM_PROCS}} + cmake --build . --target openfast_cpp -- -j ${{env.NUM_PROCS}} + cmake --build . --target openfastcpp -- -j ${{env.NUM_PROCS}} + cmake --build . --target ifw_c_binding -- -j ${{env.NUM_PROCS}} + cmake --build . --target hydrodyn_c_binding -- -j ${{env.NUM_PROCS}} + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-interfaces-release-${{ github.sha }} - - name: Run FAST.Farm tests + + build-openfast-release: + runs-on: ubuntu-20.04 + needs: build-postlib-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-postlib-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies run: | - ctest -VV -L fastfarm -j ${{env.NUM_PROCS}} + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Build OpenFAST glue-code working-directory: ${{runner.workspace}}/openfast/build - shell: bash + run: | + cmake --build . --target openfast -- -j ${{env.NUM_PROCS}} + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + + build-fastfarm-release: + runs-on: ubuntu-20.04 + needs: build-postlib-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-postlib-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Build FAST.Farm + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake --build . --target FAST.Farm -- -j ${{env.NUM_PROCS}} + - name: Upload build + uses: actions/upload-artifact@main + with: + name: fastfarm-build + path: build-fastfarm-${{ github.sha }}.tar + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-fastfarm-release-${{ github.sha }} + + + ### TEST JOBS + + rtest-module-drivers: + runs-on: ubuntu-20.04 + needs: build-drivers-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-drivers-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Run AeroDyn tests + uses: ./.github/actions/tests-module-aerodyn + with: + test-target: regression + - name: Run BeamDyn tests + uses: ./.github/actions/tests-module-beamdyn + with: + test-target: regression + - name: Run HydroDyn tests + uses: ./.github/actions/tests-module-hydrodyn + - name: Run InflowWind tests + uses: ./.github/actions/tests-module-inflowwind + with: + test-target: regression + - name: Run SubDyn tests + uses: ./.github/actions/tests-module-subdyn - name: Failing test artifacts uses: actions/upload-artifact@v2 if: failure() with: - name: test-results + name: rtest-module-drivers path: | - ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/fastfarm + ${{runner.workspace}}/openfast/build/reg_tests/modules + - unit-test: + rtest-modules-debug: runs-on: ubuntu-20.04 + needs: build-all-debug steps: - - name: Checkout - uses: actions/checkout@main + - name: Cache the workspace + uses: actions/cache@v3.0.4 with: - submodules: recursive - + path: ${{runner.workspace}} + key: build-all-debug-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.7' + python-version: '3.9' + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install numpy Bokeh==1.4 - + pip install numpy Bokeh sudo apt-get update -y - sudo apt-get install -y gcovr - - - name: Setup Workspace - run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure Build + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | cmake \ - -DCMAKE_INSTALL_PREFIX:PATH=${{runner.workspace}}/openfast/install \ - -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ - -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ - -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ - -DCMAKE_BUILD_TYPE:STRING=Debug \ -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ ${GITHUB_WORKSPACE} - - - name: Build unit tests - working-directory: ${{runner.workspace}}/openfast/build - run: cmake --build . --target unit_tests -- -j ${{env.NUM_PROCS}} - - - name: Run NWTC Library tests - uses: ./.github/actions/tests-module-nwtclibrary + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} - name: Run AeroDyn tests uses: ./.github/actions/tests-module-aerodyn with: + # Don't run regression tests here since they currently fail inconsistently test-target: unit - name: Run BeamDyn tests uses: ./.github/actions/tests-module-beamdyn - with: - test-target: unit + - name: Run HydroDyn tests + uses: ./.github/actions/tests-module-hydrodyn - name: Run InflowWind tests uses: ./.github/actions/tests-module-inflowwind + - name: Run NWTC Library tests + uses: ./.github/actions/tests-module-nwtclibrary + - name: Run SubDyn tests + uses: ./.github/actions/tests-module-subdyn + - name: Run VersionInfo tests + uses: ./.github/actions/tests-module-version + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() with: - test-target: unit + name: rtest-modules-debug + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/unit_tests - # Disabled Codecov since the dashboard and GitHub comments were buggy, - # but it may be useful to post the gcov coverage reports to GitHub Actions - # artifacts. - # Note: if reenabling Codecov, the reports must be in xml format not html. - # - name: Generate coverage report - # working-directory: ${{runner.workspace}}/openfast/build - # run: | - # find . -type f -name '*.gcno' -not -path "**tests**" -exec ${{env.GCOV_EXE}} -pb {} + - # cd .. - # gcovr -g -k -r . --html --html-details unitcov.html - # - name: Success artifacts - # uses: actions/upload-artifact@v2 - # if: success() - # with: - # name: unit-tests - # path: | - # ${{runner.workspace}}/openfast/unitcov.html + rtest-interfaces: + runs-on: ubuntu-20.04 + needs: build-interfaces-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-interfaces-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Run Interface / API tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L "cpp|python" -j ${{env.NUM_PROCS}} - name: Failing test artifacts uses: actions/upload-artifact@v2 if: failure() with: - name: unit-tests + name: rtest-interfaces path: | - ${{runner.workspace}}/openfast/build/unit_tests + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast-cpp + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/python + ${{runner.workspace}}/openfast/build/reg_tests/modules/inflowwind + ${{runner.workspace}}/openfast/build/reg_tests/modules/hydrodyn + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast-cpp/5MW_Baseline - compile-all-single-precision: - # Test if single precision compile completes. - # Compiles all targets excluding tests. - # Run with the OpenFAST registry generating the types files. - # Do not run the test suite. + rtest-OF: runs-on: ubuntu-20.04 + needs: build-openfast-release steps: - - name: Checkout - uses: actions/checkout@main + - name: Cache the workspace + uses: actions/cache@v3.0.4 with: - submodules: recursive - - name: Setup - run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure - working-directory: ${{runner.workspace}}/openfast/build + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies run: | - cmake \ - -DCMAKE_INSTALL_PREFIX:PATH=${{runner.workspace}}/openfast/install \ - -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ - -DCMAKE_BUILD_TYPE:STRING=Debug \ - -DDOUBLE_PRECISION:BOOL=OFF \ - -DGENERATE_TYPES:BOOL=ON \ - ${GITHUB_WORKSPACE} - - name: Build all + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build - run: cmake --build . --target all -- -j ${{env.NUM_PROCS}} - - name: Test + run: | + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build - run: ./glue-codes/openfast/openfast -v + run: | + ctest -VV -j8 \ + -L openfast \ + -LE "cpp|linear|python" \ + -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@v2 + if: failure() + with: + name: rtest-OF + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline - interface-tests: + + rtest-OF-5MW_OC4Semi_WSt_WavesWN: runs-on: ubuntu-20.04 + needs: build-openfast-release steps: - - name: Checkout - uses: actions/checkout@main + - name: Cache the workspace + uses: actions/cache@v3.0.4 with: - submodules: recursive - + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: - python-version: '3.7' + python-version: '3.9' + cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install numpy Bokeh==1.4 + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC4Semi_WSt_WavesWN + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-5MW_OC4Semi_WSt_WavesWN + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + + rtest-OF-5MW_OC3Mnpl_DLL_WTurb_WavesIrr: + runs-on: ubuntu-20.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh sudo apt-get update -y - sudo apt-get install -y gcovr sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC3Mnpl_DLL_WTurb_WavesIrr + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-5MW_OC3Mnpl_DLL_WTurb_WavesIrr + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline - - name: Setup Workspace - run: cmake -E make_directory ${{runner.workspace}}/openfast/build - - name: Configure Build + + rtest-OF-5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth: + runs-on: ubuntu-20.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | - cmake \ - -DCMAKE_INSTALL_PREFIX:PATH=${{runner.workspace}}/openfast/install \ - -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ - -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ - -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ - -DCMAKE_BUILD_TYPE:STRING=Debug \ - -DBUILD_OPENFAST_CPP_API:BOOL=ON \ - -DBUILD_SHARED_LIBS:BOOL=ON \ - -DBUILD_TESTING:BOOL=ON \ - -DCTEST_PLOT_ERRORS:BOOL=ON \ - ${GITHUB_WORKSPACE} + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline - - name: Build OpenFAST C-Interfaces + + rtest-OF-5MW_OC3Trpd_DLL_WSt_WavesReg: + runs-on: ubuntu-20.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | - cmake --build . --target openfastlib -- -j ${{env.NUM_PROCS}} - cmake --build . --target openfastcpp -- -j ${{env.NUM_PROCS}} - cmake --build . --target ifw_c_binding -- -j ${{env.NUM_PROCS}} - cmake --build . --target regression_tests -- -j ${{env.NUM_PROCS}} + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_OC3Trpd_DLL_WSt_WavesReg + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-5MW_OC3Trpd_DLL_WSt_WavesReg + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + - - name: Run C++ API tests + rtest-OF-5MW_Land_BD_DLL_WTurb: + runs-on: ubuntu-20.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | - ctest -VV -L cpp + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run 5MW tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L openfast -LE "cpp|linear|python" -R 5MW_Land_BD_DLL_WTurb + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-5MW_Land_BD_DLL_WTurb + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + - - name: Run Python API tests + rtest-OF-linearization: + runs-on: ubuntu-20.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run OpenFAST linearization tests working-directory: ${{runner.workspace}}/openfast/build run: | - ctest -VV -L python - - # Disabled Codecov since the dashboard and GitHub comments were buggy, - # but it may be useful to post the gcov coverage reports to GitHub Actions - # artifacts. - # Note: if reenabling Codecov, the reports must be in xml format not html. - # - name: Generate coverage report - # working-directory: ${{runner.workspace}}/openfast/build - # run: | - # find . -type f -name '*.gcno' -not -path "**tests**" -exec ${{env.GCOV_EXE}} -pb {} + - # cd .. - # gcovr -g -k -r . --html --html-details regressioncov.html - # - name: Success artifacts - # uses: actions/upload-artifact@v2 - # if: success() - # with: - # name: c-interface-reg-tests - # path: | - # ${{runner.workspace}}/openfast/regressioncov.html + ctest -VV -j8 -L linear + - name: Failing test artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: rtest-OF-linearization + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + + rtest-FF: + runs-on: ubuntu-20.04 + needs: build-fastfarm-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-fastfarm-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + python-version: '3.9' + cache: 'pip' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install numpy Bokeh + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake --build . --target regression_test_controllers -- -j ${{env.NUM_PROCS}} + - name: Run FAST.Farm tests + working-directory: ${{runner.workspace}}/openfast/build + shell: bash + run: | + ctest -VV -L fastfarm -j ${{env.NUM_PROCS}} - name: Failing test artifacts uses: actions/upload-artifact@v2 if: failure() with: - name: c-interface-reg-tests + name: rtest-FF path: | - ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast-cpp - ${{runner.workspace}}/openfast/build/reg_tests/modules/inflowwind - !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast-cpp/5MW_Baseline + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/fastfarm diff --git a/CMakeLists.txt b/CMakeLists.txt index 47e4aea36f..5dbe95b4e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ if (NOT CMAKE_BUILD_TYPE) "Choose the build type: Debug Release" FORCE) endif (NOT CMAKE_BUILD_TYPE) +option(VARIABLE_TRACKING "Enables variable tracking for better runtime debugging output. May increase compile time. Valid only for GNU." on) option(GENERATE_TYPES "Use the openfast-regsitry to autogenerate types modules" off) option(BUILD_SHARED_LIBS "Enable building shared libraries" off) option(DOUBLE_PRECISION "Treat REAL as double precision" on) @@ -45,6 +46,12 @@ if(APPLE) option(CMAKE_MACOSX_RPATH "Use RPATH runtime linking" on) endif() +# Warn if atypical configuration for variable tracking and build type +string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type) +if(NOT ${VARIABLE_TRACKING} AND (${_build_type} STREQUAL "DEBUG" OR ${_build_type} STREQUAL "RELWITHDEBINFO") ) + message(WARNING "Variable tracking is disabled and build type includes debug symbols. This may reduce the ability to debug.") +endif() + # Precompiler/preprocessor flag configuration # Do this before configuring modules so that the flags are included option(BUILD_TESTING "Build the testing tree." OFF) diff --git a/docs/OtherSupporting/3DRotations_Rev2.docx b/docs/OtherSupporting/3DRotations_Rev2.docx new file mode 100644 index 0000000000..5e3d206297 Binary files /dev/null and b/docs/OtherSupporting/3DRotations_Rev2.docx differ diff --git a/docs/OtherSupporting/AeroDyn/AeroDynMesh_Rev4.docx b/docs/OtherSupporting/AeroDyn/AeroDynMesh_Rev4.docx new file mode 100644 index 0000000000..2e61fd6959 Binary files /dev/null and b/docs/OtherSupporting/AeroDyn/AeroDynMesh_Rev4.docx differ diff --git a/docs/OtherSupporting/AeroDyn/AeroLin_2019-12.pdf b/docs/OtherSupporting/AeroDyn/AeroLin_2019-12.pdf new file mode 100644 index 0000000000..be315baf0b Binary files /dev/null and b/docs/OtherSupporting/AeroDyn/AeroLin_2019-12.pdf differ diff --git a/docs/OtherSupporting/AeroDyn/Buoyancy_Implementation_Plan_Rev3.docx b/docs/OtherSupporting/AeroDyn/Buoyancy_Implementation_Plan_Rev3.docx new file mode 100644 index 0000000000..b690d9c7e7 Binary files /dev/null and b/docs/OtherSupporting/AeroDyn/Buoyancy_Implementation_Plan_Rev3.docx differ diff --git a/docs/OtherSupporting/BeamDyn/beamdyn_inputs_sectional_props.pdf b/docs/OtherSupporting/BeamDyn/beamdyn_inputs_sectional_props.pdf new file mode 100644 index 0000000000..c16a1f04b7 Binary files /dev/null and b/docs/OtherSupporting/BeamDyn/beamdyn_inputs_sectional_props.pdf differ diff --git a/docs/OtherSupporting/FAST.Farm_Plan_Rev25.doc b/docs/OtherSupporting/FAST.Farm_Plan_Rev25.doc new file mode 100644 index 0000000000..58ad2aad71 Binary files /dev/null and b/docs/OtherSupporting/FAST.Farm_Plan_Rev25.doc differ diff --git a/docs/OtherSupporting/FEAMooring/FEAM_Theory_Manual.pdf b/docs/OtherSupporting/FEAMooring/FEAM_Theory_Manual.pdf new file mode 100644 index 0000000000..5da9c8e2d6 Binary files /dev/null and b/docs/OtherSupporting/FEAMooring/FEAM_Theory_Manual.pdf differ diff --git a/docs/OtherSupporting/FEAMooring/FEAM_Users_Guide.pdf b/docs/OtherSupporting/FEAMooring/FEAM_Users_Guide.pdf new file mode 100644 index 0000000000..c184759d37 Binary files /dev/null and b/docs/OtherSupporting/FEAMooring/FEAM_Users_Guide.pdf differ diff --git a/docs/OtherSupporting/HydroDyn/Breaking_Wave_Modeling_Approach_for_FAST.docx b/docs/OtherSupporting/HydroDyn/Breaking_Wave_Modeling_Approach_for_FAST.docx new file mode 100644 index 0000000000..0a17aeea29 Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/Breaking_Wave_Modeling_Approach_for_FAST.docx differ diff --git a/docs/OtherSupporting/HydroDyn/HydroDyn_2ndOrderForces_Plan.pdf b/docs/OtherSupporting/HydroDyn/HydroDyn_2ndOrderForces_Plan.pdf new file mode 100644 index 0000000000..62306bd3a1 Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/HydroDyn_2ndOrderForces_Plan.pdf differ diff --git a/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_Morison.docx b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_Morison.docx new file mode 100644 index 0000000000..a0977849ed Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_Morison.docx differ diff --git a/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBody.docx b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBody.docx new file mode 100644 index 0000000000..869f40ca2a Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBody.docx differ diff --git a/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBodyStateSpace.docx b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBodyStateSpace.docx new file mode 100644 index 0000000000..037d66c95f Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBodyStateSpace.docx differ diff --git a/docs/OtherSupporting/HydroDyn/HydroDyn_WaveStretching_Plan.docx b/docs/OtherSupporting/HydroDyn/HydroDyn_WaveStretching_Plan.docx new file mode 100644 index 0000000000..9537a3f256 Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/HydroDyn_WaveStretching_Plan.docx differ diff --git a/docs/OtherSupporting/HydroDyn/WAVE2_document.pdf b/docs/OtherSupporting/HydroDyn/WAVE2_document.pdf new file mode 100644 index 0000000000..5aeb36bd2b Binary files /dev/null and b/docs/OtherSupporting/HydroDyn/WAVE2_document.pdf differ diff --git a/docs/OtherSupporting/IceDyn/IceDyn_Manual.pdf b/docs/OtherSupporting/IceDyn/IceDyn_Manual.pdf new file mode 100644 index 0000000000..a62038e3ba Binary files /dev/null and b/docs/OtherSupporting/IceDyn/IceDyn_Manual.pdf differ diff --git a/docs/OtherSupporting/IceFloe/Ice_Load_Final_Report.pdf b/docs/OtherSupporting/IceFloe/Ice_Load_Final_Report.pdf new file mode 100644 index 0000000000..b998784546 Binary files /dev/null and b/docs/OtherSupporting/IceFloe/Ice_Load_Final_Report.pdf differ diff --git a/docs/OtherSupporting/MAP/cable_model_development.pdf b/docs/OtherSupporting/MAP/cable_model_development.pdf new file mode 100644 index 0000000000..5f72fbe32d Binary files /dev/null and b/docs/OtherSupporting/MAP/cable_model_development.pdf differ diff --git a/docs/OtherSupporting/NWTC_Library_Description.pdf b/docs/OtherSupporting/NWTC_Library_Description.pdf new file mode 100644 index 0000000000..292c49013a Binary files /dev/null and b/docs/OtherSupporting/NWTC_Library_Description.pdf differ diff --git a/docs/OtherSupporting/NWTC_Programmers_Handbook.pdf b/docs/OtherSupporting/NWTC_Programmers_Handbook.pdf new file mode 100644 index 0000000000..5aca0aa67c Binary files /dev/null and b/docs/OtherSupporting/NWTC_Programmers_Handbook.pdf differ diff --git a/docs/OtherSupporting/OrcaFlex/User_Guide_OrcaFlexInterface.pdf b/docs/OtherSupporting/OrcaFlex/User_Guide_OrcaFlexInterface.pdf new file mode 100644 index 0000000000..6f93e18113 Binary files /dev/null and b/docs/OtherSupporting/OrcaFlex/User_Guide_OrcaFlexInterface.pdf differ diff --git a/docs/OtherSupporting/ServoDyn/Extended_Bladed_Interface.pptx b/docs/OtherSupporting/ServoDyn/Extended_Bladed_Interface.pptx new file mode 100644 index 0000000000..8ce553a8f5 Binary files /dev/null and b/docs/OtherSupporting/ServoDyn/Extended_Bladed_Interface.pptx differ diff --git a/docs/OtherSupporting/TurbSim/TurbSim_v2.00.pdf b/docs/OtherSupporting/TurbSim/TurbSim_v2.00.pdf new file mode 100644 index 0000000000..bf32c756ed Binary files /dev/null and b/docs/OtherSupporting/TurbSim/TurbSim_v2.00.pdf differ diff --git a/docs/conf.py b/docs/conf.py index 0ab42f63a5..7bd700a916 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -128,16 +128,16 @@ def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): # built documents. # # The short X.Y version. -version = u'3.1' +version = u'3.2' # The full version, including alpha/beta/rc tags. -release = u'v3.1.0' +release = u'v3.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +# language = None # Default is English and None is not a valid option #If true, figures, tables and code-blocks are automatically numbered if they #have a caption. At same time, the numref role is enabled. For now, it works diff --git a/docs/source/dev/code_style.rst b/docs/source/dev/code_style.rst index eac515713b..9e383738b9 100644 --- a/docs/source/dev/code_style.rst +++ b/docs/source/dev/code_style.rst @@ -4,7 +4,7 @@ Code Style ~~~~~~~~~~ OpenFAST and its underlying modules are mostly written in Fortran adhering to the 2003 standard, but modules can be written in C or C++. The -`NWTC Programmer's Handbook `__ +:download:`NWTC Programmer's Handbook <../../OtherSupporting/NWTC_Programmers_Handbook.pdf>` is the definitive reference for all questions related to working with the FAST Framework and adding code to OpenFAST. diff --git a/docs/source/dev/index.rst b/docs/source/dev/index.rst index 8c6b92d7ea..a10aced968 100644 --- a/docs/source/dev/index.rst +++ b/docs/source/dev/index.rst @@ -43,49 +43,188 @@ For other questions regarding OpenFAST, please contact - :ref:`code_style` - :ref:`debugging` -API Reference -~~~~~~~~~~~~~ -Some subroutines and derived types throughout the source code have in-source -documentation which is compiled with Doxygen. Though this portion of the -documentation is always under development, the existing API reference can -be found in the following pages: +.. _development_philosophy: -- `Main Page <../../html/index.html>`_ -- `Index of Types <../../html/classes.html>`_ -- `Source Files <../../html/files.html>`_ +Development Philosophy and Guidelines +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _development_philosophy: +OpenFAST is intended to be a self-sustaining, community developed software. +While the NREL OpenFAST team serves as the gatekeeper of the repository, we +actively encourage the community to share new ideas and contribute code. +Considerations for contributing code are outlined here. + +Engagement with NREL +-------------------- + +The process for community code contribution starts with engaging directly +with the NREL OpenFAST team to define the scope of the work and coordinate +development efforts. This is particularly important since many groups +work on OpenFAST simultaneously. By engaging early, all developers can +stay up to date and minimize conflicts during the code merge. +The prefered method of communication is `GitHub Issues `_. +An initial post should contain all relevant information about the planned +development work, the areas of the software that will be impacted, +and any model validation materials. See :ref:`development_plan` +for more information on describing the planned work. + +The NREL OpenFAST team is always working on internal projects +that require the majority of our attention, but we will make every effort +to engage with the community and support development efforts in +a reasonable time frame. After posting an Issue, the NREL OpenFAST +team may reach out to schedule a meeting to talk through the details. + +.. _development_plan: + +Development Plan / Implementation Plan +-------------------------------------- +Significant code development efforts at NREL begin with the development +of a detailed implementation plan, and a few such plans are available to +download for reference: + +- :download:`Development Plan for the Aerodynamic Linearization of OpenFAST <../../OtherSupporting/AeroDyn/AeroLin_2019-12.pdf>` +- :download:`FAST.Farm Development Plan <../../OtherSupporting/FAST.Farm_Plan_Rev25.doc>`. +- :download:`Implementation Plan - 2nd-order Forces Within HydroDyn <../../OtherSupporting/HydroDyn/HydroDyn_2ndOrderForces_Plan.pdf>` +- :download:`Implementation Plan - 2nd-order Wave Kinematics Within HydroDyn <../../OtherSupporting/HydroDyn/WAVE2_document.pdf>` + +A good plan within the modularization framework of OpenFAST will +follow the definitions and nomenclature used by the +:download:`NWTC Programmer's Handbook <../../OtherSupporting/NWTC_Programmers_Handbook.pdf>`. +It should communication the following information: + +- State whether the module is intended for loose coupling, + tight coupling for time marching, and/or linearization. +- Define the module's inputs (including initialization), + outputs (including initialization), states (continous, + discrete, and constraint), and parameters, including units. +- Lay out an example input file for the module. +- Explain the module's mathemetical formulation, including + Jacobians (for tight coupling and linearization), in the form + required of the framework. +- Prescribe how the module's inputs are derived from the + outputs of other specific modules +- Identify any potential numerical problems and how to avoid + them in the code. +- Lay out the module's subroutines using pseudocode (as opposed + to actual code), including identifying which mathematical formulas + are used by which subroutines, and describing the algorithms used + in the solution process. + +This information is very helpful since it is easier to review, iterate, +and agree on a plan before making changes to source code. Additionally, +an implementation plan will greatly aid in the programming effort and is +a useful starting point for writing the user and develop documentation. + +Qualities of a good submission +------------------------------ + +Development efforts should include adequate testing throughout +the development process. When possible, new subroutines should include unit-level tests, +and the existing regression tests should be run periodically to ensure that +the full system behavior has not changed unintentionally. For new features, +additional regression tests should be added to cover the new code. +If the regression test results change in an expected manner, the baseline +results should be updated locally and in the `openfast/r-test `_ +repository. The `r-test README `_ +describes updating the baselines and the :ref:`testing` +section in this documentation contains additional details on testing. -Development Philosophy -~~~~~~~~~~~~~~~~~~~~~~ +New code should consider robustness from both the developer and user +perspectives. Here are some questions to consider during +code development: -OpenFAST is intended to be a self sustaining community developed software. -A couple of tenets of this goal are that the code should be reasonably -straightforward to comprehend and manageable to improve. With that in mind, we -expect that new capabilities will include adequate testing and documentation. +- Is it clear to other developers how to use your subroutine? +- Does your new code exhibit clear and predictable behavior? +- How will your code perform under different qualities of data? +- How does your code impact the performance of the simulation? -We have the following guidance for developers: +Additionally, user and developer documentation should be included +with new code. User documentation includes theory, modeling guidance, +and a description of any inputs and outputs. User documentation should be +included as part of the online documentation described in :ref:`build_doc`. +Developer documentation is typically included in comments in the source +code. This should describe subroutine API's (inputs and outputs) as well +as any algorithms or lines of code that are unclear. Ask yourself +what you would need to know to fully understand your code if you don't +see it again for two years. -- When fixing a bug, first introduce a unit test that exposes the bug, fix the - bug, and submit a Pull Request. See :ref:`testing` and - :ref:`github_workflow` for more information. +Submit for review and NREL feedback +----------------------------------- -- When adding a new feature, create appropriate automated unit and regression - tests as described in :ref:`testing`. The objective is to create a GitHub - pull request that provides adequate verification and validation so that the - NREL OpenFAST developer team can merge the pull request with confidence that - the new feature is "correct" and supports our goal of self-sustaining - software. See :ref:`pull_requests` for more information on submitting - a pull request. +New code can be submitted for review from the NREL OpenFAST team by +opening a `pull request `_ +as described in :ref:`github_workflow`. We will review the code for +accuracy, validity, quality, and robustness. Reviewing open source +code contributions can be difficult, so it is worthwhile to review +your own code and consider what information would help you to +determine whether it is ready to merge. -- If a code modification affects regression test results in an expected manner, - work with the NREL OpenFAST developer team to upgrade the regression test - suite via a GitHub issue or pull request at the `openfast/r-test `_ - repository. +The review process begins with simply ensuring that the automated +tests pass in `GitHub Actions `_. +**Please ensure that all automated tests pass prior to requesting a review.** +After that, the process will involve some communication between the +reviewer and the submitter, possibly requests for more information +on the background or validation, and comments in the pull request +to gain additional insight into specific lines of code. -Development Guidelines -~~~~~~~~~~~~~~~~~~~~~~ -The following sections provide extended guidance on how to develop source code, +After a consensus is reached between the submitter and reviewer, +the pull request will be merged into the target branch (typically +`dev`) and the pull request will be closed. You're done! +This change will be included in the subsequent release of OpenFAST +when the `dev` branch is merged into `main`. + +Bug fixes +--------- + +If you've found a bug in the code, it is important to fully describe +it both in a `GitHub Issue `_ +and through a minimal test. Before making a commit with the bug fix, +commit the new test that exposes the bug. This test should fail. +Then, commit the bug fix and show that the test passes. The git-commit +history should look something like this (progresses bottom to top): + +.. mermaid:: + + gitGraph BT: + options + { + "nodeSpacing": 60, + "nodeFillColor": "white", + "nodeStrokeWidth": 2, + "nodeStrokeColor": "#747474", + "lineStrokeWidth": 2, + "branchOffset": 30, + "lineColor": "grey", + "leftMargin": 20, + "branchColors": ["#007bff", "#ff2d54"], + "nodeRadius": 5, + "nodeLabel": { + "width": 75, + "height": 100, + "x": -25, + "y": 0 + } + } + end + + commit + branch dev + checkout dev + commit "Merge pull request #123" + commit "Merge pull request #124" + branch bugfix + checkout bugfix + commit "Add unit test exposing out of bounds error" + commit "Fix out of bounds error in array" + checkout dev + commit "Merge pull request #125" + merge bugfix + +See :ref:`testing` and :ref:`github_workflow` for more information. + +Additional guidance +------------------- + +The following sections provide extended guidance on developing source code, interacting with the NREL OpenFAST team and other community contributors, and generally debugging and building out features. @@ -100,12 +239,26 @@ generally debugging and building out features. performance.rst versioning.rst + + + +API Reference +~~~~~~~~~~~~~ +Some subroutines and derived types throughout the source code have in-source +documentation which is compiled with Doxygen. Though this portion of the +documentation is always under development, the existing API reference can +be found in the following pages: + +- `Main Page <../../html/index.html>`_ +- `Index of Types <../../html/classes.html>`_ +- `Source Files <../../html/files.html>`_ + Other Documentation ~~~~~~~~~~~~~~~~~~~ Additional documentation exists that may be useful for developers seeking deeper understanding of the solver and mathematics. -- `NWTC Programmer’s Handbook `_ +- :download:`NWTC Programmer's Handbook <../../OtherSupporting/NWTC_Programmers_Handbook.pdf>` This is an overview of programming guidelines for FAST 8. While some syntax and minor details have changed in OpenFAST, most of this guide is still relevant. - :download:`OutListParameters.xlsx <../../OtherSupporting/OutListParameters.xlsx>` diff --git a/docs/source/testing/index.rst b/docs/source/testing/index.rst index a8dad20a20..77fea3c218 100644 --- a/docs/source/testing/index.rst +++ b/docs/source/testing/index.rst @@ -29,8 +29,6 @@ GitHub users and is highly recommended as part of the development workflow. After enabling GitHub Actions in an OpenFAST repository, simply pushing new commits will trigger the tests. -Test specific documentation ---------------------------- .. toctree:: :maxdepth: 1 diff --git a/docs/source/testing/regression_test.rst b/docs/source/testing/regression_test.rst index 212e7dd4ca..bb134c501f 100644 --- a/docs/source/testing/regression_test.rst +++ b/docs/source/testing/regression_test.rst @@ -1,7 +1,7 @@ .. _regression_test: -Regression test -=============== +Regression tests +================ The regression test executes a series of test cases which intend to fully describe OpenFAST and its module's capabilities. Jump to one of the following sections for instructions on running the regression diff --git a/docs/source/testing/unit_test.rst b/docs/source/testing/unit_test.rst index e8bfd3f9e7..31c9cca58c 100644 --- a/docs/source/testing/unit_test.rst +++ b/docs/source/testing/unit_test.rst @@ -1,7 +1,7 @@ .. _unit_test: -Unit test -========= +Unit tests +========== In a software package as dynamic and collaborative as OpenFAST, confidence in multiple layers of code is best accomplished with a strong system of unit tests. Through robust testing practices, the entire OpenFAST community can diff --git a/docs/source/this_doc.rst b/docs/source/this_doc.rst index 78b3ffa5df..2991b53fa4 100644 --- a/docs/source/this_doc.rst +++ b/docs/source/this_doc.rst @@ -19,7 +19,7 @@ and link to other relevant websites. While OpenFAST developer documentation is being enhanced here, developers are encouraged to consult the legacy FAST v8 -`Programmer's Handbook `_. +:download:`NWTC Programmer's Handbook <../OtherSupporting/NWTC_Programmers_Handbook.pdf>`. Instructions on obtaining and installing OpenFAST are available in :ref:`installation`, and documentation for verifying an installation with the automated tests is at :ref:`testing`. diff --git a/docs/source/user/aerodyn-olaf/InputFiles.rst b/docs/source/user/aerodyn-olaf/InputFiles.rst index 3e6a04bef2..4a05165cbe 100644 --- a/docs/source/user/aerodyn-olaf/InputFiles.rst +++ b/docs/source/user/aerodyn-olaf/InputFiles.rst @@ -195,11 +195,14 @@ Speedup Options ~~~~~~~~~~~~~~~ **VelocityMethod** [switch] specifies the method used to determine the velocity. -There are two options: 1) Biot-Savart law applied to the vortex segments *[1]* -,2) tree formulation using a particle representation *[2]*. and 3) tree formulation -using a segment representation. The default option is *[1]*. -Option *[2]* requires the specification of *PartPerSegment* (see below). -Option *[3]* is expected to give results close to option *[1]* while offering +There are four options: +1) :math:`N^2` Biot-Savart computation on the vortex segments *[1]*, +2) Particle-Tree formulation *[2]*, +3) :math:`N^2` Biot-Savart computation using a particle representation, +4) Segment-Tree formulation. +The default option is *[1]*. +Option *[2]* and *[3]* requires the specification of *PartPerSegment* (see below). +Option *[4]* is expected to give results close to option *[1]* while offering significant speedup, and this option does not require the specification of *PartPerSegment*. diff --git a/docs/source/user/aerodyn/appendix.rst b/docs/source/user/aerodyn/appendix.rst index 0a92e1bb0a..97b8f43758 100644 --- a/docs/source/user/aerodyn/appendix.rst +++ b/docs/source/user/aerodyn/appendix.rst @@ -57,10 +57,10 @@ The local tower coordinate system is shown in :numref:`ad_tower_geom` and the lo .. _ad_blade_local_cs: -.. figure:: figs/ad_blade_local_cs.png +.. figure:: figs/aerodyn_blade_local_cs.png :width: 80% :align: center - :alt: ad_blade_local_cs.png + :alt: aerodyn_blade_local_cs.png AeroDyn Local Blade Coordinate System (Looking Toward the Tip, from the Root) – l: Lift, d: Drag, m: Pitching, x: Normal (to Plane), @@ -69,9 +69,9 @@ The local tower coordinate system is shown in :numref:`ad_tower_geom` and the lo .. _ad-output-channel: -.. figure:: figs/ad_output_channel.pdf +.. figure:: figs/aerodyn_output_channel.pdf :width: 500px :align: center - :alt: ad_output_channel.pdf + :alt: aerodyn_output_channel.pdf AeroDyn Output Channel List diff --git a/docs/source/user/aerodyn/driver.rst b/docs/source/user/aerodyn/driver.rst index 0c214249e8..4d8748ce5b 100644 --- a/docs/source/user/aerodyn/driver.rst +++ b/docs/source/user/aerodyn/driver.rst @@ -152,7 +152,7 @@ Two turbine input formats are supported: In this format, the turbine geometry is entirely determined by the number of blades (`NumBlades`), the hub radius (`HubRad`), the hub height (`HubHt`), the overhang (`Overhang`), the shaft tilt (`ShftTilt`), the precone (`Precone`), and the vertical distance from the tower-top to the rotor shaft (`Twr2Shft`), as shown in :numref:`fig:BasicGeometry`. The definition of each parameter follows the ElastoDyn convention. For example, `HubRad` specifies the radius from the center-of-rotation to the blade root along the (possibly preconed) blade-pitch axis and must be greater than zero. `HubHt` specifies the elevation of the hub center above the ground for land-based wind turbines, above the mean sea level (MSL) for offshore wind turbines, or above the seabed for MHK turbines. `Overhang` specifies the distance along the (possibly tilted) rotor shaft between the tower centerline and hub center and is positive downwind (use a negative number for upwind rotors). `ShftTilt` is the angle (in degrees) between the rotor shaft and the horizontal plane, and positive `ShftTilt` means that the downwind end of the shaft is the highest (upwind turbines have negative `ShftTilt` for improved tower clearance). `Precone` is the angle (in degrees) between a flat rotor disk and the cone swept by the blades, positive downwind (upwind turbines have negative `Precone` for improved tower clearance). - .. figure:: figs/ad_driver_geom.png + .. figure:: figs/aerodyn_driver_geom.png :width: 60% :name: fig:BasicGeometry diff --git a/docs/source/user/aerodyn/examples/ad_driver_example.dvr b/docs/source/user/aerodyn/examples/ad_driver_example.dvr index d390e38561..ea92c3edd1 100644 --- a/docs/source/user/aerodyn/examples/ad_driver_example.dvr +++ b/docs/source/user/aerodyn/examples/ad_driver_example.dvr @@ -34,9 +34,9 @@ False Echo - Echo input parameters to ".ech"? 3.09343 Twr2Shft(1) - Vertical distance from the tower-top to the rotor shaft (m) ----- Turbine(1) Motion [used only when AnalysisType=1] --------------------------------- 1 BaseMotionType(1) - Type of motion prescribed for this base {0: fixed, 1: Sinusoidal motion, 2: arbitrary motion} (flag) -1 DegreeOfFreedom(1) - {1:xg, 2:yg, 3:zg, 4:theta_xg, 5:theta_yg, 6:theta_zg} [used only when BaseMotionType=1] (flag) -5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] -0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] +1 DegreeOfFreedom(1) - {1:xt, 2:yt, 3:zt, 4:theta_xt, 5:theta_yt, 6:theta_zt} [used only when BaseMotionType=1] (flag) +5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] (m or rad) +0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) "" BaseMotionFileName(1) - Filename containing arbitrary base motion (19 columns: Time, x, y, z, theta_x, ..., alpha_z) [used only when BaseMotionType=2] 0 NacYaw(1) - Yaw angle (about z_t) of the nacelle (deg) 7 RotSpeed(1) - Rotational speed of rotor in rotor coordinates (rpm) @@ -54,6 +54,7 @@ HWndSpeed PLExp RotSpd Pitch Yaw dT Tmax DOF Amplitude Frequency ----- Output Settings ------------------------------------------------------------------- "ES15.8E2" OutFmt - Format used for text tabular output, excluding the time channel. Resulting field should be 10 characters. (quoted string) 2 OutFileFmt - Format for tabular (time-marching) output file (switch) {1: text file [.out], 2: binary file [.outb], 3: both} -0 WrVTK - VTK visualization data output: (switch) {0=none; 1=animation} +0 WrVTK - VTK visualization data output: (switch) {0=none; 1=init; 2=animation} +1 WrVTK_Type - VTK visualization data type: (switch) {1=surfaces; 2=lines; 3=both} 2 VTKHubRad - HubRadius for VTK visualization (m) -1,-1,-1,2,2,2 VTKNacDim - Nacelle Dimension for VTK visualization x0,y0,z0,Lx,Ly,Lz (m) diff --git a/docs/source/user/aerodyn/examples/ad_driver_multiple.dvr b/docs/source/user/aerodyn/examples/ad_driver_multiple.dvr index 43e601ae87..00cf198871 100644 --- a/docs/source/user/aerodyn/examples/ad_driver_multiple.dvr +++ b/docs/source/user/aerodyn/examples/ad_driver_multiple.dvr @@ -46,8 +46,8 @@ True HAWTprojection(1) - True if turbine is a horizontal axis tu ----- Turbine(1) Motion [used only when AnalysisType=1] --------------------------------- 0 BaseMotionType(1) - Type of motion prescribed for this base {0: fixed, 1: Sinusoidal motion, 2: arbitrary motion} (flag) 1 DegreeOfFreedom(1) - {1:xt, 2:yt, 3:zt, 4:theta_xt, 5:theta_yt, 6:theta_zt} [used only when BaseMotionType=1] (flag) -0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] -0 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] +0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] (m or rad) +0 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) "unused" BaseMotionFileName(1) - Filename containing arbitrary base motion (19 columns: Time, x, y, z, theta_x, ..., alpha_z) [used only when BaseMotionType=2] 0 NacMotionType(1) - Type of motion prescribed for the nacelle {0: fixed yaw, 1: time varying yaw angle} (flag) 0 NacYaw(1) - Yaw angle (about z_t) of the nacelle [user only when NacMotionType=0] (deg) @@ -75,8 +75,8 @@ True HAWTprojection(1) - True if turbine is a horizontal axis tu ----- Turbine(2) Motion [used only when AnalysisType=1] --------------------------------- 0 BaseMotionType(2) - Type of motion prescribed for this base {0: fixed, 1: Sinusoidal motion, 2: arbitrary motion} (flag) 0 DegreeOfFreedom(2) - {1:xt, 2:yt, 3:zt, 4:theta_xt, 5:theta_yt, 6:theta_zt} [used only when BaseMotionType=1] (flag) -0.0 Amplitude(2) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] -0.0 Frequency(2) - Frequency of sinusoidal motion [used only when BaseMotionType=1] +0.0 Amplitude(2) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] (m or deg) +0.0 Frequency(2) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) "unused" BaseMotionFileName(2) - Filename containing arbitrary base motion (29 columns: Time, x, y, z, theta_x, ..., alpha_z) [used only when BaseMotionType=2] 0 NacYaw(2) - Yaw angle (about z_t) of the nacelle [user only when NacMotionType=0] (deg) 6 RotSpeed(2) - Rotational speed of rotor in rotor coordinates [used only when RotorMotionType=0] (rpm) @@ -86,10 +86,11 @@ True HAWTprojection(1) - True if turbine is a horizontal axis tu ----- Combined-Case Analysis [used only when AnalysisType=3, numTurbines=1] ------------- 0 NumCases - Number of cases to run HWndSpeed PLExp RotSpd Pitch Yaw dT Tmax DOF Amplitude Frequency -(m/s) (-) (rpm) (deg) (deg) (s) (s) (-) (-) (Hz) +(m/s) (-) (rpm) (deg) (deg) (s) (s) (-) (m or rad) (Hz) ----- Output Settings ------------------------------------------------------------------- "ES15.8E2" OutFmt - Format used for text tabular output, excluding the time channel. Resulting field should be 10 characters. (quoted string) 2 OutFileFmt - Format for tabular (time-marching) output file (switch) {1: text file [.out], 2: binary file [.outb], 3: both} -0 WrVTK - VTK visualization data output: (switch) {0=none; 1=animation} +0 WrVTK - VTK visualization data output: (switch) {0=none; 1=init; 2=animation} +1 WrVTK_Type - VTK visualization data type: (switch) {1=surfaces; 2=lines; 3=both} 2 VTKHubRad - HubRadius for VTK visualization (m) -7,-4,0,21,8,8 VTKNacDim - Nacelle Dimension for VTK visualization x0,y0,z0,Lx,Ly,Lz (m) diff --git a/docs/source/user/aerodyn/figs/ad_blade_geom.png b/docs/source/user/aerodyn/figs/aerodyn_blade_geom.png similarity index 100% rename from docs/source/user/aerodyn/figs/ad_blade_geom.png rename to docs/source/user/aerodyn/figs/aerodyn_blade_geom.png diff --git a/docs/source/user/aerodyn/figs/ad_blade_local_cs.png b/docs/source/user/aerodyn/figs/aerodyn_blade_local_cs.png similarity index 100% rename from docs/source/user/aerodyn/figs/ad_blade_local_cs.png rename to docs/source/user/aerodyn/figs/aerodyn_blade_local_cs.png diff --git a/docs/source/user/aerodyn/figs/ad_driver_geom.png b/docs/source/user/aerodyn/figs/aerodyn_driver_geom.png similarity index 100% rename from docs/source/user/aerodyn/figs/ad_driver_geom.png rename to docs/source/user/aerodyn/figs/aerodyn_driver_geom.png diff --git a/docs/source/user/aerodyn/figs/aerodyn_not_ad.README.txt b/docs/source/user/aerodyn/figs/aerodyn_not_ad.README.txt new file mode 100644 index 0000000000..4e929b42df --- /dev/null +++ b/docs/source/user/aerodyn/figs/aerodyn_not_ad.README.txt @@ -0,0 +1,5 @@ + +The AeroDyn documentation should not reference images that are prefixed with "ad_". +This can lead to ad-blockers in browsers blocking these images. Instead, simply +use the prefix "aerodyn_". +See https://github.com/OpenFAST/openfast/issues/912 for details. diff --git a/docs/source/user/aerodyn/figs/ad_output_channel.pdf b/docs/source/user/aerodyn/figs/aerodyn_output_channel.pdf similarity index 100% rename from docs/source/user/aerodyn/figs/ad_output_channel.pdf rename to docs/source/user/aerodyn/figs/aerodyn_output_channel.pdf diff --git a/docs/source/user/aerodyn/figs/ad_tower_geom.png b/docs/source/user/aerodyn/figs/aerodyn_tower_geom.png similarity index 100% rename from docs/source/user/aerodyn/figs/ad_tower_geom.png rename to docs/source/user/aerodyn/figs/aerodyn_tower_geom.png diff --git a/docs/source/user/aerodyn/index.rst b/docs/source/user/aerodyn/index.rst index 38ec6cfd6a..c7a08118c5 100644 --- a/docs/source/user/aerodyn/index.rst +++ b/docs/source/user/aerodyn/index.rst @@ -1,15 +1,25 @@ AeroDyn Users Guide and Theory Manual ====================================== -.. only:: html +This document offers a quick reference guide for the AeroDyn software +program. It is intended to be used by the general user in combination +with other OpenFAST manuals. The manual will be updated as new releases are +issued and as needed to provide further information on advancements or +modifications to the software. For reference, additional materials +such as presentation slides, development plans, and publications +can be downladed from the list below. - This document offers a quick reference guide for the AeroDyn software - program. It is intended to be used by the general user in combination - with other OpenFAST manuals. The manual will be updated as new releases are - issued and as needed to provide further information on advancements or - modifications to the software. +- :download:`Development and Validation of a New Blade Element Momentum Skewed-Wake Model within AeroDyn ` +- :download:`The Unsteady Aerodynamics Module for FAST 8 ` +- :download:`Added-Mass Effects on a Horizontal-Axis Tidal Turbine Using FAST v8 ` +- :download:`Predicting Cavitation on Marine and Hydrokinetic Turbine Blades with AeroDyn V15.04 ` +- :download:`Development Plan for the Aerodynamic Linearization of OpenFAST <../../../OtherSupporting/AeroDyn/AeroLin_2019-12.pdf>` +- :download:`AeroDyn Meshes and Related Calculations <../../../OtherSupporting/AeroDyn/AeroDynMesh_Rev4.docx>` +- :download:`Calculation of Buoyancy on a Marine Hydrokinetic Turbine in AeroDyn <../../../OtherSupporting/AeroDyn/Buoyancy_Implementation_Plan_Rev3.docx>` - The documentation here was derived from AeroDyn Manual for AeroDyn version 15.04 by J.\ Jonkman et al. +.. - :download:` ` + +The documentation here was derived from AeroDyn Manual for AeroDyn version 15.04 by J.\ Jonkman et al. .. toctree:: diff --git a/docs/source/user/aerodyn/input.rst b/docs/source/user/aerodyn/input.rst index a49686c455..f99fc1216c 100644 --- a/docs/source/user/aerodyn/input.rst +++ b/docs/source/user/aerodyn/input.rst @@ -371,10 +371,10 @@ quantities are actually output at these nodes. .. _ad_tower_geom: -.. figure:: figs/ad_tower_geom.png +.. figure:: figs/aerodyn_tower_geom.png :width: 60% :align: center - :alt: ad_tower_geom.png + :alt: aerodyn_tower_geom.png AeroDyn Tower Geometry @@ -740,10 +740,10 @@ See :numref:`ad_blade_geom`. Twist is shown in :numref:`ad_blade_local_cs` of :n .. _ad_blade_geom: -.. figure:: figs/ad_blade_geom.png +.. figure:: figs/aerodyn_blade_geom.png :width: 90% :align: center - :alt: ad_blade_geom.png + :alt: aerodyn_blade_geom.png AeroDyn Blade Geometry – Left: Side View; Right: Front View (Looking Downwind) diff --git a/docs/source/user/api_change.rst b/docs/source/user/api_change.rst index fe8430ede4..1ca495b838 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -10,10 +10,38 @@ 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.0.0 to OpenFAST `dev` ---------------------------------- +OpenFAST v3.2.0 to OpenFAST `dev` +---------------------------------- + +============================================= ==== =============== ======================================================================================================================================================================================================== +Added in OpenFAST dev +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +Module Line Flag Name Example Value +============================================= ==== =============== ======================================================================================================================================================================================================== +AeroDyn driver 54\* WrVTK_Type 1 WrVTK_Type - VTK visualization data type: (switch) {1=surfaces; 2=lines; 3=both} +============================================= ==== =============== ======================================================================================================================================================================================================== + +\*Exact line number depends on number of entries in various preceeding tables. + + +OpenFAST v3.1.0 to OpenFAST v3.2.0 +---------------------------------- + +============================================= ==== =============== ======================================================================================================================================================================================================== +Added in OpenFAST v3.2.0 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +Module Line Flag Name Example Value +============================================= ==== =============== ======================================================================================================================================================================================================== +TurbSim 13 WrHAWCFF False WrHAWCFF - Output full-field time-series data in HAWC form? (Generates RootName-u.bin, RootName-v.bin, RootName-w.bin, RootName.hawc) +============================================= ==== =============== ======================================================================================================================================================================================================== -No change +============================================= ==== =============== ======================================================================================================================================================================================================== +Removed in OpenFAST v3.2.0 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +Module Line Flag Name Example Value +============================================= ==== =============== ======================================================================================================================================================================================================== +TurbSim 14 Clockwise True Clockwise - Clockwise rotation looking downwind? (used only for full-field binary files - not necessary for AeroDyn) +============================================= ==== =============== ======================================================================================================================================================================================================== @@ -27,9 +55,9 @@ Module Line Flag Name Example Val ============================================= ==== =============== ======================================================================================================================================================================================================== ServoDyn 60 AeroControlSec ---------------------- AERODYNAMIC FLOW CONTROL -------------------------------- ServoDyn 61 AfCmode 0 AfCmode - Airfoil control mode {0: none, 1: cosine wave cycle, 4: user-defined from Simulink/Labview, 5: user-defined from Bladed-style DLL} (switch) -ServoDyn 61 AfC_Mean 0 AfC_Mean - Mean level for cosine cycling or steady value (-) [used only with AfCmode==1] -ServoDyn 61 AfC_Amp 0 AfC_Amp - Amplitude for cosine cycling of flap signal (-) [used only with AfCmode==1] -ServoDyn 61 AfC_Phase 0 AfC_Phase - Phase relative to the blade azimuth (0 is vertical) for cosine cycling of flap signal (deg) [used only with AfCmode==1] +ServoDyn 62 AfC_Mean 0 AfC_Mean - Mean level for cosine cycling or steady value (-) [used only with AfCmode==1] +ServoDyn 63 AfC_Amp 0 AfC_Amp - Amplitude for cosine cycling of flap signal (-) [used only with AfCmode==1] +ServoDyn 64 AfC_Phase 0 AfC_Phase - Phase relative to the blade azimuth (0 is vertical) for cosine cycling of flap signal (deg) [used only with AfCmode==1] ServoDyn 74 CablesSection ---------------------- CABLE CONTROL ------------------------------------------- ServoDyn 75 CCmode 0 CCmode - Cable control mode {0: none, 4: user-defined from Simulink/Labview, 5: user-defined from Bladed-style DLL} (switch) HydroDyn driver 6 WtrDens 1025 WtrDens - Water density (kg/m^3) @@ -120,19 +148,32 @@ SubDyn n+2 OutFEMModes Output first 30 FEM modes {0: No output, OpenFAST v2.6.0 to OpenFAST v3.0.0 ---------------------------------- -- ServoDyn +**ServoDyn Changes** - - The input file parser is updated to a keyword/value pair based input. - Each entry must have a corresponding keyword with the same spelling as - expected - - The TMD submodule of ServoDyn is replaced by an updated Structural Control - module (StC) with updated capabilities and input file. +- The input file parser is updated to a keyword/value pair based input. + Each entry must have a corresponding keyword with the same spelling as + expected. +- The TMD submodule of ServoDyn is replaced by an updated Structural Control + module (StC) with updated capabilities and input file. + +============================================= ==== =============== ======================================================================================================================================================================================================== +Removed in OpenFAST v3.0.0 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +Module Line Flag Name Example Value +============================================= ==== =============== ======================================================================================================================================================================================================== +ServoDyn 60 na ---------------------- TUNED MASS DAMPER --------------------------------------- +ServoDyn 61 CompNTMD False CompNTMD - Compute nacelle tuned mass damper {true/false} (flag) +ServoDyn 62 NTMDfile "NRELOffshrBsline5MW_ServoDyn_TMD.dat" NTMDfile - Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false] +ServoDyn 63 CompTTMD False CompTTMD - Compute tower tuned mass damper {true/false} (flag) +ServoDyn 64 TTMDfile "NRELOffshrBsline5MW_ServoDyn_TMD.dat" TTMDfile - Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false] +============================================= ==== =============== ======================================================================================================================================================================================================== ============================================= ==== =============== ======================================================================================================================================================================================================== Added in OpenFAST v3.0.0 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Module Line Flag Name Example Value ============================================= ==== =============== ======================================================================================================================================================================================================== +ServoDyn 60 na ---------------------- STRUCTURAL CONTROL -------------------------------------- ServoDyn 61 NumBStC 0 NumBStC - Number of blade structural controllers (integer) ServoDyn 62 BStCfiles "unused" BStCfiles - Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0] ServoDyn 63 NumNStC 0 NumNStC - Number of nacelle structural controllers (integer) @@ -271,13 +312,23 @@ Modified in OpenFAST v2.5.0 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Module Line Flag Name / section Example Value ============================ ====== ================================================ ==================================================================================== -MoorDyn na added CtrlChan column in LINE PROPERTIES table .. code-block:: none - - Line LineType UnstrLen NumSegs NodeAnch NodeFair Outputs CtrlChan - (-) (-) (m) (-) (-) (-) (-) (-) - 1 main 835.35 20 1 4 - 0 +MoorDyn na added CtrlChan column in LINE PROPERTIES table ============================ ====== ================================================ ==================================================================================== +============== ====== =============== ============== ============================================================================================================================================================================= +Renamed in OpenFAST v2.5.0 +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +Module Line Previous Name New Name Example Value +============== ====== =============== ============== ============================================================================================================================================================================= +InflowWind 17 Filename FileName_Uni "Shr11_30.wnd" FileName_Uni - Filename of time series data for uniform wind field. (-) +InflowWind 18 RefHt RefHt_Uni 90 RefHt_Uni - Reference height for horizontal wind speed (m) +InflowWind 21 Filename FileName_BTS "unused" FileName_BTS - Name of the Full field wind file to use (.bts) (-) +InflowWind 23 Filename FileNameRoot "unused" FileNameRoot - WindType=4: Rootname of the full-field wind file to use (.wnd, .sum); WindType=7: name of the intermediate file with wind scaling values +InflowWind 35 RefHt RefHt_Hawc 90 RefHt_Hawc - reference height; the height (in meters) of the vertical center of the grid (m) +InflowWind 47 PLExp PLExp_Hawc 0.2 PLExp_Hawc - Power law exponent (-) (used for PL wind profile type only) +InflowWind 49 InitPosition(x) XOffset 0 XOffset - Initial offset in +x direction (shift of wind box) +============== ====== =============== ============== ============================================================================================================================================================================= + OpenFAST v2.3.0 to OpenFAST v2.4.0 @@ -311,11 +362,6 @@ Modified in OpenFAST v2.4.0 Module Line New Flag Name Example Value Previous Flag Name/Value ============== ==== ================== ======================================================================================================================================================= ========================= AirFoilTables 40\* filtCutOff "DEFAULT" filtCutOff - Reduced frequency cut-off for low-pass filtering the AoA input to UA, as well as the 1st and 2nd deriv (-) [default = 0.5] [default = 20] -InflowWind 17 Filename_Uni "unused" Filename_Uni - Filename of time series data for uniform wind field. (-) Filename -InflowWind 18 RefHt_Uni 90 RefHt_Uni - Reference height for horizontal wind speed (m) RefHt -InflowWind 35 RefHt_Hawc 90 RefHt_Hawc - reference height; the height (in meters) of the vertical center of the grid (m) RefHt -InflowWind 47 PLExp_Hawc 0.2 PLExp_Hawc - Power law exponent (-) (used for PL wind profile type only) PLExp -InflowWind 49 XOffset 0 XOffset - Initial offset in +x direction (shift of wind box) InitPosition(x) ============== ==== ================== ======================================================================================================================================================= ========================= \*non-comment line count, excluding lines contained if NumCoords is not 0. diff --git a/docs/source/user/beamdyn/index.rst b/docs/source/user/beamdyn/index.rst index 073917ba03..ce14098d1c 100644 --- a/docs/source/user/beamdyn/index.rst +++ b/docs/source/user/beamdyn/index.rst @@ -1,19 +1,21 @@ BeamDyn User Guide and Theory Manual ====================================== -.. only:: html +This document offers a quick reference guide for the BeamDyn software +program. It is intended to be used by the general user in combination +with other OpenFAST manuals. The manual will be updated as new releases are +issued and as needed to provide further information on advancements or +modifications to the software. For reference, additional materials +such as presentation slides, development plans, and publications +can be downladed from the list below. - This document offers a quick reference guide for the BeamDyn software - program. It is intended to be used by the general user in combination - with other FAST manuals. The manual will be updated as new releases are - issued and as needed to provide further information on advancements or - modifications to the software. +- :download:`BeamDyn inputs from sectional beam properties <../../../OtherSupporting/BeamDyn/beamdyn_inputs_sectional_props.pdf>` - The authors are grateful to the U.S. Department of Energy Wind and Water - Power Program and the NREL Laboratory Directed Research and Development - (LDRD) program through the grant “High-Fidelity Computational Modeling - of Wind-Turbine Structural Dynamics” for supporting the development of - this software. +The authors are grateful to the U.S. Department of Energy Wind and Water +Power Program and the NREL Laboratory Directed Research and Development +(LDRD) program through the grant “High-Fidelity Computational Modeling +of Wind-Turbine Structural Dynamics” for supporting the development of +this software. .. toctree:: diff --git a/docs/source/user/elastodyn/index.rst b/docs/source/user/elastodyn/index.rst index ac69e9ae31..1cec77ef75 100644 --- a/docs/source/user/elastodyn/index.rst +++ b/docs/source/user/elastodyn/index.rst @@ -5,8 +5,12 @@ This document offers a quick reference guide for the ElastoDyn software program. It is intended to be used by the general user in combination with other OpenFAST manuals. The manual will be updated as new releases are issued and as needed to provide further information on advancements or -modifications to the software. For general information on OpenFAST, -users should refer to section :numref:`general-reference-docs`. +modifications to the software. + +Much more documentation for this module is available in the legacy documentation +listed in :ref:`general-reference-docs`. Specifically, the FAST v6 User's Guide +as well as small updates in the FAST v8 README describe this module and contain +general information on OpenFAST. .. note:: @@ -45,7 +49,7 @@ with careful study. Note that the "unofficial FAST Theory Manual" applies to the structural equations of FAST v7 and the ElastoDyn module of FAST v8 and OpenFAST. - + .. toctree:: input.rst diff --git a/docs/source/user/fast.farm/index.rst b/docs/source/user/fast.farm/index.rst index 66773d2b1c..1263a64144 100644 --- a/docs/source/user/fast.farm/index.rst +++ b/docs/source/user/fast.farm/index.rst @@ -1,15 +1,13 @@ -.. _FAST.Farm: -FAST.Farm User’s Guide and Theory Manual +FAST.Farm User's Guide and Theory Manual ======================================== -.. only:: html +The FAST.Farm implementation plan is also available for download: +:download:`FAST.Farm Development Plan <../../../OtherSupporting/FAST.Farm_Plan_Rev25.doc>`. - This document offers a quick reference guide for the FAST.Farm driver for - OpenFAST. +The documentation here was derived from the FAST.Farm User's Guide and Theory Manual by Jason +Jonkman and Kelsey Shaler. - The documentation here was derived from the FAST.Farm User's Guide and Theory Manual by Jason - Jonkman and Kelsey Shaler. .. Update this link and uncomment when published: (`https://www.nrel.gov/docs/fy20osti/75959.pdf diff --git a/docs/source/user/hydrodyn/appendix.rst b/docs/source/user/hydrodyn/appendix.rst index 37b720ede2..21493a3ada 100644 --- a/docs/source/user/hydrodyn/appendix.rst +++ b/docs/source/user/hydrodyn/appendix.rst @@ -301,53 +301,58 @@ range [1,9] and corresponds to row α in the MEMBER OUTPUT LIST table and β is a number in the range [1,9] and corresponds to location β in the **NodeLocs** list of that table entry. Jα refers to output joint α, where α is a number in the range [1,9] and corresponds to row α in the -JOINT OUTPUT LIST table. All outputs are in the global inertial-frame -coordinate system. +JOINT OUTPUT LIST table. Bα refers to body α, where α is a number in +the range [1,9]. Setting α > NBody yields invalid output; if NBody > 9, +only the first 9 bodies can be output. Waveα refers to point α where +wave elevations can be output, where α is a number in the range [1,9]. +Setting α > NWaveElev yields invalid output. All outputs are in the +global inertial-frame coordinate. -================================================================ ============================================================================================== ======================================================================================== -Channel Name(s) Units Description -================================================================ ============================================================================================== ======================================================================================== -*Wave and Current Kinematics* -Wave1Elev, Wave2Elev, …, Wave9Elev (m) Total (first- plus second-order) wave elevations (up to 9 designated locations) -Wave1Elv1, Wave2Elv1, …, Wave9Elv1 (m) First-order wave elevations (up to 9 designated locations) -Wave1Elv2, Wave2Elv2, …, Wave9Elv2 (m) Second-order wave elevations (up to 9 designated locations) -MαNβVxi, MαNβVyi, MαNβVzi (m/s), (m/s), (m/s) Total (first- plus second-order) fluid particle velocities at MαNβ -MαNβAxi, MαNβAyi, MαNβAzi (m/s:sup:`2`), (m/s:sup:`2`), (m/s:sup:`2`) Total (first- plus second-order) fluid particle accelerations at MαNβ -MαNβDynP (Pa) Total (first- plus second-order) fluid particle dynamic pressure at MαNβ -JαVxi, JαVyi, JαVzi (m/s), (m/s), (m/s) Total (first- plus second-order) fluid particle velocities at Jα -JαAxi, JαAyi, JαAzi (m/s:sup:`2`), (m/s:sup:`2`), (m/s:sup:`2`) Total (first- plus second-order) fluid particle accelerations at Jα -JαDynP (Pa) Total (first- plus second-order) fluid particle dynamic pressure at Jα -*Total and Additional Loads* -AddFxi, AddFyi, AddFzi, AddMxi, AddMyi, AddMzi (N), (N), (N), (N·m), (N·m), (N·m) Forces and moments due to additional preload, stiffness, and damping at the WRP -HydroFxi, HydroFyi, HydroFzi, HydroMxi, HydroMyi, HydroMzi (N), (N), (N), (N·m), (N·m), (N·m) Total integrated hydrodynamic loads from both potential flow and strip theory at the WRP -*Loads from Potential-Flow Solution* -WavesFxi, WavesFyi, WavesFzi, WavesMxi, WavesMyi, WavesMzi (N), (N), (N), (N·m), (N·m), (N·m) Total (first- plus second-order) wave-excitation loads from diffraction at the WRP -WavesF1xi, WavesF1yi, WavesF1zi, WavesM1xi, WavesM1yi, WavesM1zi (N), (N), (N), (N·m), (N·m), (N·m) First-order wave-excitation loads from diffraction at the WRP -WavesF2xi, WavesF2yi, WavesF2zi, WavesM2xi, WavesM2yi, WavesM2zi (N), (N), (N), (N·m), (N·m), (N·m) Second-order wave-excitation loads from diffraction at the WRP -HdrStcFxi, HdrStcFyi, HdrStcFzi, HdrStcMxi, HdrStcMyi, HdrStcMzi (N), (N), (N), (N·m), (N·m), (N·m) Hydrostatic loads at the WRP -RdtnFxi, RdtnFyi, RdtnFzi, RdtnMxi, RdtnMyi, RdtnMzi (N), (N), (N), (N·m), (N·m), (N·m) Radiation loads at the WRP -*Structural Motions* -WRPSurge, WRPSway, WRPHeave, WRPRoll, WRPPitch WRPYaw (m), (m), (m), (rad), (rad), (rad) Displacements and rotations at the WRP -WRPTVxi, WRPTVyi, WRPTVzi, WRPRVxi, WRPRVyi, WRPVzi (m/s), (m/s), (m/s), (rad/s), (rad/s), (rad/s) Translational and rotational velocities at the WRP -WRPTAxi, WRPTAyi, WRPTAzi, WRPRAxi, WRPRAyi, WRPAzi (m/s:sup:`2`), (m/s:sup:`2`), (m/s:sup:`2`), (rad/s:sup:`2`), (rad/s:sup:`2`), (rad/s:sup:`2`) Translational and rotational accelerations at the WRP -MαNβSTVxi, MαNβSTVyi, MαNβSTVzi (m/s), (m/s), (m/s) Structural translational velocities at MαNβ -MαNβSTAxi, MαNβSTAyi, MαNβSTAzi (m/s:sup:`2`), (m/s:sup:`2`), (m/s:sup:`2`) Structural translational accelerations at MαNβ -JαSTVxi, JαSTVyi, JαSTVzi (m/s), (m/s), (m/s) Structural translational velocities at Jα -JαSTAxi, JαSTAyi, JαSTAzi (m/s:sup:`2`), (m/s:sup:`2`), (m/s:sup:`2`) Structural translational accelerations at Jα -*Distributed Loads (Per Unit Length) on Members* -MαNβFDxi, MαNβFDyi, MαNβFDzi (N/m), (N/m), (N/m) Viscous-drag force at MαNβ -MαNβFIxi, MαNβFIyi, MαNβFIzi (N/m), (N/m), (N/m) Fluid-inertia force at MαNβ -MαNβFBxi, MαNβFByi, MαNβFBzi, MαNβMBxi, MαNβMByi, MαNβMBzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Buoyancy loads at MαNβ -MαNβFBFxi, MαNβFBFyi, MαNβFBFzi, MαNβMBFxi, MαNβMBFyi, MαNβMBFzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Negative buoyancy loads due to flooding/ballasting at MαNβ -MαNβFMGxi, MαNβFMGyi, MαNβFMGzi (N/m), (N/m), (N/m) Forces due to marine growth weight at MαNβ -MαNβFAMxi, MαNβFAMyi, MαNβFAMzi (N/m), (N/m), (N/m) Hydrodynamic added-mass forces at MαNβ -MαNβFAGxi, MαNβFAGyi, MαNβFAGzi (N/m), (N/m), (N/m) Marine growth mass inertia forces at MαNβ -MαNβFAFxi, MαNβFAFyi, MαNβFAFzi (N/m), (N/m), (N/m) Flooding/ballasting mass inertia forces at MαNβ -MαNβFAxi, MαNβFAyi, MαNβFAzi (N/m), (N/m), (N/m) Total effective added-mass forces at MαNβ -*Lumped Loads at Joints* -JαFDxi, JαFDyi, JαFDzi (N), (N), (N) Viscous-drag force at Jα -JαFIxi, JαFIyi, JαFIzi (N), (N), (N) Fluid-inertia force at Jα -JαFBxi, JαFByi, JαFBzi, JαMBxi, JαMByi, JαMBzi (N), (N), (N), (N·m), (N·m), (N·m) Buoyancy loads at Jα -JαFBFxi, JαFBFyi, JαFBFzi, JαMBFxi, JαMBFyi, JαMBFzi (N), (N), (N), (N·m), (N·m), (N·m) Negative buoyancy loads due to flooding/ballasting at Jα -JαFAMxi, JαFAMyi, JαFAMzi (N), (N), (N) Hydrodynamic added-mass forces at Jα -================================================================ ============================================================================================== ======================================================================================== +================================================================ ========================================================================================================== ======================================================================================== +Channel Name(s) Units Description +================================================================ ========================================================================================================== ======================================================================================== +**Wave and Current Kinematics** +WaveαElev (m) Total (first- plus second-order) wave elevations (up to 9 designated locations) +WaveαElv1 (m) First-order wave elevations (up to 9 designated locations) +WaveαElv2 (m) Second-order wave elevations (up to 9 designated locations) +MαNβVxi, MαNβVyi, MαNβVzi (m/s), (m/s), (m/s) Total (first- plus second-order) fluid particle velocities at MαNβ +MαNβAxi, MαNβAyi, MαNβAzi (m/s\ :sup:`2`), (m/s\ :sup:`2`), (m/s\ :sup:`2`) Total (first- plus second-order) fluid particle accelerations at MαNβ +MαNβDynP (Pa) Total (first- plus second-order) fluid particle dynamic pressure at MαNβ +JαVxi, JαVyi, JαVzi (m/s), (m/s), (m/s) Total (first- plus second-order) fluid particle velocities at Jα +JαAxi, JαAyi, JαAzi (m/s\ :sup:`2`), (m/s\ :sup:`2`), (m/s\ :sup:`2`) Total (first- plus second-order) fluid particle accelerations at Jα +JαDynP (Pa) Total (first- plus second-order) fluid particle dynamic pressure at Jα +**Total and Additional Loads** +BαAddFxi, BαAddFyi, BαAddFzi, BαAddMxi, BαAddMyi, BαAddMzi (N), (N), (N), (N·m), (N·m), (N·m) Loads due to additional preload, stiffness, and damping at Bα +HydroFxi, HydroFyi, HydroFzi, HydroMxi, HydroMyi, HydroMzi (N), (N), (N), (N·m), (N·m), (N·m) Total integrated hydrodynamic loads from both potential flow and strip theory at (0,0,0) +**Loads from Potential-Flow Solution** +BαWvsFxi, BαWvsFyi, BαWvsFzi, BαWvsMxi, BαWvsMyi, BαWvsMzi (N), (N), (N), (N·m), (N·m), (N·m) Total (first- plus second-order) wave-excitation loads from diffraction at Bα +BαWvsF1xi, BαWvsF1yi, BαWvsF1zi, BαWvsM1xi, BαWvsM1yi, BαWvsM1zi (N), (N), (N), (N·m), (N·m), (N·m) First-order wave-excitation loads from diffraction at Bα +BαWvsF2xi, BαWvsF2yi, BαWvsF2zi, BαWvsM2xi, BαWvsM2yi, BαWvsM2zi (N), (N), (N), (N·m), (N·m), (N·m) Second-order wave-excitation loads from diffraction at Bα +BαHdSFxi, BαHdSFyi, BαHdSFzi, BαHdSMxi, BαHdSMyi, BαHdSMzi (N), (N), (N), (N·m), (N·m), (N·m) Hydrostatic loads at Bα +BαRdtFxi, BαRdtFyi, BαRdtFzi, BαRdtMxi, BαRdtMyi, BαRdtMzi (N), (N), (N), (N·m), (N·m), (N·m) Wave-radiation loads at Bα +**Structural Motions** +BαSurge, BαSway, BαHeave, BαRoll, BαPitch BαYaw (m), (m), (m), (rad), (rad), (rad) Displacements and rotations at Bα +BαTVxi, BαTVyi, BαTVzi, BαRVxi, BαRVyi, BαRVzi (m/s), (m/s), (m/s), (rad/s), (rad/s), (rad/s) Translational and rotational velocities at Bα +BαTAxi, BαTAyi, BαTAzi, BαRAxi, BαRAyi, BαRAzi (m/s\ :sup:`2`), (m/s\ :sup:`2`), (m/s\ :sup:`2`), (rad/s\ :sup:`2`), (rad/s\ :sup:`2`), (rad/s\ :sup:`2`) Translational and rotational accelerations at Bα +MαNβSTVxi, MαNβSTVyi, MαNβSTVzi (m/s), (m/s), (m/s) Structural translational velocities at MαNβ +MαNβSTAxi, MαNβSTAyi, MαNβSTAzi (m/s\ :sup:`2`), (m/s\ :sup:`2`), (m/s\ :sup:`2`) Structural translational accelerations at MαNβ +JαSTVxi, JαSTVyi, JαSTVzi (m/s), (m/s), (m/s) Structural translational velocities at Jα +JαSTAxi, JαSTAyi, JαSTAzi (m/s\ :sup:`2`), (m/s\ :sup:`2`), (m/s\ :sup:`2`) Structural translational accelerations at Jα +**Distributed Loads (Per Unit Length) on Members** +MαNβFDxi, MαNβFDyi, MαNβFDzi (N/m), (N/m), (N/m) Viscous-drag forces at MαNβ +MαNβFIxi, MαNβFIyi, MαNβFIzi (N/m), (N/m), (N/m) Fluid-inertia forces at MαNβ +MαNβFBxi, MαNβFByi, MαNβFBzi, MαNβMBxi, MαNβMByi, MαNβMBzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Buoyancy loads at MαNβ +MαNβFBFxi, MαNβFBFyi, MαNβFBFzi, MαNβMBFxi, MαNβMBFyi, MαNβMBFzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Negative buoyancy loads due to flooding/ballasting at MαNβ +MαNβFMGxi, MαNβFMGyi, MαNβFMGzi, MαNβMMGxi, MαNβMMGyi, MαNβMMGzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Loads due to marine growth weight at MαNβ +MαNβFAMxi, MαNβFAMyi, MαNβFAMzi (N/m), (N/m), (N/m) Hydrodynamic added-mass forces at MαNβ +MαNβFAGxi, MαNβFAGyi, MαNβFAGzi, MαNβMAGxi, MαNβMAGyi, MαNβMAGzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Marine growth mass inertia loads at MαNβ +MαNβFAFxi, MαNβFAFyi, MαNβFAFzi, MαNβMAFxi, MαNβMAFyi, MαNβMAFzi (N/m), (N/m), (N/m), (N·m/m), (N·m/m), (N·m/m) Flooding/ballasting mass inertia loads at MαNβ +**Lumped Loads at Joints** +JαFDxi, JαFDyi, JαFDzi (N), (N), (N) Viscous-drag forces at Jα +JαFIxi, JαFIyi, JαFIzi (N), (N), (N) Fluid-inertia forces at Jα +JαFBxi, JαFByi, JαFBzi, JαMBxi, JαMByi, JαMBzi (N), (N), (N), (N·m), (N·m), (N·m) Buoyancy loads at Jα +JαFBFxi, JαFBFyi, JαFBFzi, JαMBFxi, JαMBFyi, JαMBFzi (N), (N), (N), (N·m), (N·m), (N·m) Negative buoyancy loads due to flooding/ballasting at Jα +JαFMGxi, JαFMGyi, JαFMGzi (N), (N), (N) Forces due to marine growth weight at Jα +JαFAMxi, JαFAMyi, JαFAMzi (N), (N), (N) Hydrodynamic added-mass forces at Jα +JαFAGxi, JαFAGyi, JαFAGzi, JαMAGxi, JαMAGyi, JαMAGzi (N), (N), (N), (N·m), (N·m), (N·m) Marine growth mass inertia loads at Jα +================================================================ ========================================================================================================== ======================================================================================== diff --git a/docs/source/user/hydrodyn/index.rst b/docs/source/user/hydrodyn/index.rst index a76daf82e1..2dd19deb89 100644 --- a/docs/source/user/hydrodyn/index.rst +++ b/docs/source/user/hydrodyn/index.rst @@ -21,6 +21,25 @@ HydroDyn integrates with OpenFAST through the FAST modularization framework. HydroDyn can also be driven as a standalone code to compute hydrodynamic loading uncoupled from OpenFAST. +In addition to this documentation, the following materials including presentation slides, +development plans, and publications are made available for reference. +Note that some of these may be outdated and pertain to older versions +of HydroDyn. + +- :download:`Computation of Wave Loads Under Multidirectional Sea States for Floating Offshore Wind Turbines ` +- :download:`Effects of Second-Order Hydrodynamic Forces on Floating Offshore Wind Turbines ` +- :download:`State-Space Realization of the Wave-Radiation Force within FAST ` +- :download:`Dynamics of Offshore Floating Wind Turbines—Model Development and Verification ` +- :download:`Dynamics Modeling and Loads Analysis of an Offshore Floating Wind Turbine ` +- :download:`Draft Implementation Plan - Changes in HydroDyn to Support Time-Varying Buoyancy Loads on Morison Members <../../../OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_Morison.docx>` +- :download:`Implementation Plan - Modifications to State-Space Modules in HydroDyn to Support Multiple WAMIT Bodies <../../../OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBodyStateSpace.docx>` +- :download:`Implementation Plan (Revised) - Changes in HydroDyn to Support Multiple WAMIT Bodies <../../../OtherSupporting/HydroDyn/HydroDyn_Plan_TCF_NBody.docx>` +- :download:`Implementation Plan - 2nd-order Forces Within HydroDyn <../../../OtherSupporting/HydroDyn/HydroDyn_2ndOrderForces_Plan.pdf>` +- :download:`Implementation Plan - 2nd-order Wave Kinematics Within HydroDyn <../../../OtherSupporting/HydroDyn/WAVE2_document.pdf>` +- :download:`Plan for Adding Wave Stretching to HydroDyn <../../../OtherSupporting/HydroDyn/HydroDyn_WaveStretching_Plan.docx>` +- :download:`Breaking Wave Modeling Approach for FAST <../../../OtherSupporting/HydroDyn/Breaking_Wave_Modeling_Approach_for_FAST.docx>` + + HydroDyn allows for multiple approaches for calculating the hydrodynamic loads on a structure: diff --git a/docs/source/user/index.rst b/docs/source/user/index.rst index 95125f5f2f..94436de674 100644 --- a/docs/source/user/index.rst +++ b/docs/source/user/index.rst @@ -24,8 +24,9 @@ General Workshop material, legacy documentation, and other resources are listed below. +- `Overview of OpenFAST at NAWEA WindTech 2019 `_ - `Workshop Presentations `_ -- :download:`Old FAST v6 User’s Guide <../../OtherSupporting/Old_FAST6_UsersGuide.pdf>` +- :download:`Old FAST v6 User's Guide <../../OtherSupporting/Old_FAST6_UsersGuide.pdf>` - :download:`FAST v8 README <../../OtherSupporting/FAST8_README.pdf>` - `Implementation of Substructure Flexibility and Member-Level Load Capabilities for Floating Offshore Wind Turbines in OpenFAST `_ - `FAST modularization framework for wind turbine simulation: full-system linearization `_ @@ -53,9 +54,46 @@ Documentation covers usage of models, underlying theory, and in some cases modul InflowWind ServoDyn Structural Control + TurbSim C++ API FAST.Farm - + +The following modules do not currently have formal documentation +or are contributed to OpenFAST from organizations +external to NREL and the core OpenFAST team. As documentation is added, +these resources will be moved to their appropriate location. If newer versions +of the external resources are available, please open a `GitHub Issue `_ +with the information for the new documentation. + +- MAP++ + + - `Official MAP++ documentation `_ + - :download:`Implementation of a Multi-Segmented, Quasi-Static Cable Model <../../OtherSupporting/MAP/cable_model_development.pdf>` + +- FEAMooring + + - :download:`Theory Manual <../../OtherSupporting/FEAMooring/FEAM_Theory_Manual.pdf>` + - :download:`User's Guide <../../OtherSupporting/FEAMooring/FEAM_Users_Guide.pdf>` + +- MoorDyn + + - `Official User's Guide `_ + +- OrcaFlex Interface: + + - :download:`User's Guide <../../OtherSupporting/OrcaFlex/User_Guide_OrcaFlexInterface.pdf>` + +- IceFloe + + - :download:`Ice Load Project Final Technical Report <../../OtherSupporting/IceFloe/Ice_Load_Final_Report.pdf>` + +- IceDyn + + - :download:`Draft: FAST Ice Module Manual <../../OtherSupporting/IceDyn/IceDyn_Manual.pdf>` + +- TurbSim + + - :download:`User's Guide <../../OtherSupporting/TurbSim/TurbSim_v2.00.pdf>` Modularization Framework ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -79,3 +117,9 @@ Glue Code and Mesh Mapping - `FAST Modular Framework for Wind Turbine Simulation: New Algorithms and Numerical Examples `_ - :download:`OpenFAST Algorithms <../../OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.pdf>` - A summary of the solve method used in the glue code. - :download:`Predictor-Corrector Approach <../../OtherSupporting/ProposedPCApproach_Rev4.docx>` + + +NWTC Subroutine Library +~~~~~~~~~~~~~~~~~~~~~~~ + +- :download:`NWTC Library - short overview of subroutines and functions <../../OtherSupporting/NWTC_Library_Description.pdf>` diff --git a/docs/source/user/inflowwind/driver.rst b/docs/source/user/inflowwind/driver.rst index b0ef7a0170..da2783c243 100644 --- a/docs/source/user/inflowwind/driver.rst +++ b/docs/source/user/inflowwind/driver.rst @@ -7,7 +7,7 @@ Command-line syntax for InflowWind driver: :: - InlowWind_Driver [options] + InflowWind_Driver [options] where: -- Name of driver input file to use options: /ifw -- treat as name of InflowWind input file (no driver input file) diff --git a/docs/source/user/servodyn/BladedExInterface.png b/docs/source/user/servodyn/BladedExInterface.png index eeb9beb229..03b92d0b18 100644 Binary files a/docs/source/user/servodyn/BladedExInterface.png and b/docs/source/user/servodyn/BladedExInterface.png differ diff --git a/docs/source/user/servodyn/SrvD--Ex.sum b/docs/source/user/servodyn/SrvD--Ex.sum index 22a4d1d0ea..1ff9fb6191 100644 --- a/docs/source/user/servodyn/SrvD--Ex.sum +++ b/docs/source/user/servodyn/SrvD--Ex.sum @@ -74,6 +74,9 @@ 95 --> Reserved (SrvD customization: set to SrvD AirDens parameter) 96 --> Reserved (SrvD customization: set to SrvD AvgWindSpeed parameter) 109 --> Shaft torque (=hub Mx for clockwise rotor) (Nm) [SrvD input] + 110 --> Thrust - Rotating low-speed shaft force x (GL co-ords) (N) [SrvD input] + 111 --> Nonrotating low-speed shaft force y (GL co-ords) (N) [SrvD input] + 112 --> Nonrotating low-speed shaft force z (GL co-ords) (N) [SrvD input] 117 --> Controller state [always set to 0] 120 <-- Airfoil command, blade 1 121 <-- Airfoil command, blade 2 diff --git a/docs/source/user/servodyn/index.rst b/docs/source/user/servodyn/index.rst index 1ec43cf0bd..0532f81d2f 100644 --- a/docs/source/user/servodyn/index.rst +++ b/docs/source/user/servodyn/index.rst @@ -1,22 +1,21 @@ -.. _srvd: ServoDyn Users Guide ==================== -.. only:: html +This document offers a quick reference guide for the ServoDyn software +program. It is intended to be used by the general user in combination +with other OpenFAST manuals. The manual will be updated as new releases are +issued and as needed to provide further information on advancements or +modifications to the software. - This document offers a quick reference guide for the ServoDyn software - program. It is intended to be used by the general user in combination - with other OpenFAST manuals. The manual will be updated as new releases are - issued and as needed to provide further information on advancements or - modifications to the software. +The Structural control sub-module of ServoDyn is documented in :numref:`StC`. - The Structural control sub-module of ServoDyn is documented in - :numref:`StC`. +**The documentation here is incomplete.** +Much more documentation for this module is available in the +FAST v6 User's Guide as well as small updates in the +FAST v8 README. These references can be downloaded in +section :numref:`general-reference-docs`. - **The documentation here is incomplete.** - - .. toctree:: :maxdepth: 2 diff --git a/docs/source/user/turbsim/appendix.rst b/docs/source/user/turbsim/appendix.rst new file mode 100644 index 0000000000..3dc79a5f06 --- /dev/null +++ b/docs/source/user/turbsim/appendix.rst @@ -0,0 +1,27 @@ +.. _TurbSim_appendix: + +Appendix +======== + +.. _TurbSim_input_files: + +TurbSim Input Files +------------------- + + +1) Primary TurbSim Input Files: +:download:`(TurbSim input file example) `: + +This is the primary input file for TurbSim. Most simulations will require only this file. + + +2) TurbSim secondary input files for user-defined input + +Input files that can be specified in the primary input file to import user-defined data. + +:download:`(user-defined profiles example) `: + +:download:`(user-defined spectra example) `: + +:download:`(user-defined time-series example) `: + diff --git a/docs/source/user/turbsim/examples/TurbSim.inp b/docs/source/user/turbsim/examples/TurbSim.inp new file mode 100644 index 0000000000..22413d4a9e --- /dev/null +++ b/docs/source/user/turbsim/examples/TurbSim.inp @@ -0,0 +1,74 @@ +---------TurbSim v2 (OpenFAST) Input File------------------ +for Certification Test #5 (SMOOTH Spectrum, formatted FF files, Coherent Structures). +---------Runtime Options----------------------------------- +False Echo - Echo input data to .ech (flag) +4433456 RandSeed1 - First random seed (-2147483648 to 2147483647) +"RanLux" RandSeed2 - Second random seed (-2147483648 to 2147483647) for intrinsic pRNG, or an alternative pRNG: "RanLux" or "RNSNLW" +False WrBHHTP - Output hub-height turbulence parameters in binary form? (Generates RootName.bin) +False WrFHHTP - Output hub-height turbulence parameters in formatted form? (Generates RootName.dat) +False WrADHH - Output hub-height time-series data in AeroDyn form? (Generates RootName.hh) +True WrADFF - Output full-field time-series data in TurbSim/AeroDyn form? (Generates RootName.bts) +False WrBLFF - Output full-field time-series data in BLADED/AeroDyn form? (Generates RootName.wnd) +False WrADTWR - Output tower time-series data? (Generates RootName.twr) +False WrHAWCFF - [Envision addition] Output full-field time-series data in HAWC form? (Generates RootName-u.bin, RootName-v.bin, RootName-w.bin, RootName.hawc) +False WrFMTFF - Output full-field time-series data in formatted (readable) form? (Generates RootName.u, RootName.v, RootName.w) +False WrACT - Output coherent turbulence time steps in AeroDyn form? (Generates RootName.cts) + 0 ScaleIEC - Scale IEC turbulence models to exact target standard deviation? [0=no additional scaling; 1=use hub scale uniformly; 2=use individual scales] + +--------Turbine/Model Specifications----------------------- + 31 NumGrid_Z - Vertical grid-point matrix dimension + 31 NumGrid_Y - Horizontal grid-point matrix dimension + 0.05 TimeStep - Time step [seconds] + 600 AnalysisTime - Length of analysis time series [seconds] (program will add time if necessary: AnalysisTime = MAX(AnalysisTime, UsableTime+GridWidth/MeanHHWS) ) +"ALL" UsableTime - Usable length of output time series [seconds] (program will add GridWidth/MeanHHWS seconds unless UsableTime is "ALL") + 90 HubHt - Hub height [m] (should be > 0.5*GridHeight) + 70 GridHeight - Grid height [m] + 70 GridWidth - Grid width [m] (should be >= 2*(RotorRadius+ShaftLength)) + 0 VFlowAng - Vertical mean flow (uptilt) angle [degrees] + 0 HFlowAng - Horizontal mean flow (skew) angle [degrees] + +--------Meteorological Boundary Conditions------------------- +"IECKAI" TurbModel - Turbulence model ("IECKAI","IECVKM","GP_LLJ","NWTCUP","SMOOTH","WF_UPW","WF_07D","WF_14D","TIDAL","API","USRINP","USRVKM","TIMESR", or "NONE") +"TurbSim_User.spectra", "TurbSim_User.timeSeriesInput" UserFile - Name of the file that contains inputs for user-defined spectra or time series inputs (used only for "USRINP" and "TIMESR" models) + 1 IECstandard - Number of IEC 61400-x standard (x=1,2, or 3 with optional 61400-1 edition number (i.e. "1-Ed2") ) +"A" IECturbc - IEC turbulence characteristic ("A", "B", "C" or the turbulence intensity in percent) ("KHTEST" option with NWTCUP model, not used for other models) +"NTM" IEC_WindType - IEC turbulence type ("NTM"=normal, "xETM"=extreme turbulence, "xEWM1"=extreme 1-year wind, "xEWM50"=extreme 50-year wind, where x=wind turbine class 1, 2, or 3) +"default" ETMc - IEC Extreme Turbulence Model "c" parameter [m/s] +"default" WindProfileType - Velocity profile type ("LOG";"PL"=power law;"JET";"H2L"=Log law for TIDAL model;"API";"USR";"TS";"IEC"=PL on rotor disk, LOG elsewhere; or "default") +"TurbSim_User.profiles" ProfileFile - Name of the file that contains input profiles for WindProfileType="USR" and/or TurbModel="USRVKM" [-] + 90 RefHt - Height of the reference velocity (URef) [m] + 17 URef - Mean (total) velocity at the reference height [m/s] (or "default" for JET velocity profile) [must be 1-hr mean for API model; otherwise is the mean over AnalysisTime seconds] + 350 ZJetMax - Jet height [m] (used only for JET velocity profile, valid 70-490 m) +"default" PLExp - Power law exponent [-] (or "default") +"default" Z0 - Surface roughness length [m] (or "default") + +--------Non-IEC Meteorological Boundary Conditions------------ +"default" Latitude - Site latitude [degrees] (or "default") + 0.05 RICH_NO - Gradient Richardson number [-] +"default" UStar - Friction or shear velocity [m/s] (or "default") +"default" ZI - Mixing layer depth [m] (or "default") +"default" PC_UW - Hub mean u'w' Reynolds stress [m^2/s^2] (or "default" or "none") +"default" PC_UV - Hub mean u'v' Reynolds stress [m^2/s^2] (or "default" or "none") +"default" PC_VW - Hub mean v'w' Reynolds stress [m^2/s^2] (or "default" or "none") + +--------Spatial Coherence Parameters---------------------------- +"default" SCMod1 - u-component coherence model ("GENERAL","IEC","API","NONE", or "default") +"default" SCMod2 - v-component coherence model ("GENERAL","IEC","NONE", or "default") +"default" SCMod3 - w-component coherence model ("GENERAL","IEC","NONE", or "default") +"default" InCDec1 - u-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0 0.3e-3" in quotes) (or "default") +"default" InCDec2 - v-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0 0.3e-3" in quotes) (or "default") +"default" InCDec3 - w-component coherence parameters for general or IEC models [-, m^-1] (e.g. "10.0 0.3e-3" in quotes) (or "default") +"default" CohExp - Coherence exponent for general model [-] (or "default") + +--------Coherent Turbulence Scaling Parameters------------------- [used only when WrACT=TRUE] +".\EventData" CTEventPath - Name of the path where event data files are located +"les" CTEventFile - Type of event files ("LES", "DNS", or "RANDOM") +true Randomize - Randomize the disturbance scale and locations? (true/false) + 1 DistScl - Disturbance scale [-] (ratio of event dataset height to rotor disk). (Ignored when Randomize = true.) + 0.5 CTLy - Fractional location of tower centerline from right [-] (looking downwind) to left side of the dataset. (Ignored when Randomize = true.) + 0.5 CTLz - Fractional location of hub height from the bottom of the dataset. [-] (Ignored when Randomize = true.) + 10 CTStartTime - Minimum start time for coherent structures in RootName.cts [seconds] + +==================================================== +! NOTE: Do not add or remove any lines in this file! +==================================================== diff --git a/docs/source/user/turbsim/examples/TurbSim_User.profiles b/docs/source/user/turbsim/examples/TurbSim_User.profiles new file mode 100644 index 0000000000..3063d952bb --- /dev/null +++ b/docs/source/user/turbsim/examples/TurbSim_User.profiles @@ -0,0 +1,16 @@ +---------TurbSim v2.00.* Profile Input File------------------------ +Made up profiles +-------- User-Defined Profiles (Used only with USR wind profile or USRVKM spectral model) ------------------- +5 NumUSRz - Number of Heights +1.092 StdScale1 - u-component scaling factor for the input standard deviation +1.0 StdScale2 - v-component scaling factor for the input standard deviation +0.534 StdScale3 - w-component scaling factor for the input standard deviation +----------------------------------------------------------------------------------- +Height Wind Speed Wind --Direction-- Standard Deviation Length Scale + (m) (m/s) (deg, cntr-clockwise ) (m/s) (m) +----------------------------------------------------------------------------------- +15.0 3 00 .100 3 +25.0 4 00 .200 4 +35.0 5 00 .300 6 +45.0 6 00 .100 9 +55.0 7 00 .500 13 diff --git a/docs/source/user/turbsim/examples/TurbSim_User.spectra b/docs/source/user/turbsim/examples/TurbSim_User.spectra new file mode 100644 index 0000000000..ce18d41f41 --- /dev/null +++ b/docs/source/user/turbsim/examples/TurbSim_User.spectra @@ -0,0 +1,10011 @@ +-------- User-Defined Spectra (Used only with USRINP spectral model) ------------------------------------ +- The Kaimal spectra IEC 61400-1 Ed. 3 for Vhub=12 m/s; Zhub=90 m; Class="B"; - +--------------------------------------------------------------------------------------------------------- +10000 NumUSRf - Number of Frequencies [dictates how many lines to read from this file] +1.0 SpecScale1 - scaling factor for the input u-component spectrum +1.0 SpecScale2 - scaling factor for the input v-component spectrum +1.0 SpecScale3 - scaling factor for the input w-component spectrum +......................................................................................................... +Frequency u-component PSD v-component PSD w-component PSD + (Hz) (m^2/s) (m^2/s) (m^2/s) +--------------------------------------------------------------------------------------------------------- + 0.001 364.644672 92.196417 9.432145 + 0.002 290.820811 84.504829 9.221093 + 0.003 238.306635 77.790863 9.017498 + 0.004 199.474346 71.891456 8.821001 + 0.005 169.860744 66.676649 8.631266 + 0.006 146.703651 62.041773 8.447977 + 0.007 128.214357 57.901706 8.270838 + 0.008 113.190378 54.186616 8.099568 + 0.009 100.797523 50.838749 7.933903 + 0.010 90.441383 47.809980 7.773593 + 0.011 81.688510 45.059936 7.618404 + 0.012 74.216397 42.554527 7.468113 + 0.013 67.780802 40.264798 7.322511 + 0.014 62.193824 38.166019 7.181398 + 0.015 57.308865 36.236959 7.044586 + 0.016 53.010107 34.459303 6.911897 + 0.017 49.205001 32.817181 6.783162 + 0.018 45.818825 31.296779 6.658222 + 0.019 42.790679 29.886027 6.536923 + 0.020 40.070501 28.574339 6.419121 + 0.021 37.616811 27.352396 6.304680 + 0.022 35.394985 26.211966 6.193469 + 0.023 33.375929 25.145755 6.085363 + 0.024 31.535043 24.147281 5.980246 + 0.025 29.851402 23.210763 5.878003 + 0.026 28.307111 22.331037 5.778530 + 0.027 26.886791 21.503472 5.681722 + 0.028 25.577156 20.723908 5.587484 + 0.029 24.366685 19.988599 5.495722 + 0.030 23.245339 19.294162 5.406347 + 0.031 22.204337 18.637537 5.319276 + 0.032 21.235972 18.015951 5.234426 + 0.033 20.333453 17.426882 5.151722 + 0.034 19.490776 16.868037 5.071089 + 0.035 18.702618 16.337324 4.992456 + 0.036 17.964245 15.832831 4.915756 + 0.037 17.271432 15.352811 4.840925 + 0.038 16.620402 14.895659 4.767899 + 0.039 16.007766 14.459904 4.696620 + 0.040 15.430479 14.044194 4.627031 + 0.041 14.885795 13.647280 4.559078 + 0.042 14.371236 13.268016 4.492707 + 0.043 13.884557 12.905338 4.427868 + 0.044 13.423722 12.558266 4.364514 + 0.045 12.986881 12.225891 4.302598 + 0.046 12.572350 11.907371 4.242075 + 0.047 12.178591 11.601924 4.182904 + 0.048 11.804199 11.308823 4.125041 + 0.049 11.447888 11.027392 4.068449 + 0.050 11.108480 10.757003 4.013089 + 0.051 10.784890 10.497067 3.958925 + 0.052 10.476123 10.247037 3.905921 + 0.053 10.181261 10.006402 3.854043 + 0.054 9.899457 9.774683 3.803259 + 0.055 9.629928 9.551431 3.753537 + 0.056 9.371952 9.336227 3.704847 + 0.057 9.124859 9.128678 3.657160 + 0.058 8.888026 8.928414 3.610447 + 0.059 8.660878 8.735088 3.564682 + 0.060 8.442877 8.548374 3.519838 + 0.061 8.233526 8.367964 3.475890 + 0.062 8.032358 8.193570 3.432813 + 0.063 7.838940 8.024920 3.390585 + 0.064 7.652869 7.861755 3.349181 + 0.065 7.473765 7.703835 3.308580 + 0.066 7.301274 7.550930 3.268761 + 0.067 7.135066 7.402823 3.229703 + 0.068 6.974831 7.259311 3.191387 + 0.069 6.820276 7.120198 3.153793 + 0.070 6.671129 6.985303 3.116903 + 0.071 6.527133 6.854450 3.080698 + 0.072 6.388046 6.727476 3.045161 + 0.073 6.253641 6.604224 3.010276 + 0.074 6.123705 6.484545 2.976026 + 0.075 5.998035 6.368299 2.942395 + 0.076 5.876441 6.255352 2.909368 + 0.077 5.758743 6.145576 2.876930 + 0.078 5.644773 6.038850 2.845067 + 0.079 5.534369 5.935060 2.813765 + 0.080 5.427380 5.834094 2.783010 + 0.081 5.323662 5.735849 2.752790 + 0.082 5.223080 5.640224 2.723091 + 0.083 5.125504 5.547125 2.693902 + 0.084 5.030812 5.456460 2.665210 + 0.085 4.938889 5.368143 2.637004 + 0.086 4.849624 5.282092 2.609272 + 0.087 4.762912 5.198226 2.582004 + 0.088 4.678655 5.116471 2.555190 + 0.089 4.596758 5.036754 2.528818 + 0.090 4.517130 4.959006 2.502879 + 0.091 4.439687 4.883160 2.477363 + 0.092 4.364346 4.809153 2.452260 + 0.093 4.291031 4.736925 2.427563 + 0.094 4.219666 4.666417 2.403260 + 0.095 4.150182 4.597574 2.379345 + 0.096 4.082510 4.530341 2.355808 + 0.097 4.016587 4.464667 2.332642 + 0.098 3.952350 4.400504 2.309838 + 0.099 3.889742 4.337803 2.287388 + 0.100 3.828706 4.276520 2.265286 + 0.101 3.769187 4.216610 2.243523 + 0.102 3.711136 4.158032 2.222093 + 0.103 3.654501 4.100745 2.200989 + 0.104 3.599238 4.044711 2.180203 + 0.105 3.545299 3.989892 2.159730 + 0.106 3.492642 3.936252 2.139563 + 0.107 3.441225 3.883756 2.119695 + 0.108 3.391009 3.832372 2.100121 + 0.109 3.341955 3.782067 2.080834 + 0.110 3.294026 3.732810 2.061830 + 0.111 3.247188 3.684572 2.043101 + 0.112 3.201407 3.637324 2.024643 + 0.113 3.156650 3.591037 2.006451 + 0.114 3.112885 3.545686 1.988519 + 0.115 3.070083 3.501244 1.970842 + 0.116 3.028216 3.457687 1.953414 + 0.117 2.987254 3.414990 1.936233 + 0.118 2.947172 3.373131 1.919291 + 0.119 2.907943 3.332087 1.902586 + 0.120 2.869543 3.291835 1.886112 + 0.121 2.831948 3.252357 1.869865 + 0.122 2.795135 3.213630 1.853841 + 0.123 2.759082 3.175636 1.838035 + 0.124 2.723767 3.138356 1.822444 + 0.125 2.689170 3.101771 1.807064 + 0.126 2.655271 3.065864 1.791890 + 0.127 2.622050 3.030617 1.776919 + 0.128 2.589489 2.996014 1.762147 + 0.129 2.557571 2.962039 1.747571 + 0.130 2.526277 2.928676 1.733186 + 0.131 2.495592 2.895910 1.718990 + 0.132 2.465498 2.863727 1.704979 + 0.133 2.435981 2.832113 1.691150 + 0.134 2.407025 2.801053 1.677500 + 0.135 2.378616 2.770535 1.664025 + 0.136 2.350740 2.740545 1.650723 + 0.137 2.323383 2.711071 1.637589 + 0.138 2.296532 2.682101 1.624623 + 0.139 2.270174 2.653624 1.611819 + 0.140 2.244296 2.625627 1.599177 + 0.141 2.218888 2.598099 1.586692 + 0.142 2.193936 2.571031 1.574362 + 0.143 2.169431 2.544411 1.562185 + 0.144 2.145360 2.518229 1.550158 + 0.145 2.121714 2.492476 1.538279 + 0.146 2.098482 2.467141 1.526544 + 0.147 2.075655 2.442216 1.514952 + 0.148 2.053222 2.417692 1.503501 + 0.149 2.031175 2.393559 1.492187 + 0.150 2.009504 2.369809 1.481009 + 0.151 1.988200 2.346434 1.469964 + 0.152 1.967256 2.323426 1.459050 + 0.153 1.946662 2.300777 1.448266 + 0.154 1.926412 2.278478 1.437608 + 0.155 1.906496 2.256524 1.427075 + 0.156 1.886907 2.234906 1.416666 + 0.157 1.867639 2.213618 1.406377 + 0.158 1.848684 2.192652 1.396207 + 0.159 1.830034 2.172002 1.386155 + 0.160 1.811684 2.151662 1.376217 + 0.161 1.793626 2.131625 1.366394 + 0.162 1.775855 2.111884 1.356681 + 0.163 1.758364 2.092434 1.347079 + 0.164 1.741146 2.073270 1.337586 + 0.165 1.724197 2.054385 1.328198 + 0.166 1.707511 2.035773 1.318916 + 0.167 1.691081 2.017430 1.309737 + 0.168 1.674902 1.999350 1.300660 + 0.169 1.658970 1.981528 1.291683 + 0.170 1.643279 1.963958 1.282805 + 0.171 1.627825 1.946637 1.274024 + 0.172 1.612601 1.929558 1.265339 + 0.173 1.597604 1.912718 1.256748 + 0.174 1.582829 1.896112 1.248251 + 0.175 1.568271 1.879736 1.239844 + 0.176 1.553926 1.863584 1.231528 + 0.177 1.539791 1.847654 1.223301 + 0.178 1.525859 1.831940 1.215161 + 0.179 1.512129 1.816439 1.207108 + 0.180 1.498595 1.801147 1.199140 + 0.181 1.485253 1.786060 1.191256 + 0.182 1.472101 1.771174 1.183454 + 0.183 1.459134 1.756485 1.175733 + 0.184 1.446349 1.741991 1.168093 + 0.185 1.433742 1.727687 1.160532 + 0.186 1.421311 1.713570 1.153050 + 0.187 1.409050 1.699636 1.145643 + 0.188 1.396958 1.685883 1.138313 + 0.189 1.385031 1.672307 1.131058 + 0.190 1.373267 1.658906 1.123876 + 0.191 1.361661 1.645675 1.116767 + 0.192 1.350212 1.632612 1.109730 + 0.193 1.338915 1.619714 1.102763 + 0.194 1.327770 1.606979 1.095866 + 0.195 1.316772 1.594403 1.089038 + 0.196 1.305919 1.581984 1.082277 + 0.197 1.295208 1.569719 1.075584 + 0.198 1.284637 1.557605 1.068956 + 0.199 1.274204 1.545640 1.062394 + 0.200 1.263905 1.533822 1.055896 + 0.201 1.253740 1.522147 1.049461 + 0.202 1.243704 1.510615 1.043088 + 0.203 1.233796 1.499221 1.036778 + 0.204 1.224014 1.487964 1.030528 + 0.205 1.214355 1.476842 1.024338 + 0.206 1.204818 1.465852 1.018208 + 0.207 1.195400 1.454992 1.012136 + 0.208 1.186099 1.444261 1.006122 + 0.209 1.176914 1.433655 1.000164 + 0.210 1.167842 1.423174 0.994263 + 0.211 1.158881 1.412815 0.988418 + 0.212 1.150030 1.402576 0.982627 + 0.213 1.141286 1.392455 0.976891 + 0.214 1.132648 1.382450 0.971207 + 0.215 1.124115 1.372560 0.965577 + 0.216 1.115683 1.362783 0.959998 + 0.217 1.107353 1.353117 0.954471 + 0.218 1.099122 1.343560 0.948995 + 0.219 1.090988 1.334110 0.943569 + 0.220 1.082950 1.324766 0.938192 + 0.221 1.075006 1.315527 0.932864 + 0.222 1.067155 1.306390 0.927584 + 0.223 1.059395 1.297355 0.922352 + 0.224 1.051726 1.288419 0.917167 + 0.225 1.044144 1.279581 0.912029 + 0.226 1.036650 1.270839 0.906936 + 0.227 1.029242 1.262193 0.901889 + 0.228 1.021918 1.253641 0.896887 + 0.229 1.014677 1.245181 0.891929 + 0.230 1.007517 1.236811 0.887014 + 0.231 1.000438 1.228532 0.882143 + 0.232 0.993439 1.220341 0.877314 + 0.233 0.986517 1.212237 0.872528 + 0.234 0.979672 1.204218 0.867783 + 0.235 0.972903 1.196284 0.863079 + 0.236 0.966209 1.188434 0.858416 + 0.237 0.959588 1.180665 0.853793 + 0.238 0.953039 1.172978 0.849210 + 0.239 0.946561 1.165370 0.844666 + 0.240 0.940154 1.157841 0.840161 + 0.241 0.933815 1.150390 0.835694 + 0.242 0.927545 1.143014 0.831266 + 0.243 0.921342 1.135715 0.826874 + 0.244 0.915205 1.128489 0.822520 + 0.245 0.909133 1.121337 0.818202 + 0.246 0.903125 1.114257 0.813920 + 0.247 0.897181 1.107248 0.809674 + 0.248 0.891299 1.100310 0.805463 + 0.249 0.885478 1.093441 0.801287 + 0.250 0.879718 1.086640 0.797146 + 0.251 0.874018 1.079907 0.793039 + 0.252 0.868376 1.073240 0.788966 + 0.253 0.862793 1.066639 0.784926 + 0.254 0.857267 1.060102 0.780919 + 0.255 0.851797 1.053630 0.776945 + 0.256 0.846383 1.047220 0.773002 + 0.257 0.841023 1.040873 0.769092 + 0.258 0.835718 1.034586 0.765214 + 0.259 0.830466 1.028361 0.761366 + 0.260 0.825267 1.022195 0.757550 + 0.261 0.820120 1.016088 0.753764 + 0.262 0.815024 1.010039 0.750008 + 0.263 0.809978 1.004048 0.746282 + 0.264 0.804982 0.998113 0.742585 + 0.265 0.800035 0.992234 0.738918 + 0.266 0.795137 0.986411 0.735280 + 0.267 0.790286 0.980642 0.731670 + 0.268 0.785483 0.974926 0.728088 + 0.269 0.780726 0.969264 0.724535 + 0.270 0.776015 0.963654 0.721009 + 0.271 0.771350 0.958096 0.717510 + 0.272 0.766729 0.952590 0.714039 + 0.273 0.762152 0.947133 0.710594 + 0.274 0.757619 0.941727 0.707176 + 0.275 0.753129 0.936369 0.703784 + 0.276 0.748681 0.931061 0.700418 + 0.277 0.744275 0.925800 0.697078 + 0.278 0.739910 0.920586 0.693763 + 0.279 0.735587 0.915420 0.690474 + 0.280 0.731303 0.910300 0.687209 + 0.281 0.727060 0.905225 0.683969 + 0.282 0.722855 0.900195 0.680753 + 0.283 0.718689 0.895211 0.677561 + 0.284 0.714562 0.890270 0.674393 + 0.285 0.710473 0.885372 0.671249 + 0.286 0.706420 0.880518 0.668128 + 0.287 0.702405 0.875706 0.665031 + 0.288 0.698426 0.870935 0.661956 + 0.289 0.694483 0.866207 0.658904 + 0.290 0.690575 0.861519 0.655875 + 0.291 0.686703 0.856872 0.652867 + 0.292 0.682865 0.852265 0.649882 + 0.293 0.679061 0.847697 0.646918 + 0.294 0.675291 0.843168 0.643976 + 0.295 0.671555 0.838678 0.641056 + 0.296 0.667851 0.834226 0.638156 + 0.297 0.664180 0.829812 0.635277 + 0.298 0.660541 0.825435 0.632420 + 0.299 0.656934 0.821094 0.629582 + 0.300 0.653359 0.816791 0.626765 + 0.301 0.649814 0.812523 0.623968 + 0.302 0.646300 0.808290 0.621191 + 0.303 0.642817 0.804093 0.618434 + 0.304 0.639363 0.799931 0.615696 + 0.305 0.635939 0.795803 0.612978 + 0.306 0.632544 0.791709 0.610278 + 0.307 0.629178 0.787649 0.607598 + 0.308 0.625841 0.783621 0.604937 + 0.309 0.622532 0.779627 0.602294 + 0.310 0.619251 0.775665 0.599669 + 0.311 0.615997 0.771735 0.597063 + 0.312 0.612771 0.767837 0.594475 + 0.313 0.609572 0.763971 0.591905 + 0.314 0.606399 0.760135 0.589352 + 0.315 0.603252 0.756330 0.586817 + 0.316 0.600132 0.752556 0.584300 + 0.317 0.597037 0.748812 0.581799 + 0.318 0.593968 0.745097 0.579316 + 0.319 0.590924 0.741412 0.576850 + 0.320 0.587905 0.737755 0.574400 + 0.321 0.584911 0.734128 0.571967 + 0.322 0.581940 0.730529 0.569551 + 0.323 0.578994 0.726958 0.567150 + 0.324 0.576072 0.723415 0.564766 + 0.325 0.573173 0.719900 0.562398 + 0.326 0.570298 0.716412 0.560046 + 0.327 0.567445 0.712950 0.557709 + 0.328 0.564615 0.709516 0.555388 + 0.329 0.561808 0.706108 0.553083 + 0.330 0.559023 0.702726 0.550793 + 0.331 0.556260 0.699369 0.548517 + 0.332 0.553519 0.696039 0.546257 + 0.333 0.550799 0.692734 0.544012 + 0.334 0.548101 0.689453 0.541781 + 0.335 0.545424 0.686198 0.539566 + 0.336 0.542767 0.682967 0.537364 + 0.337 0.540132 0.679760 0.535177 + 0.338 0.537516 0.676577 0.533004 + 0.339 0.534921 0.673419 0.530845 + 0.340 0.532346 0.670283 0.528700 + 0.341 0.529791 0.667171 0.526569 + 0.342 0.527255 0.664082 0.524452 + 0.343 0.524739 0.661016 0.522348 + 0.344 0.522242 0.657972 0.520258 + 0.345 0.519763 0.654951 0.518181 + 0.346 0.517304 0.651952 0.516117 + 0.347 0.514863 0.648975 0.514066 + 0.348 0.512440 0.646019 0.512029 + 0.349 0.510036 0.643085 0.510004 + 0.350 0.507649 0.640173 0.507992 + 0.351 0.505281 0.637281 0.505993 + 0.352 0.502930 0.634410 0.504006 + 0.353 0.500596 0.631560 0.502032 + 0.354 0.498280 0.628730 0.500070 + 0.355 0.495981 0.625920 0.498120 + 0.356 0.493699 0.623131 0.496183 + 0.357 0.491434 0.620361 0.494257 + 0.358 0.489185 0.617611 0.492344 + 0.359 0.486952 0.614881 0.490442 + 0.360 0.484736 0.612169 0.488552 + 0.361 0.482536 0.609477 0.486674 + 0.362 0.480352 0.606804 0.484807 + 0.363 0.478184 0.604149 0.482951 + 0.364 0.476031 0.601513 0.481107 + 0.365 0.473894 0.598895 0.479274 + 0.366 0.471772 0.596296 0.477453 + 0.367 0.469665 0.593714 0.475642 + 0.368 0.467573 0.591150 0.473842 + 0.369 0.465496 0.588604 0.472053 + 0.370 0.463434 0.586076 0.470275 + 0.371 0.461386 0.583564 0.468508 + 0.372 0.459353 0.581070 0.466751 + 0.373 0.457334 0.578593 0.465005 + 0.374 0.455329 0.576133 0.463269 + 0.375 0.453339 0.573690 0.461544 + 0.376 0.451362 0.571263 0.459829 + 0.377 0.449399 0.568852 0.458124 + 0.378 0.447449 0.566458 0.456429 + 0.379 0.445513 0.564080 0.454744 + 0.380 0.443591 0.561717 0.453069 + 0.381 0.441682 0.559371 0.451404 + 0.382 0.439785 0.557040 0.449748 + 0.383 0.437902 0.554724 0.448102 + 0.384 0.436032 0.552424 0.446466 + 0.385 0.434174 0.550140 0.444840 + 0.386 0.432329 0.547870 0.443223 + 0.387 0.430497 0.545615 0.441615 + 0.388 0.428677 0.543375 0.440017 + 0.389 0.426869 0.541150 0.438428 + 0.390 0.425073 0.538939 0.436848 + 0.391 0.423290 0.536743 0.435277 + 0.392 0.421518 0.534561 0.433715 + 0.393 0.419758 0.532393 0.432162 + 0.394 0.418010 0.530239 0.430618 + 0.395 0.416274 0.528099 0.429083 + 0.396 0.414549 0.525973 0.427556 + 0.397 0.412835 0.523860 0.426038 + 0.398 0.411133 0.521761 0.424529 + 0.399 0.409442 0.519676 0.423028 + 0.400 0.407762 0.517604 0.421536 + 0.401 0.406093 0.515545 0.420052 + 0.402 0.404435 0.513499 0.418577 + 0.403 0.402788 0.511466 0.417110 + 0.404 0.401151 0.509446 0.415651 + 0.405 0.399526 0.507438 0.414200 + 0.406 0.397910 0.505443 0.412757 + 0.407 0.396305 0.503461 0.411322 + 0.408 0.394711 0.501491 0.409896 + 0.409 0.393126 0.499534 0.408477 + 0.410 0.391552 0.497588 0.407066 + 0.411 0.389988 0.495655 0.405663 + 0.412 0.388434 0.493734 0.404267 + 0.413 0.386889 0.491824 0.402879 + 0.414 0.385355 0.489927 0.401499 + 0.415 0.383830 0.488041 0.400126 + 0.416 0.382315 0.486167 0.398761 + 0.417 0.380809 0.484304 0.397403 + 0.418 0.379313 0.482452 0.396053 + 0.419 0.377826 0.480612 0.394710 + 0.420 0.376349 0.478783 0.393374 + 0.421 0.374881 0.476965 0.392046 + 0.422 0.373422 0.475159 0.390724 + 0.423 0.371972 0.473363 0.389410 + 0.424 0.370531 0.471578 0.388103 + 0.425 0.369098 0.469803 0.386802 + 0.426 0.367675 0.468040 0.385509 + 0.427 0.366261 0.466287 0.384223 + 0.428 0.364855 0.464544 0.382943 + 0.429 0.363458 0.462812 0.381671 + 0.430 0.362069 0.461090 0.380405 + 0.431 0.360689 0.459378 0.379145 + 0.432 0.359317 0.457677 0.377893 + 0.433 0.357953 0.455985 0.376647 + 0.434 0.356598 0.454304 0.375407 + 0.435 0.355251 0.452632 0.374175 + 0.436 0.353912 0.450971 0.372948 + 0.437 0.352581 0.449319 0.371728 + 0.438 0.351258 0.447676 0.370514 + 0.439 0.349944 0.446043 0.369307 + 0.440 0.348636 0.444420 0.368106 + 0.441 0.347337 0.442806 0.366911 + 0.442 0.346046 0.441202 0.365723 + 0.443 0.344762 0.439607 0.364540 + 0.444 0.343485 0.438021 0.363364 + 0.445 0.342217 0.436444 0.362194 + 0.446 0.340955 0.434876 0.361029 + 0.447 0.339702 0.433317 0.359871 + 0.448 0.338455 0.431767 0.358719 + 0.449 0.337216 0.430226 0.357572 + 0.450 0.335984 0.428694 0.356432 + 0.451 0.334759 0.427171 0.355297 + 0.452 0.333542 0.425656 0.354168 + 0.453 0.332331 0.424149 0.353044 + 0.454 0.331127 0.422652 0.351927 + 0.455 0.329931 0.421162 0.350815 + 0.456 0.328741 0.419681 0.349708 + 0.457 0.327558 0.418209 0.348608 + 0.458 0.326382 0.416744 0.347512 + 0.459 0.325213 0.415288 0.346423 + 0.460 0.324050 0.413840 0.345338 + 0.461 0.322894 0.412400 0.344259 + 0.462 0.321745 0.410968 0.343186 + 0.463 0.320602 0.409544 0.342118 + 0.464 0.319466 0.408128 0.341055 + 0.465 0.318336 0.406719 0.339997 + 0.466 0.317212 0.405318 0.338945 + 0.467 0.316095 0.403926 0.337898 + 0.468 0.314984 0.402540 0.336856 + 0.469 0.313879 0.401163 0.335819 + 0.470 0.312781 0.399792 0.334787 + 0.471 0.311689 0.398430 0.333761 + 0.472 0.310602 0.397074 0.332739 + 0.473 0.309522 0.395726 0.331722 + 0.474 0.308448 0.394386 0.330711 + 0.475 0.307379 0.393052 0.329704 + 0.476 0.306317 0.391726 0.328702 + 0.477 0.305260 0.390407 0.327705 + 0.478 0.304210 0.389095 0.326713 + 0.479 0.303165 0.387790 0.325726 + 0.480 0.302126 0.386493 0.324743 + 0.481 0.301092 0.385202 0.323765 + 0.482 0.300064 0.383918 0.322792 + 0.483 0.299042 0.382640 0.321823 + 0.484 0.298025 0.381370 0.320860 + 0.485 0.297014 0.380106 0.319900 + 0.486 0.296008 0.378849 0.318946 + 0.487 0.295008 0.377599 0.317996 + 0.488 0.294013 0.376355 0.317050 + 0.489 0.293024 0.375118 0.316109 + 0.490 0.292040 0.373887 0.315172 + 0.491 0.291061 0.372662 0.314240 + 0.492 0.290087 0.371445 0.313312 + 0.493 0.289118 0.370233 0.312389 + 0.494 0.288155 0.369028 0.311470 + 0.495 0.287197 0.367829 0.310555 + 0.496 0.286244 0.366636 0.309644 + 0.497 0.285296 0.365449 0.308738 + 0.498 0.284353 0.364269 0.307836 + 0.499 0.283415 0.363095 0.306938 + 0.500 0.282482 0.361926 0.306045 + 0.501 0.281553 0.360764 0.305155 + 0.502 0.280630 0.359608 0.304270 + 0.503 0.279711 0.358457 0.303389 + 0.504 0.278798 0.357313 0.302512 + 0.505 0.277889 0.356174 0.301639 + 0.506 0.276985 0.355041 0.300770 + 0.507 0.276085 0.353914 0.299905 + 0.508 0.275190 0.352792 0.299044 + 0.509 0.274300 0.351676 0.298186 + 0.510 0.273414 0.350566 0.297333 + 0.511 0.272533 0.349462 0.296484 + 0.512 0.271657 0.348363 0.295638 + 0.513 0.270785 0.347269 0.294797 + 0.514 0.269917 0.346181 0.293959 + 0.515 0.269054 0.345099 0.293125 + 0.516 0.268195 0.344022 0.292295 + 0.517 0.267341 0.342950 0.291469 + 0.518 0.266491 0.341883 0.290646 + 0.519 0.265646 0.340822 0.289827 + 0.520 0.264804 0.339766 0.289012 + 0.521 0.263967 0.338716 0.288200 + 0.522 0.263134 0.337670 0.287392 + 0.523 0.262305 0.336630 0.286588 + 0.524 0.261481 0.335595 0.285787 + 0.525 0.260660 0.334565 0.284990 + 0.526 0.259844 0.333539 0.284196 + 0.527 0.259032 0.332519 0.283406 + 0.528 0.258224 0.331504 0.282619 + 0.529 0.257420 0.330494 0.281836 + 0.530 0.256620 0.329489 0.281057 + 0.531 0.255823 0.328489 0.280280 + 0.532 0.255031 0.327493 0.279508 + 0.533 0.254243 0.326503 0.278738 + 0.534 0.253459 0.325517 0.277972 + 0.535 0.252678 0.324536 0.277210 + 0.536 0.251901 0.323559 0.276450 + 0.537 0.251129 0.322587 0.275694 + 0.538 0.250359 0.321620 0.274942 + 0.539 0.249594 0.320658 0.274192 + 0.540 0.248833 0.319700 0.273446 + 0.541 0.248075 0.318747 0.272703 + 0.542 0.247320 0.317798 0.271964 + 0.543 0.246570 0.316854 0.271227 + 0.544 0.245823 0.315914 0.270494 + 0.545 0.245080 0.314979 0.269764 + 0.546 0.244340 0.314048 0.269037 + 0.547 0.243604 0.313122 0.268313 + 0.548 0.242871 0.312200 0.267592 + 0.549 0.242142 0.311282 0.266875 + 0.550 0.241417 0.310369 0.266160 + 0.551 0.240695 0.309459 0.265449 + 0.552 0.239976 0.308554 0.264740 + 0.553 0.239261 0.307654 0.264035 + 0.554 0.238549 0.306757 0.263332 + 0.555 0.237841 0.305865 0.262633 + 0.556 0.237135 0.304977 0.261937 + 0.557 0.236434 0.304093 0.261243 + 0.558 0.235735 0.303213 0.260552 + 0.559 0.235040 0.302337 0.259865 + 0.560 0.234348 0.301465 0.259180 + 0.561 0.233660 0.300597 0.258498 + 0.562 0.232974 0.299734 0.257819 + 0.563 0.232292 0.298874 0.257143 + 0.564 0.231613 0.298018 0.256470 + 0.565 0.230937 0.297166 0.255799 + 0.566 0.230265 0.296318 0.255131 + 0.567 0.229595 0.295473 0.254466 + 0.568 0.228929 0.294633 0.253804 + 0.569 0.228266 0.293796 0.253145 + 0.570 0.227605 0.292964 0.252488 + 0.571 0.226948 0.292135 0.251834 + 0.572 0.226294 0.291309 0.251183 + 0.573 0.225643 0.290488 0.250534 + 0.574 0.224995 0.289670 0.249888 + 0.575 0.224349 0.288856 0.249245 + 0.576 0.223707 0.288045 0.248605 + 0.577 0.223068 0.287238 0.247967 + 0.578 0.222432 0.286435 0.247331 + 0.579 0.221798 0.285635 0.246699 + 0.580 0.221167 0.284839 0.246068 + 0.581 0.220540 0.284047 0.245441 + 0.582 0.219915 0.283258 0.244816 + 0.583 0.219293 0.282472 0.244193 + 0.584 0.218674 0.281690 0.243573 + 0.585 0.218057 0.280911 0.242956 + 0.586 0.217443 0.280136 0.242341 + 0.587 0.216832 0.279364 0.241729 + 0.588 0.216224 0.278596 0.241119 + 0.589 0.215619 0.277831 0.240511 + 0.590 0.215016 0.277069 0.239906 + 0.591 0.214416 0.276311 0.239303 + 0.592 0.213819 0.275556 0.238703 + 0.593 0.213224 0.274804 0.238105 + 0.594 0.212632 0.274056 0.237510 + 0.595 0.212042 0.273311 0.236917 + 0.596 0.211456 0.272569 0.236326 + 0.597 0.210871 0.271830 0.235738 + 0.598 0.210290 0.271095 0.235152 + 0.599 0.209711 0.270362 0.234568 + 0.600 0.209134 0.269633 0.233987 + 0.601 0.208560 0.268907 0.233408 + 0.602 0.207988 0.268184 0.232831 + 0.603 0.207419 0.267464 0.232256 + 0.604 0.206853 0.266748 0.231684 + 0.605 0.206289 0.266034 0.231114 + 0.606 0.205727 0.265323 0.230547 + 0.607 0.205168 0.264616 0.229981 + 0.608 0.204611 0.263911 0.229418 + 0.609 0.204057 0.263210 0.228857 + 0.610 0.203505 0.262511 0.228298 + 0.611 0.202956 0.261816 0.227741 + 0.612 0.202408 0.261123 0.227187 + 0.613 0.201864 0.260433 0.226634 + 0.614 0.201321 0.259746 0.226084 + 0.615 0.200781 0.259062 0.225536 + 0.616 0.200243 0.258381 0.224990 + 0.617 0.199708 0.257703 0.224446 + 0.618 0.199175 0.257028 0.223904 + 0.619 0.198644 0.256355 0.223365 + 0.620 0.198115 0.255686 0.222827 + 0.621 0.197588 0.255019 0.222292 + 0.622 0.197064 0.254355 0.221758 + 0.623 0.196542 0.253693 0.221227 + 0.624 0.196022 0.253035 0.220697 + 0.625 0.195505 0.252379 0.220170 + 0.626 0.194990 0.251725 0.219645 + 0.627 0.194476 0.251075 0.219121 + 0.628 0.193965 0.250427 0.218600 + 0.629 0.193456 0.249782 0.218080 + 0.630 0.192949 0.249140 0.217563 + 0.631 0.192445 0.248500 0.217048 + 0.632 0.191942 0.247863 0.216534 + 0.633 0.191442 0.247228 0.216023 + 0.634 0.190943 0.246596 0.215513 + 0.635 0.190447 0.245967 0.215005 + 0.636 0.189953 0.245340 0.214499 + 0.637 0.189461 0.244715 0.213996 + 0.638 0.188970 0.244094 0.213494 + 0.639 0.188482 0.243474 0.212993 + 0.640 0.187996 0.242858 0.212495 + 0.641 0.187512 0.242243 0.211999 + 0.642 0.187030 0.241632 0.211504 + 0.643 0.186550 0.241022 0.211012 + 0.644 0.186072 0.240416 0.210521 + 0.645 0.185595 0.239811 0.210032 + 0.646 0.185121 0.239209 0.209545 + 0.647 0.184649 0.238610 0.209059 + 0.648 0.184178 0.238012 0.208576 + 0.649 0.183710 0.237418 0.208094 + 0.650 0.183243 0.236825 0.207614 + 0.651 0.182779 0.236235 0.207135 + 0.652 0.182316 0.235648 0.206659 + 0.653 0.181855 0.235062 0.206184 + 0.654 0.181396 0.234479 0.205711 + 0.655 0.180939 0.233899 0.205240 + 0.656 0.180483 0.233320 0.204770 + 0.657 0.180030 0.232744 0.204302 + 0.658 0.179578 0.232170 0.203836 + 0.659 0.179128 0.231599 0.203372 + 0.660 0.178680 0.231029 0.202909 + 0.661 0.178234 0.230462 0.202448 + 0.662 0.177789 0.229897 0.201989 + 0.663 0.177346 0.229335 0.201531 + 0.664 0.176905 0.228774 0.201075 + 0.665 0.176466 0.228216 0.200620 + 0.666 0.176028 0.227660 0.200168 + 0.667 0.175593 0.227106 0.199717 + 0.668 0.175159 0.226554 0.199267 + 0.669 0.174726 0.226004 0.198819 + 0.670 0.174295 0.225457 0.198373 + 0.671 0.173867 0.224911 0.197928 + 0.672 0.173439 0.224368 0.197485 + 0.673 0.173014 0.223827 0.197044 + 0.674 0.172590 0.223288 0.196604 + 0.675 0.172168 0.222751 0.196165 + 0.676 0.171747 0.222216 0.195728 + 0.677 0.171328 0.221683 0.195293 + 0.678 0.170911 0.221152 0.194859 + 0.679 0.170495 0.220623 0.194427 + 0.680 0.170081 0.220096 0.193997 + 0.681 0.169668 0.219572 0.193568 + 0.682 0.169257 0.219049 0.193140 + 0.683 0.168848 0.218528 0.192714 + 0.684 0.168440 0.218009 0.192289 + 0.685 0.168034 0.217492 0.191866 + 0.686 0.167630 0.216977 0.191445 + 0.687 0.167227 0.216464 0.191024 + 0.688 0.166825 0.215953 0.190606 + 0.689 0.166425 0.215444 0.190189 + 0.690 0.166027 0.214937 0.189773 + 0.691 0.165630 0.214432 0.189359 + 0.692 0.165235 0.213928 0.188946 + 0.693 0.164841 0.213427 0.188534 + 0.694 0.164448 0.212927 0.188124 + 0.695 0.164057 0.212430 0.187716 + 0.696 0.163668 0.211934 0.187309 + 0.697 0.163280 0.211440 0.186903 + 0.698 0.162894 0.210947 0.186499 + 0.699 0.162509 0.210457 0.186096 + 0.700 0.162125 0.209968 0.185694 + 0.701 0.161743 0.209482 0.185294 + 0.702 0.161363 0.208997 0.184896 + 0.703 0.160983 0.208514 0.184498 + 0.704 0.160606 0.208032 0.184102 + 0.705 0.160229 0.207553 0.183708 + 0.706 0.159854 0.207075 0.183314 + 0.707 0.159481 0.206599 0.182922 + 0.708 0.159109 0.206125 0.182532 + 0.709 0.158738 0.205652 0.182142 + 0.710 0.158368 0.205181 0.181754 + 0.711 0.158000 0.204712 0.181368 + 0.712 0.157634 0.204245 0.180982 + 0.713 0.157268 0.203779 0.180598 + 0.714 0.156904 0.203315 0.180216 + 0.715 0.156542 0.202853 0.179834 + 0.716 0.156181 0.202392 0.179454 + 0.717 0.155821 0.201933 0.179075 + 0.718 0.155462 0.201476 0.178698 + 0.719 0.155105 0.201020 0.178321 + 0.720 0.154749 0.200566 0.177946 + 0.721 0.154394 0.200114 0.177573 + 0.722 0.154041 0.199663 0.177200 + 0.723 0.153689 0.199214 0.176829 + 0.724 0.153338 0.198766 0.176459 + 0.725 0.152988 0.198321 0.176090 + 0.726 0.152640 0.197876 0.175723 + 0.727 0.152293 0.197434 0.175356 + 0.728 0.151948 0.196992 0.174991 + 0.729 0.151603 0.196553 0.174627 + 0.730 0.151260 0.196115 0.174265 + 0.731 0.150918 0.195679 0.173903 + 0.732 0.150577 0.195244 0.173543 + 0.733 0.150238 0.194810 0.173184 + 0.734 0.149899 0.194379 0.172826 + 0.735 0.149562 0.193948 0.172469 + 0.736 0.149227 0.193520 0.172114 + 0.737 0.148892 0.193092 0.171759 + 0.738 0.148558 0.192667 0.171406 + 0.739 0.148226 0.192243 0.171054 + 0.740 0.147895 0.191820 0.170703 + 0.741 0.147565 0.191399 0.170353 + 0.742 0.147237 0.190979 0.170005 + 0.743 0.146909 0.190561 0.169657 + 0.744 0.146583 0.190144 0.169311 + 0.745 0.146257 0.189728 0.168966 + 0.746 0.145933 0.189314 0.168622 + 0.747 0.145610 0.188902 0.168279 + 0.748 0.145289 0.188491 0.167937 + 0.749 0.144968 0.188081 0.167596 + 0.750 0.144649 0.187673 0.167257 + 0.751 0.144330 0.187266 0.166918 + 0.752 0.144013 0.186861 0.166581 + 0.753 0.143697 0.186457 0.166244 + 0.754 0.143382 0.186055 0.165909 + 0.755 0.143068 0.185653 0.165575 + 0.756 0.142755 0.185254 0.165242 + 0.757 0.142443 0.184855 0.164910 + 0.758 0.142133 0.184458 0.164579 + 0.759 0.141823 0.184062 0.164249 + 0.760 0.141514 0.183668 0.163920 + 0.761 0.141207 0.183275 0.163592 + 0.762 0.140901 0.182884 0.163266 + 0.763 0.140595 0.182493 0.162940 + 0.764 0.140291 0.182104 0.162615 + 0.765 0.139988 0.181717 0.162292 + 0.766 0.139686 0.181330 0.161969 + 0.767 0.139385 0.180945 0.161647 + 0.768 0.139085 0.180562 0.161327 + 0.769 0.138786 0.180179 0.161007 + 0.770 0.138488 0.179798 0.160689 + 0.771 0.138191 0.179418 0.160371 + 0.772 0.137895 0.179040 0.160055 + 0.773 0.137600 0.178663 0.159739 + 0.774 0.137306 0.178287 0.159425 + 0.775 0.137013 0.177912 0.159111 + 0.776 0.136721 0.177538 0.158799 + 0.777 0.136430 0.177166 0.158487 + 0.778 0.136140 0.176795 0.158177 + 0.779 0.135851 0.176425 0.157867 + 0.780 0.135563 0.176057 0.157558 + 0.781 0.135276 0.175690 0.157251 + 0.782 0.134990 0.175324 0.156944 + 0.783 0.134705 0.174959 0.156638 + 0.784 0.134421 0.174595 0.156333 + 0.785 0.134138 0.174233 0.156030 + 0.786 0.133856 0.173872 0.155727 + 0.787 0.133574 0.173512 0.155425 + 0.788 0.133294 0.173153 0.155124 + 0.789 0.133015 0.172795 0.154824 + 0.790 0.132736 0.172439 0.154524 + 0.791 0.132459 0.172084 0.154226 + 0.792 0.132182 0.171729 0.153929 + 0.793 0.131906 0.171377 0.153632 + 0.794 0.131632 0.171025 0.153337 + 0.795 0.131358 0.170674 0.153042 + 0.796 0.131085 0.170325 0.152749 + 0.797 0.130813 0.169976 0.152456 + 0.798 0.130542 0.169629 0.152164 + 0.799 0.130272 0.169283 0.151873 + 0.800 0.130002 0.168938 0.151583 + 0.801 0.129734 0.168594 0.151293 + 0.802 0.129466 0.168252 0.151005 + 0.803 0.129200 0.167910 0.150718 + 0.804 0.128934 0.167570 0.150431 + 0.805 0.128669 0.167230 0.150145 + 0.806 0.128405 0.166892 0.149860 + 0.807 0.128142 0.166555 0.149576 + 0.808 0.127880 0.166219 0.149293 + 0.809 0.127618 0.165884 0.149011 + 0.810 0.127358 0.165550 0.148730 + 0.811 0.127098 0.165217 0.148449 + 0.812 0.126839 0.164885 0.148169 + 0.813 0.126581 0.164555 0.147890 + 0.814 0.126324 0.164225 0.147612 + 0.815 0.126067 0.163896 0.147335 + 0.816 0.125812 0.163569 0.147059 + 0.817 0.125557 0.163242 0.146783 + 0.818 0.125303 0.162917 0.146509 + 0.819 0.125050 0.162592 0.146235 + 0.820 0.124798 0.162269 0.145962 + 0.821 0.124546 0.161947 0.145689 + 0.822 0.124296 0.161625 0.145418 + 0.823 0.124046 0.161305 0.145147 + 0.824 0.123797 0.160986 0.144877 + 0.825 0.123549 0.160667 0.144608 + 0.826 0.123301 0.160350 0.144340 + 0.827 0.123055 0.160034 0.144073 + 0.828 0.122809 0.159719 0.143806 + 0.829 0.122564 0.159404 0.143540 + 0.830 0.122319 0.159091 0.143275 + 0.831 0.122076 0.158779 0.143011 + 0.832 0.121833 0.158467 0.142747 + 0.833 0.121591 0.158157 0.142484 + 0.834 0.121350 0.157848 0.142222 + 0.835 0.121110 0.157539 0.141961 + 0.836 0.120870 0.157232 0.141701 + 0.837 0.120631 0.156925 0.141441 + 0.838 0.120393 0.156620 0.141182 + 0.839 0.120155 0.156315 0.140924 + 0.840 0.119919 0.156011 0.140667 + 0.841 0.119683 0.155709 0.140410 + 0.842 0.119448 0.155407 0.140154 + 0.843 0.119213 0.155106 0.139899 + 0.844 0.118980 0.154806 0.139645 + 0.845 0.118747 0.154507 0.139391 + 0.846 0.118514 0.154209 0.139138 + 0.847 0.118283 0.153912 0.138886 + 0.848 0.118052 0.153616 0.138634 + 0.849 0.117822 0.153320 0.138384 + 0.850 0.117593 0.153026 0.138134 + 0.851 0.117364 0.152733 0.137884 + 0.852 0.117136 0.152440 0.137636 + 0.853 0.116909 0.152148 0.137388 + 0.854 0.116682 0.151857 0.137141 + 0.855 0.116457 0.151567 0.136894 + 0.856 0.116232 0.151278 0.136648 + 0.857 0.116007 0.150990 0.136403 + 0.858 0.115783 0.150703 0.136159 + 0.859 0.115560 0.150417 0.135915 + 0.860 0.115338 0.150131 0.135673 + 0.861 0.115116 0.149846 0.135430 + 0.862 0.114895 0.149563 0.135189 + 0.863 0.114675 0.149280 0.134948 + 0.864 0.114455 0.148998 0.134708 + 0.865 0.114236 0.148716 0.134468 + 0.866 0.114018 0.148436 0.134229 + 0.867 0.113801 0.148156 0.133991 + 0.868 0.113584 0.147878 0.133754 + 0.869 0.113367 0.147600 0.133517 + 0.870 0.113152 0.147323 0.133281 + 0.871 0.112937 0.147047 0.133046 + 0.872 0.112722 0.146771 0.132811 + 0.873 0.112509 0.146497 0.132577 + 0.874 0.112296 0.146223 0.132343 + 0.875 0.112083 0.145950 0.132110 + 0.876 0.111871 0.145678 0.131878 + 0.877 0.111660 0.145407 0.131647 + 0.878 0.111450 0.145136 0.131416 + 0.879 0.111240 0.144866 0.131186 + 0.880 0.111031 0.144598 0.130956 + 0.881 0.110822 0.144329 0.130727 + 0.882 0.110614 0.144062 0.130499 + 0.883 0.110407 0.143796 0.130271 + 0.884 0.110200 0.143530 0.130044 + 0.885 0.109994 0.143265 0.129818 + 0.886 0.109789 0.143001 0.129592 + 0.887 0.109584 0.142738 0.129367 + 0.888 0.109380 0.142475 0.129143 + 0.889 0.109176 0.142213 0.128919 + 0.890 0.108973 0.141952 0.128696 + 0.891 0.108771 0.141692 0.128473 + 0.892 0.108569 0.141432 0.128251 + 0.893 0.108367 0.141174 0.128030 + 0.894 0.108167 0.140916 0.127809 + 0.895 0.107967 0.140658 0.127589 + 0.896 0.107767 0.140402 0.127369 + 0.897 0.107569 0.140146 0.127150 + 0.898 0.107370 0.139891 0.126932 + 0.899 0.107173 0.139637 0.126714 + 0.900 0.106975 0.139383 0.126497 + 0.901 0.106779 0.139130 0.126280 + 0.902 0.106583 0.138878 0.126064 + 0.903 0.106388 0.138627 0.125849 + 0.904 0.106193 0.138376 0.125634 + 0.905 0.105999 0.138127 0.125420 + 0.906 0.105805 0.137877 0.125206 + 0.907 0.105612 0.137629 0.124993 + 0.908 0.105419 0.137381 0.124781 + 0.909 0.105227 0.137134 0.124569 + 0.910 0.105036 0.136888 0.124357 + 0.911 0.104845 0.136642 0.124147 + 0.912 0.104655 0.136397 0.123937 + 0.913 0.104465 0.136153 0.123727 + 0.914 0.104276 0.135910 0.123518 + 0.915 0.104087 0.135667 0.123309 + 0.916 0.103899 0.135425 0.123102 + 0.917 0.103711 0.135184 0.122894 + 0.918 0.103524 0.134943 0.122687 + 0.919 0.103338 0.134703 0.122481 + 0.920 0.103152 0.134463 0.122275 + 0.921 0.102967 0.134225 0.122070 + 0.922 0.102782 0.133987 0.121866 + 0.923 0.102597 0.133749 0.121662 + 0.924 0.102413 0.133513 0.121458 + 0.925 0.102230 0.133277 0.121255 + 0.926 0.102047 0.133041 0.121053 + 0.927 0.101865 0.132807 0.120851 + 0.928 0.101683 0.132573 0.120650 + 0.929 0.101502 0.132340 0.120449 + 0.930 0.101321 0.132107 0.120249 + 0.931 0.101141 0.131875 0.120049 + 0.932 0.100962 0.131643 0.119850 + 0.933 0.100782 0.131413 0.119651 + 0.934 0.100604 0.131183 0.119453 + 0.935 0.100426 0.130953 0.119255 + 0.936 0.100248 0.130724 0.119058 + 0.937 0.100071 0.130496 0.118862 + 0.938 0.099894 0.130269 0.118666 + 0.939 0.099718 0.130042 0.118470 + 0.940 0.099542 0.129816 0.118275 + 0.941 0.099367 0.129590 0.118081 + 0.942 0.099193 0.129365 0.117887 + 0.943 0.099018 0.129141 0.117693 + 0.944 0.098845 0.128917 0.117500 + 0.945 0.098672 0.128694 0.117308 + 0.946 0.098499 0.128471 0.117116 + 0.947 0.098327 0.128249 0.116924 + 0.948 0.098155 0.128028 0.116733 + 0.949 0.097984 0.127807 0.116543 + 0.950 0.097813 0.127587 0.116353 + 0.951 0.097643 0.127368 0.116163 + 0.952 0.097473 0.127149 0.115974 + 0.953 0.097303 0.126931 0.115786 + 0.954 0.097135 0.126713 0.115598 + 0.955 0.096966 0.126496 0.115410 + 0.956 0.096798 0.126280 0.115223 + 0.957 0.096631 0.126064 0.115037 + 0.958 0.096464 0.125849 0.114851 + 0.959 0.096297 0.125634 0.114665 + 0.960 0.096131 0.125420 0.114480 + 0.961 0.095965 0.125206 0.114296 + 0.962 0.095800 0.124993 0.114111 + 0.963 0.095635 0.124781 0.113928 + 0.964 0.095471 0.124569 0.113745 + 0.965 0.095307 0.124358 0.113562 + 0.966 0.095144 0.124147 0.113380 + 0.967 0.094981 0.123937 0.113198 + 0.968 0.094818 0.123728 0.113016 + 0.969 0.094656 0.123519 0.112836 + 0.970 0.094495 0.123310 0.112655 + 0.971 0.094334 0.123103 0.112475 + 0.972 0.094173 0.122895 0.112296 + 0.973 0.094013 0.122689 0.112117 + 0.974 0.093853 0.122483 0.111938 + 0.975 0.093693 0.122277 0.111760 + 0.976 0.093534 0.122072 0.111582 + 0.977 0.093376 0.121867 0.111405 + 0.978 0.093218 0.121664 0.111229 + 0.979 0.093060 0.121460 0.111052 + 0.980 0.092903 0.121257 0.110876 + 0.981 0.092746 0.121055 0.110701 + 0.982 0.092589 0.120853 0.110526 + 0.983 0.092433 0.120652 0.110351 + 0.984 0.092278 0.120451 0.110177 + 0.985 0.092123 0.120251 0.110004 + 0.986 0.091968 0.120051 0.109830 + 0.987 0.091814 0.119852 0.109658 + 0.988 0.091660 0.119654 0.109485 + 0.989 0.091506 0.119456 0.109313 + 0.990 0.091353 0.119258 0.109142 + 0.991 0.091200 0.119061 0.108971 + 0.992 0.091048 0.118865 0.108800 + 0.993 0.090896 0.118669 0.108630 + 0.994 0.090745 0.118473 0.108460 + 0.995 0.090594 0.118278 0.108291 + 0.996 0.090443 0.118084 0.108122 + 0.997 0.090293 0.117890 0.107954 + 0.998 0.090143 0.117697 0.107786 + 0.999 0.089994 0.117504 0.107618 + 1.000 0.089844 0.117311 0.107451 + 1.001 0.089696 0.117120 0.107284 + 1.002 0.089548 0.116928 0.107117 + 1.003 0.089400 0.116737 0.106951 + 1.004 0.089252 0.116547 0.106786 + 1.005 0.089105 0.116357 0.106621 + 1.006 0.088958 0.116168 0.106456 + 1.007 0.088812 0.115979 0.106292 + 1.008 0.088666 0.115790 0.106128 + 1.009 0.088521 0.115602 0.105964 + 1.010 0.088375 0.115415 0.105801 + 1.011 0.088231 0.115228 0.105638 + 1.012 0.088086 0.115042 0.105476 + 1.013 0.087942 0.114856 0.105314 + 1.014 0.087798 0.114670 0.105152 + 1.015 0.087655 0.114485 0.104991 + 1.016 0.087512 0.114301 0.104830 + 1.017 0.087370 0.114117 0.104670 + 1.018 0.087227 0.113933 0.104510 + 1.019 0.087086 0.113750 0.104350 + 1.020 0.086944 0.113567 0.104191 + 1.021 0.086803 0.113385 0.104032 + 1.022 0.086662 0.113203 0.103874 + 1.023 0.086522 0.113022 0.103716 + 1.024 0.086382 0.112841 0.103558 + 1.025 0.086243 0.112661 0.103401 + 1.026 0.086103 0.112481 0.103244 + 1.027 0.085964 0.112302 0.103088 + 1.028 0.085826 0.112123 0.102932 + 1.029 0.085688 0.111944 0.102776 + 1.030 0.085550 0.111766 0.102620 + 1.031 0.085412 0.111589 0.102465 + 1.032 0.085275 0.111412 0.102311 + 1.033 0.085139 0.111235 0.102157 + 1.034 0.085002 0.111059 0.102003 + 1.035 0.084866 0.110883 0.101849 + 1.036 0.084730 0.110707 0.101696 + 1.037 0.084595 0.110533 0.101543 + 1.038 0.084460 0.110358 0.101391 + 1.039 0.084325 0.110184 0.101239 + 1.040 0.084191 0.110011 0.101087 + 1.041 0.084057 0.109837 0.100936 + 1.042 0.083923 0.109665 0.100785 + 1.043 0.083790 0.109492 0.100634 + 1.044 0.083657 0.109321 0.100484 + 1.045 0.083524 0.109149 0.100334 + 1.046 0.083392 0.108978 0.100185 + 1.047 0.083260 0.108808 0.100036 + 1.048 0.083128 0.108638 0.099887 + 1.049 0.082997 0.108468 0.099738 + 1.050 0.082866 0.108299 0.099590 + 1.051 0.082736 0.108130 0.099443 + 1.052 0.082605 0.107961 0.099295 + 1.053 0.082475 0.107793 0.099148 + 1.054 0.082346 0.107626 0.099001 + 1.055 0.082216 0.107458 0.098855 + 1.056 0.082087 0.107292 0.098709 + 1.057 0.081959 0.107125 0.098563 + 1.058 0.081830 0.106959 0.098418 + 1.059 0.081702 0.106794 0.098273 + 1.060 0.081575 0.106629 0.098128 + 1.061 0.081447 0.106464 0.097984 + 1.062 0.081320 0.106300 0.097840 + 1.063 0.081193 0.106136 0.097697 + 1.064 0.081067 0.105972 0.097553 + 1.065 0.080941 0.105809 0.097410 + 1.066 0.080815 0.105647 0.097268 + 1.067 0.080689 0.105484 0.097126 + 1.068 0.080564 0.105322 0.096984 + 1.069 0.080439 0.105161 0.096842 + 1.070 0.080315 0.105000 0.096701 + 1.071 0.080190 0.104839 0.096560 + 1.072 0.080067 0.104679 0.096419 + 1.073 0.079943 0.104519 0.096279 + 1.074 0.079820 0.104359 0.096139 + 1.075 0.079697 0.104200 0.095999 + 1.076 0.079574 0.104042 0.095860 + 1.077 0.079451 0.103883 0.095721 + 1.078 0.079329 0.103725 0.095582 + 1.079 0.079207 0.103568 0.095444 + 1.080 0.079086 0.103410 0.095306 + 1.081 0.078965 0.103254 0.095168 + 1.082 0.078844 0.103097 0.095031 + 1.083 0.078723 0.102941 0.094894 + 1.084 0.078603 0.102785 0.094757 + 1.085 0.078483 0.102630 0.094621 + 1.086 0.078363 0.102475 0.094484 + 1.087 0.078243 0.102321 0.094349 + 1.088 0.078124 0.102166 0.094213 + 1.089 0.078005 0.102012 0.094078 + 1.090 0.077887 0.101859 0.093943 + 1.091 0.077768 0.101706 0.093808 + 1.092 0.077650 0.101553 0.093674 + 1.093 0.077533 0.101401 0.093540 + 1.094 0.077415 0.101249 0.093407 + 1.095 0.077298 0.101097 0.093273 + 1.096 0.077181 0.100946 0.093140 + 1.097 0.077065 0.100795 0.093007 + 1.098 0.076948 0.100645 0.092875 + 1.099 0.076832 0.100494 0.092743 + 1.100 0.076716 0.100345 0.092611 + 1.101 0.076601 0.100195 0.092480 + 1.102 0.076486 0.100046 0.092348 + 1.103 0.076371 0.099897 0.092217 + 1.104 0.076256 0.099749 0.092087 + 1.105 0.076142 0.099601 0.091956 + 1.106 0.076028 0.099453 0.091826 + 1.107 0.075914 0.099306 0.091697 + 1.108 0.075800 0.099159 0.091567 + 1.109 0.075687 0.099012 0.091438 + 1.110 0.075574 0.098866 0.091309 + 1.111 0.075461 0.098720 0.091181 + 1.112 0.075349 0.098574 0.091052 + 1.113 0.075237 0.098429 0.090924 + 1.114 0.075125 0.098284 0.090796 + 1.115 0.075013 0.098140 0.090669 + 1.116 0.074902 0.097995 0.090542 + 1.117 0.074790 0.097851 0.090415 + 1.118 0.074680 0.097708 0.090288 + 1.119 0.074569 0.097565 0.090162 + 1.120 0.074459 0.097422 0.090036 + 1.121 0.074349 0.097279 0.089910 + 1.122 0.074239 0.097137 0.089785 + 1.123 0.074129 0.096995 0.089660 + 1.124 0.074020 0.096853 0.089535 + 1.125 0.073911 0.096712 0.089410 + 1.126 0.073802 0.096571 0.089286 + 1.127 0.073693 0.096431 0.089162 + 1.128 0.073585 0.096291 0.089038 + 1.129 0.073477 0.096151 0.088915 + 1.130 0.073369 0.096011 0.088791 + 1.131 0.073262 0.095872 0.088668 + 1.132 0.073154 0.095733 0.088546 + 1.133 0.073047 0.095594 0.088423 + 1.134 0.072941 0.095456 0.088301 + 1.135 0.072834 0.095318 0.088179 + 1.136 0.072728 0.095180 0.088058 + 1.137 0.072622 0.095043 0.087936 + 1.138 0.072516 0.094906 0.087815 + 1.139 0.072411 0.094769 0.087694 + 1.140 0.072305 0.094633 0.087574 + 1.141 0.072200 0.094497 0.087454 + 1.142 0.072095 0.094361 0.087334 + 1.143 0.071991 0.094225 0.087214 + 1.144 0.071887 0.094090 0.087094 + 1.145 0.071782 0.093955 0.086975 + 1.146 0.071679 0.093821 0.086856 + 1.147 0.071575 0.093687 0.086737 + 1.148 0.071472 0.093553 0.086619 + 1.149 0.071369 0.093419 0.086501 + 1.150 0.071266 0.093286 0.086383 + 1.151 0.071163 0.093153 0.086265 + 1.152 0.071061 0.093020 0.086148 + 1.153 0.070958 0.092888 0.086031 + 1.154 0.070857 0.092756 0.085914 + 1.155 0.070755 0.092624 0.085797 + 1.156 0.070653 0.092492 0.085681 + 1.157 0.070552 0.092361 0.085564 + 1.158 0.070451 0.092230 0.085449 + 1.159 0.070350 0.092100 0.085333 + 1.160 0.070250 0.091969 0.085218 + 1.161 0.070150 0.091839 0.085102 + 1.162 0.070049 0.091710 0.084988 + 1.163 0.069950 0.091580 0.084873 + 1.164 0.069850 0.091451 0.084758 + 1.165 0.069751 0.091322 0.084644 + 1.166 0.069651 0.091194 0.084530 + 1.167 0.069552 0.091065 0.084417 + 1.168 0.069454 0.090937 0.084303 + 1.169 0.069355 0.090810 0.084190 + 1.170 0.069257 0.090682 0.084077 + 1.171 0.069159 0.090555 0.083965 + 1.172 0.069061 0.090428 0.083852 + 1.173 0.068963 0.090302 0.083740 + 1.174 0.068866 0.090176 0.083628 + 1.175 0.068769 0.090050 0.083516 + 1.176 0.068672 0.089924 0.083405 + 1.177 0.068575 0.089798 0.083293 + 1.178 0.068479 0.089673 0.083182 + 1.179 0.068382 0.089548 0.083072 + 1.180 0.068286 0.089424 0.082961 + 1.181 0.068190 0.089300 0.082851 + 1.182 0.068095 0.089176 0.082741 + 1.183 0.067999 0.089052 0.082631 + 1.184 0.067904 0.088928 0.082521 + 1.185 0.067809 0.088805 0.082412 + 1.186 0.067714 0.088682 0.082303 + 1.187 0.067620 0.088559 0.082194 + 1.188 0.067525 0.088437 0.082085 + 1.189 0.067431 0.088315 0.081977 + 1.190 0.067337 0.088193 0.081868 + 1.191 0.067244 0.088072 0.081760 + 1.192 0.067150 0.087950 0.081653 + 1.193 0.067057 0.087829 0.081545 + 1.194 0.066964 0.087708 0.081438 + 1.195 0.066871 0.087588 0.081331 + 1.196 0.066778 0.087468 0.081224 + 1.197 0.066685 0.087348 0.081117 + 1.198 0.066593 0.087228 0.081011 + 1.199 0.066501 0.087108 0.080905 + 1.200 0.066409 0.086989 0.080799 + 1.201 0.066318 0.086870 0.080693 + 1.202 0.066226 0.086752 0.080587 + 1.203 0.066135 0.086633 0.080482 + 1.204 0.066044 0.086515 0.080377 + 1.205 0.065953 0.086397 0.080272 + 1.206 0.065862 0.086280 0.080168 + 1.207 0.065772 0.086162 0.080063 + 1.208 0.065681 0.086045 0.079959 + 1.209 0.065591 0.085928 0.079855 + 1.210 0.065501 0.085811 0.079751 + 1.211 0.065412 0.085695 0.079648 + 1.212 0.065322 0.085579 0.079544 + 1.213 0.065233 0.085463 0.079441 + 1.214 0.065144 0.085347 0.079338 + 1.215 0.065055 0.085232 0.079235 + 1.216 0.064966 0.085117 0.079133 + 1.217 0.064878 0.085002 0.079031 + 1.218 0.064789 0.084888 0.078929 + 1.219 0.064701 0.084773 0.078827 + 1.220 0.064613 0.084659 0.078725 + 1.221 0.064526 0.084545 0.078624 + 1.222 0.064438 0.084431 0.078522 + 1.223 0.064351 0.084318 0.078421 + 1.224 0.064263 0.084205 0.078321 + 1.225 0.064176 0.084092 0.078220 + 1.226 0.064090 0.083979 0.078120 + 1.227 0.064003 0.083867 0.078019 + 1.228 0.063917 0.083755 0.077919 + 1.229 0.063830 0.083643 0.077820 + 1.230 0.063744 0.083531 0.077720 + 1.231 0.063658 0.083420 0.077621 + 1.232 0.063573 0.083308 0.077522 + 1.233 0.063487 0.083197 0.077423 + 1.234 0.063402 0.083087 0.077324 + 1.235 0.063317 0.082976 0.077225 + 1.236 0.063232 0.082866 0.077127 + 1.237 0.063147 0.082756 0.077029 + 1.238 0.063062 0.082646 0.076931 + 1.239 0.062978 0.082536 0.076833 + 1.240 0.062894 0.082427 0.076735 + 1.241 0.062810 0.082318 0.076638 + 1.242 0.062726 0.082209 0.076541 + 1.243 0.062642 0.082100 0.076444 + 1.244 0.062559 0.081992 0.076347 + 1.245 0.062475 0.081884 0.076251 + 1.246 0.062392 0.081776 0.076154 + 1.247 0.062309 0.081668 0.076058 + 1.248 0.062226 0.081561 0.075962 + 1.249 0.062144 0.081453 0.075866 + 1.250 0.062061 0.081346 0.075771 + 1.251 0.061979 0.081239 0.075675 + 1.252 0.061897 0.081133 0.075580 + 1.253 0.061815 0.081026 0.075485 + 1.254 0.061733 0.080920 0.075390 + 1.255 0.061652 0.080814 0.075295 + 1.256 0.061570 0.080708 0.075201 + 1.257 0.061489 0.080603 0.075107 + 1.258 0.061408 0.080498 0.075013 + 1.259 0.061327 0.080393 0.074919 + 1.260 0.061246 0.080288 0.074825 + 1.261 0.061166 0.080183 0.074731 + 1.262 0.061085 0.080079 0.074638 + 1.263 0.061005 0.079975 0.074545 + 1.264 0.060925 0.079871 0.074452 + 1.265 0.060845 0.079767 0.074359 + 1.266 0.060766 0.079663 0.074267 + 1.267 0.060686 0.079560 0.074174 + 1.268 0.060607 0.079457 0.074082 + 1.269 0.060528 0.079354 0.073990 + 1.270 0.060448 0.079251 0.073898 + 1.271 0.060370 0.079149 0.073806 + 1.272 0.060291 0.079047 0.073715 + 1.273 0.060212 0.078944 0.073624 + 1.274 0.060134 0.078843 0.073532 + 1.275 0.060056 0.078741 0.073442 + 1.276 0.059978 0.078640 0.073351 + 1.277 0.059900 0.078538 0.073260 + 1.278 0.059822 0.078437 0.073170 + 1.279 0.059744 0.078337 0.073080 + 1.280 0.059667 0.078236 0.072989 + 1.281 0.059590 0.078136 0.072900 + 1.282 0.059513 0.078035 0.072810 + 1.283 0.059436 0.077935 0.072720 + 1.284 0.059359 0.077836 0.072631 + 1.285 0.059282 0.077736 0.072542 + 1.286 0.059206 0.077637 0.072453 + 1.287 0.059130 0.077538 0.072364 + 1.288 0.059053 0.077439 0.072275 + 1.289 0.058977 0.077340 0.072187 + 1.290 0.058902 0.077241 0.072099 + 1.291 0.058826 0.077143 0.072010 + 1.292 0.058750 0.077045 0.071923 + 1.293 0.058675 0.076947 0.071835 + 1.294 0.058600 0.076849 0.071747 + 1.295 0.058525 0.076752 0.071660 + 1.296 0.058450 0.076654 0.071572 + 1.297 0.058375 0.076557 0.071485 + 1.298 0.058300 0.076460 0.071398 + 1.299 0.058226 0.076363 0.071312 + 1.300 0.058152 0.076267 0.071225 + 1.301 0.058078 0.076170 0.071139 + 1.302 0.058004 0.076074 0.071052 + 1.303 0.057930 0.075978 0.070966 + 1.304 0.057856 0.075883 0.070880 + 1.305 0.057783 0.075787 0.070795 + 1.306 0.057709 0.075692 0.070709 + 1.307 0.057636 0.075596 0.070623 + 1.308 0.057563 0.075501 0.070538 + 1.309 0.057490 0.075406 0.070453 + 1.310 0.057417 0.075312 0.070368 + 1.311 0.057344 0.075217 0.070283 + 1.312 0.057272 0.075123 0.070199 + 1.313 0.057200 0.075029 0.070114 + 1.314 0.057127 0.074935 0.070030 + 1.315 0.057055 0.074841 0.069946 + 1.316 0.056983 0.074748 0.069862 + 1.317 0.056912 0.074655 0.069778 + 1.318 0.056840 0.074561 0.069695 + 1.319 0.056768 0.074469 0.069611 + 1.320 0.056697 0.074376 0.069528 + 1.321 0.056626 0.074283 0.069445 + 1.322 0.056555 0.074191 0.069362 + 1.323 0.056484 0.074099 0.069279 + 1.324 0.056413 0.074007 0.069196 + 1.325 0.056343 0.073915 0.069114 + 1.326 0.056272 0.073823 0.069031 + 1.327 0.056202 0.073732 0.068949 + 1.328 0.056132 0.073640 0.068867 + 1.329 0.056061 0.073549 0.068785 + 1.330 0.055992 0.073458 0.068703 + 1.331 0.055922 0.073367 0.068622 + 1.332 0.055852 0.073277 0.068540 + 1.333 0.055783 0.073186 0.068459 + 1.334 0.055713 0.073096 0.068378 + 1.335 0.055644 0.073006 0.068297 + 1.336 0.055575 0.072916 0.068216 + 1.337 0.055506 0.072827 0.068135 + 1.338 0.055437 0.072737 0.068055 + 1.339 0.055368 0.072648 0.067975 + 1.340 0.055300 0.072559 0.067894 + 1.341 0.055231 0.072470 0.067814 + 1.342 0.055163 0.072381 0.067734 + 1.343 0.055095 0.072292 0.067655 + 1.344 0.055027 0.072204 0.067575 + 1.345 0.054959 0.072115 0.067496 + 1.346 0.054891 0.072027 0.067416 + 1.347 0.054824 0.071939 0.067337 + 1.348 0.054756 0.071852 0.067258 + 1.349 0.054689 0.071764 0.067179 + 1.350 0.054622 0.071677 0.067101 + 1.351 0.054555 0.071589 0.067022 + 1.352 0.054488 0.071502 0.066944 + 1.353 0.054421 0.071415 0.066865 + 1.354 0.054354 0.071329 0.066787 + 1.355 0.054288 0.071242 0.066709 + 1.356 0.054221 0.071156 0.066631 + 1.357 0.054155 0.071069 0.066554 + 1.358 0.054089 0.070983 0.066476 + 1.359 0.054023 0.070897 0.066399 + 1.360 0.053957 0.070812 0.066321 + 1.361 0.053891 0.070726 0.066244 + 1.362 0.053826 0.070641 0.066167 + 1.363 0.053760 0.070555 0.066091 + 1.364 0.053695 0.070470 0.066014 + 1.365 0.053629 0.070385 0.065937 + 1.366 0.053564 0.070300 0.065861 + 1.367 0.053499 0.070216 0.065785 + 1.368 0.053434 0.070131 0.065709 + 1.369 0.053370 0.070047 0.065633 + 1.370 0.053305 0.069963 0.065557 + 1.371 0.053240 0.069879 0.065481 + 1.372 0.053176 0.069795 0.065406 + 1.373 0.053112 0.069712 0.065330 + 1.374 0.053048 0.069628 0.065255 + 1.375 0.052984 0.069545 0.065180 + 1.376 0.052920 0.069462 0.065105 + 1.377 0.052856 0.069379 0.065030 + 1.378 0.052792 0.069296 0.064955 + 1.379 0.052729 0.069213 0.064881 + 1.380 0.052665 0.069131 0.064806 + 1.381 0.052602 0.069048 0.064732 + 1.382 0.052539 0.068966 0.064658 + 1.383 0.052476 0.068884 0.064584 + 1.384 0.052413 0.068802 0.064510 + 1.385 0.052350 0.068721 0.064436 + 1.386 0.052288 0.068639 0.064362 + 1.387 0.052225 0.068558 0.064289 + 1.388 0.052163 0.068476 0.064215 + 1.389 0.052100 0.068395 0.064142 + 1.390 0.052038 0.068314 0.064069 + 1.391 0.051976 0.068233 0.063996 + 1.392 0.051914 0.068153 0.063923 + 1.393 0.051852 0.068072 0.063851 + 1.394 0.051791 0.067992 0.063778 + 1.395 0.051729 0.067912 0.063706 + 1.396 0.051667 0.067832 0.063633 + 1.397 0.051606 0.067752 0.063561 + 1.398 0.051545 0.067672 0.063489 + 1.399 0.051484 0.067592 0.063417 + 1.400 0.051423 0.067513 0.063345 + 1.401 0.051362 0.067434 0.063274 + 1.402 0.051301 0.067354 0.063202 + 1.403 0.051240 0.067275 0.063131 + 1.404 0.051180 0.067197 0.063060 + 1.405 0.051119 0.067118 0.062988 + 1.406 0.051059 0.067039 0.062917 + 1.407 0.050999 0.066961 0.062847 + 1.408 0.050939 0.066883 0.062776 + 1.409 0.050879 0.066805 0.062705 + 1.410 0.050819 0.066727 0.062635 + 1.411 0.050759 0.066649 0.062564 + 1.412 0.050699 0.066571 0.062494 + 1.413 0.050640 0.066494 0.062424 + 1.414 0.050580 0.066416 0.062354 + 1.415 0.050521 0.066339 0.062284 + 1.416 0.050462 0.066262 0.062214 + 1.417 0.050403 0.066185 0.062145 + 1.418 0.050344 0.066108 0.062075 + 1.419 0.050285 0.066031 0.062006 + 1.420 0.050226 0.065955 0.061937 + 1.421 0.050167 0.065878 0.061868 + 1.422 0.050109 0.065802 0.061799 + 1.423 0.050051 0.065726 0.061730 + 1.424 0.049992 0.065650 0.061661 + 1.425 0.049934 0.065574 0.061592 + 1.426 0.049876 0.065499 0.061524 + 1.427 0.049818 0.065423 0.061455 + 1.428 0.049760 0.065348 0.061387 + 1.429 0.049702 0.065272 0.061319 + 1.430 0.049645 0.065197 0.061251 + 1.431 0.049587 0.065122 0.061183 + 1.432 0.049529 0.065047 0.061115 + 1.433 0.049472 0.064973 0.061048 + 1.434 0.049415 0.064898 0.060980 + 1.435 0.049358 0.064824 0.060913 + 1.436 0.049301 0.064749 0.060845 + 1.437 0.049244 0.064675 0.060778 + 1.438 0.049187 0.064601 0.060711 + 1.439 0.049130 0.064527 0.060644 + 1.440 0.049074 0.064453 0.060577 + 1.441 0.049017 0.064380 0.060511 + 1.442 0.048961 0.064306 0.060444 + 1.443 0.048904 0.064233 0.060378 + 1.444 0.048848 0.064160 0.060311 + 1.445 0.048792 0.064087 0.060245 + 1.446 0.048736 0.064014 0.060179 + 1.447 0.048680 0.063941 0.060113 + 1.448 0.048624 0.063868 0.060047 + 1.449 0.048569 0.063796 0.059981 + 1.450 0.048513 0.063723 0.059916 + 1.451 0.048458 0.063651 0.059850 + 1.452 0.048402 0.063579 0.059785 + 1.453 0.048347 0.063507 0.059719 + 1.454 0.048292 0.063435 0.059654 + 1.455 0.048237 0.063363 0.059589 + 1.456 0.048182 0.063291 0.059524 + 1.457 0.048127 0.063220 0.059459 + 1.458 0.048072 0.063148 0.059394 + 1.459 0.048017 0.063077 0.059330 + 1.460 0.047963 0.063006 0.059265 + 1.461 0.047908 0.062935 0.059201 + 1.462 0.047854 0.062864 0.059136 + 1.463 0.047800 0.062793 0.059072 + 1.464 0.047745 0.062723 0.059008 + 1.465 0.047691 0.062652 0.058944 + 1.466 0.047637 0.062582 0.058880 + 1.467 0.047583 0.062512 0.058817 + 1.468 0.047530 0.062442 0.058753 + 1.469 0.047476 0.062372 0.058689 + 1.470 0.047422 0.062302 0.058626 + 1.471 0.047369 0.062232 0.058563 + 1.472 0.047315 0.062162 0.058500 + 1.473 0.047262 0.062093 0.058436 + 1.474 0.047209 0.062024 0.058373 + 1.475 0.047156 0.061954 0.058311 + 1.476 0.047103 0.061885 0.058248 + 1.477 0.047050 0.061816 0.058185 + 1.478 0.046997 0.061747 0.058123 + 1.479 0.046944 0.061679 0.058060 + 1.480 0.046892 0.061610 0.057998 + 1.481 0.046839 0.061541 0.057936 + 1.482 0.046787 0.061473 0.057874 + 1.483 0.046734 0.061405 0.057812 + 1.484 0.046682 0.061337 0.057750 + 1.485 0.046630 0.061269 0.057688 + 1.486 0.046578 0.061201 0.057626 + 1.487 0.046526 0.061133 0.057565 + 1.488 0.046474 0.061065 0.057503 + 1.489 0.046422 0.060998 0.057442 + 1.490 0.046370 0.060930 0.057380 + 1.491 0.046319 0.060863 0.057319 + 1.492 0.046267 0.060796 0.057258 + 1.493 0.046216 0.060729 0.057197 + 1.494 0.046164 0.060662 0.057136 + 1.495 0.046113 0.060595 0.057076 + 1.496 0.046062 0.060528 0.057015 + 1.497 0.046011 0.060462 0.056954 + 1.498 0.045960 0.060395 0.056894 + 1.499 0.045909 0.060329 0.056834 + 1.500 0.045858 0.060263 0.056773 + 1.501 0.045808 0.060197 0.056713 + 1.502 0.045757 0.060131 0.056653 + 1.503 0.045706 0.060065 0.056593 + 1.504 0.045656 0.059999 0.056533 + 1.505 0.045606 0.059933 0.056474 + 1.506 0.045555 0.059868 0.056414 + 1.507 0.045505 0.059802 0.056355 + 1.508 0.045455 0.059737 0.056295 + 1.509 0.045405 0.059672 0.056236 + 1.510 0.045355 0.059607 0.056177 + 1.511 0.045305 0.059542 0.056117 + 1.512 0.045256 0.059477 0.056058 + 1.513 0.045206 0.059412 0.056000 + 1.514 0.045156 0.059347 0.055941 + 1.515 0.045107 0.059283 0.055882 + 1.516 0.045058 0.059219 0.055823 + 1.517 0.045008 0.059154 0.055765 + 1.518 0.044959 0.059090 0.055706 + 1.519 0.044910 0.059026 0.055648 + 1.520 0.044861 0.058962 0.055590 + 1.521 0.044812 0.058898 0.055532 + 1.522 0.044763 0.058834 0.055474 + 1.523 0.044714 0.058771 0.055416 + 1.524 0.044666 0.058707 0.055358 + 1.525 0.044617 0.058644 0.055300 + 1.526 0.044568 0.058581 0.055242 + 1.527 0.044520 0.058517 0.055185 + 1.528 0.044472 0.058454 0.055127 + 1.529 0.044423 0.058391 0.055070 + 1.530 0.044375 0.058328 0.055013 + 1.531 0.044327 0.058266 0.054956 + 1.532 0.044279 0.058203 0.054898 + 1.533 0.044231 0.058140 0.054841 + 1.534 0.044183 0.058078 0.054785 + 1.535 0.044135 0.058016 0.054728 + 1.536 0.044088 0.057953 0.054671 + 1.537 0.044040 0.057891 0.054614 + 1.538 0.043993 0.057829 0.054558 + 1.539 0.043945 0.057767 0.054501 + 1.540 0.043898 0.057706 0.054445 + 1.541 0.043850 0.057644 0.054389 + 1.542 0.043803 0.057582 0.054333 + 1.543 0.043756 0.057521 0.054277 + 1.544 0.043709 0.057459 0.054221 + 1.545 0.043662 0.057398 0.054165 + 1.546 0.043615 0.057337 0.054109 + 1.547 0.043568 0.057276 0.054053 + 1.548 0.043522 0.057215 0.053998 + 1.549 0.043475 0.057154 0.053942 + 1.550 0.043428 0.057093 0.053887 + 1.551 0.043382 0.057033 0.053832 + 1.552 0.043336 0.056972 0.053776 + 1.553 0.043289 0.056912 0.053721 + 1.554 0.043243 0.056851 0.053666 + 1.555 0.043197 0.056791 0.053611 + 1.556 0.043151 0.056731 0.053556 + 1.557 0.043105 0.056671 0.053502 + 1.558 0.043059 0.056611 0.053447 + 1.559 0.043013 0.056551 0.053392 + 1.560 0.042967 0.056492 0.053338 + 1.561 0.042922 0.056432 0.053283 + 1.562 0.042876 0.056372 0.053229 + 1.563 0.042830 0.056313 0.053175 + 1.564 0.042785 0.056254 0.053121 + 1.565 0.042740 0.056194 0.053067 + 1.566 0.042694 0.056135 0.053013 + 1.567 0.042649 0.056076 0.052959 + 1.568 0.042604 0.056017 0.052905 + 1.569 0.042559 0.055958 0.052851 + 1.570 0.042514 0.055900 0.052798 + 1.571 0.042469 0.055841 0.052744 + 1.572 0.042424 0.055783 0.052691 + 1.573 0.042379 0.055724 0.052637 + 1.574 0.042335 0.055666 0.052584 + 1.575 0.042290 0.055608 0.052531 + 1.576 0.042245 0.055549 0.052478 + 1.577 0.042201 0.055491 0.052425 + 1.578 0.042156 0.055433 0.052372 + 1.579 0.042112 0.055376 0.052319 + 1.580 0.042068 0.055318 0.052266 + 1.581 0.042024 0.055260 0.052213 + 1.582 0.041980 0.055203 0.052161 + 1.583 0.041936 0.055145 0.052108 + 1.584 0.041892 0.055088 0.052056 + 1.585 0.041848 0.055030 0.052003 + 1.586 0.041804 0.054973 0.051951 + 1.587 0.041760 0.054916 0.051899 + 1.588 0.041717 0.054859 0.051847 + 1.589 0.041673 0.054802 0.051795 + 1.590 0.041629 0.054746 0.051743 + 1.591 0.041586 0.054689 0.051691 + 1.592 0.041543 0.054632 0.051639 + 1.593 0.041499 0.054576 0.051588 + 1.594 0.041456 0.054519 0.051536 + 1.595 0.041413 0.054463 0.051485 + 1.596 0.041370 0.054407 0.051433 + 1.597 0.041327 0.054351 0.051382 + 1.598 0.041284 0.054294 0.051331 + 1.599 0.041241 0.054239 0.051279 + 1.600 0.041198 0.054183 0.051228 + 1.601 0.041156 0.054127 0.051177 + 1.602 0.041113 0.054071 0.051126 + 1.603 0.041070 0.054016 0.051075 + 1.604 0.041028 0.053960 0.051025 + 1.605 0.040985 0.053905 0.050974 + 1.606 0.040943 0.053849 0.050923 + 1.607 0.040901 0.053794 0.050873 + 1.608 0.040859 0.053739 0.050822 + 1.609 0.040816 0.053684 0.050772 + 1.610 0.040774 0.053629 0.050722 + 1.611 0.040732 0.053574 0.050671 + 1.612 0.040690 0.053519 0.050621 + 1.613 0.040648 0.053465 0.050571 + 1.614 0.040607 0.053410 0.050521 + 1.615 0.040565 0.053356 0.050471 + 1.616 0.040523 0.053301 0.050422 + 1.617 0.040482 0.053247 0.050372 + 1.618 0.040440 0.053192 0.050322 + 1.619 0.040399 0.053138 0.050273 + 1.620 0.040357 0.053084 0.050223 + 1.621 0.040316 0.053030 0.050174 + 1.622 0.040275 0.052976 0.050124 + 1.623 0.040233 0.052923 0.050075 + 1.624 0.040192 0.052869 0.050026 + 1.625 0.040151 0.052815 0.049977 + 1.626 0.040110 0.052762 0.049928 + 1.627 0.040069 0.052708 0.049879 + 1.628 0.040028 0.052655 0.049830 + 1.629 0.039988 0.052602 0.049781 + 1.630 0.039947 0.052548 0.049732 + 1.631 0.039906 0.052495 0.049684 + 1.632 0.039866 0.052442 0.049635 + 1.633 0.039825 0.052389 0.049587 + 1.634 0.039785 0.052336 0.049538 + 1.635 0.039744 0.052284 0.049490 + 1.636 0.039704 0.052231 0.049442 + 1.637 0.039664 0.052178 0.049393 + 1.638 0.039623 0.052126 0.049345 + 1.639 0.039583 0.052073 0.049297 + 1.640 0.039543 0.052021 0.049249 + 1.641 0.039503 0.051969 0.049201 + 1.642 0.039463 0.051917 0.049153 + 1.643 0.039423 0.051865 0.049106 + 1.644 0.039383 0.051813 0.049058 + 1.645 0.039344 0.051761 0.049010 + 1.646 0.039304 0.051709 0.048963 + 1.647 0.039264 0.051657 0.048915 + 1.648 0.039225 0.051605 0.048868 + 1.649 0.039185 0.051554 0.048821 + 1.650 0.039146 0.051502 0.048773 + 1.651 0.039107 0.051451 0.048726 + 1.652 0.039067 0.051399 0.048679 + 1.653 0.039028 0.051348 0.048632 + 1.654 0.038989 0.051297 0.048585 + 1.655 0.038950 0.051246 0.048538 + 1.656 0.038911 0.051195 0.048492 + 1.657 0.038872 0.051144 0.048445 + 1.658 0.038833 0.051093 0.048398 + 1.659 0.038794 0.051042 0.048352 + 1.660 0.038755 0.050992 0.048305 + 1.661 0.038716 0.050941 0.048259 + 1.662 0.038678 0.050890 0.048212 + 1.663 0.038639 0.050840 0.048166 + 1.664 0.038600 0.050790 0.048120 + 1.665 0.038562 0.050739 0.048074 + 1.666 0.038524 0.050689 0.048027 + 1.667 0.038485 0.050639 0.047981 + 1.668 0.038447 0.050589 0.047935 + 1.669 0.038409 0.050539 0.047890 + 1.670 0.038370 0.050489 0.047844 + 1.671 0.038332 0.050439 0.047798 + 1.672 0.038294 0.050389 0.047752 + 1.673 0.038256 0.050340 0.047707 + 1.674 0.038218 0.050290 0.047661 + 1.675 0.038180 0.050241 0.047616 + 1.676 0.038143 0.050191 0.047570 + 1.677 0.038105 0.050142 0.047525 + 1.678 0.038067 0.050093 0.047480 + 1.679 0.038029 0.050043 0.047435 + 1.680 0.037992 0.049994 0.047390 + 1.681 0.037954 0.049945 0.047345 + 1.682 0.037917 0.049896 0.047300 + 1.683 0.037879 0.049847 0.047255 + 1.684 0.037842 0.049799 0.047210 + 1.685 0.037805 0.049750 0.047165 + 1.686 0.037768 0.049701 0.047120 + 1.687 0.037730 0.049653 0.047076 + 1.688 0.037693 0.049604 0.047031 + 1.689 0.037656 0.049556 0.046987 + 1.690 0.037619 0.049507 0.046942 + 1.691 0.037582 0.049459 0.046898 + 1.692 0.037545 0.049411 0.046854 + 1.693 0.037509 0.049363 0.046809 + 1.694 0.037472 0.049315 0.046765 + 1.695 0.037435 0.049267 0.046721 + 1.696 0.037398 0.049219 0.046677 + 1.697 0.037362 0.049171 0.046633 + 1.698 0.037325 0.049123 0.046589 + 1.699 0.037289 0.049075 0.046545 + 1.700 0.037252 0.049028 0.046502 + 1.701 0.037216 0.048980 0.046458 + 1.702 0.037180 0.048933 0.046414 + 1.703 0.037143 0.048885 0.046371 + 1.704 0.037107 0.048838 0.046327 + 1.705 0.037071 0.048791 0.046284 + 1.706 0.037035 0.048744 0.046240 + 1.707 0.036999 0.048697 0.046197 + 1.708 0.036963 0.048650 0.046154 + 1.709 0.036927 0.048603 0.046111 + 1.710 0.036891 0.048556 0.046067 + 1.711 0.036855 0.048509 0.046024 + 1.712 0.036820 0.048462 0.045981 + 1.713 0.036784 0.048416 0.045939 + 1.714 0.036748 0.048369 0.045896 + 1.715 0.036713 0.048322 0.045853 + 1.716 0.036677 0.048276 0.045810 + 1.717 0.036642 0.048230 0.045767 + 1.718 0.036606 0.048183 0.045725 + 1.719 0.036571 0.048137 0.045682 + 1.720 0.036536 0.048091 0.045640 + 1.721 0.036500 0.048045 0.045597 + 1.722 0.036465 0.047999 0.045555 + 1.723 0.036430 0.047953 0.045513 + 1.724 0.036395 0.047907 0.045471 + 1.725 0.036360 0.047861 0.045428 + 1.726 0.036325 0.047815 0.045386 + 1.727 0.036290 0.047770 0.045344 + 1.728 0.036255 0.047724 0.045302 + 1.729 0.036220 0.047679 0.045260 + 1.730 0.036186 0.047633 0.045219 + 1.731 0.036151 0.047588 0.045177 + 1.732 0.036116 0.047542 0.045135 + 1.733 0.036082 0.047497 0.045093 + 1.734 0.036047 0.047452 0.045052 + 1.735 0.036013 0.047407 0.045010 + 1.736 0.035978 0.047362 0.044969 + 1.737 0.035944 0.047317 0.044927 + 1.738 0.035909 0.047272 0.044886 + 1.739 0.035875 0.047227 0.044845 + 1.740 0.035841 0.047182 0.044803 + 1.741 0.035807 0.047138 0.044762 + 1.742 0.035772 0.047093 0.044721 + 1.743 0.035738 0.047048 0.044680 + 1.744 0.035704 0.047004 0.044639 + 1.745 0.035670 0.046960 0.044598 + 1.746 0.035636 0.046915 0.044557 + 1.747 0.035603 0.046871 0.044516 + 1.748 0.035569 0.046827 0.044476 + 1.749 0.035535 0.046782 0.044435 + 1.750 0.035501 0.046738 0.044394 + 1.751 0.035468 0.046694 0.044354 + 1.752 0.035434 0.046650 0.044313 + 1.753 0.035400 0.046606 0.044273 + 1.754 0.035367 0.046563 0.044232 + 1.755 0.035333 0.046519 0.044192 + 1.756 0.035300 0.046475 0.044152 + 1.757 0.035267 0.046431 0.044112 + 1.758 0.035233 0.046388 0.044071 + 1.759 0.035200 0.046344 0.044031 + 1.760 0.035167 0.046301 0.043991 + 1.761 0.035134 0.046258 0.043951 + 1.762 0.035101 0.046214 0.043911 + 1.763 0.035067 0.046171 0.043871 + 1.764 0.035034 0.046128 0.043832 + 1.765 0.035001 0.046085 0.043792 + 1.766 0.034969 0.046042 0.043752 + 1.767 0.034936 0.045999 0.043713 + 1.768 0.034903 0.045956 0.043673 + 1.769 0.034870 0.045913 0.043633 + 1.770 0.034837 0.045870 0.043594 + 1.771 0.034805 0.045827 0.043555 + 1.772 0.034772 0.045785 0.043515 + 1.773 0.034740 0.045742 0.043476 + 1.774 0.034707 0.045700 0.043437 + 1.775 0.034675 0.045657 0.043398 + 1.776 0.034642 0.045615 0.043358 + 1.777 0.034610 0.045572 0.043319 + 1.778 0.034577 0.045530 0.043280 + 1.779 0.034545 0.045488 0.043241 + 1.780 0.034513 0.045446 0.043202 + 1.781 0.034481 0.045404 0.043164 + 1.782 0.034449 0.045361 0.043125 + 1.783 0.034416 0.045319 0.043086 + 1.784 0.034384 0.045278 0.043047 + 1.785 0.034352 0.045236 0.043009 + 1.786 0.034320 0.045194 0.042970 + 1.787 0.034289 0.045152 0.042932 + 1.788 0.034257 0.045111 0.042893 + 1.789 0.034225 0.045069 0.042855 + 1.790 0.034193 0.045027 0.042816 + 1.791 0.034161 0.044986 0.042778 + 1.792 0.034130 0.044944 0.042740 + 1.793 0.034098 0.044903 0.042702 + 1.794 0.034067 0.044862 0.042664 + 1.795 0.034035 0.044821 0.042626 + 1.796 0.034004 0.044779 0.042587 + 1.797 0.033972 0.044738 0.042550 + 1.798 0.033941 0.044697 0.042512 + 1.799 0.033909 0.044656 0.042474 + 1.800 0.033878 0.044615 0.042436 + 1.801 0.033847 0.044574 0.042398 + 1.802 0.033816 0.044534 0.042361 + 1.803 0.033785 0.044493 0.042323 + 1.804 0.033753 0.044452 0.042285 + 1.805 0.033722 0.044411 0.042248 + 1.806 0.033691 0.044371 0.042210 + 1.807 0.033660 0.044330 0.042173 + 1.808 0.033630 0.044290 0.042135 + 1.809 0.033599 0.044249 0.042098 + 1.810 0.033568 0.044209 0.042061 + 1.811 0.033537 0.044169 0.042024 + 1.812 0.033506 0.044129 0.041986 + 1.813 0.033476 0.044088 0.041949 + 1.814 0.033445 0.044048 0.041912 + 1.815 0.033414 0.044008 0.041875 + 1.816 0.033384 0.043968 0.041838 + 1.817 0.033353 0.043928 0.041801 + 1.818 0.033323 0.043888 0.041765 + 1.819 0.033292 0.043849 0.041728 + 1.820 0.033262 0.043809 0.041691 + 1.821 0.033232 0.043769 0.041654 + 1.822 0.033201 0.043730 0.041618 + 1.823 0.033171 0.043690 0.041581 + 1.824 0.033141 0.043650 0.041545 + 1.825 0.033111 0.043611 0.041508 + 1.826 0.033081 0.043572 0.041472 + 1.827 0.033050 0.043532 0.041435 + 1.828 0.033020 0.043493 0.041399 + 1.829 0.032990 0.043454 0.041363 + 1.830 0.032961 0.043414 0.041326 + 1.831 0.032931 0.043375 0.041290 + 1.832 0.032901 0.043336 0.041254 + 1.833 0.032871 0.043297 0.041218 + 1.834 0.032841 0.043258 0.041182 + 1.835 0.032811 0.043219 0.041146 + 1.836 0.032782 0.043180 0.041110 + 1.837 0.032752 0.043142 0.041074 + 1.838 0.032723 0.043103 0.041038 + 1.839 0.032693 0.043064 0.041003 + 1.840 0.032663 0.043026 0.040967 + 1.841 0.032634 0.042987 0.040931 + 1.842 0.032605 0.042949 0.040895 + 1.843 0.032575 0.042910 0.040860 + 1.844 0.032546 0.042872 0.040824 + 1.845 0.032517 0.042833 0.040789 + 1.846 0.032487 0.042795 0.040753 + 1.847 0.032458 0.042757 0.040718 + 1.848 0.032429 0.042719 0.040683 + 1.849 0.032400 0.042680 0.040647 + 1.850 0.032371 0.042642 0.040612 + 1.851 0.032342 0.042604 0.040577 + 1.852 0.032313 0.042566 0.040542 + 1.853 0.032284 0.042528 0.040507 + 1.854 0.032255 0.042491 0.040472 + 1.855 0.032226 0.042453 0.040437 + 1.856 0.032197 0.042415 0.040402 + 1.857 0.032168 0.042377 0.040367 + 1.858 0.032139 0.042340 0.040332 + 1.859 0.032111 0.042302 0.040297 + 1.860 0.032082 0.042265 0.040262 + 1.861 0.032053 0.042227 0.040228 + 1.862 0.032025 0.042190 0.040193 + 1.863 0.031996 0.042152 0.040158 + 1.864 0.031968 0.042115 0.040124 + 1.865 0.031939 0.042078 0.040089 + 1.866 0.031911 0.042040 0.040055 + 1.867 0.031882 0.042003 0.040021 + 1.868 0.031854 0.041966 0.039986 + 1.869 0.031826 0.041929 0.039952 + 1.870 0.031798 0.041892 0.039918 + 1.871 0.031769 0.041855 0.039883 + 1.872 0.031741 0.041818 0.039849 + 1.873 0.031713 0.041781 0.039815 + 1.874 0.031685 0.041744 0.039781 + 1.875 0.031657 0.041708 0.039747 + 1.876 0.031629 0.041671 0.039713 + 1.877 0.031601 0.041634 0.039679 + 1.878 0.031573 0.041598 0.039645 + 1.879 0.031545 0.041561 0.039611 + 1.880 0.031517 0.041525 0.039577 + 1.881 0.031489 0.041488 0.039544 + 1.882 0.031461 0.041452 0.039510 + 1.883 0.031434 0.041416 0.039476 + 1.884 0.031406 0.041379 0.039443 + 1.885 0.031378 0.041343 0.039409 + 1.886 0.031351 0.041307 0.039375 + 1.887 0.031323 0.041271 0.039342 + 1.888 0.031295 0.041235 0.039308 + 1.889 0.031268 0.041199 0.039275 + 1.890 0.031240 0.041163 0.039242 + 1.891 0.031213 0.041127 0.039208 + 1.892 0.031186 0.041091 0.039175 + 1.893 0.031158 0.041055 0.039142 + 1.894 0.031131 0.041019 0.039109 + 1.895 0.031104 0.040983 0.039076 + 1.896 0.031076 0.040948 0.039043 + 1.897 0.031049 0.040912 0.039009 + 1.898 0.031022 0.040876 0.038977 + 1.899 0.030995 0.040841 0.038944 + 1.900 0.030968 0.040805 0.038911 + 1.901 0.030941 0.040770 0.038878 + 1.902 0.030914 0.040735 0.038845 + 1.903 0.030887 0.040699 0.038812 + 1.904 0.030860 0.040664 0.038779 + 1.905 0.030833 0.040629 0.038747 + 1.906 0.030806 0.040594 0.038714 + 1.907 0.030779 0.040558 0.038682 + 1.908 0.030752 0.040523 0.038649 + 1.909 0.030725 0.040488 0.038616 + 1.910 0.030699 0.040453 0.038584 + 1.911 0.030672 0.040418 0.038552 + 1.912 0.030645 0.040383 0.038519 + 1.913 0.030619 0.040349 0.038487 + 1.914 0.030592 0.040314 0.038455 + 1.915 0.030566 0.040279 0.038422 + 1.916 0.030539 0.040244 0.038390 + 1.917 0.030513 0.040210 0.038358 + 1.918 0.030486 0.040175 0.038326 + 1.919 0.030460 0.040140 0.038294 + 1.920 0.030434 0.040106 0.038262 + 1.921 0.030407 0.040071 0.038230 + 1.922 0.030381 0.040037 0.038198 + 1.923 0.030355 0.040003 0.038166 + 1.924 0.030328 0.039968 0.038134 + 1.925 0.030302 0.039934 0.038102 + 1.926 0.030276 0.039900 0.038070 + 1.927 0.030250 0.039866 0.038039 + 1.928 0.030224 0.039831 0.038007 + 1.929 0.030198 0.039797 0.037975 + 1.930 0.030172 0.039763 0.037944 + 1.931 0.030146 0.039729 0.037912 + 1.932 0.030120 0.039695 0.037881 + 1.933 0.030094 0.039661 0.037849 + 1.934 0.030068 0.039628 0.037818 + 1.935 0.030043 0.039594 0.037786 + 1.936 0.030017 0.039560 0.037755 + 1.937 0.029991 0.039526 0.037724 + 1.938 0.029965 0.039493 0.037692 + 1.939 0.029940 0.039459 0.037661 + 1.940 0.029914 0.039425 0.037630 + 1.941 0.029888 0.039392 0.037599 + 1.942 0.029863 0.039358 0.037568 + 1.943 0.029837 0.039325 0.037537 + 1.944 0.029812 0.039291 0.037506 + 1.945 0.029786 0.039258 0.037475 + 1.946 0.029761 0.039225 0.037444 + 1.947 0.029736 0.039191 0.037413 + 1.948 0.029710 0.039158 0.037382 + 1.949 0.029685 0.039125 0.037351 + 1.950 0.029660 0.039092 0.037320 + 1.951 0.029634 0.039059 0.037290 + 1.952 0.029609 0.039026 0.037259 + 1.953 0.029584 0.038993 0.037228 + 1.954 0.029559 0.038960 0.037198 + 1.955 0.029534 0.038927 0.037167 + 1.956 0.029509 0.038894 0.037137 + 1.957 0.029483 0.038861 0.037106 + 1.958 0.029458 0.038828 0.037076 + 1.959 0.029433 0.038796 0.037045 + 1.960 0.029409 0.038763 0.037015 + 1.961 0.029384 0.038730 0.036984 + 1.962 0.029359 0.038698 0.036954 + 1.963 0.029334 0.038665 0.036924 + 1.964 0.029309 0.038633 0.036894 + 1.965 0.029284 0.038600 0.036864 + 1.966 0.029260 0.038568 0.036833 + 1.967 0.029235 0.038535 0.036803 + 1.968 0.029210 0.038503 0.036773 + 1.969 0.029185 0.038471 0.036743 + 1.970 0.029161 0.038439 0.036713 + 1.971 0.029136 0.038406 0.036683 + 1.972 0.029112 0.038374 0.036653 + 1.973 0.029087 0.038342 0.036623 + 1.974 0.029063 0.038310 0.036594 + 1.975 0.029038 0.038278 0.036564 + 1.976 0.029014 0.038246 0.036534 + 1.977 0.028989 0.038214 0.036504 + 1.978 0.028965 0.038182 0.036475 + 1.979 0.028941 0.038150 0.036445 + 1.980 0.028917 0.038118 0.036416 + 1.981 0.028892 0.038087 0.036386 + 1.982 0.028868 0.038055 0.036356 + 1.983 0.028844 0.038023 0.036327 + 1.984 0.028820 0.037991 0.036298 + 1.985 0.028796 0.037960 0.036268 + 1.986 0.028772 0.037928 0.036239 + 1.987 0.028747 0.037897 0.036209 + 1.988 0.028723 0.037865 0.036180 + 1.989 0.028699 0.037834 0.036151 + 1.990 0.028675 0.037802 0.036122 + 1.991 0.028652 0.037771 0.036093 + 1.992 0.028628 0.037740 0.036063 + 1.993 0.028604 0.037708 0.036034 + 1.994 0.028580 0.037677 0.036005 + 1.995 0.028556 0.037646 0.035976 + 1.996 0.028532 0.037615 0.035947 + 1.997 0.028509 0.037584 0.035918 + 1.998 0.028485 0.037553 0.035889 + 1.999 0.028461 0.037522 0.035860 + 2.000 0.028438 0.037491 0.035832 + 2.001 0.028414 0.037460 0.035803 + 2.002 0.028390 0.037429 0.035774 + 2.003 0.028367 0.037398 0.035745 + 2.004 0.028343 0.037367 0.035717 + 2.005 0.028320 0.037336 0.035688 + 2.006 0.028296 0.037306 0.035659 + 2.007 0.028273 0.037275 0.035631 + 2.008 0.028250 0.037244 0.035602 + 2.009 0.028226 0.037214 0.035574 + 2.010 0.028203 0.037183 0.035545 + 2.011 0.028180 0.037152 0.035517 + 2.012 0.028156 0.037122 0.035488 + 2.013 0.028133 0.037092 0.035460 + 2.014 0.028110 0.037061 0.035432 + 2.015 0.028087 0.037031 0.035403 + 2.016 0.028064 0.037000 0.035375 + 2.017 0.028040 0.036970 0.035347 + 2.018 0.028017 0.036940 0.035319 + 2.019 0.027994 0.036910 0.035291 + 2.020 0.027971 0.036879 0.035263 + 2.021 0.027948 0.036849 0.035234 + 2.022 0.027925 0.036819 0.035206 + 2.023 0.027902 0.036789 0.035178 + 2.024 0.027879 0.036759 0.035150 + 2.025 0.027857 0.036729 0.035123 + 2.026 0.027834 0.036699 0.035095 + 2.027 0.027811 0.036669 0.035067 + 2.028 0.027788 0.036639 0.035039 + 2.029 0.027765 0.036610 0.035011 + 2.030 0.027743 0.036580 0.034983 + 2.031 0.027720 0.036550 0.034956 + 2.032 0.027697 0.036520 0.034928 + 2.033 0.027675 0.036491 0.034900 + 2.034 0.027652 0.036461 0.034873 + 2.035 0.027629 0.036431 0.034845 + 2.036 0.027607 0.036402 0.034818 + 2.037 0.027584 0.036372 0.034790 + 2.038 0.027562 0.036343 0.034763 + 2.039 0.027539 0.036313 0.034735 + 2.040 0.027517 0.036284 0.034708 + 2.041 0.027495 0.036255 0.034680 + 2.042 0.027472 0.036225 0.034653 + 2.043 0.027450 0.036196 0.034626 + 2.044 0.027428 0.036167 0.034599 + 2.045 0.027405 0.036137 0.034571 + 2.046 0.027383 0.036108 0.034544 + 2.047 0.027361 0.036079 0.034517 + 2.048 0.027339 0.036050 0.034490 + 2.049 0.027316 0.036021 0.034463 + 2.050 0.027294 0.035992 0.034436 + 2.051 0.027272 0.035963 0.034409 + 2.052 0.027250 0.035934 0.034382 + 2.053 0.027228 0.035905 0.034355 + 2.054 0.027206 0.035876 0.034328 + 2.055 0.027184 0.035847 0.034301 + 2.056 0.027162 0.035818 0.034274 + 2.057 0.027140 0.035790 0.034247 + 2.058 0.027118 0.035761 0.034220 + 2.059 0.027096 0.035732 0.034194 + 2.060 0.027074 0.035704 0.034167 + 2.061 0.027053 0.035675 0.034140 + 2.062 0.027031 0.035646 0.034114 + 2.063 0.027009 0.035618 0.034087 + 2.064 0.026987 0.035589 0.034060 + 2.065 0.026966 0.035561 0.034034 + 2.066 0.026944 0.035532 0.034007 + 2.067 0.026922 0.035504 0.033981 + 2.068 0.026901 0.035476 0.033954 + 2.069 0.026879 0.035447 0.033928 + 2.070 0.026857 0.035419 0.033901 + 2.071 0.026836 0.035391 0.033875 + 2.072 0.026814 0.035363 0.033849 + 2.073 0.026793 0.035334 0.033822 + 2.074 0.026771 0.035306 0.033796 + 2.075 0.026750 0.035278 0.033770 + 2.076 0.026729 0.035250 0.033744 + 2.077 0.026707 0.035222 0.033718 + 2.078 0.026686 0.035194 0.033692 + 2.079 0.026664 0.035166 0.033665 + 2.080 0.026643 0.035138 0.033639 + 2.081 0.026622 0.035110 0.033613 + 2.082 0.026601 0.035082 0.033587 + 2.083 0.026579 0.035054 0.033561 + 2.084 0.026558 0.035027 0.033535 + 2.085 0.026537 0.034999 0.033509 + 2.086 0.026516 0.034971 0.033484 + 2.087 0.026495 0.034944 0.033458 + 2.088 0.026474 0.034916 0.033432 + 2.089 0.026453 0.034888 0.033406 + 2.090 0.026432 0.034861 0.033380 + 2.091 0.026411 0.034833 0.033355 + 2.092 0.026390 0.034806 0.033329 + 2.093 0.026369 0.034778 0.033303 + 2.094 0.026348 0.034751 0.033278 + 2.095 0.026327 0.034723 0.033252 + 2.096 0.026306 0.034696 0.033227 + 2.097 0.026285 0.034669 0.033201 + 2.098 0.026264 0.034641 0.033176 + 2.099 0.026244 0.034614 0.033150 + 2.100 0.026223 0.034587 0.033125 + 2.101 0.026202 0.034560 0.033099 + 2.102 0.026181 0.034532 0.033074 + 2.103 0.026161 0.034505 0.033049 + 2.104 0.026140 0.034478 0.033023 + 2.105 0.026119 0.034451 0.032998 + 2.106 0.026099 0.034424 0.032973 + 2.107 0.026078 0.034397 0.032948 + 2.108 0.026058 0.034370 0.032922 + 2.109 0.026037 0.034343 0.032897 + 2.110 0.026017 0.034316 0.032872 + 2.111 0.025996 0.034289 0.032847 + 2.112 0.025976 0.034263 0.032822 + 2.113 0.025955 0.034236 0.032797 + 2.114 0.025935 0.034209 0.032772 + 2.115 0.025914 0.034182 0.032747 + 2.116 0.025894 0.034156 0.032722 + 2.117 0.025874 0.034129 0.032697 + 2.118 0.025853 0.034102 0.032672 + 2.119 0.025833 0.034076 0.032647 + 2.120 0.025813 0.034049 0.032623 + 2.121 0.025793 0.034023 0.032598 + 2.122 0.025772 0.033996 0.032573 + 2.123 0.025752 0.033970 0.032548 + 2.124 0.025732 0.033943 0.032524 + 2.125 0.025712 0.033917 0.032499 + 2.126 0.025692 0.033890 0.032474 + 2.127 0.025672 0.033864 0.032450 + 2.128 0.025652 0.033838 0.032425 + 2.129 0.025632 0.033811 0.032401 + 2.130 0.025612 0.033785 0.032376 + 2.131 0.025592 0.033759 0.032352 + 2.132 0.025572 0.033733 0.032327 + 2.133 0.025552 0.033707 0.032303 + 2.134 0.025532 0.033681 0.032278 + 2.135 0.025512 0.033655 0.032254 + 2.136 0.025492 0.033629 0.032230 + 2.137 0.025473 0.033603 0.032205 + 2.138 0.025453 0.033577 0.032181 + 2.139 0.025433 0.033551 0.032157 + 2.140 0.025413 0.033525 0.032132 + 2.141 0.025393 0.033499 0.032108 + 2.142 0.025374 0.033473 0.032084 + 2.143 0.025354 0.033447 0.032060 + 2.144 0.025334 0.033421 0.032036 + 2.145 0.025315 0.033396 0.032012 + 2.146 0.025295 0.033370 0.031988 + 2.147 0.025276 0.033344 0.031964 + 2.148 0.025256 0.033319 0.031940 + 2.149 0.025237 0.033293 0.031916 + 2.150 0.025217 0.033267 0.031892 + 2.151 0.025198 0.033242 0.031868 + 2.152 0.025178 0.033216 0.031844 + 2.153 0.025159 0.033191 0.031820 + 2.154 0.025139 0.033165 0.031796 + 2.155 0.025120 0.033140 0.031773 + 2.156 0.025100 0.033114 0.031749 + 2.157 0.025081 0.033089 0.031725 + 2.158 0.025062 0.033064 0.031701 + 2.159 0.025043 0.033038 0.031678 + 2.160 0.025023 0.033013 0.031654 + 2.161 0.025004 0.032988 0.031630 + 2.162 0.024985 0.032963 0.031607 + 2.163 0.024966 0.032937 0.031583 + 2.164 0.024946 0.032912 0.031560 + 2.165 0.024927 0.032887 0.031536 + 2.166 0.024908 0.032862 0.031513 + 2.167 0.024889 0.032837 0.031489 + 2.168 0.024870 0.032812 0.031466 + 2.169 0.024851 0.032787 0.031442 + 2.170 0.024832 0.032762 0.031419 + 2.171 0.024813 0.032737 0.031396 + 2.172 0.024794 0.032712 0.031372 + 2.173 0.024775 0.032687 0.031349 + 2.174 0.024756 0.032662 0.031326 + 2.175 0.024737 0.032638 0.031303 + 2.176 0.024718 0.032613 0.031279 + 2.177 0.024699 0.032588 0.031256 + 2.178 0.024680 0.032563 0.031233 + 2.179 0.024662 0.032539 0.031210 + 2.180 0.024643 0.032514 0.031187 + 2.181 0.024624 0.032489 0.031164 + 2.182 0.024605 0.032465 0.031141 + 2.183 0.024587 0.032440 0.031118 + 2.184 0.024568 0.032415 0.031095 + 2.185 0.024549 0.032391 0.031072 + 2.186 0.024531 0.032366 0.031049 + 2.187 0.024512 0.032342 0.031026 + 2.188 0.024493 0.032318 0.031003 + 2.189 0.024475 0.032293 0.030980 + 2.190 0.024456 0.032269 0.030958 + 2.191 0.024438 0.032244 0.030935 + 2.192 0.024419 0.032220 0.030912 + 2.193 0.024401 0.032196 0.030889 + 2.194 0.024382 0.032172 0.030866 + 2.195 0.024364 0.032147 0.030844 + 2.196 0.024345 0.032123 0.030821 + 2.197 0.024327 0.032099 0.030799 + 2.198 0.024308 0.032075 0.030776 + 2.199 0.024290 0.032051 0.030753 + 2.200 0.024272 0.032027 0.030731 + 2.201 0.024253 0.032003 0.030708 + 2.202 0.024235 0.031979 0.030686 + 2.203 0.024217 0.031955 0.030663 + 2.204 0.024198 0.031931 0.030641 + 2.205 0.024180 0.031907 0.030618 + 2.206 0.024162 0.031883 0.030596 + 2.207 0.024144 0.031859 0.030574 + 2.208 0.024126 0.031835 0.030551 + 2.209 0.024107 0.031811 0.030529 + 2.210 0.024089 0.031787 0.030507 + 2.211 0.024071 0.031764 0.030484 + 2.212 0.024053 0.031740 0.030462 + 2.213 0.024035 0.031716 0.030440 + 2.214 0.024017 0.031692 0.030418 + 2.215 0.023999 0.031669 0.030396 + 2.216 0.023981 0.031645 0.030373 + 2.217 0.023963 0.031622 0.030351 + 2.218 0.023945 0.031598 0.030329 + 2.219 0.023927 0.031574 0.030307 + 2.220 0.023909 0.031551 0.030285 + 2.221 0.023891 0.031527 0.030263 + 2.222 0.023873 0.031504 0.030241 + 2.223 0.023856 0.031481 0.030219 + 2.224 0.023838 0.031457 0.030197 + 2.225 0.023820 0.031434 0.030175 + 2.226 0.023802 0.031410 0.030154 + 2.227 0.023784 0.031387 0.030132 + 2.228 0.023767 0.031364 0.030110 + 2.229 0.023749 0.031341 0.030088 + 2.230 0.023731 0.031317 0.030066 + 2.231 0.023714 0.031294 0.030044 + 2.232 0.023696 0.031271 0.030023 + 2.233 0.023678 0.031248 0.030001 + 2.234 0.023661 0.031225 0.029979 + 2.235 0.023643 0.031202 0.029958 + 2.236 0.023625 0.031179 0.029936 + 2.237 0.023608 0.031155 0.029914 + 2.238 0.023590 0.031132 0.029893 + 2.239 0.023573 0.031109 0.029871 + 2.240 0.023555 0.031086 0.029850 + 2.241 0.023538 0.031064 0.029828 + 2.242 0.023520 0.031041 0.029807 + 2.243 0.023503 0.031018 0.029785 + 2.244 0.023486 0.030995 0.029764 + 2.245 0.023468 0.030972 0.029743 + 2.246 0.023451 0.030949 0.029721 + 2.247 0.023434 0.030927 0.029700 + 2.248 0.023416 0.030904 0.029678 + 2.249 0.023399 0.030881 0.029657 + 2.250 0.023382 0.030858 0.029636 + 2.251 0.023364 0.030836 0.029615 + 2.252 0.023347 0.030813 0.029593 + 2.253 0.023330 0.030790 0.029572 + 2.254 0.023313 0.030768 0.029551 + 2.255 0.023296 0.030745 0.029530 + 2.256 0.023278 0.030723 0.029509 + 2.257 0.023261 0.030700 0.029488 + 2.258 0.023244 0.030678 0.029467 + 2.259 0.023227 0.030655 0.029445 + 2.260 0.023210 0.030633 0.029424 + 2.261 0.023193 0.030610 0.029403 + 2.262 0.023176 0.030588 0.029382 + 2.263 0.023159 0.030566 0.029361 + 2.264 0.023142 0.030543 0.029340 + 2.265 0.023125 0.030521 0.029320 + 2.266 0.023108 0.030499 0.029299 + 2.267 0.023091 0.030477 0.029278 + 2.268 0.023074 0.030454 0.029257 + 2.269 0.023057 0.030432 0.029236 + 2.270 0.023040 0.030410 0.029215 + 2.271 0.023023 0.030388 0.029195 + 2.272 0.023006 0.030366 0.029174 + 2.273 0.022990 0.030344 0.029153 + 2.274 0.022973 0.030322 0.029132 + 2.275 0.022956 0.030300 0.029112 + 2.276 0.022939 0.030278 0.029091 + 2.277 0.022923 0.030256 0.029070 + 2.278 0.022906 0.030234 0.029050 + 2.279 0.022889 0.030212 0.029029 + 2.280 0.022872 0.030190 0.029009 + 2.281 0.022856 0.030168 0.028988 + 2.282 0.022839 0.030146 0.028968 + 2.283 0.022822 0.030124 0.028947 + 2.284 0.022806 0.030102 0.028927 + 2.285 0.022789 0.030081 0.028906 + 2.286 0.022773 0.030059 0.028886 + 2.287 0.022756 0.030037 0.028865 + 2.288 0.022740 0.030015 0.028845 + 2.289 0.022723 0.029994 0.028825 + 2.290 0.022707 0.029972 0.028804 + 2.291 0.022690 0.029950 0.028784 + 2.292 0.022674 0.029929 0.028764 + 2.293 0.022657 0.029907 0.028743 + 2.294 0.022641 0.029886 0.028723 + 2.295 0.022624 0.029864 0.028703 + 2.296 0.022608 0.029843 0.028683 + 2.297 0.022592 0.029821 0.028663 + 2.298 0.022575 0.029800 0.028642 + 2.299 0.022559 0.029778 0.028622 + 2.300 0.022543 0.029757 0.028602 + 2.301 0.022526 0.029735 0.028582 + 2.302 0.022510 0.029714 0.028562 + 2.303 0.022494 0.029693 0.028542 + 2.304 0.022478 0.029671 0.028522 + 2.305 0.022462 0.029650 0.028502 + 2.306 0.022445 0.029629 0.028482 + 2.307 0.022429 0.029608 0.028462 + 2.308 0.022413 0.029586 0.028442 + 2.309 0.022397 0.029565 0.028422 + 2.310 0.022381 0.029544 0.028402 + 2.311 0.022365 0.029523 0.028382 + 2.312 0.022349 0.029502 0.028363 + 2.313 0.022333 0.029481 0.028343 + 2.314 0.022316 0.029460 0.028323 + 2.315 0.022300 0.029439 0.028303 + 2.316 0.022284 0.029418 0.028283 + 2.317 0.022268 0.029397 0.028264 + 2.318 0.022252 0.029376 0.028244 + 2.319 0.022237 0.029355 0.028224 + 2.320 0.022221 0.029334 0.028205 + 2.321 0.022205 0.029313 0.028185 + 2.322 0.022189 0.029292 0.028165 + 2.323 0.022173 0.029271 0.028146 + 2.324 0.022157 0.029250 0.028126 + 2.325 0.022141 0.029229 0.028107 + 2.326 0.022125 0.029209 0.028087 + 2.327 0.022110 0.029188 0.028068 + 2.328 0.022094 0.029167 0.028048 + 2.329 0.022078 0.029146 0.028029 + 2.330 0.022062 0.029126 0.028009 + 2.331 0.022047 0.029105 0.027990 + 2.332 0.022031 0.029084 0.027970 + 2.333 0.022015 0.029064 0.027951 + 2.334 0.021999 0.029043 0.027932 + 2.335 0.021984 0.029023 0.027912 + 2.336 0.021968 0.029002 0.027893 + 2.337 0.021953 0.028982 0.027874 + 2.338 0.021937 0.028961 0.027854 + 2.339 0.021921 0.028941 0.027835 + 2.340 0.021906 0.028920 0.027816 + 2.341 0.021890 0.028900 0.027797 + 2.342 0.021875 0.028879 0.027778 + 2.343 0.021859 0.028859 0.027758 + 2.344 0.021844 0.028839 0.027739 + 2.345 0.021828 0.028818 0.027720 + 2.346 0.021813 0.028798 0.027701 + 2.347 0.021797 0.028778 0.027682 + 2.348 0.021782 0.028757 0.027663 + 2.349 0.021766 0.028737 0.027644 + 2.350 0.021751 0.028717 0.027625 + 2.351 0.021736 0.028697 0.027606 + 2.352 0.021720 0.028676 0.027587 + 2.353 0.021705 0.028656 0.027568 + 2.354 0.021690 0.028636 0.027549 + 2.355 0.021674 0.028616 0.027530 + 2.356 0.021659 0.028596 0.027511 + 2.357 0.021644 0.028576 0.027492 + 2.358 0.021628 0.028556 0.027473 + 2.359 0.021613 0.028536 0.027455 + 2.360 0.021598 0.028516 0.027436 + 2.361 0.021583 0.028496 0.027417 + 2.362 0.021568 0.028476 0.027398 + 2.363 0.021552 0.028456 0.027379 + 2.364 0.021537 0.028436 0.027361 + 2.365 0.021522 0.028416 0.027342 + 2.366 0.021507 0.028396 0.027323 + 2.367 0.021492 0.028376 0.027305 + 2.368 0.021477 0.028357 0.027286 + 2.369 0.021462 0.028337 0.027267 + 2.370 0.021447 0.028317 0.027249 + 2.371 0.021432 0.028297 0.027230 + 2.372 0.021417 0.028278 0.027212 + 2.373 0.021402 0.028258 0.027193 + 2.374 0.021387 0.028238 0.027175 + 2.375 0.021372 0.028218 0.027156 + 2.376 0.021357 0.028199 0.027138 + 2.377 0.021342 0.028179 0.027119 + 2.378 0.021327 0.028160 0.027101 + 2.379 0.021312 0.028140 0.027082 + 2.380 0.021297 0.028120 0.027064 + 2.381 0.021282 0.028101 0.027045 + 2.382 0.021267 0.028081 0.027027 + 2.383 0.021253 0.028062 0.027009 + 2.384 0.021238 0.028042 0.026990 + 2.385 0.021223 0.028023 0.026972 + 2.386 0.021208 0.028004 0.026954 + 2.387 0.021193 0.027984 0.026936 + 2.388 0.021179 0.027965 0.026917 + 2.389 0.021164 0.027945 0.026899 + 2.390 0.021149 0.027926 0.026881 + 2.391 0.021134 0.027907 0.026863 + 2.392 0.021120 0.027887 0.026845 + 2.393 0.021105 0.027868 0.026826 + 2.394 0.021090 0.027849 0.026808 + 2.395 0.021076 0.027830 0.026790 + 2.396 0.021061 0.027810 0.026772 + 2.397 0.021047 0.027791 0.026754 + 2.398 0.021032 0.027772 0.026736 + 2.399 0.021017 0.027753 0.026718 + 2.400 0.021003 0.027734 0.026700 + 2.401 0.020988 0.027715 0.026682 + 2.402 0.020974 0.027696 0.026664 + 2.403 0.020959 0.027677 0.026646 + 2.404 0.020945 0.027658 0.026628 + 2.405 0.020930 0.027639 0.026610 + 2.406 0.020916 0.027620 0.026592 + 2.407 0.020901 0.027601 0.026574 + 2.408 0.020887 0.027582 0.026557 + 2.409 0.020873 0.027563 0.026539 + 2.410 0.020858 0.027544 0.026521 + 2.411 0.020844 0.027525 0.026503 + 2.412 0.020829 0.027506 0.026485 + 2.413 0.020815 0.027487 0.026468 + 2.414 0.020801 0.027468 0.026450 + 2.415 0.020786 0.027449 0.026432 + 2.416 0.020772 0.027431 0.026414 + 2.417 0.020758 0.027412 0.026397 + 2.418 0.020744 0.027393 0.026379 + 2.419 0.020729 0.027374 0.026361 + 2.420 0.020715 0.027356 0.026344 + 2.421 0.020701 0.027337 0.026326 + 2.422 0.020687 0.027318 0.026309 + 2.423 0.020672 0.027300 0.026291 + 2.424 0.020658 0.027281 0.026273 + 2.425 0.020644 0.027262 0.026256 + 2.426 0.020630 0.027244 0.026238 + 2.427 0.020616 0.027225 0.026221 + 2.428 0.020602 0.027207 0.026203 + 2.429 0.020588 0.027188 0.026186 + 2.430 0.020573 0.027170 0.026169 + 2.431 0.020559 0.027151 0.026151 + 2.432 0.020545 0.027133 0.026134 + 2.433 0.020531 0.027114 0.026116 + 2.434 0.020517 0.027096 0.026099 + 2.435 0.020503 0.027077 0.026082 + 2.436 0.020489 0.027059 0.026064 + 2.437 0.020475 0.027041 0.026047 + 2.438 0.020461 0.027022 0.026030 + 2.439 0.020447 0.027004 0.026012 + 2.440 0.020433 0.026986 0.025995 + 2.441 0.020420 0.026967 0.025978 + 2.442 0.020406 0.026949 0.025961 + 2.443 0.020392 0.026931 0.025943 + 2.444 0.020378 0.026913 0.025926 + 2.445 0.020364 0.026894 0.025909 + 2.446 0.020350 0.026876 0.025892 + 2.447 0.020336 0.026858 0.025875 + 2.448 0.020323 0.026840 0.025858 + 2.449 0.020309 0.026822 0.025841 + 2.450 0.020295 0.026804 0.025824 + 2.451 0.020281 0.026786 0.025807 + 2.452 0.020267 0.026767 0.025790 + 2.453 0.020254 0.026749 0.025772 + 2.454 0.020240 0.026731 0.025755 + 2.455 0.020226 0.026713 0.025739 + 2.456 0.020213 0.026695 0.025722 + 2.457 0.020199 0.026677 0.025705 + 2.458 0.020185 0.026659 0.025688 + 2.459 0.020172 0.026641 0.025671 + 2.460 0.020158 0.026624 0.025654 + 2.461 0.020144 0.026606 0.025637 + 2.462 0.020131 0.026588 0.025620 + 2.463 0.020117 0.026570 0.025603 + 2.464 0.020104 0.026552 0.025586 + 2.465 0.020090 0.026534 0.025570 + 2.466 0.020077 0.026516 0.025553 + 2.467 0.020063 0.026499 0.025536 + 2.468 0.020050 0.026481 0.025519 + 2.469 0.020036 0.026463 0.025503 + 2.470 0.020023 0.026445 0.025486 + 2.471 0.020009 0.026428 0.025469 + 2.472 0.019996 0.026410 0.025453 + 2.473 0.019982 0.026392 0.025436 + 2.474 0.019969 0.026375 0.025419 + 2.475 0.019955 0.026357 0.025403 + 2.476 0.019942 0.026339 0.025386 + 2.477 0.019929 0.026322 0.025369 + 2.478 0.019915 0.026304 0.025353 + 2.479 0.019902 0.026287 0.025336 + 2.480 0.019888 0.026269 0.025320 + 2.481 0.019875 0.026252 0.025303 + 2.482 0.019862 0.026234 0.025287 + 2.483 0.019849 0.026217 0.025270 + 2.484 0.019835 0.026199 0.025254 + 2.485 0.019822 0.026182 0.025237 + 2.486 0.019809 0.026164 0.025221 + 2.487 0.019795 0.026147 0.025204 + 2.488 0.019782 0.026130 0.025188 + 2.489 0.019769 0.026112 0.025172 + 2.490 0.019756 0.026095 0.025155 + 2.491 0.019743 0.026077 0.025139 + 2.492 0.019729 0.026060 0.025122 + 2.493 0.019716 0.026043 0.025106 + 2.494 0.019703 0.026026 0.025090 + 2.495 0.019690 0.026008 0.025074 + 2.496 0.019677 0.025991 0.025057 + 2.497 0.019664 0.025974 0.025041 + 2.498 0.019651 0.025957 0.025025 + 2.499 0.019638 0.025939 0.025009 + 2.500 0.019625 0.025922 0.024992 + 2.501 0.019612 0.025905 0.024976 + 2.502 0.019599 0.025888 0.024960 + 2.503 0.019586 0.025871 0.024944 + 2.504 0.019573 0.025854 0.024928 + 2.505 0.019560 0.025837 0.024912 + 2.506 0.019547 0.025820 0.024896 + 2.507 0.019534 0.025803 0.024879 + 2.508 0.019521 0.025786 0.024863 + 2.509 0.019508 0.025769 0.024847 + 2.510 0.019495 0.025752 0.024831 + 2.511 0.019482 0.025735 0.024815 + 2.512 0.019469 0.025718 0.024799 + 2.513 0.019456 0.025701 0.024783 + 2.514 0.019443 0.025684 0.024767 + 2.515 0.019430 0.025667 0.024751 + 2.516 0.019418 0.025650 0.024735 + 2.517 0.019405 0.025633 0.024719 + 2.518 0.019392 0.025616 0.024704 + 2.519 0.019379 0.025599 0.024688 + 2.520 0.019366 0.025583 0.024672 + 2.521 0.019354 0.025566 0.024656 + 2.522 0.019341 0.025549 0.024640 + 2.523 0.019328 0.025532 0.024624 + 2.524 0.019315 0.025516 0.024609 + 2.525 0.019303 0.025499 0.024593 + 2.526 0.019290 0.025482 0.024577 + 2.527 0.019277 0.025465 0.024561 + 2.528 0.019265 0.025449 0.024545 + 2.529 0.019252 0.025432 0.024530 + 2.530 0.019239 0.025416 0.024514 + 2.531 0.019227 0.025399 0.024498 + 2.532 0.019214 0.025382 0.024483 + 2.533 0.019201 0.025366 0.024467 + 2.534 0.019189 0.025349 0.024451 + 2.535 0.019176 0.025333 0.024436 + 2.536 0.019164 0.025316 0.024420 + 2.537 0.019151 0.025300 0.024405 + 2.538 0.019138 0.025283 0.024389 + 2.539 0.019126 0.025267 0.024373 + 2.540 0.019113 0.025250 0.024358 + 2.541 0.019101 0.025234 0.024342 + 2.542 0.019088 0.025217 0.024327 + 2.543 0.019076 0.025201 0.024311 + 2.544 0.019063 0.025184 0.024296 + 2.545 0.019051 0.025168 0.024280 + 2.546 0.019039 0.025152 0.024265 + 2.547 0.019026 0.025135 0.024249 + 2.548 0.019014 0.025119 0.024234 + 2.549 0.019001 0.025103 0.024219 + 2.550 0.018989 0.025086 0.024203 + 2.551 0.018977 0.025070 0.024188 + 2.552 0.018964 0.025054 0.024172 + 2.553 0.018952 0.025038 0.024157 + 2.554 0.018940 0.025021 0.024142 + 2.555 0.018927 0.025005 0.024126 + 2.556 0.018915 0.024989 0.024111 + 2.557 0.018903 0.024973 0.024096 + 2.558 0.018890 0.024957 0.024081 + 2.559 0.018878 0.024941 0.024065 + 2.560 0.018866 0.024924 0.024050 + 2.561 0.018854 0.024908 0.024035 + 2.562 0.018841 0.024892 0.024020 + 2.563 0.018829 0.024876 0.024005 + 2.564 0.018817 0.024860 0.023989 + 2.565 0.018805 0.024844 0.023974 + 2.566 0.018792 0.024828 0.023959 + 2.567 0.018780 0.024812 0.023944 + 2.568 0.018768 0.024796 0.023929 + 2.569 0.018756 0.024780 0.023914 + 2.570 0.018744 0.024764 0.023899 + 2.571 0.018732 0.024748 0.023884 + 2.572 0.018720 0.024732 0.023868 + 2.573 0.018708 0.024716 0.023853 + 2.574 0.018695 0.024700 0.023838 + 2.575 0.018683 0.024685 0.023823 + 2.576 0.018671 0.024669 0.023808 + 2.577 0.018659 0.024653 0.023793 + 2.578 0.018647 0.024637 0.023778 + 2.579 0.018635 0.024621 0.023764 + 2.580 0.018623 0.024605 0.023749 + 2.581 0.018611 0.024590 0.023734 + 2.582 0.018599 0.024574 0.023719 + 2.583 0.018587 0.024558 0.023704 + 2.584 0.018575 0.024542 0.023689 + 2.585 0.018563 0.024527 0.023674 + 2.586 0.018551 0.024511 0.023659 + 2.587 0.018539 0.024495 0.023645 + 2.588 0.018528 0.024480 0.023630 + 2.589 0.018516 0.024464 0.023615 + 2.590 0.018504 0.024448 0.023600 + 2.591 0.018492 0.024433 0.023585 + 2.592 0.018480 0.024417 0.023571 + 2.593 0.018468 0.024402 0.023556 + 2.594 0.018456 0.024386 0.023541 + 2.595 0.018445 0.024370 0.023526 + 2.596 0.018433 0.024355 0.023512 + 2.597 0.018421 0.024339 0.023497 + 2.598 0.018409 0.024324 0.023482 + 2.599 0.018397 0.024308 0.023468 + 2.600 0.018386 0.024293 0.023453 + 2.601 0.018374 0.024277 0.023438 + 2.602 0.018362 0.024262 0.023424 + 2.603 0.018350 0.024247 0.023409 + 2.604 0.018339 0.024231 0.023395 + 2.605 0.018327 0.024216 0.023380 + 2.606 0.018315 0.024200 0.023366 + 2.607 0.018304 0.024185 0.023351 + 2.608 0.018292 0.024170 0.023337 + 2.609 0.018280 0.024154 0.023322 + 2.610 0.018269 0.024139 0.023308 + 2.611 0.018257 0.024124 0.023293 + 2.612 0.018245 0.024108 0.023279 + 2.613 0.018234 0.024093 0.023264 + 2.614 0.018222 0.024078 0.023250 + 2.615 0.018211 0.024063 0.023235 + 2.616 0.018199 0.024047 0.023221 + 2.617 0.018187 0.024032 0.023207 + 2.618 0.018176 0.024017 0.023192 + 2.619 0.018164 0.024002 0.023178 + 2.620 0.018153 0.023987 0.023163 + 2.621 0.018141 0.023972 0.023149 + 2.622 0.018130 0.023956 0.023135 + 2.623 0.018118 0.023941 0.023120 + 2.624 0.018107 0.023926 0.023106 + 2.625 0.018095 0.023911 0.023092 + 2.626 0.018084 0.023896 0.023078 + 2.627 0.018072 0.023881 0.023063 + 2.628 0.018061 0.023866 0.023049 + 2.629 0.018050 0.023851 0.023035 + 2.630 0.018038 0.023836 0.023021 + 2.631 0.018027 0.023821 0.023007 + 2.632 0.018015 0.023806 0.022992 + 2.633 0.018004 0.023791 0.022978 + 2.634 0.017993 0.023776 0.022964 + 2.635 0.017981 0.023761 0.022950 + 2.636 0.017970 0.023746 0.022936 + 2.637 0.017959 0.023731 0.022922 + 2.638 0.017947 0.023716 0.022908 + 2.639 0.017936 0.023701 0.022894 + 2.640 0.017925 0.023687 0.022879 + 2.641 0.017913 0.023672 0.022865 + 2.642 0.017902 0.023657 0.022851 + 2.643 0.017891 0.023642 0.022837 + 2.644 0.017880 0.023627 0.022823 + 2.645 0.017868 0.023612 0.022809 + 2.646 0.017857 0.023598 0.022795 + 2.647 0.017846 0.023583 0.022781 + 2.648 0.017835 0.023568 0.022767 + 2.649 0.017824 0.023553 0.022753 + 2.650 0.017812 0.023539 0.022740 + 2.651 0.017801 0.023524 0.022726 + 2.652 0.017790 0.023509 0.022712 + 2.653 0.017779 0.023495 0.022698 + 2.654 0.017768 0.023480 0.022684 + 2.655 0.017757 0.023465 0.022670 + 2.656 0.017745 0.023451 0.022656 + 2.657 0.017734 0.023436 0.022642 + 2.658 0.017723 0.023422 0.022629 + 2.659 0.017712 0.023407 0.022615 + 2.660 0.017701 0.023392 0.022601 + 2.661 0.017690 0.023378 0.022587 + 2.662 0.017679 0.023363 0.022573 + 2.663 0.017668 0.023349 0.022560 + 2.664 0.017657 0.023334 0.022546 + 2.665 0.017646 0.023320 0.022532 + 2.666 0.017635 0.023305 0.022519 + 2.667 0.017624 0.023291 0.022505 + 2.668 0.017613 0.023276 0.022491 + 2.669 0.017602 0.023262 0.022477 + 2.670 0.017591 0.023248 0.022464 + 2.671 0.017580 0.023233 0.022450 + 2.672 0.017569 0.023219 0.022437 + 2.673 0.017558 0.023204 0.022423 + 2.674 0.017547 0.023190 0.022409 + 2.675 0.017536 0.023176 0.022396 + 2.676 0.017525 0.023161 0.022382 + 2.677 0.017515 0.023147 0.022369 + 2.678 0.017504 0.023133 0.022355 + 2.679 0.017493 0.023118 0.022341 + 2.680 0.017482 0.023104 0.022328 + 2.681 0.017471 0.023090 0.022314 + 2.682 0.017460 0.023076 0.022301 + 2.683 0.017449 0.023061 0.022287 + 2.684 0.017439 0.023047 0.022274 + 2.685 0.017428 0.023033 0.022260 + 2.686 0.017417 0.023019 0.022247 + 2.687 0.017406 0.023005 0.022234 + 2.688 0.017396 0.022990 0.022220 + 2.689 0.017385 0.022976 0.022207 + 2.690 0.017374 0.022962 0.022193 + 2.691 0.017363 0.022948 0.022180 + 2.692 0.017353 0.022934 0.022167 + 2.693 0.017342 0.022920 0.022153 + 2.694 0.017331 0.022906 0.022140 + 2.695 0.017320 0.022892 0.022127 + 2.696 0.017310 0.022878 0.022113 + 2.697 0.017299 0.022863 0.022100 + 2.698 0.017288 0.022849 0.022087 + 2.699 0.017278 0.022835 0.022073 + 2.700 0.017267 0.022821 0.022060 + 2.701 0.017257 0.022807 0.022047 + 2.702 0.017246 0.022793 0.022034 + 2.703 0.017235 0.022780 0.022020 + 2.704 0.017225 0.022766 0.022007 + 2.705 0.017214 0.022752 0.021994 + 2.706 0.017204 0.022738 0.021981 + 2.707 0.017193 0.022724 0.021968 + 2.708 0.017182 0.022710 0.021954 + 2.709 0.017172 0.022696 0.021941 + 2.710 0.017161 0.022682 0.021928 + 2.711 0.017151 0.022668 0.021915 + 2.712 0.017140 0.022654 0.021902 + 2.713 0.017130 0.022641 0.021889 + 2.714 0.017119 0.022627 0.021876 + 2.715 0.017109 0.022613 0.021863 + 2.716 0.017098 0.022599 0.021849 + 2.717 0.017088 0.022585 0.021836 + 2.718 0.017077 0.022572 0.021823 + 2.719 0.017067 0.022558 0.021810 + 2.720 0.017057 0.022544 0.021797 + 2.721 0.017046 0.022531 0.021784 + 2.722 0.017036 0.022517 0.021771 + 2.723 0.017025 0.022503 0.021758 + 2.724 0.017015 0.022489 0.021745 + 2.725 0.017004 0.022476 0.021732 + 2.726 0.016994 0.022462 0.021720 + 2.727 0.016984 0.022448 0.021707 + 2.728 0.016973 0.022435 0.021694 + 2.729 0.016963 0.022421 0.021681 + 2.730 0.016953 0.022408 0.021668 + 2.731 0.016942 0.022394 0.021655 + 2.732 0.016932 0.022380 0.021642 + 2.733 0.016922 0.022367 0.021629 + 2.734 0.016911 0.022353 0.021616 + 2.735 0.016901 0.022340 0.021604 + 2.736 0.016891 0.022326 0.021591 + 2.737 0.016881 0.022313 0.021578 + 2.738 0.016870 0.022299 0.021565 + 2.739 0.016860 0.022286 0.021552 + 2.740 0.016850 0.022272 0.021540 + 2.741 0.016840 0.022259 0.021527 + 2.742 0.016830 0.022245 0.021514 + 2.743 0.016819 0.022232 0.021501 + 2.744 0.016809 0.022219 0.021489 + 2.745 0.016799 0.022205 0.021476 + 2.746 0.016789 0.022192 0.021463 + 2.747 0.016779 0.022178 0.021451 + 2.748 0.016768 0.022165 0.021438 + 2.749 0.016758 0.022152 0.021425 + 2.750 0.016748 0.022138 0.021413 + 2.751 0.016738 0.022125 0.021400 + 2.752 0.016728 0.022112 0.021387 + 2.753 0.016718 0.022098 0.021375 + 2.754 0.016708 0.022085 0.021362 + 2.755 0.016698 0.022072 0.021349 + 2.756 0.016688 0.022059 0.021337 + 2.757 0.016678 0.022045 0.021324 + 2.758 0.016667 0.022032 0.021312 + 2.759 0.016657 0.022019 0.021299 + 2.760 0.016647 0.022006 0.021287 + 2.761 0.016637 0.021993 0.021274 + 2.762 0.016627 0.021979 0.021262 + 2.763 0.016617 0.021966 0.021249 + 2.764 0.016607 0.021953 0.021237 + 2.765 0.016597 0.021940 0.021224 + 2.766 0.016587 0.021927 0.021212 + 2.767 0.016577 0.021914 0.021199 + 2.768 0.016567 0.021901 0.021187 + 2.769 0.016557 0.021887 0.021174 + 2.770 0.016548 0.021874 0.021162 + 2.771 0.016538 0.021861 0.021150 + 2.772 0.016528 0.021848 0.021137 + 2.773 0.016518 0.021835 0.021125 + 2.774 0.016508 0.021822 0.021112 + 2.775 0.016498 0.021809 0.021100 + 2.776 0.016488 0.021796 0.021088 + 2.777 0.016478 0.021783 0.021075 + 2.778 0.016468 0.021770 0.021063 + 2.779 0.016459 0.021757 0.021051 + 2.780 0.016449 0.021744 0.021038 + 2.781 0.016439 0.021731 0.021026 + 2.782 0.016429 0.021718 0.021014 + 2.783 0.016419 0.021705 0.021002 + 2.784 0.016409 0.021692 0.020989 + 2.785 0.016400 0.021680 0.020977 + 2.786 0.016390 0.021667 0.020965 + 2.787 0.016380 0.021654 0.020953 + 2.788 0.016370 0.021641 0.020940 + 2.789 0.016360 0.021628 0.020928 + 2.790 0.016351 0.021615 0.020916 + 2.791 0.016341 0.021602 0.020904 + 2.792 0.016331 0.021590 0.020892 + 2.793 0.016322 0.021577 0.020880 + 2.794 0.016312 0.021564 0.020867 + 2.795 0.016302 0.021551 0.020855 + 2.796 0.016292 0.021538 0.020843 + 2.797 0.016283 0.021526 0.020831 + 2.798 0.016273 0.021513 0.020819 + 2.799 0.016263 0.021500 0.020807 + 2.800 0.016254 0.021488 0.020795 + 2.801 0.016244 0.021475 0.020783 + 2.802 0.016234 0.021462 0.020771 + 2.803 0.016225 0.021449 0.020759 + 2.804 0.016215 0.021437 0.020747 + 2.805 0.016206 0.021424 0.020735 + 2.806 0.016196 0.021412 0.020723 + 2.807 0.016186 0.021399 0.020711 + 2.808 0.016177 0.021386 0.020699 + 2.809 0.016167 0.021374 0.020687 + 2.810 0.016158 0.021361 0.020675 + 2.811 0.016148 0.021348 0.020663 + 2.812 0.016139 0.021336 0.020651 + 2.813 0.016129 0.021323 0.020639 + 2.814 0.016119 0.021311 0.020627 + 2.815 0.016110 0.021298 0.020615 + 2.816 0.016100 0.021286 0.020603 + 2.817 0.016091 0.021273 0.020591 + 2.818 0.016081 0.021261 0.020579 + 2.819 0.016072 0.021248 0.020568 + 2.820 0.016062 0.021236 0.020556 + 2.821 0.016053 0.021223 0.020544 + 2.822 0.016044 0.021211 0.020532 + 2.823 0.016034 0.021198 0.020520 + 2.824 0.016025 0.021186 0.020508 + 2.825 0.016015 0.021174 0.020497 + 2.826 0.016006 0.021161 0.020485 + 2.827 0.015996 0.021149 0.020473 + 2.828 0.015987 0.021136 0.020461 + 2.829 0.015978 0.021124 0.020450 + 2.830 0.015968 0.021112 0.020438 + 2.831 0.015959 0.021099 0.020426 + 2.832 0.015949 0.021087 0.020414 + 2.833 0.015940 0.021075 0.020403 + 2.834 0.015931 0.021062 0.020391 + 2.835 0.015921 0.021050 0.020379 + 2.836 0.015912 0.021038 0.020368 + 2.837 0.015903 0.021025 0.020356 + 2.838 0.015893 0.021013 0.020344 + 2.839 0.015884 0.021001 0.020333 + 2.840 0.015875 0.020989 0.020321 + 2.841 0.015865 0.020976 0.020309 + 2.842 0.015856 0.020964 0.020298 + 2.843 0.015847 0.020952 0.020286 + 2.844 0.015838 0.020940 0.020275 + 2.845 0.015828 0.020928 0.020263 + 2.846 0.015819 0.020915 0.020251 + 2.847 0.015810 0.020903 0.020240 + 2.848 0.015801 0.020891 0.020228 + 2.849 0.015791 0.020879 0.020217 + 2.850 0.015782 0.020867 0.020205 + 2.851 0.015773 0.020855 0.020194 + 2.852 0.015764 0.020843 0.020182 + 2.853 0.015755 0.020830 0.020171 + 2.854 0.015745 0.020818 0.020159 + 2.855 0.015736 0.020806 0.020148 + 2.856 0.015727 0.020794 0.020136 + 2.857 0.015718 0.020782 0.020125 + 2.858 0.015709 0.020770 0.020113 + 2.859 0.015700 0.020758 0.020102 + 2.860 0.015691 0.020746 0.020091 + 2.861 0.015681 0.020734 0.020079 + 2.862 0.015672 0.020722 0.020068 + 2.863 0.015663 0.020710 0.020056 + 2.864 0.015654 0.020698 0.020045 + 2.865 0.015645 0.020686 0.020034 + 2.866 0.015636 0.020674 0.020022 + 2.867 0.015627 0.020662 0.020011 + 2.868 0.015618 0.020650 0.020000 + 2.869 0.015609 0.020638 0.019988 + 2.870 0.015600 0.020626 0.019977 + 2.871 0.015591 0.020615 0.019966 + 2.872 0.015582 0.020603 0.019954 + 2.873 0.015573 0.020591 0.019943 + 2.874 0.015564 0.020579 0.019932 + 2.875 0.015555 0.020567 0.019920 + 2.876 0.015546 0.020555 0.019909 + 2.877 0.015537 0.020543 0.019898 + 2.878 0.015528 0.020532 0.019887 + 2.879 0.015519 0.020520 0.019875 + 2.880 0.015510 0.020508 0.019864 + 2.881 0.015501 0.020496 0.019853 + 2.882 0.015492 0.020484 0.019842 + 2.883 0.015483 0.020473 0.019831 + 2.884 0.015474 0.020461 0.019819 + 2.885 0.015465 0.020449 0.019808 + 2.886 0.015456 0.020437 0.019797 + 2.887 0.015447 0.020426 0.019786 + 2.888 0.015438 0.020414 0.019775 + 2.889 0.015429 0.020402 0.019764 + 2.890 0.015421 0.020391 0.019753 + 2.891 0.015412 0.020379 0.019741 + 2.892 0.015403 0.020367 0.019730 + 2.893 0.015394 0.020356 0.019719 + 2.894 0.015385 0.020344 0.019708 + 2.895 0.015376 0.020332 0.019697 + 2.896 0.015367 0.020321 0.019686 + 2.897 0.015359 0.020309 0.019675 + 2.898 0.015350 0.020297 0.019664 + 2.899 0.015341 0.020286 0.019653 + 2.900 0.015332 0.020274 0.019642 + 2.901 0.015323 0.020263 0.019631 + 2.902 0.015315 0.020251 0.019620 + 2.903 0.015306 0.020239 0.019609 + 2.904 0.015297 0.020228 0.019598 + 2.905 0.015288 0.020216 0.019587 + 2.906 0.015280 0.020205 0.019576 + 2.907 0.015271 0.020193 0.019565 + 2.908 0.015262 0.020182 0.019554 + 2.909 0.015253 0.020170 0.019543 + 2.910 0.015245 0.020159 0.019532 + 2.911 0.015236 0.020147 0.019521 + 2.912 0.015227 0.020136 0.019510 + 2.913 0.015219 0.020125 0.019500 + 2.914 0.015210 0.020113 0.019489 + 2.915 0.015201 0.020102 0.019478 + 2.916 0.015193 0.020090 0.019467 + 2.917 0.015184 0.020079 0.019456 + 2.918 0.015175 0.020067 0.019445 + 2.919 0.015167 0.020056 0.019434 + 2.920 0.015158 0.020045 0.019424 + 2.921 0.015149 0.020033 0.019413 + 2.922 0.015141 0.020022 0.019402 + 2.923 0.015132 0.020011 0.019391 + 2.924 0.015123 0.019999 0.019380 + 2.925 0.015115 0.019988 0.019370 + 2.926 0.015106 0.019977 0.019359 + 2.927 0.015098 0.019965 0.019348 + 2.928 0.015089 0.019954 0.019337 + 2.929 0.015081 0.019943 0.019327 + 2.930 0.015072 0.019931 0.019316 + 2.931 0.015063 0.019920 0.019305 + 2.932 0.015055 0.019909 0.019294 + 2.933 0.015046 0.019898 0.019284 + 2.934 0.015038 0.019886 0.019273 + 2.935 0.015029 0.019875 0.019262 + 2.936 0.015021 0.019864 0.019252 + 2.937 0.015012 0.019853 0.019241 + 2.938 0.015004 0.019842 0.019230 + 2.939 0.014995 0.019830 0.019220 + 2.940 0.014987 0.019819 0.019209 + 2.941 0.014978 0.019808 0.019198 + 2.942 0.014970 0.019797 0.019188 + 2.943 0.014961 0.019786 0.019177 + 2.944 0.014953 0.019775 0.019167 + 2.945 0.014945 0.019764 0.019156 + 2.946 0.014936 0.019752 0.019146 + 2.947 0.014928 0.019741 0.019135 + 2.948 0.014919 0.019730 0.019124 + 2.949 0.014911 0.019719 0.019114 + 2.950 0.014902 0.019708 0.019103 + 2.951 0.014894 0.019697 0.019093 + 2.952 0.014886 0.019686 0.019082 + 2.953 0.014877 0.019675 0.019072 + 2.954 0.014869 0.019664 0.019061 + 2.955 0.014860 0.019653 0.019051 + 2.956 0.014852 0.019642 0.019040 + 2.957 0.014844 0.019631 0.019030 + 2.958 0.014835 0.019620 0.019019 + 2.959 0.014827 0.019609 0.019009 + 2.960 0.014819 0.019598 0.018998 + 2.961 0.014810 0.019587 0.018988 + 2.962 0.014802 0.019576 0.018978 + 2.963 0.014794 0.019565 0.018967 + 2.964 0.014786 0.019554 0.018957 + 2.965 0.014777 0.019543 0.018946 + 2.966 0.014769 0.019532 0.018936 + 2.967 0.014761 0.019521 0.018926 + 2.968 0.014752 0.019510 0.018915 + 2.969 0.014744 0.019500 0.018905 + 2.970 0.014736 0.019489 0.018894 + 2.971 0.014728 0.019478 0.018884 + 2.972 0.014719 0.019467 0.018874 + 2.973 0.014711 0.019456 0.018863 + 2.974 0.014703 0.019445 0.018853 + 2.975 0.014695 0.019434 0.018843 + 2.976 0.014686 0.019424 0.018832 + 2.977 0.014678 0.019413 0.018822 + 2.978 0.014670 0.019402 0.018812 + 2.979 0.014662 0.019391 0.018802 + 2.980 0.014654 0.019380 0.018791 + 2.981 0.014646 0.019370 0.018781 + 2.982 0.014637 0.019359 0.018771 + 2.983 0.014629 0.019348 0.018761 + 2.984 0.014621 0.019337 0.018750 + 2.985 0.014613 0.019327 0.018740 + 2.986 0.014605 0.019316 0.018730 + 2.987 0.014597 0.019305 0.018720 + 2.988 0.014588 0.019295 0.018710 + 2.989 0.014580 0.019284 0.018699 + 2.990 0.014572 0.019273 0.018689 + 2.991 0.014564 0.019262 0.018679 + 2.992 0.014556 0.019252 0.018669 + 2.993 0.014548 0.019241 0.018659 + 2.994 0.014540 0.019231 0.018649 + 2.995 0.014532 0.019220 0.018638 + 2.996 0.014524 0.019209 0.018628 + 2.997 0.014516 0.019199 0.018618 + 2.998 0.014508 0.019188 0.018608 + 2.999 0.014500 0.019177 0.018598 + 3.000 0.014492 0.019167 0.018588 + 3.001 0.014484 0.019156 0.018578 + 3.002 0.014476 0.019146 0.018568 + 3.003 0.014467 0.019135 0.018558 + 3.004 0.014459 0.019125 0.018548 + 3.005 0.014451 0.019114 0.018538 + 3.006 0.014443 0.019103 0.018528 + 3.007 0.014435 0.019093 0.018518 + 3.008 0.014428 0.019082 0.018508 + 3.009 0.014420 0.019072 0.018498 + 3.010 0.014412 0.019061 0.018488 + 3.011 0.014404 0.019051 0.018478 + 3.012 0.014396 0.019040 0.018468 + 3.013 0.014388 0.019030 0.018458 + 3.014 0.014380 0.019020 0.018448 + 3.015 0.014372 0.019009 0.018438 + 3.016 0.014364 0.018999 0.018428 + 3.017 0.014356 0.018988 0.018418 + 3.018 0.014348 0.018978 0.018408 + 3.019 0.014340 0.018967 0.018398 + 3.020 0.014332 0.018957 0.018388 + 3.021 0.014324 0.018947 0.018378 + 3.022 0.014316 0.018936 0.018368 + 3.023 0.014309 0.018926 0.018358 + 3.024 0.014301 0.018915 0.018348 + 3.025 0.014293 0.018905 0.018339 + 3.026 0.014285 0.018895 0.018329 + 3.027 0.014277 0.018884 0.018319 + 3.028 0.014269 0.018874 0.018309 + 3.029 0.014262 0.018864 0.018299 + 3.030 0.014254 0.018853 0.018289 + 3.031 0.014246 0.018843 0.018279 + 3.032 0.014238 0.018833 0.018270 + 3.033 0.014230 0.018823 0.018260 + 3.034 0.014222 0.018812 0.018250 + 3.035 0.014215 0.018802 0.018240 + 3.036 0.014207 0.018792 0.018230 + 3.037 0.014199 0.018781 0.018221 + 3.038 0.014191 0.018771 0.018211 + 3.039 0.014184 0.018761 0.018201 + 3.040 0.014176 0.018751 0.018191 + 3.041 0.014168 0.018741 0.018182 + 3.042 0.014160 0.018730 0.018172 + 3.043 0.014153 0.018720 0.018162 + 3.044 0.014145 0.018710 0.018153 + 3.045 0.014137 0.018700 0.018143 + 3.046 0.014129 0.018690 0.018133 + 3.047 0.014122 0.018679 0.018123 + 3.048 0.014114 0.018669 0.018114 + 3.049 0.014106 0.018659 0.018104 + 3.050 0.014099 0.018649 0.018094 + 3.051 0.014091 0.018639 0.018085 + 3.052 0.014083 0.018629 0.018075 + 3.053 0.014076 0.018619 0.018066 + 3.054 0.014068 0.018609 0.018056 + 3.055 0.014060 0.018598 0.018046 + 3.056 0.014053 0.018588 0.018037 + 3.057 0.014045 0.018578 0.018027 + 3.058 0.014037 0.018568 0.018017 + 3.059 0.014030 0.018558 0.018008 + 3.060 0.014022 0.018548 0.017998 + 3.061 0.014014 0.018538 0.017989 + 3.062 0.014007 0.018528 0.017979 + 3.063 0.013999 0.018518 0.017970 + 3.064 0.013992 0.018508 0.017960 + 3.065 0.013984 0.018498 0.017950 + 3.066 0.013976 0.018488 0.017941 + 3.067 0.013969 0.018478 0.017931 + 3.068 0.013961 0.018468 0.017922 + 3.069 0.013954 0.018458 0.017912 + 3.070 0.013946 0.018448 0.017903 + 3.071 0.013939 0.018438 0.017893 + 3.072 0.013931 0.018428 0.017884 + 3.073 0.013923 0.018418 0.017874 + 3.074 0.013916 0.018408 0.017865 + 3.075 0.013908 0.018398 0.017856 + 3.076 0.013901 0.018388 0.017846 + 3.077 0.013893 0.018379 0.017837 + 3.078 0.013886 0.018369 0.017827 + 3.079 0.013878 0.018359 0.017818 + 3.080 0.013871 0.018349 0.017808 + 3.081 0.013863 0.018339 0.017799 + 3.082 0.013856 0.018329 0.017790 + 3.083 0.013848 0.018319 0.017780 + 3.084 0.013841 0.018310 0.017771 + 3.085 0.013833 0.018300 0.017761 + 3.086 0.013826 0.018290 0.017752 + 3.087 0.013819 0.018280 0.017743 + 3.088 0.013811 0.018270 0.017733 + 3.089 0.013804 0.018260 0.017724 + 3.090 0.013796 0.018251 0.017715 + 3.091 0.013789 0.018241 0.017705 + 3.092 0.013781 0.018231 0.017696 + 3.093 0.013774 0.018221 0.017687 + 3.094 0.013767 0.018212 0.017677 + 3.095 0.013759 0.018202 0.017668 + 3.096 0.013752 0.018192 0.017659 + 3.097 0.013744 0.018182 0.017649 + 3.098 0.013737 0.018173 0.017640 + 3.099 0.013730 0.018163 0.017631 + 3.100 0.013722 0.018153 0.017622 + 3.101 0.013715 0.018143 0.017612 + 3.102 0.013708 0.018134 0.017603 + 3.103 0.013700 0.018124 0.017594 + 3.104 0.013693 0.018114 0.017585 + 3.105 0.013686 0.018105 0.017575 + 3.106 0.013678 0.018095 0.017566 + 3.107 0.013671 0.018085 0.017557 + 3.108 0.013664 0.018076 0.017548 + 3.109 0.013656 0.018066 0.017539 + 3.110 0.013649 0.018057 0.017529 + 3.111 0.013642 0.018047 0.017520 + 3.112 0.013634 0.018037 0.017511 + 3.113 0.013627 0.018028 0.017502 + 3.114 0.013620 0.018018 0.017493 + 3.115 0.013613 0.018009 0.017484 + 3.116 0.013605 0.017999 0.017474 + 3.117 0.013598 0.017989 0.017465 + 3.118 0.013591 0.017980 0.017456 + 3.119 0.013584 0.017970 0.017447 + 3.120 0.013576 0.017961 0.017438 + 3.121 0.013569 0.017951 0.017429 + 3.122 0.013562 0.017942 0.017420 + 3.123 0.013555 0.017932 0.017411 + 3.124 0.013547 0.017923 0.017402 + 3.125 0.013540 0.017913 0.017393 + 3.126 0.013533 0.017904 0.017383 + 3.127 0.013526 0.017894 0.017374 + 3.128 0.013519 0.017885 0.017365 + 3.129 0.013511 0.017875 0.017356 + 3.130 0.013504 0.017866 0.017347 + 3.131 0.013497 0.017856 0.017338 + 3.132 0.013490 0.017847 0.017329 + 3.133 0.013483 0.017837 0.017320 + 3.134 0.013476 0.017828 0.017311 + 3.135 0.013468 0.017819 0.017302 + 3.136 0.013461 0.017809 0.017293 + 3.137 0.013454 0.017800 0.017284 + 3.138 0.013447 0.017790 0.017275 + 3.139 0.013440 0.017781 0.017266 + 3.140 0.013433 0.017772 0.017257 + 3.141 0.013426 0.017762 0.017248 + 3.142 0.013419 0.017753 0.017240 + 3.143 0.013411 0.017743 0.017231 + 3.144 0.013404 0.017734 0.017222 + 3.145 0.013397 0.017725 0.017213 + 3.146 0.013390 0.017715 0.017204 + 3.147 0.013383 0.017706 0.017195 + 3.148 0.013376 0.017697 0.017186 + 3.149 0.013369 0.017687 0.017177 + 3.150 0.013362 0.017678 0.017168 + 3.151 0.013355 0.017669 0.017159 + 3.152 0.013348 0.017660 0.017150 + 3.153 0.013341 0.017650 0.017142 + 3.154 0.013334 0.017641 0.017133 + 3.155 0.013327 0.017632 0.017124 + 3.156 0.013320 0.017622 0.017115 + 3.157 0.013313 0.017613 0.017106 + 3.158 0.013306 0.017604 0.017097 + 3.159 0.013299 0.017595 0.017089 + 3.160 0.013292 0.017586 0.017080 + 3.161 0.013285 0.017576 0.017071 + 3.162 0.013278 0.017567 0.017062 + 3.163 0.013271 0.017558 0.017053 + 3.164 0.013264 0.017549 0.017045 + 3.165 0.013257 0.017539 0.017036 + 3.166 0.013250 0.017530 0.017027 + 3.167 0.013243 0.017521 0.017018 + 3.168 0.013236 0.017512 0.017010 + 3.169 0.013229 0.017503 0.017001 + 3.170 0.013222 0.017494 0.016992 + 3.171 0.013215 0.017485 0.016983 + 3.172 0.013208 0.017475 0.016975 + 3.173 0.013201 0.017466 0.016966 + 3.174 0.013194 0.017457 0.016957 + 3.175 0.013187 0.017448 0.016948 + 3.176 0.013180 0.017439 0.016940 + 3.177 0.013173 0.017430 0.016931 + 3.178 0.013167 0.017421 0.016922 + 3.179 0.013160 0.017412 0.016914 + 3.180 0.013153 0.017403 0.016905 + 3.181 0.013146 0.017393 0.016896 + 3.182 0.013139 0.017384 0.016888 + 3.183 0.013132 0.017375 0.016879 + 3.184 0.013125 0.017366 0.016870 + 3.185 0.013118 0.017357 0.016862 + 3.186 0.013112 0.017348 0.016853 + 3.187 0.013105 0.017339 0.016845 + 3.188 0.013098 0.017330 0.016836 + 3.189 0.013091 0.017321 0.016827 + 3.190 0.013084 0.017312 0.016819 + 3.191 0.013077 0.017303 0.016810 + 3.192 0.013071 0.017294 0.016802 + 3.193 0.013064 0.017285 0.016793 + 3.194 0.013057 0.017276 0.016784 + 3.195 0.013050 0.017267 0.016776 + 3.196 0.013043 0.017258 0.016767 + 3.197 0.013037 0.017249 0.016759 + 3.198 0.013030 0.017241 0.016750 + 3.199 0.013023 0.017232 0.016742 + 3.200 0.013016 0.017223 0.016733 + 3.201 0.013010 0.017214 0.016725 + 3.202 0.013003 0.017205 0.016716 + 3.203 0.012996 0.017196 0.016708 + 3.204 0.012989 0.017187 0.016699 + 3.205 0.012983 0.017178 0.016691 + 3.206 0.012976 0.017169 0.016682 + 3.207 0.012969 0.017160 0.016674 + 3.208 0.012962 0.017152 0.016665 + 3.209 0.012956 0.017143 0.016657 + 3.210 0.012949 0.017134 0.016648 + 3.211 0.012942 0.017125 0.016640 + 3.212 0.012936 0.017116 0.016631 + 3.213 0.012929 0.017107 0.016623 + 3.214 0.012922 0.017098 0.016615 + 3.215 0.012915 0.017090 0.016606 + 3.216 0.012909 0.017081 0.016598 + 3.217 0.012902 0.017072 0.016589 + 3.218 0.012895 0.017063 0.016581 + 3.219 0.012889 0.017054 0.016573 + 3.220 0.012882 0.017046 0.016564 + 3.221 0.012875 0.017037 0.016556 + 3.222 0.012869 0.017028 0.016547 + 3.223 0.012862 0.017019 0.016539 + 3.224 0.012856 0.017011 0.016531 + 3.225 0.012849 0.017002 0.016522 + 3.226 0.012842 0.016993 0.016514 + 3.227 0.012836 0.016984 0.016506 + 3.228 0.012829 0.016976 0.016497 + 3.229 0.012822 0.016967 0.016489 + 3.230 0.012816 0.016958 0.016481 + 3.231 0.012809 0.016950 0.016472 + 3.232 0.012803 0.016941 0.016464 + 3.233 0.012796 0.016932 0.016456 + 3.234 0.012789 0.016924 0.016447 + 3.235 0.012783 0.016915 0.016439 + 3.236 0.012776 0.016906 0.016431 + 3.237 0.012770 0.016898 0.016423 + 3.238 0.012763 0.016889 0.016414 + 3.239 0.012757 0.016880 0.016406 + 3.240 0.012750 0.016872 0.016398 + 3.241 0.012744 0.016863 0.016390 + 3.242 0.012737 0.016854 0.016381 + 3.243 0.012730 0.016846 0.016373 + 3.244 0.012724 0.016837 0.016365 + 3.245 0.012717 0.016829 0.016357 + 3.246 0.012711 0.016820 0.016348 + 3.247 0.012704 0.016811 0.016340 + 3.248 0.012698 0.016803 0.016332 + 3.249 0.012691 0.016794 0.016324 + 3.250 0.012685 0.016786 0.016316 + 3.251 0.012678 0.016777 0.016307 + 3.252 0.012672 0.016769 0.016299 + 3.253 0.012665 0.016760 0.016291 + 3.254 0.012659 0.016751 0.016283 + 3.255 0.012653 0.016743 0.016275 + 3.256 0.012646 0.016734 0.016267 + 3.257 0.012640 0.016726 0.016258 + 3.258 0.012633 0.016717 0.016250 + 3.259 0.012627 0.016709 0.016242 + 3.260 0.012620 0.016700 0.016234 + 3.261 0.012614 0.016692 0.016226 + 3.262 0.012607 0.016683 0.016218 + 3.263 0.012601 0.016675 0.016210 + 3.264 0.012595 0.016666 0.016202 + 3.265 0.012588 0.016658 0.016194 + 3.266 0.012582 0.016650 0.016185 + 3.267 0.012575 0.016641 0.016177 + 3.268 0.012569 0.016633 0.016169 + 3.269 0.012562 0.016624 0.016161 + 3.270 0.012556 0.016616 0.016153 + 3.271 0.012550 0.016607 0.016145 + 3.272 0.012543 0.016599 0.016137 + 3.273 0.012537 0.016591 0.016129 + 3.274 0.012531 0.016582 0.016121 + 3.275 0.012524 0.016574 0.016113 + 3.276 0.012518 0.016565 0.016105 + 3.277 0.012512 0.016557 0.016097 + 3.278 0.012505 0.016549 0.016089 + 3.279 0.012499 0.016540 0.016081 + 3.280 0.012492 0.016532 0.016073 + 3.281 0.012486 0.016524 0.016065 + 3.282 0.012480 0.016515 0.016057 + 3.283 0.012473 0.016507 0.016049 + 3.284 0.012467 0.016499 0.016041 + 3.285 0.012461 0.016490 0.016033 + 3.286 0.012455 0.016482 0.016025 + 3.287 0.012448 0.016474 0.016017 + 3.288 0.012442 0.016465 0.016009 + 3.289 0.012436 0.016457 0.016001 + 3.290 0.012429 0.016449 0.015993 + 3.291 0.012423 0.016440 0.015985 + 3.292 0.012417 0.016432 0.015978 + 3.293 0.012411 0.016424 0.015970 + 3.294 0.012404 0.016416 0.015962 + 3.295 0.012398 0.016407 0.015954 + 3.296 0.012392 0.016399 0.015946 + 3.297 0.012385 0.016391 0.015938 + 3.298 0.012379 0.016383 0.015930 + 3.299 0.012373 0.016374 0.015922 + 3.300 0.012367 0.016366 0.015914 + 3.301 0.012361 0.016358 0.015907 + 3.302 0.012354 0.016350 0.015899 + 3.303 0.012348 0.016342 0.015891 + 3.304 0.012342 0.016333 0.015883 + 3.305 0.012336 0.016325 0.015875 + 3.306 0.012329 0.016317 0.015867 + 3.307 0.012323 0.016309 0.015859 + 3.308 0.012317 0.016301 0.015852 + 3.309 0.012311 0.016292 0.015844 + 3.310 0.012305 0.016284 0.015836 + 3.311 0.012298 0.016276 0.015828 + 3.312 0.012292 0.016268 0.015820 + 3.313 0.012286 0.016260 0.015813 + 3.314 0.012280 0.016252 0.015805 + 3.315 0.012274 0.016244 0.015797 + 3.316 0.012268 0.016235 0.015789 + 3.317 0.012261 0.016227 0.015782 + 3.318 0.012255 0.016219 0.015774 + 3.319 0.012249 0.016211 0.015766 + 3.320 0.012243 0.016203 0.015758 + 3.321 0.012237 0.016195 0.015751 + 3.322 0.012231 0.016187 0.015743 + 3.323 0.012225 0.016179 0.015735 + 3.324 0.012219 0.016171 0.015727 + 3.325 0.012212 0.016163 0.015720 + 3.326 0.012206 0.016155 0.015712 + 3.327 0.012200 0.016147 0.015704 + 3.328 0.012194 0.016139 0.015697 + 3.329 0.012188 0.016130 0.015689 + 3.330 0.012182 0.016122 0.015681 + 3.331 0.012176 0.016114 0.015674 + 3.332 0.012170 0.016106 0.015666 + 3.333 0.012164 0.016098 0.015658 + 3.334 0.012158 0.016090 0.015651 + 3.335 0.012152 0.016082 0.015643 + 3.336 0.012146 0.016074 0.015635 + 3.337 0.012139 0.016066 0.015628 + 3.338 0.012133 0.016058 0.015620 + 3.339 0.012127 0.016050 0.015612 + 3.340 0.012121 0.016043 0.015605 + 3.341 0.012115 0.016035 0.015597 + 3.342 0.012109 0.016027 0.015589 + 3.343 0.012103 0.016019 0.015582 + 3.344 0.012097 0.016011 0.015574 + 3.345 0.012091 0.016003 0.015567 + 3.346 0.012085 0.015995 0.015559 + 3.347 0.012079 0.015987 0.015551 + 3.348 0.012073 0.015979 0.015544 + 3.349 0.012067 0.015971 0.015536 + 3.350 0.012061 0.015963 0.015529 + 3.351 0.012055 0.015955 0.015521 + 3.352 0.012049 0.015947 0.015514 + 3.353 0.012043 0.015940 0.015506 + 3.354 0.012037 0.015932 0.015499 + 3.355 0.012031 0.015924 0.015491 + 3.356 0.012025 0.015916 0.015483 + 3.357 0.012019 0.015908 0.015476 + 3.358 0.012013 0.015900 0.015468 + 3.359 0.012007 0.015892 0.015461 + 3.360 0.012002 0.015885 0.015453 + 3.361 0.011996 0.015877 0.015446 + 3.362 0.011990 0.015869 0.015438 + 3.363 0.011984 0.015861 0.015431 + 3.364 0.011978 0.015853 0.015423 + 3.365 0.011972 0.015845 0.015416 + 3.366 0.011966 0.015838 0.015408 + 3.367 0.011960 0.015830 0.015401 + 3.368 0.011954 0.015822 0.015394 + 3.369 0.011948 0.015814 0.015386 + 3.370 0.011942 0.015806 0.015379 + 3.371 0.011936 0.015799 0.015371 + 3.372 0.011931 0.015791 0.015364 + 3.373 0.011925 0.015783 0.015356 + 3.374 0.011919 0.015775 0.015349 + 3.375 0.011913 0.015768 0.015342 + 3.376 0.011907 0.015760 0.015334 + 3.377 0.011901 0.015752 0.015327 + 3.378 0.011895 0.015744 0.015319 + 3.379 0.011889 0.015737 0.015312 + 3.380 0.011884 0.015729 0.015304 + 3.381 0.011878 0.015721 0.015297 + 3.382 0.011872 0.015714 0.015290 + 3.383 0.011866 0.015706 0.015282 + 3.384 0.011860 0.015698 0.015275 + 3.385 0.011854 0.015690 0.015268 + 3.386 0.011849 0.015683 0.015260 + 3.387 0.011843 0.015675 0.015253 + 3.388 0.011837 0.015667 0.015246 + 3.389 0.011831 0.015660 0.015238 + 3.390 0.011825 0.015652 0.015231 + 3.391 0.011820 0.015644 0.015224 + 3.392 0.011814 0.015637 0.015216 + 3.393 0.011808 0.015629 0.015209 + 3.394 0.011802 0.015622 0.015202 + 3.395 0.011796 0.015614 0.015194 + 3.396 0.011791 0.015606 0.015187 + 3.397 0.011785 0.015599 0.015180 + 3.398 0.011779 0.015591 0.015172 + 3.399 0.011773 0.015583 0.015165 + 3.400 0.011768 0.015576 0.015158 + 3.401 0.011762 0.015568 0.015151 + 3.402 0.011756 0.015561 0.015143 + 3.403 0.011750 0.015553 0.015136 + 3.404 0.011745 0.015546 0.015129 + 3.405 0.011739 0.015538 0.015122 + 3.406 0.011733 0.015530 0.015114 + 3.407 0.011727 0.015523 0.015107 + 3.408 0.011722 0.015515 0.015100 + 3.409 0.011716 0.015508 0.015093 + 3.410 0.011710 0.015500 0.015085 + 3.411 0.011704 0.015493 0.015078 + 3.412 0.011699 0.015485 0.015071 + 3.413 0.011693 0.015478 0.015064 + 3.414 0.011687 0.015470 0.015057 + 3.415 0.011682 0.015463 0.015049 + 3.416 0.011676 0.015455 0.015042 + 3.417 0.011670 0.015448 0.015035 + 3.418 0.011665 0.015440 0.015028 + 3.419 0.011659 0.015433 0.015021 + 3.420 0.011653 0.015425 0.015013 + 3.421 0.011648 0.015418 0.015006 + 3.422 0.011642 0.015410 0.014999 + 3.423 0.011636 0.015403 0.014992 + 3.424 0.011631 0.015395 0.014985 + 3.425 0.011625 0.015388 0.014978 + 3.426 0.011619 0.015380 0.014971 + 3.427 0.011614 0.015373 0.014963 + 3.428 0.011608 0.015365 0.014956 + 3.429 0.011602 0.015358 0.014949 + 3.430 0.011597 0.015351 0.014942 + 3.431 0.011591 0.015343 0.014935 + 3.432 0.011586 0.015336 0.014928 + 3.433 0.011580 0.015328 0.014921 + 3.434 0.011574 0.015321 0.014914 + 3.435 0.011569 0.015314 0.014907 + 3.436 0.011563 0.015306 0.014899 + 3.437 0.011558 0.015299 0.014892 + 3.438 0.011552 0.015291 0.014885 + 3.439 0.011546 0.015284 0.014878 + 3.440 0.011541 0.015277 0.014871 + 3.441 0.011535 0.015269 0.014864 + 3.442 0.011530 0.015262 0.014857 + 3.443 0.011524 0.015255 0.014850 + 3.444 0.011518 0.015247 0.014843 + 3.445 0.011513 0.015240 0.014836 + 3.446 0.011507 0.015233 0.014829 + 3.447 0.011502 0.015225 0.014822 + 3.448 0.011496 0.015218 0.014815 + 3.449 0.011491 0.015211 0.014808 + 3.450 0.011485 0.015203 0.014801 + 3.451 0.011480 0.015196 0.014794 + 3.452 0.011474 0.015189 0.014787 + 3.453 0.011469 0.015181 0.014780 + 3.454 0.011463 0.015174 0.014773 + 3.455 0.011458 0.015167 0.014766 + 3.456 0.011452 0.015160 0.014759 + 3.457 0.011446 0.015152 0.014752 + 3.458 0.011441 0.015145 0.014745 + 3.459 0.011435 0.015138 0.014738 + 3.460 0.011430 0.015131 0.014731 + 3.461 0.011424 0.015123 0.014724 + 3.462 0.011419 0.015116 0.014717 + 3.463 0.011414 0.015109 0.014710 + 3.464 0.011408 0.015102 0.014703 + 3.465 0.011403 0.015094 0.014696 + 3.466 0.011397 0.015087 0.014690 + 3.467 0.011392 0.015080 0.014683 + 3.468 0.011386 0.015073 0.014676 + 3.469 0.011381 0.015066 0.014669 + 3.470 0.011375 0.015058 0.014662 + 3.471 0.011370 0.015051 0.014655 + 3.472 0.011364 0.015044 0.014648 + 3.473 0.011359 0.015037 0.014641 + 3.474 0.011353 0.015030 0.014634 + 3.475 0.011348 0.015022 0.014627 + 3.476 0.011343 0.015015 0.014621 + 3.477 0.011337 0.015008 0.014614 + 3.478 0.011332 0.015001 0.014607 + 3.479 0.011326 0.014994 0.014600 + 3.480 0.011321 0.014987 0.014593 + 3.481 0.011315 0.014979 0.014586 + 3.482 0.011310 0.014972 0.014579 + 3.483 0.011305 0.014965 0.014573 + 3.484 0.011299 0.014958 0.014566 + 3.485 0.011294 0.014951 0.014559 + 3.486 0.011288 0.014944 0.014552 + 3.487 0.011283 0.014937 0.014545 + 3.488 0.011278 0.014930 0.014539 + 3.489 0.011272 0.014923 0.014532 + 3.490 0.011267 0.014915 0.014525 + 3.491 0.011262 0.014908 0.014518 + 3.492 0.011256 0.014901 0.014511 + 3.493 0.011251 0.014894 0.014505 + 3.494 0.011246 0.014887 0.014498 + 3.495 0.011240 0.014880 0.014491 + 3.496 0.011235 0.014873 0.014484 + 3.497 0.011229 0.014866 0.014478 + 3.498 0.011224 0.014859 0.014471 + 3.499 0.011219 0.014852 0.014464 + 3.500 0.011213 0.014845 0.014457 + 3.501 0.011208 0.014838 0.014451 + 3.502 0.011203 0.014831 0.014444 + 3.503 0.011197 0.014824 0.014437 + 3.504 0.011192 0.014817 0.014430 + 3.505 0.011187 0.014810 0.014424 + 3.506 0.011182 0.014803 0.014417 + 3.507 0.011176 0.014796 0.014410 + 3.508 0.011171 0.014789 0.014403 + 3.509 0.011166 0.014782 0.014397 + 3.510 0.011160 0.014775 0.014390 + 3.511 0.011155 0.014768 0.014383 + 3.512 0.011150 0.014761 0.014377 + 3.513 0.011144 0.014754 0.014370 + 3.514 0.011139 0.014747 0.014363 + 3.515 0.011134 0.014740 0.014357 + 3.516 0.011129 0.014733 0.014350 + 3.517 0.011123 0.014726 0.014343 + 3.518 0.011118 0.014719 0.014337 + 3.519 0.011113 0.014712 0.014330 + 3.520 0.011108 0.014705 0.014323 + 3.521 0.011102 0.014698 0.014317 + 3.522 0.011097 0.014691 0.014310 + 3.523 0.011092 0.014685 0.014303 + 3.524 0.011087 0.014678 0.014297 + 3.525 0.011081 0.014671 0.014290 + 3.526 0.011076 0.014664 0.014284 + 3.527 0.011071 0.014657 0.014277 + 3.528 0.011066 0.014650 0.014270 + 3.529 0.011061 0.014643 0.014264 + 3.530 0.011055 0.014636 0.014257 + 3.531 0.011050 0.014629 0.014251 + 3.532 0.011045 0.014623 0.014244 + 3.533 0.011040 0.014616 0.014237 + 3.534 0.011035 0.014609 0.014231 + 3.535 0.011029 0.014602 0.014224 + 3.536 0.011024 0.014595 0.014218 + 3.537 0.011019 0.014588 0.014211 + 3.538 0.011014 0.014581 0.014205 + 3.539 0.011009 0.014575 0.014198 + 3.540 0.011003 0.014568 0.014191 + 3.541 0.010998 0.014561 0.014185 + 3.542 0.010993 0.014554 0.014178 + 3.543 0.010988 0.014547 0.014172 + 3.544 0.010983 0.014540 0.014165 + 3.545 0.010978 0.014534 0.014159 + 3.546 0.010972 0.014527 0.014152 + 3.547 0.010967 0.014520 0.014146 + 3.548 0.010962 0.014513 0.014139 + 3.549 0.010957 0.014507 0.014133 + 3.550 0.010952 0.014500 0.014126 + 3.551 0.010947 0.014493 0.014120 + 3.552 0.010942 0.014486 0.014113 + 3.553 0.010937 0.014479 0.014107 + 3.554 0.010931 0.014473 0.014100 + 3.555 0.010926 0.014466 0.014094 + 3.556 0.010921 0.014459 0.014087 + 3.557 0.010916 0.014452 0.014081 + 3.558 0.010911 0.014446 0.014074 + 3.559 0.010906 0.014439 0.014068 + 3.560 0.010901 0.014432 0.014061 + 3.561 0.010896 0.014426 0.014055 + 3.562 0.010891 0.014419 0.014049 + 3.563 0.010885 0.014412 0.014042 + 3.564 0.010880 0.014405 0.014036 + 3.565 0.010875 0.014399 0.014029 + 3.566 0.010870 0.014392 0.014023 + 3.567 0.010865 0.014385 0.014016 + 3.568 0.010860 0.014379 0.014010 + 3.569 0.010855 0.014372 0.014004 + 3.570 0.010850 0.014365 0.013997 + 3.571 0.010845 0.014359 0.013991 + 3.572 0.010840 0.014352 0.013984 + 3.573 0.010835 0.014345 0.013978 + 3.574 0.010830 0.014339 0.013972 + 3.575 0.010825 0.014332 0.013965 + 3.576 0.010820 0.014325 0.013959 + 3.577 0.010815 0.014319 0.013952 + 3.578 0.010810 0.014312 0.013946 + 3.579 0.010805 0.014305 0.013940 + 3.580 0.010800 0.014299 0.013933 + 3.581 0.010795 0.014292 0.013927 + 3.582 0.010790 0.014286 0.013921 + 3.583 0.010785 0.014279 0.013914 + 3.584 0.010780 0.014272 0.013908 + 3.585 0.010775 0.014266 0.013902 + 3.586 0.010770 0.014259 0.013895 + 3.587 0.010765 0.014253 0.013889 + 3.588 0.010760 0.014246 0.013883 + 3.589 0.010755 0.014239 0.013876 + 3.590 0.010750 0.014233 0.013870 + 3.591 0.010745 0.014226 0.013864 + 3.592 0.010740 0.014220 0.013857 + 3.593 0.010735 0.014213 0.013851 + 3.594 0.010730 0.014207 0.013845 + 3.595 0.010725 0.014200 0.013838 + 3.596 0.010720 0.014193 0.013832 + 3.597 0.010715 0.014187 0.013826 + 3.598 0.010710 0.014180 0.013820 + 3.599 0.010705 0.014174 0.013813 + 3.600 0.010700 0.014167 0.013807 + 3.601 0.010695 0.014161 0.013801 + 3.602 0.010690 0.014154 0.013795 + 3.603 0.010685 0.014148 0.013788 + 3.604 0.010680 0.014141 0.013782 + 3.605 0.010675 0.014135 0.013776 + 3.606 0.010670 0.014128 0.013770 + 3.607 0.010665 0.014122 0.013763 + 3.608 0.010661 0.014115 0.013757 + 3.609 0.010656 0.014109 0.013751 + 3.610 0.010651 0.014102 0.013745 + 3.611 0.010646 0.014096 0.013738 + 3.612 0.010641 0.014089 0.013732 + 3.613 0.010636 0.014083 0.013726 + 3.614 0.010631 0.014076 0.013720 + 3.615 0.010626 0.014070 0.013714 + 3.616 0.010621 0.014063 0.013707 + 3.617 0.010616 0.014057 0.013701 + 3.618 0.010612 0.014051 0.013695 + 3.619 0.010607 0.014044 0.013689 + 3.620 0.010602 0.014038 0.013683 + 3.621 0.010597 0.014031 0.013676 + 3.622 0.010592 0.014025 0.013670 + 3.623 0.010587 0.014018 0.013664 + 3.624 0.010582 0.014012 0.013658 + 3.625 0.010577 0.014006 0.013652 + 3.626 0.010573 0.013999 0.013646 + 3.627 0.010568 0.013993 0.013640 + 3.628 0.010563 0.013986 0.013633 + 3.629 0.010558 0.013980 0.013627 + 3.630 0.010553 0.013974 0.013621 + 3.631 0.010548 0.013967 0.013615 + 3.632 0.010544 0.013961 0.013609 + 3.633 0.010539 0.013954 0.013603 + 3.634 0.010534 0.013948 0.013597 + 3.635 0.010529 0.013942 0.013590 + 3.636 0.010524 0.013935 0.013584 + 3.637 0.010519 0.013929 0.013578 + 3.638 0.010515 0.013923 0.013572 + 3.639 0.010510 0.013916 0.013566 + 3.640 0.010505 0.013910 0.013560 + 3.641 0.010500 0.013904 0.013554 + 3.642 0.010495 0.013897 0.013548 + 3.643 0.010491 0.013891 0.013542 + 3.644 0.010486 0.013885 0.013536 + 3.645 0.010481 0.013878 0.013530 + 3.646 0.010476 0.013872 0.013524 + 3.647 0.010471 0.013866 0.013517 + 3.648 0.010467 0.013859 0.013511 + 3.649 0.010462 0.013853 0.013505 + 3.650 0.010457 0.013847 0.013499 + 3.651 0.010452 0.013841 0.013493 + 3.652 0.010448 0.013834 0.013487 + 3.653 0.010443 0.013828 0.013481 + 3.654 0.010438 0.013822 0.013475 + 3.655 0.010433 0.013815 0.013469 + 3.656 0.010429 0.013809 0.013463 + 3.657 0.010424 0.013803 0.013457 + 3.658 0.010419 0.013797 0.013451 + 3.659 0.010414 0.013790 0.013445 + 3.660 0.010410 0.013784 0.013439 + 3.661 0.010405 0.013778 0.013433 + 3.662 0.010400 0.013772 0.013427 + 3.663 0.010395 0.013765 0.013421 + 3.664 0.010391 0.013759 0.013415 + 3.665 0.010386 0.013753 0.013409 + 3.666 0.010381 0.013747 0.013403 + 3.667 0.010377 0.013741 0.013397 + 3.668 0.010372 0.013734 0.013391 + 3.669 0.010367 0.013728 0.013385 + 3.670 0.010363 0.013722 0.013379 + 3.671 0.010358 0.013716 0.013373 + 3.672 0.010353 0.013710 0.013367 + 3.673 0.010348 0.013703 0.013361 + 3.674 0.010344 0.013697 0.013355 + 3.675 0.010339 0.013691 0.013350 + 3.676 0.010334 0.013685 0.013344 + 3.677 0.010330 0.013679 0.013338 + 3.678 0.010325 0.013672 0.013332 + 3.679 0.010320 0.013666 0.013326 + 3.680 0.010316 0.013660 0.013320 + 3.681 0.010311 0.013654 0.013314 + 3.682 0.010306 0.013648 0.013308 + 3.683 0.010302 0.013642 0.013302 + 3.684 0.010297 0.013636 0.013296 + 3.685 0.010292 0.013629 0.013290 + 3.686 0.010288 0.013623 0.013284 + 3.687 0.010283 0.013617 0.013279 + 3.688 0.010279 0.013611 0.013273 + 3.689 0.010274 0.013605 0.013267 + 3.690 0.010269 0.013599 0.013261 + 3.691 0.010265 0.013593 0.013255 + 3.692 0.010260 0.013587 0.013249 + 3.693 0.010255 0.013580 0.013243 + 3.694 0.010251 0.013574 0.013237 + 3.695 0.010246 0.013568 0.013232 + 3.696 0.010242 0.013562 0.013226 + 3.697 0.010237 0.013556 0.013220 + 3.698 0.010232 0.013550 0.013214 + 3.699 0.010228 0.013544 0.013208 + 3.700 0.010223 0.013538 0.013202 + 3.701 0.010218 0.013532 0.013197 + 3.702 0.010214 0.013526 0.013191 + 3.703 0.010209 0.013520 0.013185 + 3.704 0.010205 0.013514 0.013179 + 3.705 0.010200 0.013508 0.013173 + 3.706 0.010196 0.013502 0.013167 + 3.707 0.010191 0.013495 0.013162 + 3.708 0.010186 0.013489 0.013156 + 3.709 0.010182 0.013483 0.013150 + 3.710 0.010177 0.013477 0.013144 + 3.711 0.010173 0.013471 0.013138 + 3.712 0.010168 0.013465 0.013133 + 3.713 0.010164 0.013459 0.013127 + 3.714 0.010159 0.013453 0.013121 + 3.715 0.010154 0.013447 0.013115 + 3.716 0.010150 0.013441 0.013110 + 3.717 0.010145 0.013435 0.013104 + 3.718 0.010141 0.013429 0.013098 + 3.719 0.010136 0.013423 0.013092 + 3.720 0.010132 0.013417 0.013087 + 3.721 0.010127 0.013411 0.013081 + 3.722 0.010123 0.013405 0.013075 + 3.723 0.010118 0.013399 0.013069 + 3.724 0.010114 0.013393 0.013064 + 3.725 0.010109 0.013387 0.013058 + 3.726 0.010105 0.013382 0.013052 + 3.727 0.010100 0.013376 0.013046 + 3.728 0.010096 0.013370 0.013041 + 3.729 0.010091 0.013364 0.013035 + 3.730 0.010087 0.013358 0.013029 + 3.731 0.010082 0.013352 0.013024 + 3.732 0.010078 0.013346 0.013018 + 3.733 0.010073 0.013340 0.013012 + 3.734 0.010069 0.013334 0.013006 + 3.735 0.010064 0.013328 0.013001 + 3.736 0.010060 0.013322 0.012995 + 3.737 0.010055 0.013316 0.012989 + 3.738 0.010051 0.013310 0.012984 + 3.739 0.010046 0.013304 0.012978 + 3.740 0.010042 0.013299 0.012972 + 3.741 0.010037 0.013293 0.012967 + 3.742 0.010033 0.013287 0.012961 + 3.743 0.010028 0.013281 0.012955 + 3.744 0.010024 0.013275 0.012950 + 3.745 0.010019 0.013269 0.012944 + 3.746 0.010015 0.013263 0.012938 + 3.747 0.010011 0.013257 0.012933 + 3.748 0.010006 0.013251 0.012927 + 3.749 0.010002 0.013246 0.012921 + 3.750 0.009997 0.013240 0.012916 + 3.751 0.009993 0.013234 0.012910 + 3.752 0.009988 0.013228 0.012905 + 3.753 0.009984 0.013222 0.012899 + 3.754 0.009980 0.013216 0.012893 + 3.755 0.009975 0.013211 0.012888 + 3.756 0.009971 0.013205 0.012882 + 3.757 0.009966 0.013199 0.012876 + 3.758 0.009962 0.013193 0.012871 + 3.759 0.009957 0.013187 0.012865 + 3.760 0.009953 0.013181 0.012860 + 3.761 0.009949 0.013176 0.012854 + 3.762 0.009944 0.013170 0.012849 + 3.763 0.009940 0.013164 0.012843 + 3.764 0.009935 0.013158 0.012837 + 3.765 0.009931 0.013152 0.012832 + 3.766 0.009927 0.013147 0.012826 + 3.767 0.009922 0.013141 0.012821 + 3.768 0.009918 0.013135 0.012815 + 3.769 0.009914 0.013129 0.012810 + 3.770 0.009909 0.013123 0.012804 + 3.771 0.009905 0.013118 0.012798 + 3.772 0.009900 0.013112 0.012793 + 3.773 0.009896 0.013106 0.012787 + 3.774 0.009892 0.013100 0.012782 + 3.775 0.009887 0.013095 0.012776 + 3.776 0.009883 0.013089 0.012771 + 3.777 0.009879 0.013083 0.012765 + 3.778 0.009874 0.013077 0.012760 + 3.779 0.009870 0.013072 0.012754 + 3.780 0.009866 0.013066 0.012749 + 3.781 0.009861 0.013060 0.012743 + 3.782 0.009857 0.013054 0.012738 + 3.783 0.009853 0.013049 0.012732 + 3.784 0.009848 0.013043 0.012727 + 3.785 0.009844 0.013037 0.012721 + 3.786 0.009840 0.013032 0.012716 + 3.787 0.009835 0.013026 0.012710 + 3.788 0.009831 0.013020 0.012705 + 3.789 0.009827 0.013014 0.012699 + 3.790 0.009822 0.013009 0.012694 + 3.791 0.009818 0.013003 0.012688 + 3.792 0.009814 0.012997 0.012683 + 3.793 0.009809 0.012992 0.012677 + 3.794 0.009805 0.012986 0.012672 + 3.795 0.009801 0.012980 0.012666 + 3.796 0.009796 0.012975 0.012661 + 3.797 0.009792 0.012969 0.012655 + 3.798 0.009788 0.012963 0.012650 + 3.799 0.009784 0.012958 0.012645 + 3.800 0.009779 0.012952 0.012639 + 3.801 0.009775 0.012946 0.012634 + 3.802 0.009771 0.012941 0.012628 + 3.803 0.009767 0.012935 0.012623 + 3.804 0.009762 0.012929 0.012617 + 3.805 0.009758 0.012924 0.012612 + 3.806 0.009754 0.012918 0.012606 + 3.807 0.009749 0.012913 0.012601 + 3.808 0.009745 0.012907 0.012596 + 3.809 0.009741 0.012901 0.012590 + 3.810 0.009737 0.012896 0.012585 + 3.811 0.009732 0.012890 0.012579 + 3.812 0.009728 0.012884 0.012574 + 3.813 0.009724 0.012879 0.012569 + 3.814 0.009720 0.012873 0.012563 + 3.815 0.009715 0.012868 0.012558 + 3.816 0.009711 0.012862 0.012552 + 3.817 0.009707 0.012856 0.012547 + 3.818 0.009703 0.012851 0.012542 + 3.819 0.009699 0.012845 0.012536 + 3.820 0.009694 0.012840 0.012531 + 3.821 0.009690 0.012834 0.012526 + 3.822 0.009686 0.012829 0.012520 + 3.823 0.009682 0.012823 0.012515 + 3.824 0.009677 0.012817 0.012510 + 3.825 0.009673 0.012812 0.012504 + 3.826 0.009669 0.012806 0.012499 + 3.827 0.009665 0.012801 0.012494 + 3.828 0.009661 0.012795 0.012488 + 3.829 0.009656 0.012790 0.012483 + 3.830 0.009652 0.012784 0.012478 + 3.831 0.009648 0.012779 0.012472 + 3.832 0.009644 0.012773 0.012467 + 3.833 0.009640 0.012768 0.012462 + 3.834 0.009635 0.012762 0.012456 + 3.835 0.009631 0.012757 0.012451 + 3.836 0.009627 0.012751 0.012446 + 3.837 0.009623 0.012745 0.012440 + 3.838 0.009619 0.012740 0.012435 + 3.839 0.009615 0.012734 0.012430 + 3.840 0.009610 0.012729 0.012424 + 3.841 0.009606 0.012723 0.012419 + 3.842 0.009602 0.012718 0.012414 + 3.843 0.009598 0.012712 0.012409 + 3.844 0.009594 0.012707 0.012403 + 3.845 0.009590 0.012702 0.012398 + 3.846 0.009585 0.012696 0.012393 + 3.847 0.009581 0.012691 0.012387 + 3.848 0.009577 0.012685 0.012382 + 3.849 0.009573 0.012680 0.012377 + 3.850 0.009569 0.012674 0.012372 + 3.851 0.009565 0.012669 0.012366 + 3.852 0.009561 0.012663 0.012361 + 3.853 0.009557 0.012658 0.012356 + 3.854 0.009552 0.012652 0.012351 + 3.855 0.009548 0.012647 0.012345 + 3.856 0.009544 0.012641 0.012340 + 3.857 0.009540 0.012636 0.012335 + 3.858 0.009536 0.012631 0.012330 + 3.859 0.009532 0.012625 0.012324 + 3.860 0.009528 0.012620 0.012319 + 3.861 0.009524 0.012614 0.012314 + 3.862 0.009519 0.012609 0.012309 + 3.863 0.009515 0.012603 0.012304 + 3.864 0.009511 0.012598 0.012298 + 3.865 0.009507 0.012593 0.012293 + 3.866 0.009503 0.012587 0.012288 + 3.867 0.009499 0.012582 0.012283 + 3.868 0.009495 0.012576 0.012278 + 3.869 0.009491 0.012571 0.012272 + 3.870 0.009487 0.012566 0.012267 + 3.871 0.009483 0.012560 0.012262 + 3.872 0.009479 0.012555 0.012257 + 3.873 0.009475 0.012550 0.012252 + 3.874 0.009470 0.012544 0.012247 + 3.875 0.009466 0.012539 0.012241 + 3.876 0.009462 0.012533 0.012236 + 3.877 0.009458 0.012528 0.012231 + 3.878 0.009454 0.012523 0.012226 + 3.879 0.009450 0.012517 0.012221 + 3.880 0.009446 0.012512 0.012216 + 3.881 0.009442 0.012507 0.012210 + 3.882 0.009438 0.012501 0.012205 + 3.883 0.009434 0.012496 0.012200 + 3.884 0.009430 0.012491 0.012195 + 3.885 0.009426 0.012485 0.012190 + 3.886 0.009422 0.012480 0.012185 + 3.887 0.009418 0.012475 0.012180 + 3.888 0.009414 0.012469 0.012174 + 3.889 0.009410 0.012464 0.012169 + 3.890 0.009406 0.012459 0.012164 + 3.891 0.009402 0.012453 0.012159 + 3.892 0.009398 0.012448 0.012154 + 3.893 0.009394 0.012443 0.012149 + 3.894 0.009390 0.012437 0.012144 + 3.895 0.009386 0.012432 0.012139 + 3.896 0.009382 0.012427 0.012134 + 3.897 0.009378 0.012422 0.012128 + 3.898 0.009374 0.012416 0.012123 + 3.899 0.009370 0.012411 0.012118 + 3.900 0.009366 0.012406 0.012113 + 3.901 0.009362 0.012400 0.012108 + 3.902 0.009358 0.012395 0.012103 + 3.903 0.009354 0.012390 0.012098 + 3.904 0.009350 0.012385 0.012093 + 3.905 0.009346 0.012379 0.012088 + 3.906 0.009342 0.012374 0.012083 + 3.907 0.009338 0.012369 0.012078 + 3.908 0.009334 0.012364 0.012073 + 3.909 0.009330 0.012358 0.012068 + 3.910 0.009326 0.012353 0.012063 + 3.911 0.009322 0.012348 0.012057 + 3.912 0.009318 0.012343 0.012052 + 3.913 0.009314 0.012337 0.012047 + 3.914 0.009310 0.012332 0.012042 + 3.915 0.009306 0.012327 0.012037 + 3.916 0.009302 0.012322 0.012032 + 3.917 0.009298 0.012317 0.012027 + 3.918 0.009294 0.012311 0.012022 + 3.919 0.009290 0.012306 0.012017 + 3.920 0.009286 0.012301 0.012012 + 3.921 0.009282 0.012296 0.012007 + 3.922 0.009278 0.012290 0.012002 + 3.923 0.009274 0.012285 0.011997 + 3.924 0.009270 0.012280 0.011992 + 3.925 0.009267 0.012275 0.011987 + 3.926 0.009263 0.012270 0.011982 + 3.927 0.009259 0.012265 0.011977 + 3.928 0.009255 0.012259 0.011972 + 3.929 0.009251 0.012254 0.011967 + 3.930 0.009247 0.012249 0.011962 + 3.931 0.009243 0.012244 0.011957 + 3.932 0.009239 0.012239 0.011952 + 3.933 0.009235 0.012233 0.011947 + 3.934 0.009231 0.012228 0.011942 + 3.935 0.009227 0.012223 0.011937 + 3.936 0.009223 0.012218 0.011932 + 3.937 0.009220 0.012213 0.011927 + 3.938 0.009216 0.012208 0.011923 + 3.939 0.009212 0.012203 0.011918 + 3.940 0.009208 0.012197 0.011913 + 3.941 0.009204 0.012192 0.011908 + 3.942 0.009200 0.012187 0.011903 + 3.943 0.009196 0.012182 0.011898 + 3.944 0.009192 0.012177 0.011893 + 3.945 0.009189 0.012172 0.011888 + 3.946 0.009185 0.012167 0.011883 + 3.947 0.009181 0.012162 0.011878 + 3.948 0.009177 0.012156 0.011873 + 3.949 0.009173 0.012151 0.011868 + 3.950 0.009169 0.012146 0.011863 + 3.951 0.009165 0.012141 0.011858 + 3.952 0.009161 0.012136 0.011853 + 3.953 0.009158 0.012131 0.011849 + 3.954 0.009154 0.012126 0.011844 + 3.955 0.009150 0.012121 0.011839 + 3.956 0.009146 0.012116 0.011834 + 3.957 0.009142 0.012111 0.011829 + 3.958 0.009138 0.012106 0.011824 + 3.959 0.009134 0.012100 0.011819 + 3.960 0.009131 0.012095 0.011814 + 3.961 0.009127 0.012090 0.011809 + 3.962 0.009123 0.012085 0.011805 + 3.963 0.009119 0.012080 0.011800 + 3.964 0.009115 0.012075 0.011795 + 3.965 0.009112 0.012070 0.011790 + 3.966 0.009108 0.012065 0.011785 + 3.967 0.009104 0.012060 0.011780 + 3.968 0.009100 0.012055 0.011775 + 3.969 0.009096 0.012050 0.011770 + 3.970 0.009092 0.012045 0.011766 + 3.971 0.009089 0.012040 0.011761 + 3.972 0.009085 0.012035 0.011756 + 3.973 0.009081 0.012030 0.011751 + 3.974 0.009077 0.012025 0.011746 + 3.975 0.009073 0.012020 0.011741 + 3.976 0.009070 0.012015 0.011737 + 3.977 0.009066 0.012010 0.011732 + 3.978 0.009062 0.012005 0.011727 + 3.979 0.009058 0.012000 0.011722 + 3.980 0.009054 0.011995 0.011717 + 3.981 0.009051 0.011990 0.011712 + 3.982 0.009047 0.011985 0.011708 + 3.983 0.009043 0.011980 0.011703 + 3.984 0.009039 0.011975 0.011698 + 3.985 0.009036 0.011970 0.011693 + 3.986 0.009032 0.011965 0.011688 + 3.987 0.009028 0.011960 0.011684 + 3.988 0.009024 0.011955 0.011679 + 3.989 0.009020 0.011950 0.011674 + 3.990 0.009017 0.011945 0.011669 + 3.991 0.009013 0.011940 0.011664 + 3.992 0.009009 0.011935 0.011660 + 3.993 0.009005 0.011930 0.011655 + 3.994 0.009002 0.011925 0.011650 + 3.995 0.008998 0.011920 0.011645 + 3.996 0.008994 0.011915 0.011641 + 3.997 0.008990 0.011910 0.011636 + 3.998 0.008987 0.011905 0.011631 + 3.999 0.008983 0.011900 0.011626 + 4.000 0.008979 0.011895 0.011621 + 4.001 0.008975 0.011890 0.011617 + 4.002 0.008972 0.011885 0.011612 + 4.003 0.008968 0.011881 0.011607 + 4.004 0.008964 0.011876 0.011602 + 4.005 0.008961 0.011871 0.011598 + 4.006 0.008957 0.011866 0.011593 + 4.007 0.008953 0.011861 0.011588 + 4.008 0.008949 0.011856 0.011584 + 4.009 0.008946 0.011851 0.011579 + 4.010 0.008942 0.011846 0.011574 + 4.011 0.008938 0.011841 0.011569 + 4.012 0.008935 0.011836 0.011565 + 4.013 0.008931 0.011831 0.011560 + 4.014 0.008927 0.011827 0.011555 + 4.015 0.008923 0.011822 0.011550 + 4.016 0.008920 0.011817 0.011546 + 4.017 0.008916 0.011812 0.011541 + 4.018 0.008912 0.011807 0.011536 + 4.019 0.008909 0.011802 0.011532 + 4.020 0.008905 0.011797 0.011527 + 4.021 0.008901 0.011792 0.011522 + 4.022 0.008898 0.011788 0.011518 + 4.023 0.008894 0.011783 0.011513 + 4.024 0.008890 0.011778 0.011508 + 4.025 0.008887 0.011773 0.011504 + 4.026 0.008883 0.011768 0.011499 + 4.027 0.008879 0.011763 0.011494 + 4.028 0.008876 0.011758 0.011490 + 4.029 0.008872 0.011754 0.011485 + 4.030 0.008868 0.011749 0.011480 + 4.031 0.008865 0.011744 0.011476 + 4.032 0.008861 0.011739 0.011471 + 4.033 0.008857 0.011734 0.011466 + 4.034 0.008854 0.011729 0.011462 + 4.035 0.008850 0.011725 0.011457 + 4.036 0.008846 0.011720 0.011452 + 4.037 0.008843 0.011715 0.011448 + 4.038 0.008839 0.011710 0.011443 + 4.039 0.008835 0.011705 0.011438 + 4.040 0.008832 0.011701 0.011434 + 4.041 0.008828 0.011696 0.011429 + 4.042 0.008824 0.011691 0.011424 + 4.043 0.008821 0.011686 0.011420 + 4.044 0.008817 0.011681 0.011415 + 4.045 0.008814 0.011677 0.011411 + 4.046 0.008810 0.011672 0.011406 + 4.047 0.008806 0.011667 0.011401 + 4.048 0.008803 0.011662 0.011397 + 4.049 0.008799 0.011657 0.011392 + 4.050 0.008795 0.011653 0.011388 + 4.051 0.008792 0.011648 0.011383 + 4.052 0.008788 0.011643 0.011378 + 4.053 0.008785 0.011638 0.011374 + 4.054 0.008781 0.011634 0.011369 + 4.055 0.008777 0.011629 0.011365 + 4.056 0.008774 0.011624 0.011360 + 4.057 0.008770 0.011619 0.011355 + 4.058 0.008767 0.011615 0.011351 + 4.059 0.008763 0.011610 0.011346 + 4.060 0.008759 0.011605 0.011342 + 4.061 0.008756 0.011600 0.011337 + 4.062 0.008752 0.011596 0.011332 + 4.063 0.008749 0.011591 0.011328 + 4.064 0.008745 0.011586 0.011323 + 4.065 0.008742 0.011581 0.011319 + 4.066 0.008738 0.011577 0.011314 + 4.067 0.008734 0.011572 0.011310 + 4.068 0.008731 0.011567 0.011305 + 4.069 0.008727 0.011562 0.011301 + 4.070 0.008724 0.011558 0.011296 + 4.071 0.008720 0.011553 0.011291 + 4.072 0.008717 0.011548 0.011287 + 4.073 0.008713 0.011544 0.011282 + 4.074 0.008709 0.011539 0.011278 + 4.075 0.008706 0.011534 0.011273 + 4.076 0.008702 0.011530 0.011269 + 4.077 0.008699 0.011525 0.011264 + 4.078 0.008695 0.011520 0.011260 + 4.079 0.008692 0.011515 0.011255 + 4.080 0.008688 0.011511 0.011251 + 4.081 0.008685 0.011506 0.011246 + 4.082 0.008681 0.011501 0.011242 + 4.083 0.008677 0.011497 0.011237 + 4.084 0.008674 0.011492 0.011233 + 4.085 0.008670 0.011487 0.011228 + 4.086 0.008667 0.011483 0.011224 + 4.087 0.008663 0.011478 0.011219 + 4.088 0.008660 0.011473 0.011215 + 4.089 0.008656 0.011469 0.011210 + 4.090 0.008653 0.011464 0.011206 + 4.091 0.008649 0.011459 0.011201 + 4.092 0.008646 0.011455 0.011197 + 4.093 0.008642 0.011450 0.011192 + 4.094 0.008639 0.011446 0.011188 + 4.095 0.008635 0.011441 0.011183 + 4.096 0.008632 0.011436 0.011179 + 4.097 0.008628 0.011432 0.011174 + 4.098 0.008625 0.011427 0.011170 + 4.099 0.008621 0.011422 0.011165 + 4.100 0.008618 0.011418 0.011161 + 4.101 0.008614 0.011413 0.011157 + 4.102 0.008611 0.011409 0.011152 + 4.103 0.008607 0.011404 0.011148 + 4.104 0.008604 0.011399 0.011143 + 4.105 0.008600 0.011395 0.011139 + 4.106 0.008597 0.011390 0.011134 + 4.107 0.008593 0.011386 0.011130 + 4.108 0.008590 0.011381 0.011125 + 4.109 0.008586 0.011376 0.011121 + 4.110 0.008583 0.011372 0.011117 + 4.111 0.008579 0.011367 0.011112 + 4.112 0.008576 0.011363 0.011108 + 4.113 0.008572 0.011358 0.011103 + 4.114 0.008569 0.011353 0.011099 + 4.115 0.008565 0.011349 0.011094 + 4.116 0.008562 0.011344 0.011090 + 4.117 0.008559 0.011340 0.011086 + 4.118 0.008555 0.011335 0.011081 + 4.119 0.008552 0.011331 0.011077 + 4.120 0.008548 0.011326 0.011072 + 4.121 0.008545 0.011321 0.011068 + 4.122 0.008541 0.011317 0.011064 + 4.123 0.008538 0.011312 0.011059 + 4.124 0.008534 0.011308 0.011055 + 4.125 0.008531 0.011303 0.011050 + 4.126 0.008527 0.011299 0.011046 + 4.127 0.008524 0.011294 0.011042 + 4.128 0.008521 0.011290 0.011037 + 4.129 0.008517 0.011285 0.011033 + 4.130 0.008514 0.011280 0.011028 + 4.131 0.008510 0.011276 0.011024 + 4.132 0.008507 0.011271 0.011020 + 4.133 0.008503 0.011267 0.011015 + 4.134 0.008500 0.011262 0.011011 + 4.135 0.008497 0.011258 0.011007 + 4.136 0.008493 0.011253 0.011002 + 4.137 0.008490 0.011249 0.010998 + 4.138 0.008486 0.011244 0.010994 + 4.139 0.008483 0.011240 0.010989 + 4.140 0.008480 0.011235 0.010985 + 4.141 0.008476 0.011231 0.010981 + 4.142 0.008473 0.011226 0.010976 + 4.143 0.008469 0.011222 0.010972 + 4.144 0.008466 0.011217 0.010968 + 4.145 0.008463 0.011213 0.010963 + 4.146 0.008459 0.011208 0.010959 + 4.147 0.008456 0.011204 0.010955 + 4.148 0.008452 0.011199 0.010950 + 4.149 0.008449 0.011195 0.010946 + 4.150 0.008446 0.011190 0.010942 + 4.151 0.008442 0.011186 0.010937 + 4.152 0.008439 0.011181 0.010933 + 4.153 0.008435 0.011177 0.010929 + 4.154 0.008432 0.011173 0.010924 + 4.155 0.008429 0.011168 0.010920 + 4.156 0.008425 0.011164 0.010916 + 4.157 0.008422 0.011159 0.010911 + 4.158 0.008419 0.011155 0.010907 + 4.159 0.008415 0.011150 0.010903 + 4.160 0.008412 0.011146 0.010898 + 4.161 0.008408 0.011141 0.010894 + 4.162 0.008405 0.011137 0.010890 + 4.163 0.008402 0.011132 0.010886 + 4.164 0.008398 0.011128 0.010881 + 4.165 0.008395 0.011124 0.010877 + 4.166 0.008392 0.011119 0.010873 + 4.167 0.008388 0.011115 0.010869 + 4.168 0.008385 0.011110 0.010864 + 4.169 0.008382 0.011106 0.010860 + 4.170 0.008378 0.011101 0.010856 + 4.171 0.008375 0.011097 0.010851 + 4.172 0.008372 0.011093 0.010847 + 4.173 0.008368 0.011088 0.010843 + 4.174 0.008365 0.011084 0.010839 + 4.175 0.008362 0.011079 0.010834 + 4.176 0.008358 0.011075 0.010830 + 4.177 0.008355 0.011071 0.010826 + 4.178 0.008352 0.011066 0.010822 + 4.179 0.008348 0.011062 0.010817 + 4.180 0.008345 0.011057 0.010813 + 4.181 0.008342 0.011053 0.010809 + 4.182 0.008338 0.011049 0.010805 + 4.183 0.008335 0.011044 0.010800 + 4.184 0.008332 0.011040 0.010796 + 4.185 0.008328 0.011036 0.010792 + 4.186 0.008325 0.011031 0.010788 + 4.187 0.008322 0.011027 0.010784 + 4.188 0.008318 0.011022 0.010779 + 4.189 0.008315 0.011018 0.010775 + 4.190 0.008312 0.011014 0.010771 + 4.191 0.008309 0.011009 0.010767 + 4.192 0.008305 0.011005 0.010763 + 4.193 0.008302 0.011001 0.010758 + 4.194 0.008299 0.010996 0.010754 + 4.195 0.008295 0.010992 0.010750 + 4.196 0.008292 0.010988 0.010746 + 4.197 0.008289 0.010983 0.010742 + 4.198 0.008285 0.010979 0.010737 + 4.199 0.008282 0.010975 0.010733 + 4.200 0.008279 0.010970 0.010729 + 4.201 0.008276 0.010966 0.010725 + 4.202 0.008272 0.010962 0.010721 + 4.203 0.008269 0.010957 0.010716 + 4.204 0.008266 0.010953 0.010712 + 4.205 0.008263 0.010949 0.010708 + 4.206 0.008259 0.010944 0.010704 + 4.207 0.008256 0.010940 0.010700 + 4.208 0.008253 0.010936 0.010696 + 4.209 0.008249 0.010931 0.010691 + 4.210 0.008246 0.010927 0.010687 + 4.211 0.008243 0.010923 0.010683 + 4.212 0.008240 0.010918 0.010679 + 4.213 0.008236 0.010914 0.010675 + 4.214 0.008233 0.010910 0.010671 + 4.215 0.008230 0.010905 0.010666 + 4.216 0.008227 0.010901 0.010662 + 4.217 0.008223 0.010897 0.010658 + 4.218 0.008220 0.010893 0.010654 + 4.219 0.008217 0.010888 0.010650 + 4.220 0.008214 0.010884 0.010646 + 4.221 0.008210 0.010880 0.010642 + 4.222 0.008207 0.010875 0.010638 + 4.223 0.008204 0.010871 0.010633 + 4.224 0.008201 0.010867 0.010629 + 4.225 0.008198 0.010863 0.010625 + 4.226 0.008194 0.010858 0.010621 + 4.227 0.008191 0.010854 0.010617 + 4.228 0.008188 0.010850 0.010613 + 4.229 0.008185 0.010846 0.010609 + 4.230 0.008181 0.010841 0.010605 + 4.231 0.008178 0.010837 0.010600 + 4.232 0.008175 0.010833 0.010596 + 4.233 0.008172 0.010829 0.010592 + 4.234 0.008169 0.010824 0.010588 + 4.235 0.008165 0.010820 0.010584 + 4.236 0.008162 0.010816 0.010580 + 4.237 0.008159 0.010812 0.010576 + 4.238 0.008156 0.010807 0.010572 + 4.239 0.008153 0.010803 0.010568 + 4.240 0.008149 0.010799 0.010564 + 4.241 0.008146 0.010795 0.010560 + 4.242 0.008143 0.010790 0.010555 + 4.243 0.008140 0.010786 0.010551 + 4.244 0.008137 0.010782 0.010547 + 4.245 0.008133 0.010778 0.010543 + 4.246 0.008130 0.010774 0.010539 + 4.247 0.008127 0.010769 0.010535 + 4.248 0.008124 0.010765 0.010531 + 4.249 0.008121 0.010761 0.010527 + 4.250 0.008117 0.010757 0.010523 + 4.251 0.008114 0.010753 0.010519 + 4.252 0.008111 0.010748 0.010515 + 4.253 0.008108 0.010744 0.010511 + 4.254 0.008105 0.010740 0.010507 + 4.255 0.008102 0.010736 0.010503 + 4.256 0.008098 0.010732 0.010499 + 4.257 0.008095 0.010727 0.010495 + 4.258 0.008092 0.010723 0.010491 + 4.259 0.008089 0.010719 0.010486 + 4.260 0.008086 0.010715 0.010482 + 4.261 0.008083 0.010711 0.010478 + 4.262 0.008079 0.010707 0.010474 + 4.263 0.008076 0.010702 0.010470 + 4.264 0.008073 0.010698 0.010466 + 4.265 0.008070 0.010694 0.010462 + 4.266 0.008067 0.010690 0.010458 + 4.267 0.008064 0.010686 0.010454 + 4.268 0.008061 0.010682 0.010450 + 4.269 0.008057 0.010677 0.010446 + 4.270 0.008054 0.010673 0.010442 + 4.271 0.008051 0.010669 0.010438 + 4.272 0.008048 0.010665 0.010434 + 4.273 0.008045 0.010661 0.010430 + 4.274 0.008042 0.010657 0.010426 + 4.275 0.008039 0.010653 0.010422 + 4.276 0.008035 0.010648 0.010418 + 4.277 0.008032 0.010644 0.010414 + 4.278 0.008029 0.010640 0.010410 + 4.279 0.008026 0.010636 0.010406 + 4.280 0.008023 0.010632 0.010402 + 4.281 0.008020 0.010628 0.010398 + 4.282 0.008017 0.010624 0.010394 + 4.283 0.008014 0.010620 0.010390 + 4.284 0.008010 0.010615 0.010386 + 4.285 0.008007 0.010611 0.010382 + 4.286 0.008004 0.010607 0.010378 + 4.287 0.008001 0.010603 0.010374 + 4.288 0.007998 0.010599 0.010370 + 4.289 0.007995 0.010595 0.010367 + 4.290 0.007992 0.010591 0.010363 + 4.291 0.007989 0.010587 0.010359 + 4.292 0.007986 0.010583 0.010355 + 4.293 0.007983 0.010579 0.010351 + 4.294 0.007979 0.010574 0.010347 + 4.295 0.007976 0.010570 0.010343 + 4.296 0.007973 0.010566 0.010339 + 4.297 0.007970 0.010562 0.010335 + 4.298 0.007967 0.010558 0.010331 + 4.299 0.007964 0.010554 0.010327 + 4.300 0.007961 0.010550 0.010323 + 4.301 0.007958 0.010546 0.010319 + 4.302 0.007955 0.010542 0.010315 + 4.303 0.007952 0.010538 0.010311 + 4.304 0.007949 0.010534 0.010307 + 4.305 0.007946 0.010530 0.010303 + 4.306 0.007942 0.010526 0.010300 + 4.307 0.007939 0.010522 0.010296 + 4.308 0.007936 0.010517 0.010292 + 4.309 0.007933 0.010513 0.010288 + 4.310 0.007930 0.010509 0.010284 + 4.311 0.007927 0.010505 0.010280 + 4.312 0.007924 0.010501 0.010276 + 4.313 0.007921 0.010497 0.010272 + 4.314 0.007918 0.010493 0.010268 + 4.315 0.007915 0.010489 0.010264 + 4.316 0.007912 0.010485 0.010260 + 4.317 0.007909 0.010481 0.010257 + 4.318 0.007906 0.010477 0.010253 + 4.319 0.007903 0.010473 0.010249 + 4.320 0.007900 0.010469 0.010245 + 4.321 0.007897 0.010465 0.010241 + 4.322 0.007894 0.010461 0.010237 + 4.323 0.007891 0.010457 0.010233 + 4.324 0.007888 0.010453 0.010229 + 4.325 0.007885 0.010449 0.010225 + 4.326 0.007881 0.010445 0.010222 + 4.327 0.007878 0.010441 0.010218 + 4.328 0.007875 0.010437 0.010214 + 4.329 0.007872 0.010433 0.010210 + 4.330 0.007869 0.010429 0.010206 + 4.331 0.007866 0.010425 0.010202 + 4.332 0.007863 0.010421 0.010198 + 4.333 0.007860 0.010417 0.010195 + 4.334 0.007857 0.010413 0.010191 + 4.335 0.007854 0.010409 0.010187 + 4.336 0.007851 0.010405 0.010183 + 4.337 0.007848 0.010401 0.010179 + 4.338 0.007845 0.010397 0.010175 + 4.339 0.007842 0.010393 0.010171 + 4.340 0.007839 0.010389 0.010168 + 4.341 0.007836 0.010385 0.010164 + 4.342 0.007833 0.010381 0.010160 + 4.343 0.007830 0.010377 0.010156 + 4.344 0.007827 0.010373 0.010152 + 4.345 0.007824 0.010369 0.010148 + 4.346 0.007821 0.010365 0.010145 + 4.347 0.007818 0.010361 0.010141 + 4.348 0.007815 0.010357 0.010137 + 4.349 0.007812 0.010353 0.010133 + 4.350 0.007809 0.010349 0.010129 + 4.351 0.007806 0.010346 0.010125 + 4.352 0.007803 0.010342 0.010122 + 4.353 0.007800 0.010338 0.010118 + 4.354 0.007797 0.010334 0.010114 + 4.355 0.007794 0.010330 0.010110 + 4.356 0.007791 0.010326 0.010106 + 4.357 0.007788 0.010322 0.010103 + 4.358 0.007785 0.010318 0.010099 + 4.359 0.007782 0.010314 0.010095 + 4.360 0.007779 0.010310 0.010091 + 4.361 0.007776 0.010306 0.010087 + 4.362 0.007774 0.010302 0.010084 + 4.363 0.007771 0.010298 0.010080 + 4.364 0.007768 0.010294 0.010076 + 4.365 0.007765 0.010290 0.010072 + 4.366 0.007762 0.010287 0.010069 + 4.367 0.007759 0.010283 0.010065 + 4.368 0.007756 0.010279 0.010061 + 4.369 0.007753 0.010275 0.010057 + 4.370 0.007750 0.010271 0.010053 + 4.371 0.007747 0.010267 0.010050 + 4.372 0.007744 0.010263 0.010046 + 4.373 0.007741 0.010259 0.010042 + 4.374 0.007738 0.010255 0.010038 + 4.375 0.007735 0.010251 0.010035 + 4.376 0.007732 0.010248 0.010031 + 4.377 0.007729 0.010244 0.010027 + 4.378 0.007726 0.010240 0.010023 + 4.379 0.007723 0.010236 0.010020 + 4.380 0.007720 0.010232 0.010016 + 4.381 0.007717 0.010228 0.010012 + 4.382 0.007715 0.010224 0.010008 + 4.383 0.007712 0.010220 0.010005 + 4.384 0.007709 0.010217 0.010001 + 4.385 0.007706 0.010213 0.009997 + 4.386 0.007703 0.010209 0.009993 + 4.387 0.007700 0.010205 0.009990 + 4.388 0.007697 0.010201 0.009986 + 4.389 0.007694 0.010197 0.009982 + 4.390 0.007691 0.010193 0.009978 + 4.391 0.007688 0.010190 0.009975 + 4.392 0.007685 0.010186 0.009971 + 4.393 0.007682 0.010182 0.009967 + 4.394 0.007680 0.010178 0.009964 + 4.395 0.007677 0.010174 0.009960 + 4.396 0.007674 0.010170 0.009956 + 4.397 0.007671 0.010166 0.009952 + 4.398 0.007668 0.010163 0.009949 + 4.399 0.007665 0.010159 0.009945 + 4.400 0.007662 0.010155 0.009941 + 4.401 0.007659 0.010151 0.009938 + 4.402 0.007656 0.010147 0.009934 + 4.403 0.007653 0.010143 0.009930 + 4.404 0.007651 0.010140 0.009926 + 4.405 0.007648 0.010136 0.009923 + 4.406 0.007645 0.010132 0.009919 + 4.407 0.007642 0.010128 0.009915 + 4.408 0.007639 0.010124 0.009912 + 4.409 0.007636 0.010121 0.009908 + 4.410 0.007633 0.010117 0.009904 + 4.411 0.007630 0.010113 0.009901 + 4.412 0.007627 0.010109 0.009897 + 4.413 0.007625 0.010105 0.009893 + 4.414 0.007622 0.010102 0.009890 + 4.415 0.007619 0.010098 0.009886 + 4.416 0.007616 0.010094 0.009882 + 4.417 0.007613 0.010090 0.009879 + 4.418 0.007610 0.010086 0.009875 + 4.419 0.007607 0.010083 0.009871 + 4.420 0.007604 0.010079 0.009868 + 4.421 0.007602 0.010075 0.009864 + 4.422 0.007599 0.010071 0.009860 + 4.423 0.007596 0.010067 0.009857 + 4.424 0.007593 0.010064 0.009853 + 4.425 0.007590 0.010060 0.009849 + 4.426 0.007587 0.010056 0.009846 + 4.427 0.007584 0.010052 0.009842 + 4.428 0.007582 0.010049 0.009838 + 4.429 0.007579 0.010045 0.009835 + 4.430 0.007576 0.010041 0.009831 + 4.431 0.007573 0.010037 0.009827 + 4.432 0.007570 0.010034 0.009824 + 4.433 0.007567 0.010030 0.009820 + 4.434 0.007565 0.010026 0.009817 + 4.435 0.007562 0.010022 0.009813 + 4.436 0.007559 0.010019 0.009809 + 4.437 0.007556 0.010015 0.009806 + 4.438 0.007553 0.010011 0.009802 + 4.439 0.007550 0.010007 0.009798 + 4.440 0.007548 0.010004 0.009795 + 4.441 0.007545 0.010000 0.009791 + 4.442 0.007542 0.009996 0.009788 + 4.443 0.007539 0.009992 0.009784 + 4.444 0.007536 0.009989 0.009780 + 4.445 0.007533 0.009985 0.009777 + 4.446 0.007531 0.009981 0.009773 + 4.447 0.007528 0.009977 0.009770 + 4.448 0.007525 0.009974 0.009766 + 4.449 0.007522 0.009970 0.009762 + 4.450 0.007519 0.009966 0.009759 + 4.451 0.007517 0.009963 0.009755 + 4.452 0.007514 0.009959 0.009752 + 4.453 0.007511 0.009955 0.009748 + 4.454 0.007508 0.009951 0.009744 + 4.455 0.007505 0.009948 0.009741 + 4.456 0.007502 0.009944 0.009737 + 4.457 0.007500 0.009940 0.009734 + 4.458 0.007497 0.009937 0.009730 + 4.459 0.007494 0.009933 0.009726 + 4.460 0.007491 0.009929 0.009723 + 4.461 0.007488 0.009925 0.009719 + 4.462 0.007486 0.009922 0.009716 + 4.463 0.007483 0.009918 0.009712 + 4.464 0.007480 0.009914 0.009709 + 4.465 0.007477 0.009911 0.009705 + 4.466 0.007475 0.009907 0.009701 + 4.467 0.007472 0.009903 0.009698 + 4.468 0.007469 0.009900 0.009694 + 4.469 0.007466 0.009896 0.009691 + 4.470 0.007463 0.009892 0.009687 + 4.471 0.007461 0.009889 0.009684 + 4.472 0.007458 0.009885 0.009680 + 4.473 0.007455 0.009881 0.009677 + 4.474 0.007452 0.009878 0.009673 + 4.475 0.007450 0.009874 0.009669 + 4.476 0.007447 0.009870 0.009666 + 4.477 0.007444 0.009867 0.009662 + 4.478 0.007441 0.009863 0.009659 + 4.479 0.007438 0.009859 0.009655 + 4.480 0.007436 0.009856 0.009652 + 4.481 0.007433 0.009852 0.009648 + 4.482 0.007430 0.009848 0.009645 + 4.483 0.007427 0.009845 0.009641 + 4.484 0.007425 0.009841 0.009638 + 4.485 0.007422 0.009837 0.009634 + 4.486 0.007419 0.009834 0.009631 + 4.487 0.007416 0.009830 0.009627 + 4.488 0.007414 0.009827 0.009624 + 4.489 0.007411 0.009823 0.009620 + 4.490 0.007408 0.009819 0.009617 + 4.491 0.007405 0.009816 0.009613 + 4.492 0.007403 0.009812 0.009610 + 4.493 0.007400 0.009808 0.009606 + 4.494 0.007397 0.009805 0.009603 + 4.495 0.007394 0.009801 0.009599 + 4.496 0.007392 0.009798 0.009596 + 4.497 0.007389 0.009794 0.009592 + 4.498 0.007386 0.009790 0.009589 + 4.499 0.007384 0.009787 0.009585 + 4.500 0.007381 0.009783 0.009582 + 4.501 0.007378 0.009779 0.009578 + 4.502 0.007375 0.009776 0.009575 + 4.503 0.007373 0.009772 0.009571 + 4.504 0.007370 0.009769 0.009568 + 4.505 0.007367 0.009765 0.009564 + 4.506 0.007364 0.009761 0.009561 + 4.507 0.007362 0.009758 0.009557 + 4.508 0.007359 0.009754 0.009554 + 4.509 0.007356 0.009751 0.009550 + 4.510 0.007354 0.009747 0.009547 + 4.511 0.007351 0.009744 0.009543 + 4.512 0.007348 0.009740 0.009540 + 4.513 0.007345 0.009736 0.009536 + 4.514 0.007343 0.009733 0.009533 + 4.515 0.007340 0.009729 0.009529 + 4.516 0.007337 0.009726 0.009526 + 4.517 0.007335 0.009722 0.009522 + 4.518 0.007332 0.009718 0.009519 + 4.519 0.007329 0.009715 0.009516 + 4.520 0.007326 0.009711 0.009512 + 4.521 0.007324 0.009708 0.009509 + 4.522 0.007321 0.009704 0.009505 + 4.523 0.007318 0.009701 0.009502 + 4.524 0.007316 0.009697 0.009498 + 4.525 0.007313 0.009694 0.009495 + 4.526 0.007310 0.009690 0.009491 + 4.527 0.007308 0.009686 0.009488 + 4.528 0.007305 0.009683 0.009485 + 4.529 0.007302 0.009679 0.009481 + 4.530 0.007300 0.009676 0.009478 + 4.531 0.007297 0.009672 0.009474 + 4.532 0.007294 0.009669 0.009471 + 4.533 0.007292 0.009665 0.009467 + 4.534 0.007289 0.009662 0.009464 + 4.535 0.007286 0.009658 0.009461 + 4.536 0.007284 0.009655 0.009457 + 4.537 0.007281 0.009651 0.009454 + 4.538 0.007278 0.009647 0.009450 + 4.539 0.007276 0.009644 0.009447 + 4.540 0.007273 0.009640 0.009443 + 4.541 0.007270 0.009637 0.009440 + 4.542 0.007268 0.009633 0.009437 + 4.543 0.007265 0.009630 0.009433 + 4.544 0.007262 0.009626 0.009430 + 4.545 0.007260 0.009623 0.009426 + 4.546 0.007257 0.009619 0.009423 + 4.547 0.007254 0.009616 0.009420 + 4.548 0.007252 0.009612 0.009416 + 4.549 0.007249 0.009609 0.009413 + 4.550 0.007246 0.009605 0.009409 + 4.551 0.007244 0.009602 0.009406 + 4.552 0.007241 0.009598 0.009403 + 4.553 0.007238 0.009595 0.009399 + 4.554 0.007236 0.009591 0.009396 + 4.555 0.007233 0.009588 0.009392 + 4.556 0.007230 0.009584 0.009389 + 4.557 0.007228 0.009581 0.009386 + 4.558 0.007225 0.009577 0.009382 + 4.559 0.007222 0.009574 0.009379 + 4.560 0.007220 0.009570 0.009376 + 4.561 0.007217 0.009567 0.009372 + 4.562 0.007215 0.009563 0.009369 + 4.563 0.007212 0.009560 0.009365 + 4.564 0.007209 0.009556 0.009362 + 4.565 0.007207 0.009553 0.009359 + 4.566 0.007204 0.009549 0.009355 + 4.567 0.007201 0.009546 0.009352 + 4.568 0.007199 0.009543 0.009349 + 4.569 0.007196 0.009539 0.009345 + 4.570 0.007194 0.009536 0.009342 + 4.571 0.007191 0.009532 0.009339 + 4.572 0.007188 0.009529 0.009335 + 4.573 0.007186 0.009525 0.009332 + 4.574 0.007183 0.009522 0.009329 + 4.575 0.007180 0.009518 0.009325 + 4.576 0.007178 0.009515 0.009322 + 4.577 0.007175 0.009511 0.009318 + 4.578 0.007173 0.009508 0.009315 + 4.579 0.007170 0.009504 0.009312 + 4.580 0.007167 0.009501 0.009308 + 4.581 0.007165 0.009498 0.009305 + 4.582 0.007162 0.009494 0.009302 + 4.583 0.007160 0.009491 0.009298 + 4.584 0.007157 0.009487 0.009295 + 4.585 0.007154 0.009484 0.009292 + 4.586 0.007152 0.009480 0.009289 + 4.587 0.007149 0.009477 0.009285 + 4.588 0.007147 0.009474 0.009282 + 4.589 0.007144 0.009470 0.009279 + 4.590 0.007141 0.009467 0.009275 + 4.591 0.007139 0.009463 0.009272 + 4.592 0.007136 0.009460 0.009269 + 4.593 0.007134 0.009456 0.009265 + 4.594 0.007131 0.009453 0.009262 + 4.595 0.007129 0.009450 0.009259 + 4.596 0.007126 0.009446 0.009255 + 4.597 0.007123 0.009443 0.009252 + 4.598 0.007121 0.009439 0.009249 + 4.599 0.007118 0.009436 0.009245 + 4.600 0.007116 0.009433 0.009242 + 4.601 0.007113 0.009429 0.009239 + 4.602 0.007110 0.009426 0.009236 + 4.603 0.007108 0.009422 0.009232 + 4.604 0.007105 0.009419 0.009229 + 4.605 0.007103 0.009416 0.009226 + 4.606 0.007100 0.009412 0.009222 + 4.607 0.007098 0.009409 0.009219 + 4.608 0.007095 0.009405 0.009216 + 4.609 0.007093 0.009402 0.009213 + 4.610 0.007090 0.009399 0.009209 + 4.611 0.007087 0.009395 0.009206 + 4.612 0.007085 0.009392 0.009203 + 4.613 0.007082 0.009388 0.009199 + 4.614 0.007080 0.009385 0.009196 + 4.615 0.007077 0.009382 0.009193 + 4.616 0.007075 0.009378 0.009190 + 4.617 0.007072 0.009375 0.009186 + 4.618 0.007070 0.009372 0.009183 + 4.619 0.007067 0.009368 0.009180 + 4.620 0.007064 0.009365 0.009177 + 4.621 0.007062 0.009361 0.009173 + 4.622 0.007059 0.009358 0.009170 + 4.623 0.007057 0.009355 0.009167 + 4.624 0.007054 0.009351 0.009164 + 4.625 0.007052 0.009348 0.009160 + 4.626 0.007049 0.009345 0.009157 + 4.627 0.007047 0.009341 0.009154 + 4.628 0.007044 0.009338 0.009151 + 4.629 0.007042 0.009335 0.009147 + 4.630 0.007039 0.009331 0.009144 + 4.631 0.007037 0.009328 0.009141 + 4.632 0.007034 0.009325 0.009138 + 4.633 0.007031 0.009321 0.009134 + 4.634 0.007029 0.009318 0.009131 + 4.635 0.007026 0.009315 0.009128 + 4.636 0.007024 0.009311 0.009125 + 4.637 0.007021 0.009308 0.009121 + 4.638 0.007019 0.009305 0.009118 + 4.639 0.007016 0.009301 0.009115 + 4.640 0.007014 0.009298 0.009112 + 4.641 0.007011 0.009295 0.009109 + 4.642 0.007009 0.009291 0.009105 + 4.643 0.007006 0.009288 0.009102 + 4.644 0.007004 0.009285 0.009099 + 4.645 0.007001 0.009281 0.009096 + 4.646 0.006999 0.009278 0.009092 + 4.647 0.006996 0.009275 0.009089 + 4.648 0.006994 0.009271 0.009086 + 4.649 0.006991 0.009268 0.009083 + 4.650 0.006989 0.009265 0.009080 + 4.651 0.006986 0.009261 0.009076 + 4.652 0.006984 0.009258 0.009073 + 4.653 0.006981 0.009255 0.009070 + 4.654 0.006979 0.009252 0.009067 + 4.655 0.006976 0.009248 0.009064 + 4.656 0.006974 0.009245 0.009060 + 4.657 0.006971 0.009242 0.009057 + 4.658 0.006969 0.009238 0.009054 + 4.659 0.006966 0.009235 0.009051 + 4.660 0.006964 0.009232 0.009048 + 4.661 0.006961 0.009228 0.009045 + 4.662 0.006959 0.009225 0.009041 + 4.663 0.006956 0.009222 0.009038 + 4.664 0.006954 0.009219 0.009035 + 4.665 0.006951 0.009215 0.009032 + 4.666 0.006949 0.009212 0.009029 + 4.667 0.006946 0.009209 0.009025 + 4.668 0.006944 0.009206 0.009022 + 4.669 0.006941 0.009202 0.009019 + 4.670 0.006939 0.009199 0.009016 + 4.671 0.006937 0.009196 0.009013 + 4.672 0.006934 0.009192 0.009010 + 4.673 0.006932 0.009189 0.009006 + 4.674 0.006929 0.009186 0.009003 + 4.675 0.006927 0.009183 0.009000 + 4.676 0.006924 0.009179 0.008997 + 4.677 0.006922 0.009176 0.008994 + 4.678 0.006919 0.009173 0.008991 + 4.679 0.006917 0.009170 0.008987 + 4.680 0.006914 0.009166 0.008984 + 4.681 0.006912 0.009163 0.008981 + 4.682 0.006909 0.009160 0.008978 + 4.683 0.006907 0.009157 0.008975 + 4.684 0.006904 0.009153 0.008972 + 4.685 0.006902 0.009150 0.008969 + 4.686 0.006900 0.009147 0.008965 + 4.687 0.006897 0.009144 0.008962 + 4.688 0.006895 0.009140 0.008959 + 4.689 0.006892 0.009137 0.008956 + 4.690 0.006890 0.009134 0.008953 + 4.691 0.006887 0.009131 0.008950 + 4.692 0.006885 0.009127 0.008947 + 4.693 0.006882 0.009124 0.008943 + 4.694 0.006880 0.009121 0.008940 + 4.695 0.006878 0.009118 0.008937 + 4.696 0.006875 0.009115 0.008934 + 4.697 0.006873 0.009111 0.008931 + 4.698 0.006870 0.009108 0.008928 + 4.699 0.006868 0.009105 0.008925 + 4.700 0.006865 0.009102 0.008922 + 4.701 0.006863 0.009098 0.008919 + 4.702 0.006861 0.009095 0.008915 + 4.703 0.006858 0.009092 0.008912 + 4.704 0.006856 0.009089 0.008909 + 4.705 0.006853 0.009086 0.008906 + 4.706 0.006851 0.009082 0.008903 + 4.707 0.006848 0.009079 0.008900 + 4.708 0.006846 0.009076 0.008897 + 4.709 0.006844 0.009073 0.008894 + 4.710 0.006841 0.009070 0.008891 + 4.711 0.006839 0.009066 0.008887 + 4.712 0.006836 0.009063 0.008884 + 4.713 0.006834 0.009060 0.008881 + 4.714 0.006832 0.009057 0.008878 + 4.715 0.006829 0.009054 0.008875 + 4.716 0.006827 0.009050 0.008872 + 4.717 0.006824 0.009047 0.008869 + 4.718 0.006822 0.009044 0.008866 + 4.719 0.006819 0.009041 0.008863 + 4.720 0.006817 0.009038 0.008860 + 4.721 0.006815 0.009035 0.008857 + 4.722 0.006812 0.009031 0.008854 + 4.723 0.006810 0.009028 0.008850 + 4.724 0.006807 0.009025 0.008847 + 4.725 0.006805 0.009022 0.008844 + 4.726 0.006803 0.009019 0.008841 + 4.727 0.006800 0.009016 0.008838 + 4.728 0.006798 0.009012 0.008835 + 4.729 0.006795 0.009009 0.008832 + 4.730 0.006793 0.009006 0.008829 + 4.731 0.006791 0.009003 0.008826 + 4.732 0.006788 0.009000 0.008823 + 4.733 0.006786 0.008997 0.008820 + 4.734 0.006784 0.008993 0.008817 + 4.735 0.006781 0.008990 0.008814 + 4.736 0.006779 0.008987 0.008811 + 4.737 0.006776 0.008984 0.008808 + 4.738 0.006774 0.008981 0.008804 + 4.739 0.006772 0.008978 0.008801 + 4.740 0.006769 0.008974 0.008798 + 4.741 0.006767 0.008971 0.008795 + 4.742 0.006764 0.008968 0.008792 + 4.743 0.006762 0.008965 0.008789 + 4.744 0.006760 0.008962 0.008786 + 4.745 0.006757 0.008959 0.008783 + 4.746 0.006755 0.008956 0.008780 + 4.747 0.006753 0.008953 0.008777 + 4.748 0.006750 0.008949 0.008774 + 4.749 0.006748 0.008946 0.008771 + 4.750 0.006746 0.008943 0.008768 + 4.751 0.006743 0.008940 0.008765 + 4.752 0.006741 0.008937 0.008762 + 4.753 0.006738 0.008934 0.008759 + 4.754 0.006736 0.008931 0.008756 + 4.755 0.006734 0.008928 0.008753 + 4.756 0.006731 0.008924 0.008750 + 4.757 0.006729 0.008921 0.008747 + 4.758 0.006727 0.008918 0.008744 + 4.759 0.006724 0.008915 0.008741 + 4.760 0.006722 0.008912 0.008738 + 4.761 0.006720 0.008909 0.008735 + 4.762 0.006717 0.008906 0.008732 + 4.763 0.006715 0.008903 0.008729 + 4.764 0.006713 0.008900 0.008726 + 4.765 0.006710 0.008896 0.008723 + 4.766 0.006708 0.008893 0.008720 + 4.767 0.006706 0.008890 0.008717 + 4.768 0.006703 0.008887 0.008714 + 4.769 0.006701 0.008884 0.008711 + 4.770 0.006699 0.008881 0.008708 + 4.771 0.006696 0.008878 0.008705 + 4.772 0.006694 0.008875 0.008702 + 4.773 0.006692 0.008872 0.008699 + 4.774 0.006689 0.008869 0.008696 + 4.775 0.006687 0.008866 0.008693 + 4.776 0.006685 0.008862 0.008690 + 4.777 0.006682 0.008859 0.008687 + 4.778 0.006680 0.008856 0.008684 + 4.779 0.006678 0.008853 0.008681 + 4.780 0.006675 0.008850 0.008678 + 4.781 0.006673 0.008847 0.008675 + 4.782 0.006671 0.008844 0.008672 + 4.783 0.006668 0.008841 0.008669 + 4.784 0.006666 0.008838 0.008666 + 4.785 0.006664 0.008835 0.008663 + 4.786 0.006661 0.008832 0.008660 + 4.787 0.006659 0.008829 0.008657 + 4.788 0.006657 0.008826 0.008654 + 4.789 0.006654 0.008823 0.008651 + 4.790 0.006652 0.008819 0.008648 + 4.791 0.006650 0.008816 0.008645 + 4.792 0.006647 0.008813 0.008642 + 4.793 0.006645 0.008810 0.008639 + 4.794 0.006643 0.008807 0.008636 + 4.795 0.006640 0.008804 0.008633 + 4.796 0.006638 0.008801 0.008630 + 4.797 0.006636 0.008798 0.008627 + 4.798 0.006634 0.008795 0.008624 + 4.799 0.006631 0.008792 0.008621 + 4.800 0.006629 0.008789 0.008619 + 4.801 0.006627 0.008786 0.008616 + 4.802 0.006624 0.008783 0.008613 + 4.803 0.006622 0.008780 0.008610 + 4.804 0.006620 0.008777 0.008607 + 4.805 0.006617 0.008774 0.008604 + 4.806 0.006615 0.008771 0.008601 + 4.807 0.006613 0.008768 0.008598 + 4.808 0.006611 0.008765 0.008595 + 4.809 0.006608 0.008762 0.008592 + 4.810 0.006606 0.008759 0.008589 + 4.811 0.006604 0.008756 0.008586 + 4.812 0.006601 0.008753 0.008583 + 4.813 0.006599 0.008750 0.008580 + 4.814 0.006597 0.008747 0.008577 + 4.815 0.006595 0.008744 0.008575 + 4.816 0.006592 0.008741 0.008572 + 4.817 0.006590 0.008738 0.008569 + 4.818 0.006588 0.008735 0.008566 + 4.819 0.006586 0.008732 0.008563 + 4.820 0.006583 0.008729 0.008560 + 4.821 0.006581 0.008725 0.008557 + 4.822 0.006579 0.008722 0.008554 + 4.823 0.006576 0.008719 0.008551 + 4.824 0.006574 0.008716 0.008548 + 4.825 0.006572 0.008713 0.008545 + 4.826 0.006570 0.008710 0.008542 + 4.827 0.006567 0.008707 0.008540 + 4.828 0.006565 0.008704 0.008537 + 4.829 0.006563 0.008702 0.008534 + 4.830 0.006561 0.008699 0.008531 + 4.831 0.006558 0.008696 0.008528 + 4.832 0.006556 0.008693 0.008525 + 4.833 0.006554 0.008690 0.008522 + 4.834 0.006552 0.008687 0.008519 + 4.835 0.006549 0.008684 0.008516 + 4.836 0.006547 0.008681 0.008513 + 4.837 0.006545 0.008678 0.008511 + 4.838 0.006543 0.008675 0.008508 + 4.839 0.006540 0.008672 0.008505 + 4.840 0.006538 0.008669 0.008502 + 4.841 0.006536 0.008666 0.008499 + 4.842 0.006534 0.008663 0.008496 + 4.843 0.006531 0.008660 0.008493 + 4.844 0.006529 0.008657 0.008490 + 4.845 0.006527 0.008654 0.008487 + 4.846 0.006525 0.008651 0.008485 + 4.847 0.006522 0.008648 0.008482 + 4.848 0.006520 0.008645 0.008479 + 4.849 0.006518 0.008642 0.008476 + 4.850 0.006516 0.008639 0.008473 + 4.851 0.006513 0.008636 0.008470 + 4.852 0.006511 0.008633 0.008467 + 4.853 0.006509 0.008630 0.008465 + 4.854 0.006507 0.008627 0.008462 + 4.855 0.006504 0.008624 0.008459 + 4.856 0.006502 0.008621 0.008456 + 4.857 0.006500 0.008618 0.008453 + 4.858 0.006498 0.008615 0.008450 + 4.859 0.006496 0.008612 0.008447 + 4.860 0.006493 0.008610 0.008445 + 4.861 0.006491 0.008607 0.008442 + 4.862 0.006489 0.008604 0.008439 + 4.863 0.006487 0.008601 0.008436 + 4.864 0.006484 0.008598 0.008433 + 4.865 0.006482 0.008595 0.008430 + 4.866 0.006480 0.008592 0.008427 + 4.867 0.006478 0.008589 0.008425 + 4.868 0.006476 0.008586 0.008422 + 4.869 0.006473 0.008583 0.008419 + 4.870 0.006471 0.008580 0.008416 + 4.871 0.006469 0.008577 0.008413 + 4.872 0.006467 0.008574 0.008410 + 4.873 0.006464 0.008571 0.008408 + 4.874 0.006462 0.008569 0.008405 + 4.875 0.006460 0.008566 0.008402 + 4.876 0.006458 0.008563 0.008399 + 4.877 0.006456 0.008560 0.008396 + 4.878 0.006453 0.008557 0.008393 + 4.879 0.006451 0.008554 0.008391 + 4.880 0.006449 0.008551 0.008388 + 4.881 0.006447 0.008548 0.008385 + 4.882 0.006445 0.008545 0.008382 + 4.883 0.006442 0.008542 0.008379 + 4.884 0.006440 0.008539 0.008376 + 4.885 0.006438 0.008536 0.008374 + 4.886 0.006436 0.008534 0.008371 + 4.887 0.006434 0.008531 0.008368 + 4.888 0.006432 0.008528 0.008365 + 4.889 0.006429 0.008525 0.008362 + 4.890 0.006427 0.008522 0.008360 + 4.891 0.006425 0.008519 0.008357 + 4.892 0.006423 0.008516 0.008354 + 4.893 0.006421 0.008513 0.008351 + 4.894 0.006418 0.008510 0.008348 + 4.895 0.006416 0.008508 0.008346 + 4.896 0.006414 0.008505 0.008343 + 4.897 0.006412 0.008502 0.008340 + 4.898 0.006410 0.008499 0.008337 + 4.899 0.006407 0.008496 0.008334 + 4.900 0.006405 0.008493 0.008332 + 4.901 0.006403 0.008490 0.008329 + 4.902 0.006401 0.008487 0.008326 + 4.903 0.006399 0.008485 0.008323 + 4.904 0.006397 0.008482 0.008320 + 4.905 0.006394 0.008479 0.008318 + 4.906 0.006392 0.008476 0.008315 + 4.907 0.006390 0.008473 0.008312 + 4.908 0.006388 0.008470 0.008309 + 4.909 0.006386 0.008467 0.008307 + 4.910 0.006384 0.008464 0.008304 + 4.911 0.006381 0.008462 0.008301 + 4.912 0.006379 0.008459 0.008298 + 4.913 0.006377 0.008456 0.008295 + 4.914 0.006375 0.008453 0.008293 + 4.915 0.006373 0.008450 0.008290 + 4.916 0.006371 0.008447 0.008287 + 4.917 0.006368 0.008444 0.008284 + 4.918 0.006366 0.008442 0.008282 + 4.919 0.006364 0.008439 0.008279 + 4.920 0.006362 0.008436 0.008276 + 4.921 0.006360 0.008433 0.008273 + 4.922 0.006358 0.008430 0.008271 + 4.923 0.006356 0.008427 0.008268 + 4.924 0.006353 0.008424 0.008265 + 4.925 0.006351 0.008422 0.008262 + 4.926 0.006349 0.008419 0.008259 + 4.927 0.006347 0.008416 0.008257 + 4.928 0.006345 0.008413 0.008254 + 4.929 0.006343 0.008410 0.008251 + 4.930 0.006341 0.008407 0.008248 + 4.931 0.006338 0.008405 0.008246 + 4.932 0.006336 0.008402 0.008243 + 4.933 0.006334 0.008399 0.008240 + 4.934 0.006332 0.008396 0.008237 + 4.935 0.006330 0.008393 0.008235 + 4.936 0.006328 0.008391 0.008232 + 4.937 0.006326 0.008388 0.008229 + 4.938 0.006323 0.008385 0.008227 + 4.939 0.006321 0.008382 0.008224 + 4.940 0.006319 0.008379 0.008221 + 4.941 0.006317 0.008376 0.008218 + 4.942 0.006315 0.008374 0.008216 + 4.943 0.006313 0.008371 0.008213 + 4.944 0.006311 0.008368 0.008210 + 4.945 0.006309 0.008365 0.008207 + 4.946 0.006306 0.008362 0.008205 + 4.947 0.006304 0.008360 0.008202 + 4.948 0.006302 0.008357 0.008199 + 4.949 0.006300 0.008354 0.008197 + 4.950 0.006298 0.008351 0.008194 + 4.951 0.006296 0.008348 0.008191 + 4.952 0.006294 0.008346 0.008188 + 4.953 0.006292 0.008343 0.008186 + 4.954 0.006289 0.008340 0.008183 + 4.955 0.006287 0.008337 0.008180 + 4.956 0.006285 0.008334 0.008178 + 4.957 0.006283 0.008332 0.008175 + 4.958 0.006281 0.008329 0.008172 + 4.959 0.006279 0.008326 0.008169 + 4.960 0.006277 0.008323 0.008167 + 4.961 0.006275 0.008320 0.008164 + 4.962 0.006273 0.008318 0.008161 + 4.963 0.006271 0.008315 0.008159 + 4.964 0.006268 0.008312 0.008156 + 4.965 0.006266 0.008309 0.008153 + 4.966 0.006264 0.008306 0.008150 + 4.967 0.006262 0.008304 0.008148 + 4.968 0.006260 0.008301 0.008145 + 4.969 0.006258 0.008298 0.008142 + 4.970 0.006256 0.008295 0.008140 + 4.971 0.006254 0.008293 0.008137 + 4.972 0.006252 0.008290 0.008134 + 4.973 0.006250 0.008287 0.008132 + 4.974 0.006247 0.008284 0.008129 + 4.975 0.006245 0.008282 0.008126 + 4.976 0.006243 0.008279 0.008124 + 4.977 0.006241 0.008276 0.008121 + 4.978 0.006239 0.008273 0.008118 + 4.979 0.006237 0.008271 0.008116 + 4.980 0.006235 0.008268 0.008113 + 4.981 0.006233 0.008265 0.008110 + 4.982 0.006231 0.008262 0.008108 + 4.983 0.006229 0.008259 0.008105 + 4.984 0.006227 0.008257 0.008102 + 4.985 0.006225 0.008254 0.008100 + 4.986 0.006222 0.008251 0.008097 + 4.987 0.006220 0.008248 0.008094 + 4.988 0.006218 0.008246 0.008092 + 4.989 0.006216 0.008243 0.008089 + 4.990 0.006214 0.008240 0.008086 + 4.991 0.006212 0.008238 0.008084 + 4.992 0.006210 0.008235 0.008081 + 4.993 0.006208 0.008232 0.008078 + 4.994 0.006206 0.008229 0.008076 + 4.995 0.006204 0.008227 0.008073 + 4.996 0.006202 0.008224 0.008070 + 4.997 0.006200 0.008221 0.008068 + 4.998 0.006198 0.008218 0.008065 + 4.999 0.006196 0.008216 0.008062 + 5.000 0.006193 0.008213 0.008060 + 5.001 0.006191 0.008210 0.008057 + 5.002 0.006189 0.008207 0.008054 + 5.003 0.006187 0.008205 0.008052 + 5.004 0.006185 0.008202 0.008049 + 5.005 0.006183 0.008199 0.008046 + 5.006 0.006181 0.008197 0.008044 + 5.007 0.006179 0.008194 0.008041 + 5.008 0.006177 0.008191 0.008038 + 5.009 0.006175 0.008188 0.008036 + 5.010 0.006173 0.008186 0.008033 + 5.011 0.006171 0.008183 0.008031 + 5.012 0.006169 0.008180 0.008028 + 5.013 0.006167 0.008178 0.008025 + 5.014 0.006165 0.008175 0.008023 + 5.015 0.006163 0.008172 0.008020 + 5.016 0.006161 0.008169 0.008017 + 5.017 0.006159 0.008167 0.008015 + 5.018 0.006157 0.008164 0.008012 + 5.019 0.006154 0.008161 0.008010 + 5.020 0.006152 0.008159 0.008007 + 5.021 0.006150 0.008156 0.008004 + 5.022 0.006148 0.008153 0.008002 + 5.023 0.006146 0.008151 0.007999 + 5.024 0.006144 0.008148 0.007996 + 5.025 0.006142 0.008145 0.007994 + 5.026 0.006140 0.008142 0.007991 + 5.027 0.006138 0.008140 0.007989 + 5.028 0.006136 0.008137 0.007986 + 5.029 0.006134 0.008134 0.007983 + 5.030 0.006132 0.008132 0.007981 + 5.031 0.006130 0.008129 0.007978 + 5.032 0.006128 0.008126 0.007976 + 5.033 0.006126 0.008124 0.007973 + 5.034 0.006124 0.008121 0.007970 + 5.035 0.006122 0.008118 0.007968 + 5.036 0.006120 0.008116 0.007965 + 5.037 0.006118 0.008113 0.007963 + 5.038 0.006116 0.008110 0.007960 + 5.039 0.006114 0.008108 0.007957 + 5.040 0.006112 0.008105 0.007955 + 5.041 0.006110 0.008102 0.007952 + 5.042 0.006108 0.008100 0.007950 + 5.043 0.006106 0.008097 0.007947 + 5.044 0.006104 0.008094 0.007944 + 5.045 0.006102 0.008092 0.007942 + 5.046 0.006100 0.008089 0.007939 + 5.047 0.006098 0.008086 0.007937 + 5.048 0.006096 0.008084 0.007934 + 5.049 0.006094 0.008081 0.007932 + 5.050 0.006092 0.008078 0.007929 + 5.051 0.006090 0.008076 0.007926 + 5.052 0.006088 0.008073 0.007924 + 5.053 0.006086 0.008070 0.007921 + 5.054 0.006084 0.008068 0.007919 + 5.055 0.006082 0.008065 0.007916 + 5.056 0.006080 0.008062 0.007913 + 5.057 0.006078 0.008060 0.007911 + 5.058 0.006076 0.008057 0.007908 + 5.059 0.006074 0.008054 0.007906 + 5.060 0.006072 0.008052 0.007903 + 5.061 0.006070 0.008049 0.007901 + 5.062 0.006068 0.008047 0.007898 + 5.063 0.006066 0.008044 0.007896 + 5.064 0.006064 0.008041 0.007893 + 5.065 0.006062 0.008039 0.007890 + 5.066 0.006060 0.008036 0.007888 + 5.067 0.006058 0.008033 0.007885 + 5.068 0.006056 0.008031 0.007883 + 5.069 0.006054 0.008028 0.007880 + 5.070 0.006052 0.008025 0.007878 + 5.071 0.006050 0.008023 0.007875 + 5.072 0.006048 0.008020 0.007872 + 5.073 0.006046 0.008018 0.007870 + 5.074 0.006044 0.008015 0.007867 + 5.075 0.006042 0.008012 0.007865 + 5.076 0.006040 0.008010 0.007862 + 5.077 0.006038 0.008007 0.007860 + 5.078 0.006036 0.008004 0.007857 + 5.079 0.006034 0.008002 0.007855 + 5.080 0.006032 0.007999 0.007852 + 5.081 0.006030 0.007997 0.007850 + 5.082 0.006028 0.007994 0.007847 + 5.083 0.006026 0.007991 0.007845 + 5.084 0.006024 0.007989 0.007842 + 5.085 0.006022 0.007986 0.007839 + 5.086 0.006020 0.007984 0.007837 + 5.087 0.006018 0.007981 0.007834 + 5.088 0.006016 0.007978 0.007832 + 5.089 0.006014 0.007976 0.007829 + 5.090 0.006012 0.007973 0.007827 + 5.091 0.006010 0.007971 0.007824 + 5.092 0.006008 0.007968 0.007822 + 5.093 0.006006 0.007965 0.007819 + 5.094 0.006004 0.007963 0.007817 + 5.095 0.006002 0.007960 0.007814 + 5.096 0.006000 0.007958 0.007812 + 5.097 0.005998 0.007955 0.007809 + 5.098 0.005997 0.007952 0.007807 + 5.099 0.005995 0.007950 0.007804 + 5.100 0.005993 0.007947 0.007802 + 5.101 0.005991 0.007945 0.007799 + 5.102 0.005989 0.007942 0.007797 + 5.103 0.005987 0.007939 0.007794 + 5.104 0.005985 0.007937 0.007792 + 5.105 0.005983 0.007934 0.007789 + 5.106 0.005981 0.007932 0.007787 + 5.107 0.005979 0.007929 0.007784 + 5.108 0.005977 0.007927 0.007782 + 5.109 0.005975 0.007924 0.007779 + 5.110 0.005973 0.007921 0.007777 + 5.111 0.005971 0.007919 0.007774 + 5.112 0.005969 0.007916 0.007772 + 5.113 0.005967 0.007914 0.007769 + 5.114 0.005965 0.007911 0.007767 + 5.115 0.005963 0.007909 0.007764 + 5.116 0.005961 0.007906 0.007762 + 5.117 0.005960 0.007903 0.007759 + 5.118 0.005958 0.007901 0.007757 + 5.119 0.005956 0.007898 0.007754 + 5.120 0.005954 0.007896 0.007752 + 5.121 0.005952 0.007893 0.007749 + 5.122 0.005950 0.007891 0.007747 + 5.123 0.005948 0.007888 0.007744 + 5.124 0.005946 0.007885 0.007742 + 5.125 0.005944 0.007883 0.007739 + 5.126 0.005942 0.007880 0.007737 + 5.127 0.005940 0.007878 0.007734 + 5.128 0.005938 0.007875 0.007732 + 5.129 0.005936 0.007873 0.007729 + 5.130 0.005934 0.007870 0.007727 + 5.131 0.005932 0.007868 0.007724 + 5.132 0.005931 0.007865 0.007722 + 5.133 0.005929 0.007862 0.007719 + 5.134 0.005927 0.007860 0.007717 + 5.135 0.005925 0.007857 0.007714 + 5.136 0.005923 0.007855 0.007712 + 5.137 0.005921 0.007852 0.007709 + 5.138 0.005919 0.007850 0.007707 + 5.139 0.005917 0.007847 0.007705 + 5.140 0.005915 0.007845 0.007702 + 5.141 0.005913 0.007842 0.007700 + 5.142 0.005911 0.007840 0.007697 + 5.143 0.005909 0.007837 0.007695 + 5.144 0.005908 0.007835 0.007692 + 5.145 0.005906 0.007832 0.007690 + 5.146 0.005904 0.007830 0.007687 + 5.147 0.005902 0.007827 0.007685 + 5.148 0.005900 0.007824 0.007682 + 5.149 0.005898 0.007822 0.007680 + 5.150 0.005896 0.007819 0.007677 + 5.151 0.005894 0.007817 0.007675 + 5.152 0.005892 0.007814 0.007673 + 5.153 0.005890 0.007812 0.007670 + 5.154 0.005888 0.007809 0.007668 + 5.155 0.005887 0.007807 0.007665 + 5.156 0.005885 0.007804 0.007663 + 5.157 0.005883 0.007802 0.007660 + 5.158 0.005881 0.007799 0.007658 + 5.159 0.005879 0.007797 0.007655 + 5.160 0.005877 0.007794 0.007653 + 5.161 0.005875 0.007792 0.007651 + 5.162 0.005873 0.007789 0.007648 + 5.163 0.005871 0.007787 0.007646 + 5.164 0.005869 0.007784 0.007643 + 5.165 0.005868 0.007782 0.007641 + 5.166 0.005866 0.007779 0.007638 + 5.167 0.005864 0.007777 0.007636 + 5.168 0.005862 0.007774 0.007634 + 5.169 0.005860 0.007772 0.007631 + 5.170 0.005858 0.007769 0.007629 + 5.171 0.005856 0.007767 0.007626 + 5.172 0.005854 0.007764 0.007624 + 5.173 0.005852 0.007762 0.007621 + 5.174 0.005851 0.007759 0.007619 + 5.175 0.005849 0.007757 0.007617 + 5.176 0.005847 0.007754 0.007614 + 5.177 0.005845 0.007752 0.007612 + 5.178 0.005843 0.007749 0.007609 + 5.179 0.005841 0.007747 0.007607 + 5.180 0.005839 0.007744 0.007605 + 5.181 0.005837 0.007742 0.007602 + 5.182 0.005836 0.007739 0.007600 + 5.183 0.005834 0.007737 0.007597 + 5.184 0.005832 0.007734 0.007595 + 5.185 0.005830 0.007732 0.007592 + 5.186 0.005828 0.007729 0.007590 + 5.187 0.005826 0.007727 0.007588 + 5.188 0.005824 0.007725 0.007585 + 5.189 0.005822 0.007722 0.007583 + 5.190 0.005821 0.007720 0.007580 + 5.191 0.005819 0.007717 0.007578 + 5.192 0.005817 0.007715 0.007576 + 5.193 0.005815 0.007712 0.007573 + 5.194 0.005813 0.007710 0.007571 + 5.195 0.005811 0.007707 0.007568 + 5.196 0.005809 0.007705 0.007566 + 5.197 0.005808 0.007702 0.007564 + 5.198 0.005806 0.007700 0.007561 + 5.199 0.005804 0.007697 0.007559 + 5.200 0.005802 0.007695 0.007557 + 5.201 0.005800 0.007692 0.007554 + 5.202 0.005798 0.007690 0.007552 + 5.203 0.005796 0.007688 0.007549 + 5.204 0.005795 0.007685 0.007547 + 5.205 0.005793 0.007683 0.007545 + 5.206 0.005791 0.007680 0.007542 + 5.207 0.005789 0.007678 0.007540 + 5.208 0.005787 0.007675 0.007537 + 5.209 0.005785 0.007673 0.007535 + 5.210 0.005783 0.007670 0.007533 + 5.211 0.005782 0.007668 0.007530 + 5.212 0.005780 0.007666 0.007528 + 5.213 0.005778 0.007663 0.007526 + 5.214 0.005776 0.007661 0.007523 + 5.215 0.005774 0.007658 0.007521 + 5.216 0.005772 0.007656 0.007518 + 5.217 0.005771 0.007653 0.007516 + 5.218 0.005769 0.007651 0.007514 + 5.219 0.005767 0.007648 0.007511 + 5.220 0.005765 0.007646 0.007509 + 5.221 0.005763 0.007644 0.007507 + 5.222 0.005761 0.007641 0.007504 + 5.223 0.005760 0.007639 0.007502 + 5.224 0.005758 0.007636 0.007500 + 5.225 0.005756 0.007634 0.007497 + 5.226 0.005754 0.007631 0.007495 + 5.227 0.005752 0.007629 0.007492 + 5.228 0.005750 0.007627 0.007490 + 5.229 0.005749 0.007624 0.007488 + 5.230 0.005747 0.007622 0.007485 + 5.231 0.005745 0.007619 0.007483 + 5.232 0.005743 0.007617 0.007481 + 5.233 0.005741 0.007615 0.007478 + 5.234 0.005739 0.007612 0.007476 + 5.235 0.005738 0.007610 0.007474 + 5.236 0.005736 0.007607 0.007471 + 5.237 0.005734 0.007605 0.007469 + 5.238 0.005732 0.007602 0.007467 + 5.239 0.005730 0.007600 0.007464 + 5.240 0.005728 0.007598 0.007462 + 5.241 0.005727 0.007595 0.007460 + 5.242 0.005725 0.007593 0.007457 + 5.243 0.005723 0.007590 0.007455 + 5.244 0.005721 0.007588 0.007453 + 5.245 0.005719 0.007586 0.007450 + 5.246 0.005718 0.007583 0.007448 + 5.247 0.005716 0.007581 0.007446 + 5.248 0.005714 0.007578 0.007443 + 5.249 0.005712 0.007576 0.007441 + 5.250 0.005710 0.007574 0.007439 + 5.251 0.005708 0.007571 0.007436 + 5.252 0.005707 0.007569 0.007434 + 5.253 0.005705 0.007566 0.007432 + 5.254 0.005703 0.007564 0.007429 + 5.255 0.005701 0.007562 0.007427 + 5.256 0.005699 0.007559 0.007425 + 5.257 0.005698 0.007557 0.007422 + 5.258 0.005696 0.007554 0.007420 + 5.259 0.005694 0.007552 0.007418 + 5.260 0.005692 0.007550 0.007415 + 5.261 0.005690 0.007547 0.007413 + 5.262 0.005689 0.007545 0.007411 + 5.263 0.005687 0.007543 0.007408 + 5.264 0.005685 0.007540 0.007406 + 5.265 0.005683 0.007538 0.007404 + 5.266 0.005681 0.007535 0.007401 + 5.267 0.005680 0.007533 0.007399 + 5.268 0.005678 0.007531 0.007397 + 5.269 0.005676 0.007528 0.007395 + 5.270 0.005674 0.007526 0.007392 + 5.271 0.005672 0.007524 0.007390 + 5.272 0.005671 0.007521 0.007388 + 5.273 0.005669 0.007519 0.007385 + 5.274 0.005667 0.007516 0.007383 + 5.275 0.005665 0.007514 0.007381 + 5.276 0.005664 0.007512 0.007378 + 5.277 0.005662 0.007509 0.007376 + 5.278 0.005660 0.007507 0.007374 + 5.279 0.005658 0.007505 0.007372 + 5.280 0.005656 0.007502 0.007369 + 5.281 0.005655 0.007500 0.007367 + 5.282 0.005653 0.007498 0.007365 + 5.283 0.005651 0.007495 0.007362 + 5.284 0.005649 0.007493 0.007360 + 5.285 0.005647 0.007490 0.007358 + 5.286 0.005646 0.007488 0.007355 + 5.287 0.005644 0.007486 0.007353 + 5.288 0.005642 0.007483 0.007351 + 5.289 0.005640 0.007481 0.007349 + 5.290 0.005639 0.007479 0.007346 + 5.291 0.005637 0.007476 0.007344 + 5.292 0.005635 0.007474 0.007342 + 5.293 0.005633 0.007472 0.007339 + 5.294 0.005632 0.007469 0.007337 + 5.295 0.005630 0.007467 0.007335 + 5.296 0.005628 0.007465 0.007333 + 5.297 0.005626 0.007462 0.007330 + 5.298 0.005624 0.007460 0.007328 + 5.299 0.005623 0.007458 0.007326 + 5.300 0.005621 0.007455 0.007324 + 5.301 0.005619 0.007453 0.007321 + 5.302 0.005617 0.007451 0.007319 + 5.303 0.005616 0.007448 0.007317 + 5.304 0.005614 0.007446 0.007314 + 5.305 0.005612 0.007444 0.007312 + 5.306 0.005610 0.007441 0.007310 + 5.307 0.005609 0.007439 0.007308 + 5.308 0.005607 0.007437 0.007305 + 5.309 0.005605 0.007434 0.007303 + 5.310 0.005603 0.007432 0.007301 + 5.311 0.005602 0.007430 0.007299 + 5.312 0.005600 0.007427 0.007296 + 5.313 0.005598 0.007425 0.007294 + 5.314 0.005596 0.007423 0.007292 + 5.315 0.005595 0.007420 0.007290 + 5.316 0.005593 0.007418 0.007287 + 5.317 0.005591 0.007416 0.007285 + 5.318 0.005589 0.007413 0.007283 + 5.319 0.005588 0.007411 0.007281 + 5.320 0.005586 0.007409 0.007278 + 5.321 0.005584 0.007406 0.007276 + 5.322 0.005582 0.007404 0.007274 + 5.323 0.005581 0.007402 0.007272 + 5.324 0.005579 0.007400 0.007269 + 5.325 0.005577 0.007397 0.007267 + 5.326 0.005575 0.007395 0.007265 + 5.327 0.005574 0.007393 0.007263 + 5.328 0.005572 0.007390 0.007260 + 5.329 0.005570 0.007388 0.007258 + 5.330 0.005568 0.007386 0.007256 + 5.331 0.005567 0.007383 0.007254 + 5.332 0.005565 0.007381 0.007251 + 5.333 0.005563 0.007379 0.007249 + 5.334 0.005561 0.007377 0.007247 + 5.335 0.005560 0.007374 0.007245 + 5.336 0.005558 0.007372 0.007242 + 5.337 0.005556 0.007370 0.007240 + 5.338 0.005554 0.007367 0.007238 + 5.339 0.005553 0.007365 0.007236 + 5.340 0.005551 0.007363 0.007234 + 5.341 0.005549 0.007360 0.007231 + 5.342 0.005548 0.007358 0.007229 + 5.343 0.005546 0.007356 0.007227 + 5.344 0.005544 0.007354 0.007225 + 5.345 0.005542 0.007351 0.007222 + 5.346 0.005541 0.007349 0.007220 + 5.347 0.005539 0.007347 0.007218 + 5.348 0.005537 0.007344 0.007216 + 5.349 0.005535 0.007342 0.007214 + 5.350 0.005534 0.007340 0.007211 + 5.351 0.005532 0.007338 0.007209 + 5.352 0.005530 0.007335 0.007207 + 5.353 0.005529 0.007333 0.007205 + 5.354 0.005527 0.007331 0.007202 + 5.355 0.005525 0.007329 0.007200 + 5.356 0.005523 0.007326 0.007198 + 5.357 0.005522 0.007324 0.007196 + 5.358 0.005520 0.007322 0.007194 + 5.359 0.005518 0.007319 0.007191 + 5.360 0.005517 0.007317 0.007189 + 5.361 0.005515 0.007315 0.007187 + 5.362 0.005513 0.007313 0.007185 + 5.363 0.005511 0.007310 0.007183 + 5.364 0.005510 0.007308 0.007180 + 5.365 0.005508 0.007306 0.007178 + 5.366 0.005506 0.007304 0.007176 + 5.367 0.005505 0.007301 0.007174 + 5.368 0.005503 0.007299 0.007172 + 5.369 0.005501 0.007297 0.007169 + 5.370 0.005499 0.007295 0.007167 + 5.371 0.005498 0.007292 0.007165 + 5.372 0.005496 0.007290 0.007163 + 5.373 0.005494 0.007288 0.007161 + 5.374 0.005493 0.007286 0.007158 + 5.375 0.005491 0.007283 0.007156 + 5.376 0.005489 0.007281 0.007154 + 5.377 0.005488 0.007279 0.007152 + 5.378 0.005486 0.007277 0.007150 + 5.379 0.005484 0.007274 0.007148 + 5.380 0.005482 0.007272 0.007145 + 5.381 0.005481 0.007270 0.007143 + 5.382 0.005479 0.007268 0.007141 + 5.383 0.005477 0.007265 0.007139 + 5.384 0.005476 0.007263 0.007137 + 5.385 0.005474 0.007261 0.007134 + 5.386 0.005472 0.007259 0.007132 + 5.387 0.005471 0.007256 0.007130 + 5.388 0.005469 0.007254 0.007128 + 5.389 0.005467 0.007252 0.007126 + 5.390 0.005466 0.007250 0.007124 + 5.391 0.005464 0.007247 0.007121 + 5.392 0.005462 0.007245 0.007119 + 5.393 0.005460 0.007243 0.007117 + 5.394 0.005459 0.007241 0.007115 + 5.395 0.005457 0.007238 0.007113 + 5.396 0.005455 0.007236 0.007111 + 5.397 0.005454 0.007234 0.007108 + 5.398 0.005452 0.007232 0.007106 + 5.399 0.005450 0.007230 0.007104 + 5.400 0.005449 0.007227 0.007102 + 5.401 0.005447 0.007225 0.007100 + 5.402 0.005445 0.007223 0.007098 + 5.403 0.005444 0.007221 0.007095 + 5.404 0.005442 0.007218 0.007093 + 5.405 0.005440 0.007216 0.007091 + 5.406 0.005439 0.007214 0.007089 + 5.407 0.005437 0.007212 0.007087 + 5.408 0.005435 0.007210 0.007085 + 5.409 0.005434 0.007207 0.007082 + 5.410 0.005432 0.007205 0.007080 + 5.411 0.005430 0.007203 0.007078 + 5.412 0.005429 0.007201 0.007076 + 5.413 0.005427 0.007199 0.007074 + 5.414 0.005425 0.007196 0.007072 + 5.415 0.005424 0.007194 0.007070 + 5.416 0.005422 0.007192 0.007067 + 5.417 0.005420 0.007190 0.007065 + 5.418 0.005419 0.007187 0.007063 + 5.419 0.005417 0.007185 0.007061 + 5.420 0.005415 0.007183 0.007059 + 5.421 0.005414 0.007181 0.007057 + 5.422 0.005412 0.007179 0.007055 + 5.423 0.005410 0.007176 0.007052 + 5.424 0.005409 0.007174 0.007050 + 5.425 0.005407 0.007172 0.007048 + 5.426 0.005405 0.007170 0.007046 + 5.427 0.005404 0.007168 0.007044 + 5.428 0.005402 0.007166 0.007042 + 5.429 0.005400 0.007163 0.007040 + 5.430 0.005399 0.007161 0.007037 + 5.431 0.005397 0.007159 0.007035 + 5.432 0.005395 0.007157 0.007033 + 5.433 0.005394 0.007155 0.007031 + 5.434 0.005392 0.007152 0.007029 + 5.435 0.005390 0.007150 0.007027 + 5.436 0.005389 0.007148 0.007025 + 5.437 0.005387 0.007146 0.007023 + 5.438 0.005385 0.007144 0.007020 + 5.439 0.005384 0.007141 0.007018 + 5.440 0.005382 0.007139 0.007016 + 5.441 0.005380 0.007137 0.007014 + 5.442 0.005379 0.007135 0.007012 + 5.443 0.005377 0.007133 0.007010 + 5.444 0.005376 0.007131 0.007008 + 5.445 0.005374 0.007128 0.007006 + 5.446 0.005372 0.007126 0.007003 + 5.447 0.005371 0.007124 0.007001 + 5.448 0.005369 0.007122 0.006999 + 5.449 0.005367 0.007120 0.006997 + 5.450 0.005366 0.007118 0.006995 + 5.451 0.005364 0.007115 0.006993 + 5.452 0.005362 0.007113 0.006991 + 5.453 0.005361 0.007111 0.006989 + 5.454 0.005359 0.007109 0.006987 + 5.455 0.005358 0.007107 0.006984 + 5.456 0.005356 0.007105 0.006982 + 5.457 0.005354 0.007102 0.006980 + 5.458 0.005353 0.007100 0.006978 + 5.459 0.005351 0.007098 0.006976 + 5.460 0.005349 0.007096 0.006974 + 5.461 0.005348 0.007094 0.006972 + 5.462 0.005346 0.007092 0.006970 + 5.463 0.005344 0.007089 0.006968 + 5.464 0.005343 0.007087 0.006966 + 5.465 0.005341 0.007085 0.006963 + 5.466 0.005340 0.007083 0.006961 + 5.467 0.005338 0.007081 0.006959 + 5.468 0.005336 0.007079 0.006957 + 5.469 0.005335 0.007076 0.006955 + 5.470 0.005333 0.007074 0.006953 + 5.471 0.005331 0.007072 0.006951 + 5.472 0.005330 0.007070 0.006949 + 5.473 0.005328 0.007068 0.006947 + 5.474 0.005327 0.007066 0.006945 + 5.475 0.005325 0.007064 0.006943 + 5.476 0.005323 0.007061 0.006940 + 5.477 0.005322 0.007059 0.006938 + 5.478 0.005320 0.007057 0.006936 + 5.479 0.005319 0.007055 0.006934 + 5.480 0.005317 0.007053 0.006932 + 5.481 0.005315 0.007051 0.006930 + 5.482 0.005314 0.007049 0.006928 + 5.483 0.005312 0.007047 0.006926 + 5.484 0.005310 0.007044 0.006924 + 5.485 0.005309 0.007042 0.006922 + 5.486 0.005307 0.007040 0.006920 + 5.487 0.005306 0.007038 0.006918 + 5.488 0.005304 0.007036 0.006916 + 5.489 0.005302 0.007034 0.006913 + 5.490 0.005301 0.007032 0.006911 + 5.491 0.005299 0.007029 0.006909 + 5.492 0.005298 0.007027 0.006907 + 5.493 0.005296 0.007025 0.006905 + 5.494 0.005294 0.007023 0.006903 + 5.495 0.005293 0.007021 0.006901 + 5.496 0.005291 0.007019 0.006899 + 5.497 0.005290 0.007017 0.006897 + 5.498 0.005288 0.007015 0.006895 + 5.499 0.005286 0.007012 0.006893 + 5.500 0.005285 0.007010 0.006891 + 5.501 0.005283 0.007008 0.006889 + 5.502 0.005282 0.007006 0.006887 + 5.503 0.005280 0.007004 0.006885 + 5.504 0.005278 0.007002 0.006882 + 5.505 0.005277 0.007000 0.006880 + 5.506 0.005275 0.006998 0.006878 + 5.507 0.005274 0.006996 0.006876 + 5.508 0.005272 0.006993 0.006874 + 5.509 0.005270 0.006991 0.006872 + 5.510 0.005269 0.006989 0.006870 + 5.511 0.005267 0.006987 0.006868 + 5.512 0.005266 0.006985 0.006866 + 5.513 0.005264 0.006983 0.006864 + 5.514 0.005262 0.006981 0.006862 + 5.515 0.005261 0.006979 0.006860 + 5.516 0.005259 0.006977 0.006858 + 5.517 0.005258 0.006975 0.006856 + 5.518 0.005256 0.006972 0.006854 + 5.519 0.005254 0.006970 0.006852 + 5.520 0.005253 0.006968 0.006850 + 5.521 0.005251 0.006966 0.006848 + 5.522 0.005250 0.006964 0.006846 + 5.523 0.005248 0.006962 0.006844 + 5.524 0.005247 0.006960 0.006842 + 5.525 0.005245 0.006958 0.006839 + 5.526 0.005243 0.006956 0.006837 + 5.527 0.005242 0.006954 0.006835 + 5.528 0.005240 0.006951 0.006833 + 5.529 0.005239 0.006949 0.006831 + 5.530 0.005237 0.006947 0.006829 + 5.531 0.005236 0.006945 0.006827 + 5.532 0.005234 0.006943 0.006825 + 5.533 0.005232 0.006941 0.006823 + 5.534 0.005231 0.006939 0.006821 + 5.535 0.005229 0.006937 0.006819 + 5.536 0.005228 0.006935 0.006817 + 5.537 0.005226 0.006933 0.006815 + 5.538 0.005225 0.006931 0.006813 + 5.539 0.005223 0.006929 0.006811 + 5.540 0.005221 0.006926 0.006809 + 5.541 0.005220 0.006924 0.006807 + 5.542 0.005218 0.006922 0.006805 + 5.543 0.005217 0.006920 0.006803 + 5.544 0.005215 0.006918 0.006801 + 5.545 0.005214 0.006916 0.006799 + 5.546 0.005212 0.006914 0.006797 + 5.547 0.005210 0.006912 0.006795 + 5.548 0.005209 0.006910 0.006793 + 5.549 0.005207 0.006908 0.006791 + 5.550 0.005206 0.006906 0.006789 + 5.551 0.005204 0.006904 0.006787 + 5.552 0.005203 0.006902 0.006785 + 5.553 0.005201 0.006900 0.006783 + 5.554 0.005199 0.006897 0.006781 + 5.555 0.005198 0.006895 0.006779 + 5.556 0.005196 0.006893 0.006777 + 5.557 0.005195 0.006891 0.006775 + 5.558 0.005193 0.006889 0.006773 + 5.559 0.005192 0.006887 0.006771 + 5.560 0.005190 0.006885 0.006769 + 5.561 0.005189 0.006883 0.006767 + 5.562 0.005187 0.006881 0.006765 + 5.563 0.005185 0.006879 0.006763 + 5.564 0.005184 0.006877 0.006761 + 5.565 0.005182 0.006875 0.006759 + 5.566 0.005181 0.006873 0.006757 + 5.567 0.005179 0.006871 0.006755 + 5.568 0.005178 0.006869 0.006753 + 5.569 0.005176 0.006867 0.006751 + 5.570 0.005175 0.006865 0.006749 + 5.571 0.005173 0.006863 0.006747 + 5.572 0.005172 0.006861 0.006745 + 5.573 0.005170 0.006858 0.006743 + 5.574 0.005168 0.006856 0.006741 + 5.575 0.005167 0.006854 0.006739 + 5.576 0.005165 0.006852 0.006737 + 5.577 0.005164 0.006850 0.006735 + 5.578 0.005162 0.006848 0.006733 + 5.579 0.005161 0.006846 0.006731 + 5.580 0.005159 0.006844 0.006729 + 5.581 0.005158 0.006842 0.006727 + 5.582 0.005156 0.006840 0.006725 + 5.583 0.005155 0.006838 0.006723 + 5.584 0.005153 0.006836 0.006721 + 5.585 0.005152 0.006834 0.006719 + 5.586 0.005150 0.006832 0.006717 + 5.587 0.005148 0.006830 0.006715 + 5.588 0.005147 0.006828 0.006713 + 5.589 0.005145 0.006826 0.006711 + 5.590 0.005144 0.006824 0.006709 + 5.591 0.005142 0.006822 0.006707 + 5.592 0.005141 0.006820 0.006705 + 5.593 0.005139 0.006818 0.006703 + 5.594 0.005138 0.006816 0.006701 + 5.595 0.005136 0.006814 0.006699 + 5.596 0.005135 0.006812 0.006697 + 5.597 0.005133 0.006810 0.006695 + 5.598 0.005132 0.006808 0.006693 + 5.599 0.005130 0.006806 0.006691 + 5.600 0.005129 0.006804 0.006689 + 5.601 0.005127 0.006802 0.006687 + 5.602 0.005126 0.006800 0.006685 + 5.603 0.005124 0.006798 0.006684 + 5.604 0.005122 0.006796 0.006682 + 5.605 0.005121 0.006794 0.006680 + 5.606 0.005119 0.006792 0.006678 + 5.607 0.005118 0.006789 0.006676 + 5.608 0.005116 0.006787 0.006674 + 5.609 0.005115 0.006785 0.006672 + 5.610 0.005113 0.006783 0.006670 + 5.611 0.005112 0.006781 0.006668 + 5.612 0.005110 0.006779 0.006666 + 5.613 0.005109 0.006777 0.006664 + 5.614 0.005107 0.006775 0.006662 + 5.615 0.005106 0.006773 0.006660 + 5.616 0.005104 0.006771 0.006658 + 5.617 0.005103 0.006769 0.006656 + 5.618 0.005101 0.006767 0.006654 + 5.619 0.005100 0.006765 0.006652 + 5.620 0.005098 0.006763 0.006650 + 5.621 0.005097 0.006761 0.006648 + 5.622 0.005095 0.006759 0.006646 + 5.623 0.005094 0.006757 0.006644 + 5.624 0.005092 0.006755 0.006643 + 5.625 0.005091 0.006753 0.006641 + 5.626 0.005089 0.006751 0.006639 + 5.627 0.005088 0.006749 0.006637 + 5.628 0.005086 0.006747 0.006635 + 5.629 0.005085 0.006745 0.006633 + 5.630 0.005083 0.006743 0.006631 + 5.631 0.005082 0.006741 0.006629 + 5.632 0.005080 0.006739 0.006627 + 5.633 0.005079 0.006738 0.006625 + 5.634 0.005077 0.006736 0.006623 + 5.635 0.005076 0.006734 0.006621 + 5.636 0.005074 0.006732 0.006619 + 5.637 0.005073 0.006730 0.006617 + 5.638 0.005071 0.006728 0.006615 + 5.639 0.005070 0.006726 0.006613 + 5.640 0.005068 0.006724 0.006612 + 5.641 0.005067 0.006722 0.006610 + 5.642 0.005065 0.006720 0.006608 + 5.643 0.005064 0.006718 0.006606 + 5.644 0.005062 0.006716 0.006604 + 5.645 0.005061 0.006714 0.006602 + 5.646 0.005059 0.006712 0.006600 + 5.647 0.005058 0.006710 0.006598 + 5.648 0.005056 0.006708 0.006596 + 5.649 0.005055 0.006706 0.006594 + 5.650 0.005053 0.006704 0.006592 + 5.651 0.005052 0.006702 0.006590 + 5.652 0.005050 0.006700 0.006588 + 5.653 0.005049 0.006698 0.006587 + 5.654 0.005047 0.006696 0.006585 + 5.655 0.005046 0.006694 0.006583 + 5.656 0.005044 0.006692 0.006581 + 5.657 0.005043 0.006690 0.006579 + 5.658 0.005041 0.006688 0.006577 + 5.659 0.005040 0.006686 0.006575 + 5.660 0.005038 0.006684 0.006573 + 5.661 0.005037 0.006682 0.006571 + 5.662 0.005035 0.006680 0.006569 + 5.663 0.005034 0.006678 0.006567 + 5.664 0.005032 0.006676 0.006565 + 5.665 0.005031 0.006674 0.006564 + 5.666 0.005029 0.006672 0.006562 + 5.667 0.005028 0.006670 0.006560 + 5.668 0.005027 0.006669 0.006558 + 5.669 0.005025 0.006667 0.006556 + 5.670 0.005024 0.006665 0.006554 + 5.671 0.005022 0.006663 0.006552 + 5.672 0.005021 0.006661 0.006550 + 5.673 0.005019 0.006659 0.006548 + 5.674 0.005018 0.006657 0.006546 + 5.675 0.005016 0.006655 0.006545 + 5.676 0.005015 0.006653 0.006543 + 5.677 0.005013 0.006651 0.006541 + 5.678 0.005012 0.006649 0.006539 + 5.679 0.005010 0.006647 0.006537 + 5.680 0.005009 0.006645 0.006535 + 5.681 0.005007 0.006643 0.006533 + 5.682 0.005006 0.006641 0.006531 + 5.683 0.005004 0.006639 0.006529 + 5.684 0.005003 0.006637 0.006528 + 5.685 0.005002 0.006635 0.006526 + 5.686 0.005000 0.006633 0.006524 + 5.687 0.004999 0.006632 0.006522 + 5.688 0.004997 0.006630 0.006520 + 5.689 0.004996 0.006628 0.006518 + 5.690 0.004994 0.006626 0.006516 + 5.691 0.004993 0.006624 0.006514 + 5.692 0.004991 0.006622 0.006512 + 5.693 0.004990 0.006620 0.006511 + 5.694 0.004988 0.006618 0.006509 + 5.695 0.004987 0.006616 0.006507 + 5.696 0.004985 0.006614 0.006505 + 5.697 0.004984 0.006612 0.006503 + 5.698 0.004983 0.006610 0.006501 + 5.699 0.004981 0.006608 0.006499 + 5.700 0.004980 0.006606 0.006497 + 5.701 0.004978 0.006605 0.006496 + 5.702 0.004977 0.006603 0.006494 + 5.703 0.004975 0.006601 0.006492 + 5.704 0.004974 0.006599 0.006490 + 5.705 0.004972 0.006597 0.006488 + 5.706 0.004971 0.006595 0.006486 + 5.707 0.004969 0.006593 0.006484 + 5.708 0.004968 0.006591 0.006482 + 5.709 0.004967 0.006589 0.006481 + 5.710 0.004965 0.006587 0.006479 + 5.711 0.004964 0.006585 0.006477 + 5.712 0.004962 0.006583 0.006475 + 5.713 0.004961 0.006581 0.006473 + 5.714 0.004959 0.006580 0.006471 + 5.715 0.004958 0.006578 0.006469 + 5.716 0.004956 0.006576 0.006467 + 5.717 0.004955 0.006574 0.006466 + 5.718 0.004954 0.006572 0.006464 + 5.719 0.004952 0.006570 0.006462 + 5.720 0.004951 0.006568 0.006460 + 5.721 0.004949 0.006566 0.006458 + 5.722 0.004948 0.006564 0.006456 + 5.723 0.004946 0.006562 0.006454 + 5.724 0.004945 0.006560 0.006453 + 5.725 0.004943 0.006559 0.006451 + 5.726 0.004942 0.006557 0.006449 + 5.727 0.004941 0.006555 0.006447 + 5.728 0.004939 0.006553 0.006445 + 5.729 0.004938 0.006551 0.006443 + 5.730 0.004936 0.006549 0.006441 + 5.731 0.004935 0.006547 0.006440 + 5.732 0.004933 0.006545 0.006438 + 5.733 0.004932 0.006543 0.006436 + 5.734 0.004931 0.006541 0.006434 + 5.735 0.004929 0.006540 0.006432 + 5.736 0.004928 0.006538 0.006430 + 5.737 0.004926 0.006536 0.006429 + 5.738 0.004925 0.006534 0.006427 + 5.739 0.004923 0.006532 0.006425 + 5.740 0.004922 0.006530 0.006423 + 5.741 0.004921 0.006528 0.006421 + 5.742 0.004919 0.006526 0.006419 + 5.743 0.004918 0.006524 0.006418 + 5.744 0.004916 0.006523 0.006416 + 5.745 0.004915 0.006521 0.006414 + 5.746 0.004913 0.006519 0.006412 + 5.747 0.004912 0.006517 0.006410 + 5.748 0.004911 0.006515 0.006408 + 5.749 0.004909 0.006513 0.006406 + 5.750 0.004908 0.006511 0.006405 + 5.751 0.004906 0.006509 0.006403 + 5.752 0.004905 0.006508 0.006401 + 5.753 0.004903 0.006506 0.006399 + 5.754 0.004902 0.006504 0.006397 + 5.755 0.004901 0.006502 0.006396 + 5.756 0.004899 0.006500 0.006394 + 5.757 0.004898 0.006498 0.006392 + 5.758 0.004896 0.006496 0.006390 + 5.759 0.004895 0.006494 0.006388 + 5.760 0.004894 0.006492 0.006386 + 5.761 0.004892 0.006491 0.006385 + 5.762 0.004891 0.006489 0.006383 + 5.763 0.004889 0.006487 0.006381 + 5.764 0.004888 0.006485 0.006379 + 5.765 0.004886 0.006483 0.006377 + 5.766 0.004885 0.006481 0.006375 + 5.767 0.004884 0.006479 0.006374 + 5.768 0.004882 0.006478 0.006372 + 5.769 0.004881 0.006476 0.006370 + 5.770 0.004879 0.006474 0.006368 + 5.771 0.004878 0.006472 0.006366 + 5.772 0.004877 0.006470 0.006365 + 5.773 0.004875 0.006468 0.006363 + 5.774 0.004874 0.006466 0.006361 + 5.775 0.004872 0.006464 0.006359 + 5.776 0.004871 0.006463 0.006357 + 5.777 0.004870 0.006461 0.006355 + 5.778 0.004868 0.006459 0.006354 + 5.779 0.004867 0.006457 0.006352 + 5.780 0.004865 0.006455 0.006350 + 5.781 0.004864 0.006453 0.006348 + 5.782 0.004863 0.006451 0.006346 + 5.783 0.004861 0.006450 0.006345 + 5.784 0.004860 0.006448 0.006343 + 5.785 0.004858 0.006446 0.006341 + 5.786 0.004857 0.006444 0.006339 + 5.787 0.004856 0.006442 0.006337 + 5.788 0.004854 0.006440 0.006336 + 5.789 0.004853 0.006439 0.006334 + 5.790 0.004851 0.006437 0.006332 + 5.791 0.004850 0.006435 0.006330 + 5.792 0.004849 0.006433 0.006328 + 5.793 0.004847 0.006431 0.006327 + 5.794 0.004846 0.006429 0.006325 + 5.795 0.004844 0.006427 0.006323 + 5.796 0.004843 0.006426 0.006321 + 5.797 0.004842 0.006424 0.006319 + 5.798 0.004840 0.006422 0.006318 + 5.799 0.004839 0.006420 0.006316 + 5.800 0.004838 0.006418 0.006314 + 5.801 0.004836 0.006416 0.006312 + 5.802 0.004835 0.006415 0.006310 + 5.803 0.004833 0.006413 0.006309 + 5.804 0.004832 0.006411 0.006307 + 5.805 0.004831 0.006409 0.006305 + 5.806 0.004829 0.006407 0.006303 + 5.807 0.004828 0.006405 0.006302 + 5.808 0.004826 0.006404 0.006300 + 5.809 0.004825 0.006402 0.006298 + 5.810 0.004824 0.006400 0.006296 + 5.811 0.004822 0.006398 0.006294 + 5.812 0.004821 0.006396 0.006293 + 5.813 0.004820 0.006394 0.006291 + 5.814 0.004818 0.006393 0.006289 + 5.815 0.004817 0.006391 0.006287 + 5.816 0.004815 0.006389 0.006285 + 5.817 0.004814 0.006387 0.006284 + 5.818 0.004813 0.006385 0.006282 + 5.819 0.004811 0.006383 0.006280 + 5.820 0.004810 0.006382 0.006278 + 5.821 0.004808 0.006380 0.006277 + 5.822 0.004807 0.006378 0.006275 + 5.823 0.004806 0.006376 0.006273 + 5.824 0.004804 0.006374 0.006271 + 5.825 0.004803 0.006373 0.006269 + 5.826 0.004802 0.006371 0.006268 + 5.827 0.004800 0.006369 0.006266 + 5.828 0.004799 0.006367 0.006264 + 5.829 0.004797 0.006365 0.006262 + 5.830 0.004796 0.006363 0.006261 + 5.831 0.004795 0.006362 0.006259 + 5.832 0.004793 0.006360 0.006257 + 5.833 0.004792 0.006358 0.006255 + 5.834 0.004791 0.006356 0.006254 + 5.835 0.004789 0.006354 0.006252 + 5.836 0.004788 0.006353 0.006250 + 5.837 0.004787 0.006351 0.006248 + 5.838 0.004785 0.006349 0.006247 + 5.839 0.004784 0.006347 0.006245 + 5.840 0.004782 0.006345 0.006243 + 5.841 0.004781 0.006344 0.006241 + 5.842 0.004780 0.006342 0.006239 + 5.843 0.004778 0.006340 0.006238 + 5.844 0.004777 0.006338 0.006236 + 5.845 0.004776 0.006336 0.006234 + 5.846 0.004774 0.006335 0.006232 + 5.847 0.004773 0.006333 0.006231 + 5.848 0.004772 0.006331 0.006229 + 5.849 0.004770 0.006329 0.006227 + 5.850 0.004769 0.006327 0.006225 + 5.851 0.004767 0.006326 0.006224 + 5.852 0.004766 0.006324 0.006222 + 5.853 0.004765 0.006322 0.006220 + 5.854 0.004763 0.006320 0.006218 + 5.855 0.004762 0.006318 0.006217 + 5.856 0.004761 0.006317 0.006215 + 5.857 0.004759 0.006315 0.006213 + 5.858 0.004758 0.006313 0.006211 + 5.859 0.004757 0.006311 0.006210 + 5.860 0.004755 0.006309 0.006208 + 5.861 0.004754 0.006308 0.006206 + 5.862 0.004753 0.006306 0.006204 + 5.863 0.004751 0.006304 0.006203 + 5.864 0.004750 0.006302 0.006201 + 5.865 0.004749 0.006301 0.006199 + 5.866 0.004747 0.006299 0.006197 + 5.867 0.004746 0.006297 0.006196 + 5.868 0.004745 0.006295 0.006194 + 5.869 0.004743 0.006293 0.006192 + 5.870 0.004742 0.006292 0.006191 + 5.871 0.004740 0.006290 0.006189 + 5.872 0.004739 0.006288 0.006187 + 5.873 0.004738 0.006286 0.006185 + 5.874 0.004736 0.006284 0.006184 + 5.875 0.004735 0.006283 0.006182 + 5.876 0.004734 0.006281 0.006180 + 5.877 0.004732 0.006279 0.006178 + 5.878 0.004731 0.006277 0.006177 + 5.879 0.004730 0.006276 0.006175 + 5.880 0.004728 0.006274 0.006173 + 5.881 0.004727 0.006272 0.006171 + 5.882 0.004726 0.006270 0.006170 + 5.883 0.004724 0.006269 0.006168 + 5.884 0.004723 0.006267 0.006166 + 5.885 0.004722 0.006265 0.006165 + 5.886 0.004720 0.006263 0.006163 + 5.887 0.004719 0.006261 0.006161 + 5.888 0.004718 0.006260 0.006159 + 5.889 0.004716 0.006258 0.006158 + 5.890 0.004715 0.006256 0.006156 + 5.891 0.004714 0.006254 0.006154 + 5.892 0.004712 0.006253 0.006153 + 5.893 0.004711 0.006251 0.006151 + 5.894 0.004710 0.006249 0.006149 + 5.895 0.004708 0.006247 0.006147 + 5.896 0.004707 0.006246 0.006146 + 5.897 0.004706 0.006244 0.006144 + 5.898 0.004704 0.006242 0.006142 + 5.899 0.004703 0.006240 0.006141 + 5.900 0.004702 0.006239 0.006139 + 5.901 0.004700 0.006237 0.006137 + 5.902 0.004699 0.006235 0.006135 + 5.903 0.004698 0.006233 0.006134 + 5.904 0.004696 0.006231 0.006132 + 5.905 0.004695 0.006230 0.006130 + 5.906 0.004694 0.006228 0.006129 + 5.907 0.004692 0.006226 0.006127 + 5.908 0.004691 0.006224 0.006125 + 5.909 0.004690 0.006223 0.006123 + 5.910 0.004689 0.006221 0.006122 + 5.911 0.004687 0.006219 0.006120 + 5.912 0.004686 0.006217 0.006118 + 5.913 0.004685 0.006216 0.006117 + 5.914 0.004683 0.006214 0.006115 + 5.915 0.004682 0.006212 0.006113 + 5.916 0.004681 0.006211 0.006111 + 5.917 0.004679 0.006209 0.006110 + 5.918 0.004678 0.006207 0.006108 + 5.919 0.004677 0.006205 0.006106 + 5.920 0.004675 0.006204 0.006105 + 5.921 0.004674 0.006202 0.006103 + 5.922 0.004673 0.006200 0.006101 + 5.923 0.004671 0.006198 0.006100 + 5.924 0.004670 0.006197 0.006098 + 5.925 0.004669 0.006195 0.006096 + 5.926 0.004667 0.006193 0.006095 + 5.927 0.004666 0.006191 0.006093 + 5.928 0.004665 0.006190 0.006091 + 5.929 0.004664 0.006188 0.006089 + 5.930 0.004662 0.006186 0.006088 + 5.931 0.004661 0.006184 0.006086 + 5.932 0.004660 0.006183 0.006084 + 5.933 0.004658 0.006181 0.006083 + 5.934 0.004657 0.006179 0.006081 + 5.935 0.004656 0.006178 0.006079 + 5.936 0.004654 0.006176 0.006078 + 5.937 0.004653 0.006174 0.006076 + 5.938 0.004652 0.006172 0.006074 + 5.939 0.004650 0.006171 0.006073 + 5.940 0.004649 0.006169 0.006071 + 5.941 0.004648 0.006167 0.006069 + 5.942 0.004647 0.006165 0.006068 + 5.943 0.004645 0.006164 0.006066 + 5.944 0.004644 0.006162 0.006064 + 5.945 0.004643 0.006160 0.006062 + 5.946 0.004641 0.006159 0.006061 + 5.947 0.004640 0.006157 0.006059 + 5.948 0.004639 0.006155 0.006057 + 5.949 0.004637 0.006153 0.006056 + 5.950 0.004636 0.006152 0.006054 + 5.951 0.004635 0.006150 0.006052 + 5.952 0.004634 0.006148 0.006051 + 5.953 0.004632 0.006146 0.006049 + 5.954 0.004631 0.006145 0.006047 + 5.955 0.004630 0.006143 0.006046 + 5.956 0.004628 0.006141 0.006044 + 5.957 0.004627 0.006140 0.006042 + 5.958 0.004626 0.006138 0.006041 + 5.959 0.004625 0.006136 0.006039 + 5.960 0.004623 0.006135 0.006037 + 5.961 0.004622 0.006133 0.006036 + 5.962 0.004621 0.006131 0.006034 + 5.963 0.004619 0.006129 0.006032 + 5.964 0.004618 0.006128 0.006031 + 5.965 0.004617 0.006126 0.006029 + 5.966 0.004615 0.006124 0.006027 + 5.967 0.004614 0.006123 0.006026 + 5.968 0.004613 0.006121 0.006024 + 5.969 0.004612 0.006119 0.006022 + 5.970 0.004610 0.006117 0.006021 + 5.971 0.004609 0.006116 0.006019 + 5.972 0.004608 0.006114 0.006017 + 5.973 0.004606 0.006112 0.006016 + 5.974 0.004605 0.006111 0.006014 + 5.975 0.004604 0.006109 0.006012 + 5.976 0.004603 0.006107 0.006011 + 5.977 0.004601 0.006106 0.006009 + 5.978 0.004600 0.006104 0.006007 + 5.979 0.004599 0.006102 0.006006 + 5.980 0.004597 0.006100 0.006004 + 5.981 0.004596 0.006099 0.006003 + 5.982 0.004595 0.006097 0.006001 + 5.983 0.004594 0.006095 0.005999 + 5.984 0.004592 0.006094 0.005998 + 5.985 0.004591 0.006092 0.005996 + 5.986 0.004590 0.006090 0.005994 + 5.987 0.004589 0.006089 0.005993 + 5.988 0.004587 0.006087 0.005991 + 5.989 0.004586 0.006085 0.005989 + 5.990 0.004585 0.006084 0.005988 + 5.991 0.004583 0.006082 0.005986 + 5.992 0.004582 0.006080 0.005984 + 5.993 0.004581 0.006078 0.005983 + 5.994 0.004580 0.006077 0.005981 + 5.995 0.004578 0.006075 0.005979 + 5.996 0.004577 0.006073 0.005978 + 5.997 0.004576 0.006072 0.005976 + 5.998 0.004575 0.006070 0.005975 + 5.999 0.004573 0.006068 0.005973 + 6.000 0.004572 0.006067 0.005971 + 6.001 0.004571 0.006065 0.005970 + 6.002 0.004569 0.006063 0.005968 + 6.003 0.004568 0.006062 0.005966 + 6.004 0.004567 0.006060 0.005965 + 6.005 0.004566 0.006058 0.005963 + 6.006 0.004564 0.006057 0.005961 + 6.007 0.004563 0.006055 0.005960 + 6.008 0.004562 0.006053 0.005958 + 6.009 0.004561 0.006052 0.005957 + 6.010 0.004559 0.006050 0.005955 + 6.011 0.004558 0.006048 0.005953 + 6.012 0.004557 0.006047 0.005952 + 6.013 0.004556 0.006045 0.005950 + 6.014 0.004554 0.006043 0.005948 + 6.015 0.004553 0.006042 0.005947 + 6.016 0.004552 0.006040 0.005945 + 6.017 0.004551 0.006038 0.005943 + 6.018 0.004549 0.006037 0.005942 + 6.019 0.004548 0.006035 0.005940 + 6.020 0.004547 0.006033 0.005939 + 6.021 0.004545 0.006032 0.005937 + 6.022 0.004544 0.006030 0.005935 + 6.023 0.004543 0.006028 0.005934 + 6.024 0.004542 0.006027 0.005932 + 6.025 0.004540 0.006025 0.005930 + 6.026 0.004539 0.006023 0.005929 + 6.027 0.004538 0.006022 0.005927 + 6.028 0.004537 0.006020 0.005926 + 6.029 0.004535 0.006018 0.005924 + 6.030 0.004534 0.006017 0.005922 + 6.031 0.004533 0.006015 0.005921 + 6.032 0.004532 0.006013 0.005919 + 6.033 0.004530 0.006012 0.005918 + 6.034 0.004529 0.006010 0.005916 + 6.035 0.004528 0.006008 0.005914 + 6.036 0.004527 0.006007 0.005913 + 6.037 0.004525 0.006005 0.005911 + 6.038 0.004524 0.006003 0.005909 + 6.039 0.004523 0.006002 0.005908 + 6.040 0.004522 0.006000 0.005906 + 6.041 0.004520 0.005998 0.005905 + 6.042 0.004519 0.005997 0.005903 + 6.043 0.004518 0.005995 0.005901 + 6.044 0.004517 0.005993 0.005900 + 6.045 0.004515 0.005992 0.005898 + 6.046 0.004514 0.005990 0.005897 + 6.047 0.004513 0.005989 0.005895 + 6.048 0.004512 0.005987 0.005893 + 6.049 0.004511 0.005985 0.005892 + 6.050 0.004509 0.005984 0.005890 + 6.051 0.004508 0.005982 0.005889 + 6.052 0.004507 0.005980 0.005887 + 6.053 0.004506 0.005979 0.005885 + 6.054 0.004504 0.005977 0.005884 + 6.055 0.004503 0.005975 0.005882 + 6.056 0.004502 0.005974 0.005881 + 6.057 0.004501 0.005972 0.005879 + 6.058 0.004499 0.005970 0.005877 + 6.059 0.004498 0.005969 0.005876 + 6.060 0.004497 0.005967 0.005874 + 6.061 0.004496 0.005966 0.005873 + 6.062 0.004494 0.005964 0.005871 + 6.063 0.004493 0.005962 0.005869 + 6.064 0.004492 0.005961 0.005868 + 6.065 0.004491 0.005959 0.005866 + 6.066 0.004489 0.005957 0.005865 + 6.067 0.004488 0.005956 0.005863 + 6.068 0.004487 0.005954 0.005861 + 6.069 0.004486 0.005953 0.005860 + 6.070 0.004485 0.005951 0.005858 + 6.071 0.004483 0.005949 0.005857 + 6.072 0.004482 0.005948 0.005855 + 6.073 0.004481 0.005946 0.005853 + 6.074 0.004480 0.005944 0.005852 + 6.075 0.004478 0.005943 0.005850 + 6.076 0.004477 0.005941 0.005849 + 6.077 0.004476 0.005939 0.005847 + 6.078 0.004475 0.005938 0.005846 + 6.079 0.004474 0.005936 0.005844 + 6.080 0.004472 0.005935 0.005842 + 6.081 0.004471 0.005933 0.005841 + 6.082 0.004470 0.005931 0.005839 + 6.083 0.004469 0.005930 0.005838 + 6.084 0.004467 0.005928 0.005836 + 6.085 0.004466 0.005927 0.005834 + 6.086 0.004465 0.005925 0.005833 + 6.087 0.004464 0.005923 0.005831 + 6.088 0.004462 0.005922 0.005830 + 6.089 0.004461 0.005920 0.005828 + 6.090 0.004460 0.005918 0.005827 + 6.091 0.004459 0.005917 0.005825 + 6.092 0.004458 0.005915 0.005823 + 6.093 0.004456 0.005914 0.005822 + 6.094 0.004455 0.005912 0.005820 + 6.095 0.004454 0.005910 0.005819 + 6.096 0.004453 0.005909 0.005817 + 6.097 0.004452 0.005907 0.005816 + 6.098 0.004450 0.005906 0.005814 + 6.099 0.004449 0.005904 0.005812 + 6.100 0.004448 0.005902 0.005811 + 6.101 0.004447 0.005901 0.005809 + 6.102 0.004445 0.005899 0.005808 + 6.103 0.004444 0.005897 0.005806 + 6.104 0.004443 0.005896 0.005805 + 6.105 0.004442 0.005894 0.005803 + 6.106 0.004441 0.005893 0.005801 + 6.107 0.004439 0.005891 0.005800 + 6.108 0.004438 0.005889 0.005798 + 6.109 0.004437 0.005888 0.005797 + 6.110 0.004436 0.005886 0.005795 + 6.111 0.004435 0.005885 0.005794 + 6.112 0.004433 0.005883 0.005792 + 6.113 0.004432 0.005881 0.005791 + 6.114 0.004431 0.005880 0.005789 + 6.115 0.004430 0.005878 0.005787 + 6.116 0.004429 0.005877 0.005786 + 6.117 0.004427 0.005875 0.005784 + 6.118 0.004426 0.005873 0.005783 + 6.119 0.004425 0.005872 0.005781 + 6.120 0.004424 0.005870 0.005780 + 6.121 0.004423 0.005869 0.005778 + 6.122 0.004421 0.005867 0.005777 + 6.123 0.004420 0.005866 0.005775 + 6.124 0.004419 0.005864 0.005773 + 6.125 0.004418 0.005862 0.005772 + 6.126 0.004417 0.005861 0.005770 + 6.127 0.004415 0.005859 0.005769 + 6.128 0.004414 0.005858 0.005767 + 6.129 0.004413 0.005856 0.005766 + 6.130 0.004412 0.005854 0.005764 + 6.131 0.004411 0.005853 0.005763 + 6.132 0.004409 0.005851 0.005761 + 6.133 0.004408 0.005850 0.005759 + 6.134 0.004407 0.005848 0.005758 + 6.135 0.004406 0.005846 0.005756 + 6.136 0.004405 0.005845 0.005755 + 6.137 0.004403 0.005843 0.005753 + 6.138 0.004402 0.005842 0.005752 + 6.139 0.004401 0.005840 0.005750 + 6.140 0.004400 0.005839 0.005749 + 6.141 0.004399 0.005837 0.005747 + 6.142 0.004397 0.005835 0.005746 + 6.143 0.004396 0.005834 0.005744 + 6.144 0.004395 0.005832 0.005742 + 6.145 0.004394 0.005831 0.005741 + 6.146 0.004393 0.005829 0.005739 + 6.147 0.004391 0.005828 0.005738 + 6.148 0.004390 0.005826 0.005736 + 6.149 0.004389 0.005824 0.005735 + 6.150 0.004388 0.005823 0.005733 + 6.151 0.004387 0.005821 0.005732 + 6.152 0.004385 0.005820 0.005730 + 6.153 0.004384 0.005818 0.005729 + 6.154 0.004383 0.005816 0.005727 + 6.155 0.004382 0.005815 0.005726 + 6.156 0.004381 0.005813 0.005724 + 6.157 0.004380 0.005812 0.005723 + 6.158 0.004378 0.005810 0.005721 + 6.159 0.004377 0.005809 0.005719 + 6.160 0.004376 0.005807 0.005718 + 6.161 0.004375 0.005806 0.005716 + 6.162 0.004374 0.005804 0.005715 + 6.163 0.004372 0.005802 0.005713 + 6.164 0.004371 0.005801 0.005712 + 6.165 0.004370 0.005799 0.005710 + 6.166 0.004369 0.005798 0.005709 + 6.167 0.004368 0.005796 0.005707 + 6.168 0.004367 0.005795 0.005706 + 6.169 0.004365 0.005793 0.005704 + 6.170 0.004364 0.005791 0.005703 + 6.171 0.004363 0.005790 0.005701 + 6.172 0.004362 0.005788 0.005700 + 6.173 0.004361 0.005787 0.005698 + 6.174 0.004359 0.005785 0.005697 + 6.175 0.004358 0.005784 0.005695 + 6.176 0.004357 0.005782 0.005694 + 6.177 0.004356 0.005781 0.005692 + 6.178 0.004355 0.005779 0.005691 + 6.179 0.004354 0.005777 0.005689 + 6.180 0.004352 0.005776 0.005687 + 6.181 0.004351 0.005774 0.005686 + 6.182 0.004350 0.005773 0.005684 + 6.183 0.004349 0.005771 0.005683 + 6.184 0.004348 0.005770 0.005681 + 6.185 0.004347 0.005768 0.005680 + 6.186 0.004345 0.005767 0.005678 + 6.187 0.004344 0.005765 0.005677 + 6.188 0.004343 0.005763 0.005675 + 6.189 0.004342 0.005762 0.005674 + 6.190 0.004341 0.005760 0.005672 + 6.191 0.004340 0.005759 0.005671 + 6.192 0.004338 0.005757 0.005669 + 6.193 0.004337 0.005756 0.005668 + 6.194 0.004336 0.005754 0.005666 + 6.195 0.004335 0.005753 0.005665 + 6.196 0.004334 0.005751 0.005663 + 6.197 0.004333 0.005750 0.005662 + 6.198 0.004331 0.005748 0.005660 + 6.199 0.004330 0.005746 0.005659 + 6.200 0.004329 0.005745 0.005657 + 6.201 0.004328 0.005743 0.005656 + 6.202 0.004327 0.005742 0.005654 + 6.203 0.004326 0.005740 0.005653 + 6.204 0.004324 0.005739 0.005651 + 6.205 0.004323 0.005737 0.005650 + 6.206 0.004322 0.005736 0.005648 + 6.207 0.004321 0.005734 0.005647 + 6.208 0.004320 0.005733 0.005645 + 6.209 0.004319 0.005731 0.005644 + 6.210 0.004317 0.005730 0.005642 + 6.211 0.004316 0.005728 0.005641 + 6.212 0.004315 0.005727 0.005639 + 6.213 0.004314 0.005725 0.005638 + 6.214 0.004313 0.005723 0.005636 + 6.215 0.004312 0.005722 0.005635 + 6.216 0.004311 0.005720 0.005633 + 6.217 0.004309 0.005719 0.005632 + 6.218 0.004308 0.005717 0.005630 + 6.219 0.004307 0.005716 0.005629 + 6.220 0.004306 0.005714 0.005627 + 6.221 0.004305 0.005713 0.005626 + 6.222 0.004304 0.005711 0.005624 + 6.223 0.004302 0.005710 0.005623 + 6.224 0.004301 0.005708 0.005621 + 6.225 0.004300 0.005707 0.005620 + 6.226 0.004299 0.005705 0.005618 + 6.227 0.004298 0.005704 0.005617 + 6.228 0.004297 0.005702 0.005615 + 6.229 0.004296 0.005701 0.005614 + 6.230 0.004294 0.005699 0.005612 + 6.231 0.004293 0.005698 0.005611 + 6.232 0.004292 0.005696 0.005609 + 6.233 0.004291 0.005694 0.005608 + 6.234 0.004290 0.005693 0.005607 + 6.235 0.004289 0.005691 0.005605 + 6.236 0.004288 0.005690 0.005604 + 6.237 0.004286 0.005688 0.005602 + 6.238 0.004285 0.005687 0.005601 + 6.239 0.004284 0.005685 0.005599 + 6.240 0.004283 0.005684 0.005598 + 6.241 0.004282 0.005682 0.005596 + 6.242 0.004281 0.005681 0.005595 + 6.243 0.004280 0.005679 0.005593 + 6.244 0.004278 0.005678 0.005592 + 6.245 0.004277 0.005676 0.005590 + 6.246 0.004276 0.005675 0.005589 + 6.247 0.004275 0.005673 0.005587 + 6.248 0.004274 0.005672 0.005586 + 6.249 0.004273 0.005670 0.005584 + 6.250 0.004272 0.005669 0.005583 + 6.251 0.004270 0.005667 0.005581 + 6.252 0.004269 0.005666 0.005580 + 6.253 0.004268 0.005664 0.005578 + 6.254 0.004267 0.005663 0.005577 + 6.255 0.004266 0.005661 0.005576 + 6.256 0.004265 0.005660 0.005574 + 6.257 0.004264 0.005658 0.005573 + 6.258 0.004262 0.005657 0.005571 + 6.259 0.004261 0.005655 0.005570 + 6.260 0.004260 0.005654 0.005568 + 6.261 0.004259 0.005652 0.005567 + 6.262 0.004258 0.005651 0.005565 + 6.263 0.004257 0.005649 0.005564 + 6.264 0.004256 0.005648 0.005562 + 6.265 0.004255 0.005646 0.005561 + 6.266 0.004253 0.005645 0.005559 + 6.267 0.004252 0.005643 0.005558 + 6.268 0.004251 0.005642 0.005557 + 6.269 0.004250 0.005640 0.005555 + 6.270 0.004249 0.005639 0.005554 + 6.271 0.004248 0.005637 0.005552 + 6.272 0.004247 0.005636 0.005551 + 6.273 0.004246 0.005634 0.005549 + 6.274 0.004244 0.005633 0.005548 + 6.275 0.004243 0.005631 0.005546 + 6.276 0.004242 0.005630 0.005545 + 6.277 0.004241 0.005628 0.005543 + 6.278 0.004240 0.005627 0.005542 + 6.279 0.004239 0.005625 0.005540 + 6.280 0.004238 0.005624 0.005539 + 6.281 0.004237 0.005622 0.005538 + 6.282 0.004235 0.005621 0.005536 + 6.283 0.004234 0.005619 0.005535 + 6.284 0.004233 0.005618 0.005533 + 6.285 0.004232 0.005616 0.005532 + 6.286 0.004231 0.005615 0.005530 + 6.287 0.004230 0.005613 0.005529 + 6.288 0.004229 0.005612 0.005527 + 6.289 0.004228 0.005610 0.005526 + 6.290 0.004226 0.005609 0.005525 + 6.291 0.004225 0.005607 0.005523 + 6.292 0.004224 0.005606 0.005522 + 6.293 0.004223 0.005605 0.005520 + 6.294 0.004222 0.005603 0.005519 + 6.295 0.004221 0.005602 0.005517 + 6.296 0.004220 0.005600 0.005516 + 6.297 0.004219 0.005599 0.005514 + 6.298 0.004217 0.005597 0.005513 + 6.299 0.004216 0.005596 0.005512 + 6.300 0.004215 0.005594 0.005510 + 6.301 0.004214 0.005593 0.005509 + 6.302 0.004213 0.005591 0.005507 + 6.303 0.004212 0.005590 0.005506 + 6.304 0.004211 0.005588 0.005504 + 6.305 0.004210 0.005587 0.005503 + 6.306 0.004209 0.005585 0.005501 + 6.307 0.004207 0.005584 0.005500 + 6.308 0.004206 0.005582 0.005499 + 6.309 0.004205 0.005581 0.005497 + 6.310 0.004204 0.005579 0.005496 + 6.311 0.004203 0.005578 0.005494 + 6.312 0.004202 0.005577 0.005493 + 6.313 0.004201 0.005575 0.005491 + 6.314 0.004200 0.005574 0.005490 + 6.315 0.004199 0.005572 0.005489 + 6.316 0.004197 0.005571 0.005487 + 6.317 0.004196 0.005569 0.005486 + 6.318 0.004195 0.005568 0.005484 + 6.319 0.004194 0.005566 0.005483 + 6.320 0.004193 0.005565 0.005481 + 6.321 0.004192 0.005563 0.005480 + 6.322 0.004191 0.005562 0.005479 + 6.323 0.004190 0.005560 0.005477 + 6.324 0.004189 0.005559 0.005476 + 6.325 0.004188 0.005557 0.005474 + 6.326 0.004186 0.005556 0.005473 + 6.327 0.004185 0.005555 0.005471 + 6.328 0.004184 0.005553 0.005470 + 6.329 0.004183 0.005552 0.005469 + 6.330 0.004182 0.005550 0.005467 + 6.331 0.004181 0.005549 0.005466 + 6.332 0.004180 0.005547 0.005464 + 6.333 0.004179 0.005546 0.005463 + 6.334 0.004178 0.005544 0.005461 + 6.335 0.004177 0.005543 0.005460 + 6.336 0.004175 0.005541 0.005459 + 6.337 0.004174 0.005540 0.005457 + 6.338 0.004173 0.005539 0.005456 + 6.339 0.004172 0.005537 0.005454 + 6.340 0.004171 0.005536 0.005453 + 6.341 0.004170 0.005534 0.005452 + 6.342 0.004169 0.005533 0.005450 + 6.343 0.004168 0.005531 0.005449 + 6.344 0.004167 0.005530 0.005447 + 6.345 0.004166 0.005528 0.005446 + 6.346 0.004165 0.005527 0.005444 + 6.347 0.004163 0.005526 0.005443 + 6.348 0.004162 0.005524 0.005442 + 6.349 0.004161 0.005523 0.005440 + 6.350 0.004160 0.005521 0.005439 + 6.351 0.004159 0.005520 0.005437 + 6.352 0.004158 0.005518 0.005436 + 6.353 0.004157 0.005517 0.005435 + 6.354 0.004156 0.005515 0.005433 + 6.355 0.004155 0.005514 0.005432 + 6.356 0.004154 0.005513 0.005430 + 6.357 0.004153 0.005511 0.005429 + 6.358 0.004151 0.005510 0.005428 + 6.359 0.004150 0.005508 0.005426 + 6.360 0.004149 0.005507 0.005425 + 6.361 0.004148 0.005505 0.005423 + 6.362 0.004147 0.005504 0.005422 + 6.363 0.004146 0.005502 0.005420 + 6.364 0.004145 0.005501 0.005419 + 6.365 0.004144 0.005500 0.005418 + 6.366 0.004143 0.005498 0.005416 + 6.367 0.004142 0.005497 0.005415 + 6.368 0.004141 0.005495 0.005413 + 6.369 0.004139 0.005494 0.005412 + 6.370 0.004138 0.005492 0.005411 + 6.371 0.004137 0.005491 0.005409 + 6.372 0.004136 0.005490 0.005408 + 6.373 0.004135 0.005488 0.005406 + 6.374 0.004134 0.005487 0.005405 + 6.375 0.004133 0.005485 0.005404 + 6.376 0.004132 0.005484 0.005402 + 6.377 0.004131 0.005482 0.005401 + 6.378 0.004130 0.005481 0.005399 + 6.379 0.004129 0.005480 0.005398 + 6.380 0.004128 0.005478 0.005397 + 6.381 0.004127 0.005477 0.005395 + 6.382 0.004125 0.005475 0.005394 + 6.383 0.004124 0.005474 0.005393 + 6.384 0.004123 0.005472 0.005391 + 6.385 0.004122 0.005471 0.005390 + 6.386 0.004121 0.005470 0.005388 + 6.387 0.004120 0.005468 0.005387 + 6.388 0.004119 0.005467 0.005386 + 6.389 0.004118 0.005465 0.005384 + 6.390 0.004117 0.005464 0.005383 + 6.391 0.004116 0.005462 0.005381 + 6.392 0.004115 0.005461 0.005380 + 6.393 0.004114 0.005460 0.005379 + 6.394 0.004113 0.005458 0.005377 + 6.395 0.004112 0.005457 0.005376 + 6.396 0.004110 0.005455 0.005374 + 6.397 0.004109 0.005454 0.005373 + 6.398 0.004108 0.005452 0.005372 + 6.399 0.004107 0.005451 0.005370 + 6.400 0.004106 0.005450 0.005369 + 6.401 0.004105 0.005448 0.005368 + 6.402 0.004104 0.005447 0.005366 + 6.403 0.004103 0.005445 0.005365 + 6.404 0.004102 0.005444 0.005363 + 6.405 0.004101 0.005443 0.005362 + 6.406 0.004100 0.005441 0.005361 + 6.407 0.004099 0.005440 0.005359 + 6.408 0.004098 0.005438 0.005358 + 6.409 0.004097 0.005437 0.005357 + 6.410 0.004096 0.005436 0.005355 + 6.411 0.004094 0.005434 0.005354 + 6.412 0.004093 0.005433 0.005352 + 6.413 0.004092 0.005431 0.005351 + 6.414 0.004091 0.005430 0.005350 + 6.415 0.004090 0.005429 0.005348 + 6.416 0.004089 0.005427 0.005347 + 6.417 0.004088 0.005426 0.005346 + 6.418 0.004087 0.005424 0.005344 + 6.419 0.004086 0.005423 0.005343 + 6.420 0.004085 0.005421 0.005341 + 6.421 0.004084 0.005420 0.005340 + 6.422 0.004083 0.005419 0.005339 + 6.423 0.004082 0.005417 0.005337 + 6.424 0.004081 0.005416 0.005336 + 6.425 0.004080 0.005414 0.005335 + 6.426 0.004079 0.005413 0.005333 + 6.427 0.004077 0.005412 0.005332 + 6.428 0.004076 0.005410 0.005330 + 6.429 0.004075 0.005409 0.005329 + 6.430 0.004074 0.005407 0.005328 + 6.431 0.004073 0.005406 0.005326 + 6.432 0.004072 0.005405 0.005325 + 6.433 0.004071 0.005403 0.005324 + 6.434 0.004070 0.005402 0.005322 + 6.435 0.004069 0.005400 0.005321 + 6.436 0.004068 0.005399 0.005320 + 6.437 0.004067 0.005398 0.005318 + 6.438 0.004066 0.005396 0.005317 + 6.439 0.004065 0.005395 0.005315 + 6.440 0.004064 0.005394 0.005314 + 6.441 0.004063 0.005392 0.005313 + 6.442 0.004062 0.005391 0.005311 + 6.443 0.004061 0.005389 0.005310 + 6.444 0.004060 0.005388 0.005309 + 6.445 0.004059 0.005387 0.005307 + 6.446 0.004057 0.005385 0.005306 + 6.447 0.004056 0.005384 0.005305 + 6.448 0.004055 0.005382 0.005303 + 6.449 0.004054 0.005381 0.005302 + 6.450 0.004053 0.005380 0.005301 + 6.451 0.004052 0.005378 0.005299 + 6.452 0.004051 0.005377 0.005298 + 6.453 0.004050 0.005375 0.005296 + 6.454 0.004049 0.005374 0.005295 + 6.455 0.004048 0.005373 0.005294 + 6.456 0.004047 0.005371 0.005292 + 6.457 0.004046 0.005370 0.005291 + 6.458 0.004045 0.005369 0.005290 + 6.459 0.004044 0.005367 0.005288 + 6.460 0.004043 0.005366 0.005287 + 6.461 0.004042 0.005364 0.005286 + 6.462 0.004041 0.005363 0.005284 + 6.463 0.004040 0.005362 0.005283 + 6.464 0.004039 0.005360 0.005282 + 6.465 0.004038 0.005359 0.005280 + 6.466 0.004037 0.005358 0.005279 + 6.467 0.004036 0.005356 0.005278 + 6.468 0.004035 0.005355 0.005276 + 6.469 0.004033 0.005353 0.005275 + 6.470 0.004032 0.005352 0.005274 + 6.471 0.004031 0.005351 0.005272 + 6.472 0.004030 0.005349 0.005271 + 6.473 0.004029 0.005348 0.005269 + 6.474 0.004028 0.005347 0.005268 + 6.475 0.004027 0.005345 0.005267 + 6.476 0.004026 0.005344 0.005265 + 6.477 0.004025 0.005342 0.005264 + 6.478 0.004024 0.005341 0.005263 + 6.479 0.004023 0.005340 0.005261 + 6.480 0.004022 0.005338 0.005260 + 6.481 0.004021 0.005337 0.005259 + 6.482 0.004020 0.005336 0.005257 + 6.483 0.004019 0.005334 0.005256 + 6.484 0.004018 0.005333 0.005255 + 6.485 0.004017 0.005331 0.005253 + 6.486 0.004016 0.005330 0.005252 + 6.487 0.004015 0.005329 0.005251 + 6.488 0.004014 0.005327 0.005249 + 6.489 0.004013 0.005326 0.005248 + 6.490 0.004012 0.005325 0.005247 + 6.491 0.004011 0.005323 0.005245 + 6.492 0.004010 0.005322 0.005244 + 6.493 0.004009 0.005321 0.005243 + 6.494 0.004008 0.005319 0.005241 + 6.495 0.004007 0.005318 0.005240 + 6.496 0.004006 0.005316 0.005239 + 6.497 0.004005 0.005315 0.005237 + 6.498 0.004004 0.005314 0.005236 + 6.499 0.004003 0.005312 0.005235 + 6.500 0.004002 0.005311 0.005233 + 6.501 0.004000 0.005310 0.005232 + 6.502 0.003999 0.005308 0.005231 + 6.503 0.003998 0.005307 0.005229 + 6.504 0.003997 0.005306 0.005228 + 6.505 0.003996 0.005304 0.005227 + 6.506 0.003995 0.005303 0.005226 + 6.507 0.003994 0.005302 0.005224 + 6.508 0.003993 0.005300 0.005223 + 6.509 0.003992 0.005299 0.005222 + 6.510 0.003991 0.005297 0.005220 + 6.511 0.003990 0.005296 0.005219 + 6.512 0.003989 0.005295 0.005218 + 6.513 0.003988 0.005293 0.005216 + 6.514 0.003987 0.005292 0.005215 + 6.515 0.003986 0.005291 0.005214 + 6.516 0.003985 0.005289 0.005212 + 6.517 0.003984 0.005288 0.005211 + 6.518 0.003983 0.005287 0.005210 + 6.519 0.003982 0.005285 0.005208 + 6.520 0.003981 0.005284 0.005207 + 6.521 0.003980 0.005283 0.005206 + 6.522 0.003979 0.005281 0.005204 + 6.523 0.003978 0.005280 0.005203 + 6.524 0.003977 0.005279 0.005202 + 6.525 0.003976 0.005277 0.005200 + 6.526 0.003975 0.005276 0.005199 + 6.527 0.003974 0.005275 0.005198 + 6.528 0.003973 0.005273 0.005197 + 6.529 0.003972 0.005272 0.005195 + 6.530 0.003971 0.005271 0.005194 + 6.531 0.003970 0.005269 0.005193 + 6.532 0.003969 0.005268 0.005191 + 6.533 0.003968 0.005267 0.005190 + 6.534 0.003967 0.005265 0.005189 + 6.535 0.003966 0.005264 0.005187 + 6.536 0.003965 0.005262 0.005186 + 6.537 0.003964 0.005261 0.005185 + 6.538 0.003963 0.005260 0.005183 + 6.539 0.003962 0.005258 0.005182 + 6.540 0.003961 0.005257 0.005181 + 6.541 0.003960 0.005256 0.005179 + 6.542 0.003959 0.005254 0.005178 + 6.543 0.003958 0.005253 0.005177 + 6.544 0.003957 0.005252 0.005176 + 6.545 0.003956 0.005250 0.005174 + 6.546 0.003955 0.005249 0.005173 + 6.547 0.003954 0.005248 0.005172 + 6.548 0.003953 0.005246 0.005170 + 6.549 0.003952 0.005245 0.005169 + 6.550 0.003951 0.005244 0.005168 + 6.551 0.003950 0.005242 0.005166 + 6.552 0.003949 0.005241 0.005165 + 6.553 0.003948 0.005240 0.005164 + 6.554 0.003947 0.005238 0.005163 + 6.555 0.003946 0.005237 0.005161 + 6.556 0.003945 0.005236 0.005160 + 6.557 0.003944 0.005235 0.005159 + 6.558 0.003943 0.005233 0.005157 + 6.559 0.003942 0.005232 0.005156 + 6.560 0.003941 0.005231 0.005155 + 6.561 0.003940 0.005229 0.005153 + 6.562 0.003939 0.005228 0.005152 + 6.563 0.003938 0.005227 0.005151 + 6.564 0.003937 0.005225 0.005150 + 6.565 0.003936 0.005224 0.005148 + 6.566 0.003935 0.005223 0.005147 + 6.567 0.003934 0.005221 0.005146 + 6.568 0.003933 0.005220 0.005144 + 6.569 0.003932 0.005219 0.005143 + 6.570 0.003931 0.005217 0.005142 + 6.571 0.003930 0.005216 0.005141 + 6.572 0.003929 0.005215 0.005139 + 6.573 0.003928 0.005213 0.005138 + 6.574 0.003927 0.005212 0.005137 + 6.575 0.003926 0.005211 0.005135 + 6.576 0.003925 0.005209 0.005134 + 6.577 0.003924 0.005208 0.005133 + 6.578 0.003923 0.005207 0.005132 + 6.579 0.003922 0.005205 0.005130 + 6.580 0.003921 0.005204 0.005129 + 6.581 0.003920 0.005203 0.005128 + 6.582 0.003919 0.005201 0.005126 + 6.583 0.003918 0.005200 0.005125 + 6.584 0.003917 0.005199 0.005124 + 6.585 0.003916 0.005198 0.005123 + 6.586 0.003915 0.005196 0.005121 + 6.587 0.003914 0.005195 0.005120 + 6.588 0.003913 0.005194 0.005119 + 6.589 0.003912 0.005192 0.005117 + 6.590 0.003911 0.005191 0.005116 + 6.591 0.003910 0.005190 0.005115 + 6.592 0.003909 0.005188 0.005114 + 6.593 0.003908 0.005187 0.005112 + 6.594 0.003907 0.005186 0.005111 + 6.595 0.003906 0.005184 0.005110 + 6.596 0.003905 0.005183 0.005108 + 6.597 0.003904 0.005182 0.005107 + 6.598 0.003903 0.005181 0.005106 + 6.599 0.003902 0.005179 0.005105 + 6.600 0.003901 0.005178 0.005103 + 6.601 0.003900 0.005177 0.005102 + 6.602 0.003899 0.005175 0.005101 + 6.603 0.003898 0.005174 0.005100 + 6.604 0.003897 0.005173 0.005098 + 6.605 0.003896 0.005171 0.005097 + 6.606 0.003895 0.005170 0.005096 + 6.607 0.003894 0.005169 0.005094 + 6.608 0.003893 0.005168 0.005093 + 6.609 0.003892 0.005166 0.005092 + 6.610 0.003891 0.005165 0.005091 + 6.611 0.003890 0.005164 0.005089 + 6.612 0.003889 0.005162 0.005088 + 6.613 0.003888 0.005161 0.005087 + 6.614 0.003887 0.005160 0.005086 + 6.615 0.003886 0.005158 0.005084 + 6.616 0.003885 0.005157 0.005083 + 6.617 0.003884 0.005156 0.005082 + 6.618 0.003883 0.005155 0.005081 + 6.619 0.003882 0.005153 0.005079 + 6.620 0.003881 0.005152 0.005078 + 6.621 0.003880 0.005151 0.005077 + 6.622 0.003880 0.005149 0.005075 + 6.623 0.003879 0.005148 0.005074 + 6.624 0.003878 0.005147 0.005073 + 6.625 0.003877 0.005146 0.005072 + 6.626 0.003876 0.005144 0.005070 + 6.627 0.003875 0.005143 0.005069 + 6.628 0.003874 0.005142 0.005068 + 6.629 0.003873 0.005140 0.005067 + 6.630 0.003872 0.005139 0.005065 + 6.631 0.003871 0.005138 0.005064 + 6.632 0.003870 0.005136 0.005063 + 6.633 0.003869 0.005135 0.005062 + 6.634 0.003868 0.005134 0.005060 + 6.635 0.003867 0.005133 0.005059 + 6.636 0.003866 0.005131 0.005058 + 6.637 0.003865 0.005130 0.005057 + 6.638 0.003864 0.005129 0.005055 + 6.639 0.003863 0.005127 0.005054 + 6.640 0.003862 0.005126 0.005053 + 6.641 0.003861 0.005125 0.005052 + 6.642 0.003860 0.005124 0.005050 + 6.643 0.003859 0.005122 0.005049 + 6.644 0.003858 0.005121 0.005048 + 6.645 0.003857 0.005120 0.005047 + 6.646 0.003856 0.005119 0.005045 + 6.647 0.003855 0.005117 0.005044 + 6.648 0.003854 0.005116 0.005043 + 6.649 0.003853 0.005115 0.005042 + 6.650 0.003852 0.005113 0.005040 + 6.651 0.003851 0.005112 0.005039 + 6.652 0.003850 0.005111 0.005038 + 6.653 0.003849 0.005110 0.005037 + 6.654 0.003848 0.005108 0.005035 + 6.655 0.003848 0.005107 0.005034 + 6.656 0.003847 0.005106 0.005033 + 6.657 0.003846 0.005104 0.005032 + 6.658 0.003845 0.005103 0.005030 + 6.659 0.003844 0.005102 0.005029 + 6.660 0.003843 0.005101 0.005028 + 6.661 0.003842 0.005099 0.005027 + 6.662 0.003841 0.005098 0.005025 + 6.663 0.003840 0.005097 0.005024 + 6.664 0.003839 0.005096 0.005023 + 6.665 0.003838 0.005094 0.005022 + 6.666 0.003837 0.005093 0.005020 + 6.667 0.003836 0.005092 0.005019 + 6.668 0.003835 0.005090 0.005018 + 6.669 0.003834 0.005089 0.005017 + 6.670 0.003833 0.005088 0.005015 + 6.671 0.003832 0.005087 0.005014 + 6.672 0.003831 0.005085 0.005013 + 6.673 0.003830 0.005084 0.005012 + 6.674 0.003829 0.005083 0.005010 + 6.675 0.003828 0.005082 0.005009 + 6.676 0.003827 0.005080 0.005008 + 6.677 0.003826 0.005079 0.005007 + 6.678 0.003825 0.005078 0.005005 + 6.679 0.003825 0.005077 0.005004 + 6.680 0.003824 0.005075 0.005003 + 6.681 0.003823 0.005074 0.005002 + 6.682 0.003822 0.005073 0.005001 + 6.683 0.003821 0.005071 0.004999 + 6.684 0.003820 0.005070 0.004998 + 6.685 0.003819 0.005069 0.004997 + 6.686 0.003818 0.005068 0.004996 + 6.687 0.003817 0.005066 0.004994 + 6.688 0.003816 0.005065 0.004993 + 6.689 0.003815 0.005064 0.004992 + 6.690 0.003814 0.005063 0.004991 + 6.691 0.003813 0.005061 0.004989 + 6.692 0.003812 0.005060 0.004988 + 6.693 0.003811 0.005059 0.004987 + 6.694 0.003810 0.005058 0.004986 + 6.695 0.003809 0.005056 0.004985 + 6.696 0.003808 0.005055 0.004983 + 6.697 0.003807 0.005054 0.004982 + 6.698 0.003806 0.005053 0.004981 + 6.699 0.003806 0.005051 0.004980 + 6.700 0.003805 0.005050 0.004978 + 6.701 0.003804 0.005049 0.004977 + 6.702 0.003803 0.005048 0.004976 + 6.703 0.003802 0.005046 0.004975 + 6.704 0.003801 0.005045 0.004974 + 6.705 0.003800 0.005044 0.004972 + 6.706 0.003799 0.005043 0.004971 + 6.707 0.003798 0.005041 0.004970 + 6.708 0.003797 0.005040 0.004969 + 6.709 0.003796 0.005039 0.004967 + 6.710 0.003795 0.005038 0.004966 + 6.711 0.003794 0.005036 0.004965 + 6.712 0.003793 0.005035 0.004964 + 6.713 0.003792 0.005034 0.004963 + 6.714 0.003791 0.005033 0.004961 + 6.715 0.003790 0.005031 0.004960 + 6.716 0.003790 0.005030 0.004959 + 6.717 0.003789 0.005029 0.004958 + 6.718 0.003788 0.005028 0.004956 + 6.719 0.003787 0.005026 0.004955 + 6.720 0.003786 0.005025 0.004954 + 6.721 0.003785 0.005024 0.004953 + 6.722 0.003784 0.005023 0.004952 + 6.723 0.003783 0.005021 0.004950 + 6.724 0.003782 0.005020 0.004949 + 6.725 0.003781 0.005019 0.004948 + 6.726 0.003780 0.005018 0.004947 + 6.727 0.003779 0.005016 0.004946 + 6.728 0.003778 0.005015 0.004944 + 6.729 0.003777 0.005014 0.004943 + 6.730 0.003776 0.005013 0.004942 + 6.731 0.003775 0.005012 0.004941 + 6.732 0.003775 0.005010 0.004939 + 6.733 0.003774 0.005009 0.004938 + 6.734 0.003773 0.005008 0.004937 + 6.735 0.003772 0.005007 0.004936 + 6.736 0.003771 0.005005 0.004935 + 6.737 0.003770 0.005004 0.004933 + 6.738 0.003769 0.005003 0.004932 + 6.739 0.003768 0.005002 0.004931 + 6.740 0.003767 0.005000 0.004930 + 6.741 0.003766 0.004999 0.004929 + 6.742 0.003765 0.004998 0.004927 + 6.743 0.003764 0.004997 0.004926 + 6.744 0.003763 0.004995 0.004925 + 6.745 0.003762 0.004994 0.004924 + 6.746 0.003761 0.004993 0.004923 + 6.747 0.003761 0.004992 0.004921 + 6.748 0.003760 0.004991 0.004920 + 6.749 0.003759 0.004989 0.004919 + 6.750 0.003758 0.004988 0.004918 + 6.751 0.003757 0.004987 0.004917 + 6.752 0.003756 0.004986 0.004915 + 6.753 0.003755 0.004984 0.004914 + 6.754 0.003754 0.004983 0.004913 + 6.755 0.003753 0.004982 0.004912 + 6.756 0.003752 0.004981 0.004911 + 6.757 0.003751 0.004979 0.004909 + 6.758 0.003750 0.004978 0.004908 + 6.759 0.003749 0.004977 0.004907 + 6.760 0.003749 0.004976 0.004906 + 6.761 0.003748 0.004975 0.004905 + 6.762 0.003747 0.004973 0.004903 + 6.763 0.003746 0.004972 0.004902 + 6.764 0.003745 0.004971 0.004901 + 6.765 0.003744 0.004970 0.004900 + 6.766 0.003743 0.004968 0.004899 + 6.767 0.003742 0.004967 0.004897 + 6.768 0.003741 0.004966 0.004896 + 6.769 0.003740 0.004965 0.004895 + 6.770 0.003739 0.004964 0.004894 + 6.771 0.003738 0.004962 0.004893 + 6.772 0.003737 0.004961 0.004891 + 6.773 0.003737 0.004960 0.004890 + 6.774 0.003736 0.004959 0.004889 + 6.775 0.003735 0.004958 0.004888 + 6.776 0.003734 0.004956 0.004887 + 6.777 0.003733 0.004955 0.004885 + 6.778 0.003732 0.004954 0.004884 + 6.779 0.003731 0.004953 0.004883 + 6.780 0.003730 0.004951 0.004882 + 6.781 0.003729 0.004950 0.004881 + 6.782 0.003728 0.004949 0.004880 + 6.783 0.003727 0.004948 0.004878 + 6.784 0.003726 0.004947 0.004877 + 6.785 0.003726 0.004945 0.004876 + 6.786 0.003725 0.004944 0.004875 + 6.787 0.003724 0.004943 0.004874 + 6.788 0.003723 0.004942 0.004872 + 6.789 0.003722 0.004941 0.004871 + 6.790 0.003721 0.004939 0.004870 + 6.791 0.003720 0.004938 0.004869 + 6.792 0.003719 0.004937 0.004868 + 6.793 0.003718 0.004936 0.004867 + 6.794 0.003717 0.004934 0.004865 + 6.795 0.003716 0.004933 0.004864 + 6.796 0.003716 0.004932 0.004863 + 6.797 0.003715 0.004931 0.004862 + 6.798 0.003714 0.004930 0.004861 + 6.799 0.003713 0.004928 0.004859 + 6.800 0.003712 0.004927 0.004858 + 6.801 0.003711 0.004926 0.004857 + 6.802 0.003710 0.004925 0.004856 + 6.803 0.003709 0.004924 0.004855 + 6.804 0.003708 0.004922 0.004854 + 6.805 0.003707 0.004921 0.004852 + 6.806 0.003706 0.004920 0.004851 + 6.807 0.003706 0.004919 0.004850 + 6.808 0.003705 0.004918 0.004849 + 6.809 0.003704 0.004916 0.004848 + 6.810 0.003703 0.004915 0.004846 + 6.811 0.003702 0.004914 0.004845 + 6.812 0.003701 0.004913 0.004844 + 6.813 0.003700 0.004912 0.004843 + 6.814 0.003699 0.004910 0.004842 + 6.815 0.003698 0.004909 0.004841 + 6.816 0.003697 0.004908 0.004839 + 6.817 0.003696 0.004907 0.004838 + 6.818 0.003696 0.004906 0.004837 + 6.819 0.003695 0.004904 0.004836 + 6.820 0.003694 0.004903 0.004835 + 6.821 0.003693 0.004902 0.004834 + 6.822 0.003692 0.004901 0.004832 + 6.823 0.003691 0.004900 0.004831 + 6.824 0.003690 0.004898 0.004830 + 6.825 0.003689 0.004897 0.004829 + 6.826 0.003688 0.004896 0.004828 + 6.827 0.003687 0.004895 0.004827 + 6.828 0.003687 0.004894 0.004825 + 6.829 0.003686 0.004893 0.004824 + 6.830 0.003685 0.004891 0.004823 + 6.831 0.003684 0.004890 0.004822 + 6.832 0.003683 0.004889 0.004821 + 6.833 0.003682 0.004888 0.004820 + 6.834 0.003681 0.004887 0.004818 + 6.835 0.003680 0.004885 0.004817 + 6.836 0.003679 0.004884 0.004816 + 6.837 0.003678 0.004883 0.004815 + 6.838 0.003678 0.004882 0.004814 + 6.839 0.003677 0.004881 0.004813 + 6.840 0.003676 0.004879 0.004811 + 6.841 0.003675 0.004878 0.004810 + 6.842 0.003674 0.004877 0.004809 + 6.843 0.003673 0.004876 0.004808 + 6.844 0.003672 0.004875 0.004807 + 6.845 0.003671 0.004874 0.004806 + 6.846 0.003670 0.004872 0.004805 + 6.847 0.003670 0.004871 0.004803 + 6.848 0.003669 0.004870 0.004802 + 6.849 0.003668 0.004869 0.004801 + 6.850 0.003667 0.004868 0.004800 + 6.851 0.003666 0.004866 0.004799 + 6.852 0.003665 0.004865 0.004798 + 6.853 0.003664 0.004864 0.004796 + 6.854 0.003663 0.004863 0.004795 + 6.855 0.003662 0.004862 0.004794 + 6.856 0.003662 0.004861 0.004793 + 6.857 0.003661 0.004859 0.004792 + 6.858 0.003660 0.004858 0.004791 + 6.859 0.003659 0.004857 0.004790 + 6.860 0.003658 0.004856 0.004788 + 6.861 0.003657 0.004855 0.004787 + 6.862 0.003656 0.004853 0.004786 + 6.863 0.003655 0.004852 0.004785 + 6.864 0.003654 0.004851 0.004784 + 6.865 0.003654 0.004850 0.004783 + 6.866 0.003653 0.004849 0.004781 + 6.867 0.003652 0.004848 0.004780 + 6.868 0.003651 0.004846 0.004779 + 6.869 0.003650 0.004845 0.004778 + 6.870 0.003649 0.004844 0.004777 + 6.871 0.003648 0.004843 0.004776 + 6.872 0.003647 0.004842 0.004775 + 6.873 0.003646 0.004841 0.004773 + 6.874 0.003646 0.004839 0.004772 + 6.875 0.003645 0.004838 0.004771 + 6.876 0.003644 0.004837 0.004770 + 6.877 0.003643 0.004836 0.004769 + 6.878 0.003642 0.004835 0.004768 + 6.879 0.003641 0.004834 0.004767 + 6.880 0.003640 0.004832 0.004765 + 6.881 0.003639 0.004831 0.004764 + 6.882 0.003639 0.004830 0.004763 + 6.883 0.003638 0.004829 0.004762 + 6.884 0.003637 0.004828 0.004761 + 6.885 0.003636 0.004827 0.004760 + 6.886 0.003635 0.004825 0.004759 + 6.887 0.003634 0.004824 0.004757 + 6.888 0.003633 0.004823 0.004756 + 6.889 0.003632 0.004822 0.004755 + 6.890 0.003631 0.004821 0.004754 + 6.891 0.003631 0.004820 0.004753 + 6.892 0.003630 0.004818 0.004752 + 6.893 0.003629 0.004817 0.004751 + 6.894 0.003628 0.004816 0.004749 + 6.895 0.003627 0.004815 0.004748 + 6.896 0.003626 0.004814 0.004747 + 6.897 0.003625 0.004813 0.004746 + 6.898 0.003624 0.004811 0.004745 + 6.899 0.003624 0.004810 0.004744 + 6.900 0.003623 0.004809 0.004743 + 6.901 0.003622 0.004808 0.004742 + 6.902 0.003621 0.004807 0.004740 + 6.903 0.003620 0.004806 0.004739 + 6.904 0.003619 0.004804 0.004738 + 6.905 0.003618 0.004803 0.004737 + 6.906 0.003617 0.004802 0.004736 + 6.907 0.003617 0.004801 0.004735 + 6.908 0.003616 0.004800 0.004734 + 6.909 0.003615 0.004799 0.004732 + 6.910 0.003614 0.004798 0.004731 + 6.911 0.003613 0.004796 0.004730 + 6.912 0.003612 0.004795 0.004729 + 6.913 0.003611 0.004794 0.004728 + 6.914 0.003611 0.004793 0.004727 + 6.915 0.003610 0.004792 0.004726 + 6.916 0.003609 0.004791 0.004725 + 6.917 0.003608 0.004789 0.004723 + 6.918 0.003607 0.004788 0.004722 + 6.919 0.003606 0.004787 0.004721 + 6.920 0.003605 0.004786 0.004720 + 6.921 0.003604 0.004785 0.004719 + 6.922 0.003604 0.004784 0.004718 + 6.923 0.003603 0.004783 0.004717 + 6.924 0.003602 0.004781 0.004716 + 6.925 0.003601 0.004780 0.004714 + 6.926 0.003600 0.004779 0.004713 + 6.927 0.003599 0.004778 0.004712 + 6.928 0.003598 0.004777 0.004711 + 6.929 0.003598 0.004776 0.004710 + 6.930 0.003597 0.004775 0.004709 + 6.931 0.003596 0.004773 0.004708 + 6.932 0.003595 0.004772 0.004707 + 6.933 0.003594 0.004771 0.004706 + 6.934 0.003593 0.004770 0.004704 + 6.935 0.003592 0.004769 0.004703 + 6.936 0.003591 0.004768 0.004702 + 6.937 0.003591 0.004767 0.004701 + 6.938 0.003590 0.004765 0.004700 + 6.939 0.003589 0.004764 0.004699 + 6.940 0.003588 0.004763 0.004698 + 6.941 0.003587 0.004762 0.004697 + 6.942 0.003586 0.004761 0.004695 + 6.943 0.003585 0.004760 0.004694 + 6.944 0.003585 0.004759 0.004693 + 6.945 0.003584 0.004757 0.004692 + 6.946 0.003583 0.004756 0.004691 + 6.947 0.003582 0.004755 0.004690 + 6.948 0.003581 0.004754 0.004689 + 6.949 0.003580 0.004753 0.004688 + 6.950 0.003579 0.004752 0.004687 + 6.951 0.003579 0.004751 0.004685 + 6.952 0.003578 0.004749 0.004684 + 6.953 0.003577 0.004748 0.004683 + 6.954 0.003576 0.004747 0.004682 + 6.955 0.003575 0.004746 0.004681 + 6.956 0.003574 0.004745 0.004680 + 6.957 0.003573 0.004744 0.004679 + 6.958 0.003573 0.004743 0.004678 + 6.959 0.003572 0.004742 0.004677 + 6.960 0.003571 0.004740 0.004675 + 6.961 0.003570 0.004739 0.004674 + 6.962 0.003569 0.004738 0.004673 + 6.963 0.003568 0.004737 0.004672 + 6.964 0.003567 0.004736 0.004671 + 6.965 0.003567 0.004735 0.004670 + 6.966 0.003566 0.004734 0.004669 + 6.967 0.003565 0.004732 0.004668 + 6.968 0.003564 0.004731 0.004667 + 6.969 0.003563 0.004730 0.004665 + 6.970 0.003562 0.004729 0.004664 + 6.971 0.003561 0.004728 0.004663 + 6.972 0.003561 0.004727 0.004662 + 6.973 0.003560 0.004726 0.004661 + 6.974 0.003559 0.004725 0.004660 + 6.975 0.003558 0.004723 0.004659 + 6.976 0.003557 0.004722 0.004658 + 6.977 0.003556 0.004721 0.004657 + 6.978 0.003556 0.004720 0.004656 + 6.979 0.003555 0.004719 0.004654 + 6.980 0.003554 0.004718 0.004653 + 6.981 0.003553 0.004717 0.004652 + 6.982 0.003552 0.004716 0.004651 + 6.983 0.003551 0.004714 0.004650 + 6.984 0.003550 0.004713 0.004649 + 6.985 0.003550 0.004712 0.004648 + 6.986 0.003549 0.004711 0.004647 + 6.987 0.003548 0.004710 0.004646 + 6.988 0.003547 0.004709 0.004645 + 6.989 0.003546 0.004708 0.004643 + 6.990 0.003545 0.004707 0.004642 + 6.991 0.003545 0.004706 0.004641 + 6.992 0.003544 0.004704 0.004640 + 6.993 0.003543 0.004703 0.004639 + 6.994 0.003542 0.004702 0.004638 + 6.995 0.003541 0.004701 0.004637 + 6.996 0.003540 0.004700 0.004636 + 6.997 0.003539 0.004699 0.004635 + 6.998 0.003539 0.004698 0.004634 + 6.999 0.003538 0.004697 0.004633 + 7.000 0.003537 0.004695 0.004631 + 7.001 0.003536 0.004694 0.004630 + 7.002 0.003535 0.004693 0.004629 + 7.003 0.003534 0.004692 0.004628 + 7.004 0.003534 0.004691 0.004627 + 7.005 0.003533 0.004690 0.004626 + 7.006 0.003532 0.004689 0.004625 + 7.007 0.003531 0.004688 0.004624 + 7.008 0.003530 0.004687 0.004623 + 7.009 0.003529 0.004685 0.004622 + 7.010 0.003529 0.004684 0.004621 + 7.011 0.003528 0.004683 0.004619 + 7.012 0.003527 0.004682 0.004618 + 7.013 0.003526 0.004681 0.004617 + 7.014 0.003525 0.004680 0.004616 + 7.015 0.003524 0.004679 0.004615 + 7.016 0.003524 0.004678 0.004614 + 7.017 0.003523 0.004677 0.004613 + 7.018 0.003522 0.004675 0.004612 + 7.019 0.003521 0.004674 0.004611 + 7.020 0.003520 0.004673 0.004610 + 7.021 0.003519 0.004672 0.004609 + 7.022 0.003519 0.004671 0.004608 + 7.023 0.003518 0.004670 0.004606 + 7.024 0.003517 0.004669 0.004605 + 7.025 0.003516 0.004668 0.004604 + 7.026 0.003515 0.004667 0.004603 + 7.027 0.003514 0.004665 0.004602 + 7.028 0.003514 0.004664 0.004601 + 7.029 0.003513 0.004663 0.004600 + 7.030 0.003512 0.004662 0.004599 + 7.031 0.003511 0.004661 0.004598 + 7.032 0.003510 0.004660 0.004597 + 7.033 0.003509 0.004659 0.004596 + 7.034 0.003509 0.004658 0.004595 + 7.035 0.003508 0.004657 0.004593 + 7.036 0.003507 0.004656 0.004592 + 7.037 0.003506 0.004654 0.004591 + 7.038 0.003505 0.004653 0.004590 + 7.039 0.003504 0.004652 0.004589 + 7.040 0.003504 0.004651 0.004588 + 7.041 0.003503 0.004650 0.004587 + 7.042 0.003502 0.004649 0.004586 + 7.043 0.003501 0.004648 0.004585 + 7.044 0.003500 0.004647 0.004584 + 7.045 0.003499 0.004646 0.004583 + 7.046 0.003499 0.004645 0.004582 + 7.047 0.003498 0.004643 0.004581 + 7.048 0.003497 0.004642 0.004580 + 7.049 0.003496 0.004641 0.004578 + 7.050 0.003495 0.004640 0.004577 + 7.051 0.003494 0.004639 0.004576 + 7.052 0.003494 0.004638 0.004575 + 7.053 0.003493 0.004637 0.004574 + 7.054 0.003492 0.004636 0.004573 + 7.055 0.003491 0.004635 0.004572 + 7.056 0.003490 0.004634 0.004571 + 7.057 0.003490 0.004633 0.004570 + 7.058 0.003489 0.004631 0.004569 + 7.059 0.003488 0.004630 0.004568 + 7.060 0.003487 0.004629 0.004567 + 7.061 0.003486 0.004628 0.004566 + 7.062 0.003485 0.004627 0.004565 + 7.063 0.003485 0.004626 0.004563 + 7.064 0.003484 0.004625 0.004562 + 7.065 0.003483 0.004624 0.004561 + 7.066 0.003482 0.004623 0.004560 + 7.067 0.003481 0.004622 0.004559 + 7.068 0.003480 0.004621 0.004558 + 7.069 0.003480 0.004619 0.004557 + 7.070 0.003479 0.004618 0.004556 + 7.071 0.003478 0.004617 0.004555 + 7.072 0.003477 0.004616 0.004554 + 7.073 0.003476 0.004615 0.004553 + 7.074 0.003476 0.004614 0.004552 + 7.075 0.003475 0.004613 0.004551 + 7.076 0.003474 0.004612 0.004550 + 7.077 0.003473 0.004611 0.004549 + 7.078 0.003472 0.004610 0.004548 + 7.079 0.003471 0.004609 0.004546 + 7.080 0.003471 0.004608 0.004545 + 7.081 0.003470 0.004606 0.004544 + 7.082 0.003469 0.004605 0.004543 + 7.083 0.003468 0.004604 0.004542 + 7.084 0.003467 0.004603 0.004541 + 7.085 0.003467 0.004602 0.004540 + 7.086 0.003466 0.004601 0.004539 + 7.087 0.003465 0.004600 0.004538 + 7.088 0.003464 0.004599 0.004537 + 7.089 0.003463 0.004598 0.004536 + 7.090 0.003463 0.004597 0.004535 + 7.091 0.003462 0.004596 0.004534 + 7.092 0.003461 0.004595 0.004533 + 7.093 0.003460 0.004594 0.004532 + 7.094 0.003459 0.004592 0.004531 + 7.095 0.003458 0.004591 0.004530 + 7.096 0.003458 0.004590 0.004529 + 7.097 0.003457 0.004589 0.004527 + 7.098 0.003456 0.004588 0.004526 + 7.099 0.003455 0.004587 0.004525 + 7.100 0.003454 0.004586 0.004524 + 7.101 0.003454 0.004585 0.004523 + 7.102 0.003453 0.004584 0.004522 + 7.103 0.003452 0.004583 0.004521 + 7.104 0.003451 0.004582 0.004520 + 7.105 0.003450 0.004581 0.004519 + 7.106 0.003450 0.004580 0.004518 + 7.107 0.003449 0.004579 0.004517 + 7.108 0.003448 0.004577 0.004516 + 7.109 0.003447 0.004576 0.004515 + 7.110 0.003446 0.004575 0.004514 + 7.111 0.003445 0.004574 0.004513 + 7.112 0.003445 0.004573 0.004512 + 7.113 0.003444 0.004572 0.004511 + 7.114 0.003443 0.004571 0.004510 + 7.115 0.003442 0.004570 0.004509 + 7.116 0.003441 0.004569 0.004508 + 7.117 0.003441 0.004568 0.004506 + 7.118 0.003440 0.004567 0.004505 + 7.119 0.003439 0.004566 0.004504 + 7.120 0.003438 0.004565 0.004503 + 7.121 0.003437 0.004564 0.004502 + 7.122 0.003437 0.004562 0.004501 + 7.123 0.003436 0.004561 0.004500 + 7.124 0.003435 0.004560 0.004499 + 7.125 0.003434 0.004559 0.004498 + 7.126 0.003433 0.004558 0.004497 + 7.127 0.003433 0.004557 0.004496 + 7.128 0.003432 0.004556 0.004495 + 7.129 0.003431 0.004555 0.004494 + 7.130 0.003430 0.004554 0.004493 + 7.131 0.003429 0.004553 0.004492 + 7.132 0.003429 0.004552 0.004491 + 7.133 0.003428 0.004551 0.004490 + 7.134 0.003427 0.004550 0.004489 + 7.135 0.003426 0.004549 0.004488 + 7.136 0.003425 0.004548 0.004487 + 7.137 0.003425 0.004547 0.004486 + 7.138 0.003424 0.004545 0.004485 + 7.139 0.003423 0.004544 0.004484 + 7.140 0.003422 0.004543 0.004483 + 7.141 0.003421 0.004542 0.004482 + 7.142 0.003421 0.004541 0.004480 + 7.143 0.003420 0.004540 0.004479 + 7.144 0.003419 0.004539 0.004478 + 7.145 0.003418 0.004538 0.004477 + 7.146 0.003417 0.004537 0.004476 + 7.147 0.003417 0.004536 0.004475 + 7.148 0.003416 0.004535 0.004474 + 7.149 0.003415 0.004534 0.004473 + 7.150 0.003414 0.004533 0.004472 + 7.151 0.003413 0.004532 0.004471 + 7.152 0.003413 0.004531 0.004470 + 7.153 0.003412 0.004530 0.004469 + 7.154 0.003411 0.004529 0.004468 + 7.155 0.003410 0.004528 0.004467 + 7.156 0.003409 0.004527 0.004466 + 7.157 0.003409 0.004525 0.004465 + 7.158 0.003408 0.004524 0.004464 + 7.159 0.003407 0.004523 0.004463 + 7.160 0.003406 0.004522 0.004462 + 7.161 0.003406 0.004521 0.004461 + 7.162 0.003405 0.004520 0.004460 + 7.163 0.003404 0.004519 0.004459 + 7.164 0.003403 0.004518 0.004458 + 7.165 0.003402 0.004517 0.004457 + 7.166 0.003402 0.004516 0.004456 + 7.167 0.003401 0.004515 0.004455 + 7.168 0.003400 0.004514 0.004454 + 7.169 0.003399 0.004513 0.004453 + 7.170 0.003398 0.004512 0.004452 + 7.171 0.003398 0.004511 0.004451 + 7.172 0.003397 0.004510 0.004450 + 7.173 0.003396 0.004509 0.004449 + 7.174 0.003395 0.004508 0.004448 + 7.175 0.003394 0.004507 0.004447 + 7.176 0.003394 0.004506 0.004446 + 7.177 0.003393 0.004505 0.004445 + 7.178 0.003392 0.004503 0.004443 + 7.179 0.003391 0.004502 0.004442 + 7.180 0.003391 0.004501 0.004441 + 7.181 0.003390 0.004500 0.004440 + 7.182 0.003389 0.004499 0.004439 + 7.183 0.003388 0.004498 0.004438 + 7.184 0.003387 0.004497 0.004437 + 7.185 0.003387 0.004496 0.004436 + 7.186 0.003386 0.004495 0.004435 + 7.187 0.003385 0.004494 0.004434 + 7.188 0.003384 0.004493 0.004433 + 7.189 0.003383 0.004492 0.004432 + 7.190 0.003383 0.004491 0.004431 + 7.191 0.003382 0.004490 0.004430 + 7.192 0.003381 0.004489 0.004429 + 7.193 0.003380 0.004488 0.004428 + 7.194 0.003380 0.004487 0.004427 + 7.195 0.003379 0.004486 0.004426 + 7.196 0.003378 0.004485 0.004425 + 7.197 0.003377 0.004484 0.004424 + 7.198 0.003376 0.004483 0.004423 + 7.199 0.003376 0.004482 0.004422 + 7.200 0.003375 0.004481 0.004421 + 7.201 0.003374 0.004480 0.004420 + 7.202 0.003373 0.004479 0.004419 + 7.203 0.003373 0.004478 0.004418 + 7.204 0.003372 0.004476 0.004417 + 7.205 0.003371 0.004475 0.004416 + 7.206 0.003370 0.004474 0.004415 + 7.207 0.003369 0.004473 0.004414 + 7.208 0.003369 0.004472 0.004413 + 7.209 0.003368 0.004471 0.004412 + 7.210 0.003367 0.004470 0.004411 + 7.211 0.003366 0.004469 0.004410 + 7.212 0.003366 0.004468 0.004409 + 7.213 0.003365 0.004467 0.004408 + 7.214 0.003364 0.004466 0.004407 + 7.215 0.003363 0.004465 0.004406 + 7.216 0.003362 0.004464 0.004405 + 7.217 0.003362 0.004463 0.004404 + 7.218 0.003361 0.004462 0.004403 + 7.219 0.003360 0.004461 0.004402 + 7.220 0.003359 0.004460 0.004401 + 7.221 0.003359 0.004459 0.004400 + 7.222 0.003358 0.004458 0.004399 + 7.223 0.003357 0.004457 0.004398 + 7.224 0.003356 0.004456 0.004397 + 7.225 0.003355 0.004455 0.004396 + 7.226 0.003355 0.004454 0.004395 + 7.227 0.003354 0.004453 0.004394 + 7.228 0.003353 0.004452 0.004393 + 7.229 0.003352 0.004451 0.004392 + 7.230 0.003352 0.004450 0.004391 + 7.231 0.003351 0.004449 0.004390 + 7.232 0.003350 0.004448 0.004389 + 7.233 0.003349 0.004447 0.004388 + 7.234 0.003348 0.004446 0.004387 + 7.235 0.003348 0.004445 0.004386 + 7.236 0.003347 0.004444 0.004385 + 7.237 0.003346 0.004443 0.004384 + 7.238 0.003345 0.004442 0.004383 + 7.239 0.003345 0.004441 0.004382 + 7.240 0.003344 0.004440 0.004381 + 7.241 0.003343 0.004439 0.004380 + 7.242 0.003342 0.004437 0.004379 + 7.243 0.003342 0.004436 0.004378 + 7.244 0.003341 0.004435 0.004377 + 7.245 0.003340 0.004434 0.004376 + 7.246 0.003339 0.004433 0.004375 + 7.247 0.003338 0.004432 0.004374 + 7.248 0.003338 0.004431 0.004373 + 7.249 0.003337 0.004430 0.004372 + 7.250 0.003336 0.004429 0.004371 + 7.251 0.003335 0.004428 0.004370 + 7.252 0.003335 0.004427 0.004369 + 7.253 0.003334 0.004426 0.004368 + 7.254 0.003333 0.004425 0.004367 + 7.255 0.003332 0.004424 0.004366 + 7.256 0.003332 0.004423 0.004365 + 7.257 0.003331 0.004422 0.004364 + 7.258 0.003330 0.004421 0.004363 + 7.259 0.003329 0.004420 0.004362 + 7.260 0.003329 0.004419 0.004361 + 7.261 0.003328 0.004418 0.004360 + 7.262 0.003327 0.004417 0.004359 + 7.263 0.003326 0.004416 0.004358 + 7.264 0.003325 0.004415 0.004357 + 7.265 0.003325 0.004414 0.004356 + 7.266 0.003324 0.004413 0.004355 + 7.267 0.003323 0.004412 0.004354 + 7.268 0.003322 0.004411 0.004353 + 7.269 0.003322 0.004410 0.004352 + 7.270 0.003321 0.004409 0.004351 + 7.271 0.003320 0.004408 0.004350 + 7.272 0.003319 0.004407 0.004349 + 7.273 0.003319 0.004406 0.004348 + 7.274 0.003318 0.004405 0.004347 + 7.275 0.003317 0.004404 0.004346 + 7.276 0.003316 0.004403 0.004345 + 7.277 0.003316 0.004402 0.004344 + 7.278 0.003315 0.004401 0.004343 + 7.279 0.003314 0.004400 0.004342 + 7.280 0.003313 0.004399 0.004341 + 7.281 0.003313 0.004398 0.004340 + 7.282 0.003312 0.004397 0.004339 + 7.283 0.003311 0.004396 0.004338 + 7.284 0.003310 0.004395 0.004337 + 7.285 0.003310 0.004394 0.004336 + 7.286 0.003309 0.004393 0.004335 + 7.287 0.003308 0.004392 0.004334 + 7.288 0.003307 0.004391 0.004333 + 7.289 0.003307 0.004390 0.004332 + 7.290 0.003306 0.004389 0.004331 + 7.291 0.003305 0.004388 0.004330 + 7.292 0.003304 0.004387 0.004329 + 7.293 0.003303 0.004386 0.004328 + 7.294 0.003303 0.004385 0.004327 + 7.295 0.003302 0.004384 0.004326 + 7.296 0.003301 0.004383 0.004326 + 7.297 0.003300 0.004382 0.004325 + 7.298 0.003300 0.004381 0.004324 + 7.299 0.003299 0.004380 0.004323 + 7.300 0.003298 0.004379 0.004322 + 7.301 0.003297 0.004378 0.004321 + 7.302 0.003297 0.004377 0.004320 + 7.303 0.003296 0.004376 0.004319 + 7.304 0.003295 0.004375 0.004318 + 7.305 0.003294 0.004374 0.004317 + 7.306 0.003294 0.004373 0.004316 + 7.307 0.003293 0.004372 0.004315 + 7.308 0.003292 0.004371 0.004314 + 7.309 0.003291 0.004370 0.004313 + 7.310 0.003291 0.004369 0.004312 + 7.311 0.003290 0.004368 0.004311 + 7.312 0.003289 0.004367 0.004310 + 7.313 0.003288 0.004366 0.004309 + 7.314 0.003288 0.004365 0.004308 + 7.315 0.003287 0.004364 0.004307 + 7.316 0.003286 0.004363 0.004306 + 7.317 0.003285 0.004362 0.004305 + 7.318 0.003285 0.004361 0.004304 + 7.319 0.003284 0.004360 0.004303 + 7.320 0.003283 0.004359 0.004302 + 7.321 0.003282 0.004358 0.004301 + 7.322 0.003282 0.004357 0.004300 + 7.323 0.003281 0.004356 0.004299 + 7.324 0.003280 0.004355 0.004298 + 7.325 0.003279 0.004354 0.004297 + 7.326 0.003279 0.004353 0.004296 + 7.327 0.003278 0.004352 0.004295 + 7.328 0.003277 0.004351 0.004294 + 7.329 0.003277 0.004350 0.004293 + 7.330 0.003276 0.004349 0.004292 + 7.331 0.003275 0.004348 0.004291 + 7.332 0.003274 0.004347 0.004291 + 7.333 0.003274 0.004346 0.004290 + 7.334 0.003273 0.004345 0.004289 + 7.335 0.003272 0.004344 0.004288 + 7.336 0.003271 0.004343 0.004287 + 7.337 0.003271 0.004342 0.004286 + 7.338 0.003270 0.004341 0.004285 + 7.339 0.003269 0.004340 0.004284 + 7.340 0.003268 0.004339 0.004283 + 7.341 0.003268 0.004338 0.004282 + 7.342 0.003267 0.004337 0.004281 + 7.343 0.003266 0.004336 0.004280 + 7.344 0.003265 0.004335 0.004279 + 7.345 0.003265 0.004335 0.004278 + 7.346 0.003264 0.004334 0.004277 + 7.347 0.003263 0.004333 0.004276 + 7.348 0.003262 0.004332 0.004275 + 7.349 0.003262 0.004331 0.004274 + 7.350 0.003261 0.004330 0.004273 + 7.351 0.003260 0.004329 0.004272 + 7.352 0.003259 0.004328 0.004271 + 7.353 0.003259 0.004327 0.004270 + 7.354 0.003258 0.004326 0.004269 + 7.355 0.003257 0.004325 0.004268 + 7.356 0.003257 0.004324 0.004267 + 7.357 0.003256 0.004323 0.004266 + 7.358 0.003255 0.004322 0.004266 + 7.359 0.003254 0.004321 0.004265 + 7.360 0.003254 0.004320 0.004264 + 7.361 0.003253 0.004319 0.004263 + 7.362 0.003252 0.004318 0.004262 + 7.363 0.003251 0.004317 0.004261 + 7.364 0.003251 0.004316 0.004260 + 7.365 0.003250 0.004315 0.004259 + 7.366 0.003249 0.004314 0.004258 + 7.367 0.003248 0.004313 0.004257 + 7.368 0.003248 0.004312 0.004256 + 7.369 0.003247 0.004311 0.004255 + 7.370 0.003246 0.004310 0.004254 + 7.371 0.003245 0.004309 0.004253 + 7.372 0.003245 0.004308 0.004252 + 7.373 0.003244 0.004307 0.004251 + 7.374 0.003243 0.004306 0.004250 + 7.375 0.003243 0.004305 0.004249 + 7.376 0.003242 0.004304 0.004248 + 7.377 0.003241 0.004303 0.004247 + 7.378 0.003240 0.004302 0.004246 + 7.379 0.003240 0.004301 0.004246 + 7.380 0.003239 0.004300 0.004245 + 7.381 0.003238 0.004299 0.004244 + 7.382 0.003237 0.004298 0.004243 + 7.383 0.003237 0.004297 0.004242 + 7.384 0.003236 0.004297 0.004241 + 7.385 0.003235 0.004296 0.004240 + 7.386 0.003235 0.004295 0.004239 + 7.387 0.003234 0.004294 0.004238 + 7.388 0.003233 0.004293 0.004237 + 7.389 0.003232 0.004292 0.004236 + 7.390 0.003232 0.004291 0.004235 + 7.391 0.003231 0.004290 0.004234 + 7.392 0.003230 0.004289 0.004233 + 7.393 0.003229 0.004288 0.004232 + 7.394 0.003229 0.004287 0.004231 + 7.395 0.003228 0.004286 0.004230 + 7.396 0.003227 0.004285 0.004229 + 7.397 0.003227 0.004284 0.004228 + 7.398 0.003226 0.004283 0.004228 + 7.399 0.003225 0.004282 0.004227 + 7.400 0.003224 0.004281 0.004226 + 7.401 0.003224 0.004280 0.004225 + 7.402 0.003223 0.004279 0.004224 + 7.403 0.003222 0.004278 0.004223 + 7.404 0.003221 0.004277 0.004222 + 7.405 0.003221 0.004276 0.004221 + 7.406 0.003220 0.004275 0.004220 + 7.407 0.003219 0.004274 0.004219 + 7.408 0.003219 0.004273 0.004218 + 7.409 0.003218 0.004272 0.004217 + 7.410 0.003217 0.004271 0.004216 + 7.411 0.003216 0.004271 0.004215 + 7.412 0.003216 0.004270 0.004214 + 7.413 0.003215 0.004269 0.004213 + 7.414 0.003214 0.004268 0.004212 + 7.415 0.003213 0.004267 0.004212 + 7.416 0.003213 0.004266 0.004211 + 7.417 0.003212 0.004265 0.004210 + 7.418 0.003211 0.004264 0.004209 + 7.419 0.003211 0.004263 0.004208 + 7.420 0.003210 0.004262 0.004207 + 7.421 0.003209 0.004261 0.004206 + 7.422 0.003208 0.004260 0.004205 + 7.423 0.003208 0.004259 0.004204 + 7.424 0.003207 0.004258 0.004203 + 7.425 0.003206 0.004257 0.004202 + 7.426 0.003206 0.004256 0.004201 + 7.427 0.003205 0.004255 0.004200 + 7.428 0.003204 0.004254 0.004199 + 7.429 0.003203 0.004253 0.004198 + 7.430 0.003203 0.004252 0.004198 + 7.431 0.003202 0.004251 0.004197 + 7.432 0.003201 0.004250 0.004196 + 7.433 0.003201 0.004250 0.004195 + 7.434 0.003200 0.004249 0.004194 + 7.435 0.003199 0.004248 0.004193 + 7.436 0.003198 0.004247 0.004192 + 7.437 0.003198 0.004246 0.004191 + 7.438 0.003197 0.004245 0.004190 + 7.439 0.003196 0.004244 0.004189 + 7.440 0.003196 0.004243 0.004188 + 7.441 0.003195 0.004242 0.004187 + 7.442 0.003194 0.004241 0.004186 + 7.443 0.003193 0.004240 0.004185 + 7.444 0.003193 0.004239 0.004184 + 7.445 0.003192 0.004238 0.004184 + 7.446 0.003191 0.004237 0.004183 + 7.447 0.003191 0.004236 0.004182 + 7.448 0.003190 0.004235 0.004181 + 7.449 0.003189 0.004234 0.004180 + 7.450 0.003188 0.004233 0.004179 + 7.451 0.003188 0.004232 0.004178 + 7.452 0.003187 0.004232 0.004177 + 7.453 0.003186 0.004231 0.004176 + 7.454 0.003186 0.004230 0.004175 + 7.455 0.003185 0.004229 0.004174 + 7.456 0.003184 0.004228 0.004173 + 7.457 0.003183 0.004227 0.004172 + 7.458 0.003183 0.004226 0.004172 + 7.459 0.003182 0.004225 0.004171 + 7.460 0.003181 0.004224 0.004170 + 7.461 0.003181 0.004223 0.004169 + 7.462 0.003180 0.004222 0.004168 + 7.463 0.003179 0.004221 0.004167 + 7.464 0.003178 0.004220 0.004166 + 7.465 0.003178 0.004219 0.004165 + 7.466 0.003177 0.004218 0.004164 + 7.467 0.003176 0.004217 0.004163 + 7.468 0.003176 0.004216 0.004162 + 7.469 0.003175 0.004216 0.004161 + 7.470 0.003174 0.004215 0.004160 + 7.471 0.003173 0.004214 0.004160 + 7.472 0.003173 0.004213 0.004159 + 7.473 0.003172 0.004212 0.004158 + 7.474 0.003171 0.004211 0.004157 + 7.475 0.003171 0.004210 0.004156 + 7.476 0.003170 0.004209 0.004155 + 7.477 0.003169 0.004208 0.004154 + 7.478 0.003169 0.004207 0.004153 + 7.479 0.003168 0.004206 0.004152 + 7.480 0.003167 0.004205 0.004151 + 7.481 0.003166 0.004204 0.004150 + 7.482 0.003166 0.004203 0.004149 + 7.483 0.003165 0.004202 0.004149 + 7.484 0.003164 0.004201 0.004148 + 7.485 0.003164 0.004201 0.004147 + 7.486 0.003163 0.004200 0.004146 + 7.487 0.003162 0.004199 0.004145 + 7.488 0.003161 0.004198 0.004144 + 7.489 0.003161 0.004197 0.004143 + 7.490 0.003160 0.004196 0.004142 + 7.491 0.003159 0.004195 0.004141 + 7.492 0.003159 0.004194 0.004140 + 7.493 0.003158 0.004193 0.004139 + 7.494 0.003157 0.004192 0.004139 + 7.495 0.003157 0.004191 0.004138 + 7.496 0.003156 0.004190 0.004137 + 7.497 0.003155 0.004189 0.004136 + 7.498 0.003154 0.004188 0.004135 + 7.499 0.003154 0.004188 0.004134 + 7.500 0.003153 0.004187 0.004133 + 7.501 0.003152 0.004186 0.004132 + 7.502 0.003152 0.004185 0.004131 + 7.503 0.003151 0.004184 0.004130 + 7.504 0.003150 0.004183 0.004129 + 7.505 0.003150 0.004182 0.004128 + 7.506 0.003149 0.004181 0.004128 + 7.507 0.003148 0.004180 0.004127 + 7.508 0.003147 0.004179 0.004126 + 7.509 0.003147 0.004178 0.004125 + 7.510 0.003146 0.004177 0.004124 + 7.511 0.003145 0.004176 0.004123 + 7.512 0.003145 0.004175 0.004122 + 7.513 0.003144 0.004175 0.004121 + 7.514 0.003143 0.004174 0.004120 + 7.515 0.003143 0.004173 0.004119 + 7.516 0.003142 0.004172 0.004119 + 7.517 0.003141 0.004171 0.004118 + 7.518 0.003140 0.004170 0.004117 + 7.519 0.003140 0.004169 0.004116 + 7.520 0.003139 0.004168 0.004115 + 7.521 0.003138 0.004167 0.004114 + 7.522 0.003138 0.004166 0.004113 + 7.523 0.003137 0.004165 0.004112 + 7.524 0.003136 0.004164 0.004111 + 7.525 0.003136 0.004163 0.004110 + 7.526 0.003135 0.004163 0.004109 + 7.527 0.003134 0.004162 0.004109 + 7.528 0.003134 0.004161 0.004108 + 7.529 0.003133 0.004160 0.004107 + 7.530 0.003132 0.004159 0.004106 + 7.531 0.003131 0.004158 0.004105 + 7.532 0.003131 0.004157 0.004104 + 7.533 0.003130 0.004156 0.004103 + 7.534 0.003129 0.004155 0.004102 + 7.535 0.003129 0.004154 0.004101 + 7.536 0.003128 0.004153 0.004100 + 7.537 0.003127 0.004152 0.004100 + 7.538 0.003127 0.004152 0.004099 + 7.539 0.003126 0.004151 0.004098 + 7.540 0.003125 0.004150 0.004097 + 7.541 0.003125 0.004149 0.004096 + 7.542 0.003124 0.004148 0.004095 + 7.543 0.003123 0.004147 0.004094 + 7.544 0.003122 0.004146 0.004093 + 7.545 0.003122 0.004145 0.004092 + 7.546 0.003121 0.004144 0.004092 + 7.547 0.003120 0.004143 0.004091 + 7.548 0.003120 0.004142 0.004090 + 7.549 0.003119 0.004141 0.004089 + 7.550 0.003118 0.004141 0.004088 + 7.551 0.003118 0.004140 0.004087 + 7.552 0.003117 0.004139 0.004086 + 7.553 0.003116 0.004138 0.004085 + 7.554 0.003116 0.004137 0.004084 + 7.555 0.003115 0.004136 0.004083 + 7.556 0.003114 0.004135 0.004083 + 7.557 0.003114 0.004134 0.004082 + 7.558 0.003113 0.004133 0.004081 + 7.559 0.003112 0.004132 0.004080 + 7.560 0.003111 0.004131 0.004079 + 7.561 0.003111 0.004131 0.004078 + 7.562 0.003110 0.004130 0.004077 + 7.563 0.003109 0.004129 0.004076 + 7.564 0.003109 0.004128 0.004075 + 7.565 0.003108 0.004127 0.004075 + 7.566 0.003107 0.004126 0.004074 + 7.567 0.003107 0.004125 0.004073 + 7.568 0.003106 0.004124 0.004072 + 7.569 0.003105 0.004123 0.004071 + 7.570 0.003105 0.004122 0.004070 + 7.571 0.003104 0.004122 0.004069 + 7.572 0.003103 0.004121 0.004068 + 7.573 0.003103 0.004120 0.004067 + 7.574 0.003102 0.004119 0.004067 + 7.575 0.003101 0.004118 0.004066 + 7.576 0.003101 0.004117 0.004065 + 7.577 0.003100 0.004116 0.004064 + 7.578 0.003099 0.004115 0.004063 + 7.579 0.003099 0.004114 0.004062 + 7.580 0.003098 0.004113 0.004061 + 7.581 0.003097 0.004112 0.004060 + 7.582 0.003096 0.004112 0.004060 + 7.583 0.003096 0.004111 0.004059 + 7.584 0.003095 0.004110 0.004058 + 7.585 0.003094 0.004109 0.004057 + 7.586 0.003094 0.004108 0.004056 + 7.587 0.003093 0.004107 0.004055 + 7.588 0.003092 0.004106 0.004054 + 7.589 0.003092 0.004105 0.004053 + 7.590 0.003091 0.004104 0.004052 + 7.591 0.003090 0.004103 0.004052 + 7.592 0.003090 0.004103 0.004051 + 7.593 0.003089 0.004102 0.004050 + 7.594 0.003088 0.004101 0.004049 + 7.595 0.003088 0.004100 0.004048 + 7.596 0.003087 0.004099 0.004047 + 7.597 0.003086 0.004098 0.004046 + 7.598 0.003086 0.004097 0.004045 + 7.599 0.003085 0.004096 0.004045 + 7.600 0.003084 0.004095 0.004044 + 7.601 0.003084 0.004094 0.004043 + 7.602 0.003083 0.004094 0.004042 + 7.603 0.003082 0.004093 0.004041 + 7.604 0.003082 0.004092 0.004040 + 7.605 0.003081 0.004091 0.004039 + 7.606 0.003080 0.004090 0.004038 + 7.607 0.003080 0.004089 0.004038 + 7.608 0.003079 0.004088 0.004037 + 7.609 0.003078 0.004087 0.004036 + 7.610 0.003078 0.004086 0.004035 + 7.611 0.003077 0.004086 0.004034 + 7.612 0.003076 0.004085 0.004033 + 7.613 0.003076 0.004084 0.004032 + 7.614 0.003075 0.004083 0.004031 + 7.615 0.003074 0.004082 0.004031 + 7.616 0.003073 0.004081 0.004030 + 7.617 0.003073 0.004080 0.004029 + 7.618 0.003072 0.004079 0.004028 + 7.619 0.003071 0.004078 0.004027 + 7.620 0.003071 0.004078 0.004026 + 7.621 0.003070 0.004077 0.004025 + 7.622 0.003069 0.004076 0.004024 + 7.623 0.003069 0.004075 0.004024 + 7.624 0.003068 0.004074 0.004023 + 7.625 0.003067 0.004073 0.004022 + 7.626 0.003067 0.004072 0.004021 + 7.627 0.003066 0.004071 0.004020 + 7.628 0.003065 0.004070 0.004019 + 7.629 0.003065 0.004070 0.004018 + 7.630 0.003064 0.004069 0.004017 + 7.631 0.003063 0.004068 0.004017 + 7.632 0.003063 0.004067 0.004016 + 7.633 0.003062 0.004066 0.004015 + 7.634 0.003061 0.004065 0.004014 + 7.635 0.003061 0.004064 0.004013 + 7.636 0.003060 0.004063 0.004012 + 7.637 0.003059 0.004062 0.004011 + 7.638 0.003059 0.004062 0.004010 + 7.639 0.003058 0.004061 0.004010 + 7.640 0.003057 0.004060 0.004009 + 7.641 0.003057 0.004059 0.004008 + 7.642 0.003056 0.004058 0.004007 + 7.643 0.003055 0.004057 0.004006 + 7.644 0.003055 0.004056 0.004005 + 7.645 0.003054 0.004055 0.004004 + 7.646 0.003053 0.004054 0.004004 + 7.647 0.003053 0.004054 0.004003 + 7.648 0.003052 0.004053 0.004002 + 7.649 0.003051 0.004052 0.004001 + 7.650 0.003051 0.004051 0.004000 + 7.651 0.003050 0.004050 0.003999 + 7.652 0.003049 0.004049 0.003998 + 7.653 0.003049 0.004048 0.003998 + 7.654 0.003048 0.004047 0.003997 + 7.655 0.003047 0.004047 0.003996 + 7.656 0.003047 0.004046 0.003995 + 7.657 0.003046 0.004045 0.003994 + 7.658 0.003045 0.004044 0.003993 + 7.659 0.003045 0.004043 0.003992 + 7.660 0.003044 0.004042 0.003991 + 7.661 0.003043 0.004041 0.003991 + 7.662 0.003043 0.004040 0.003990 + 7.663 0.003042 0.004040 0.003989 + 7.664 0.003041 0.004039 0.003988 + 7.665 0.003041 0.004038 0.003987 + 7.666 0.003040 0.004037 0.003986 + 7.667 0.003040 0.004036 0.003985 + 7.668 0.003039 0.004035 0.003985 + 7.669 0.003038 0.004034 0.003984 + 7.670 0.003038 0.004033 0.003983 + 7.671 0.003037 0.004033 0.003982 + 7.672 0.003036 0.004032 0.003981 + 7.673 0.003036 0.004031 0.003980 + 7.674 0.003035 0.004030 0.003979 + 7.675 0.003034 0.004029 0.003979 + 7.676 0.003034 0.004028 0.003978 + 7.677 0.003033 0.004027 0.003977 + 7.678 0.003032 0.004026 0.003976 + 7.679 0.003032 0.004026 0.003975 + 7.680 0.003031 0.004025 0.003974 + 7.681 0.003030 0.004024 0.003973 + 7.682 0.003030 0.004023 0.003973 + 7.683 0.003029 0.004022 0.003972 + 7.684 0.003028 0.004021 0.003971 + 7.685 0.003028 0.004020 0.003970 + 7.686 0.003027 0.004019 0.003969 + 7.687 0.003026 0.004019 0.003968 + 7.688 0.003026 0.004018 0.003968 + 7.689 0.003025 0.004017 0.003967 + 7.690 0.003024 0.004016 0.003966 + 7.691 0.003024 0.004015 0.003965 + 7.692 0.003023 0.004014 0.003964 + 7.693 0.003022 0.004013 0.003963 + 7.694 0.003022 0.004013 0.003962 + 7.695 0.003021 0.004012 0.003962 + 7.696 0.003020 0.004011 0.003961 + 7.697 0.003020 0.004010 0.003960 + 7.698 0.003019 0.004009 0.003959 + 7.699 0.003019 0.004008 0.003958 + 7.700 0.003018 0.004007 0.003957 + 7.701 0.003017 0.004006 0.003956 + 7.702 0.003017 0.004006 0.003956 + 7.703 0.003016 0.004005 0.003955 + 7.704 0.003015 0.004004 0.003954 + 7.705 0.003015 0.004003 0.003953 + 7.706 0.003014 0.004002 0.003952 + 7.707 0.003013 0.004001 0.003951 + 7.708 0.003013 0.004000 0.003951 + 7.709 0.003012 0.004000 0.003950 + 7.710 0.003011 0.003999 0.003949 + 7.711 0.003011 0.003998 0.003948 + 7.712 0.003010 0.003997 0.003947 + 7.713 0.003009 0.003996 0.003946 + 7.714 0.003009 0.003995 0.003945 + 7.715 0.003008 0.003994 0.003945 + 7.716 0.003007 0.003994 0.003944 + 7.717 0.003007 0.003993 0.003943 + 7.718 0.003006 0.003992 0.003942 + 7.719 0.003005 0.003991 0.003941 + 7.720 0.003005 0.003990 0.003940 + 7.721 0.003004 0.003989 0.003940 + 7.722 0.003004 0.003988 0.003939 + 7.723 0.003003 0.003987 0.003938 + 7.724 0.003002 0.003987 0.003937 + 7.725 0.003002 0.003986 0.003936 + 7.726 0.003001 0.003985 0.003935 + 7.727 0.003000 0.003984 0.003935 + 7.728 0.003000 0.003983 0.003934 + 7.729 0.002999 0.003982 0.003933 + 7.730 0.002998 0.003981 0.003932 + 7.731 0.002998 0.003981 0.003931 + 7.732 0.002997 0.003980 0.003930 + 7.733 0.002996 0.003979 0.003929 + 7.734 0.002996 0.003978 0.003929 + 7.735 0.002995 0.003977 0.003928 + 7.736 0.002994 0.003976 0.003927 + 7.737 0.002994 0.003976 0.003926 + 7.738 0.002993 0.003975 0.003925 + 7.739 0.002993 0.003974 0.003924 + 7.740 0.002992 0.003973 0.003924 + 7.741 0.002991 0.003972 0.003923 + 7.742 0.002991 0.003971 0.003922 + 7.743 0.002990 0.003970 0.003921 + 7.744 0.002989 0.003970 0.003920 + 7.745 0.002989 0.003969 0.003919 + 7.746 0.002988 0.003968 0.003919 + 7.747 0.002987 0.003967 0.003918 + 7.748 0.002987 0.003966 0.003917 + 7.749 0.002986 0.003965 0.003916 + 7.750 0.002985 0.003964 0.003915 + 7.751 0.002985 0.003964 0.003914 + 7.752 0.002984 0.003963 0.003914 + 7.753 0.002984 0.003962 0.003913 + 7.754 0.002983 0.003961 0.003912 + 7.755 0.002982 0.003960 0.003911 + 7.756 0.002982 0.003959 0.003910 + 7.757 0.002981 0.003958 0.003909 + 7.758 0.002980 0.003958 0.003909 + 7.759 0.002980 0.003957 0.003908 + 7.760 0.002979 0.003956 0.003907 + 7.761 0.002978 0.003955 0.003906 + 7.762 0.002978 0.003954 0.003905 + 7.763 0.002977 0.003953 0.003904 + 7.764 0.002977 0.003953 0.003904 + 7.765 0.002976 0.003952 0.003903 + 7.766 0.002975 0.003951 0.003902 + 7.767 0.002975 0.003950 0.003901 + 7.768 0.002974 0.003949 0.003900 + 7.769 0.002973 0.003948 0.003899 + 7.770 0.002973 0.003947 0.003899 + 7.771 0.002972 0.003947 0.003898 + 7.772 0.002971 0.003946 0.003897 + 7.773 0.002971 0.003945 0.003896 + 7.774 0.002970 0.003944 0.003895 + 7.775 0.002970 0.003943 0.003894 + 7.776 0.002969 0.003942 0.003894 + 7.777 0.002968 0.003942 0.003893 + 7.778 0.002968 0.003941 0.003892 + 7.779 0.002967 0.003940 0.003891 + 7.780 0.002966 0.003939 0.003890 + 7.781 0.002966 0.003938 0.003890 + 7.782 0.002965 0.003937 0.003889 + 7.783 0.002964 0.003937 0.003888 + 7.784 0.002964 0.003936 0.003887 + 7.785 0.002963 0.003935 0.003886 + 7.786 0.002963 0.003934 0.003885 + 7.787 0.002962 0.003933 0.003885 + 7.788 0.002961 0.003932 0.003884 + 7.789 0.002961 0.003931 0.003883 + 7.790 0.002960 0.003931 0.003882 + 7.791 0.002959 0.003930 0.003881 + 7.792 0.002959 0.003929 0.003880 + 7.793 0.002958 0.003928 0.003880 + 7.794 0.002957 0.003927 0.003879 + 7.795 0.002957 0.003926 0.003878 + 7.796 0.002956 0.003926 0.003877 + 7.797 0.002956 0.003925 0.003876 + 7.798 0.002955 0.003924 0.003876 + 7.799 0.002954 0.003923 0.003875 + 7.800 0.002954 0.003922 0.003874 + 7.801 0.002953 0.003921 0.003873 + 7.802 0.002952 0.003921 0.003872 + 7.803 0.002952 0.003920 0.003871 + 7.804 0.002951 0.003919 0.003871 + 7.805 0.002951 0.003918 0.003870 + 7.806 0.002950 0.003917 0.003869 + 7.807 0.002949 0.003916 0.003868 + 7.808 0.002949 0.003916 0.003867 + 7.809 0.002948 0.003915 0.003867 + 7.810 0.002947 0.003914 0.003866 + 7.811 0.002947 0.003913 0.003865 + 7.812 0.002946 0.003912 0.003864 + 7.813 0.002946 0.003911 0.003863 + 7.814 0.002945 0.003911 0.003862 + 7.815 0.002944 0.003910 0.003862 + 7.816 0.002944 0.003909 0.003861 + 7.817 0.002943 0.003908 0.003860 + 7.818 0.002942 0.003907 0.003859 + 7.819 0.002942 0.003906 0.003858 + 7.820 0.002941 0.003906 0.003858 + 7.821 0.002940 0.003905 0.003857 + 7.822 0.002940 0.003904 0.003856 + 7.823 0.002939 0.003903 0.003855 + 7.824 0.002939 0.003902 0.003854 + 7.825 0.002938 0.003901 0.003853 + 7.826 0.002937 0.003901 0.003853 + 7.827 0.002937 0.003900 0.003852 + 7.828 0.002936 0.003899 0.003851 + 7.829 0.002935 0.003898 0.003850 + 7.830 0.002935 0.003897 0.003849 + 7.831 0.002934 0.003896 0.003849 + 7.832 0.002934 0.003896 0.003848 + 7.833 0.002933 0.003895 0.003847 + 7.834 0.002932 0.003894 0.003846 + 7.835 0.002932 0.003893 0.003845 + 7.836 0.002931 0.003892 0.003845 + 7.837 0.002931 0.003892 0.003844 + 7.838 0.002930 0.003891 0.003843 + 7.839 0.002929 0.003890 0.003842 + 7.840 0.002929 0.003889 0.003841 + 7.841 0.002928 0.003888 0.003840 + 7.842 0.002927 0.003887 0.003840 + 7.843 0.002927 0.003887 0.003839 + 7.844 0.002926 0.003886 0.003838 + 7.845 0.002926 0.003885 0.003837 + 7.846 0.002925 0.003884 0.003836 + 7.847 0.002924 0.003883 0.003836 + 7.848 0.002924 0.003882 0.003835 + 7.849 0.002923 0.003882 0.003834 + 7.850 0.002922 0.003881 0.003833 + 7.851 0.002922 0.003880 0.003832 + 7.852 0.002921 0.003879 0.003832 + 7.853 0.002921 0.003878 0.003831 + 7.854 0.002920 0.003878 0.003830 + 7.855 0.002919 0.003877 0.003829 + 7.856 0.002919 0.003876 0.003828 + 7.857 0.002918 0.003875 0.003828 + 7.858 0.002917 0.003874 0.003827 + 7.859 0.002917 0.003873 0.003826 + 7.860 0.002916 0.003873 0.003825 + 7.861 0.002916 0.003872 0.003824 + 7.862 0.002915 0.003871 0.003824 + 7.863 0.002914 0.003870 0.003823 + 7.864 0.002914 0.003869 0.003822 + 7.865 0.002913 0.003869 0.003821 + 7.866 0.002913 0.003868 0.003820 + 7.867 0.002912 0.003867 0.003820 + 7.868 0.002911 0.003866 0.003819 + 7.869 0.002911 0.003865 0.003818 + 7.870 0.002910 0.003864 0.003817 + 7.871 0.002909 0.003864 0.003816 + 7.872 0.002909 0.003863 0.003816 + 7.873 0.002908 0.003862 0.003815 + 7.874 0.002908 0.003861 0.003814 + 7.875 0.002907 0.003860 0.003813 + 7.876 0.002906 0.003860 0.003812 + 7.877 0.002906 0.003859 0.003812 + 7.878 0.002905 0.003858 0.003811 + 7.879 0.002905 0.003857 0.003810 + 7.880 0.002904 0.003856 0.003809 + 7.881 0.002903 0.003855 0.003808 + 7.882 0.002903 0.003855 0.003808 + 7.883 0.002902 0.003854 0.003807 + 7.884 0.002901 0.003853 0.003806 + 7.885 0.002901 0.003852 0.003805 + 7.886 0.002900 0.003851 0.003804 + 7.887 0.002900 0.003851 0.003804 + 7.888 0.002899 0.003850 0.003803 + 7.889 0.002898 0.003849 0.003802 + 7.890 0.002898 0.003848 0.003801 + 7.891 0.002897 0.003847 0.003800 + 7.892 0.002897 0.003847 0.003800 + 7.893 0.002896 0.003846 0.003799 + 7.894 0.002895 0.003845 0.003798 + 7.895 0.002895 0.003844 0.003797 + 7.896 0.002894 0.003843 0.003796 + 7.897 0.002894 0.003842 0.003796 + 7.898 0.002893 0.003842 0.003795 + 7.899 0.002892 0.003841 0.003794 + 7.900 0.002892 0.003840 0.003793 + 7.901 0.002891 0.003839 0.003792 + 7.902 0.002890 0.003838 0.003792 + 7.903 0.002890 0.003838 0.003791 + 7.904 0.002889 0.003837 0.003790 + 7.905 0.002889 0.003836 0.003789 + 7.906 0.002888 0.003835 0.003788 + 7.907 0.002887 0.003834 0.003788 + 7.908 0.002887 0.003834 0.003787 + 7.909 0.002886 0.003833 0.003786 + 7.910 0.002886 0.003832 0.003785 + 7.911 0.002885 0.003831 0.003785 + 7.912 0.002884 0.003830 0.003784 + 7.913 0.002884 0.003830 0.003783 + 7.914 0.002883 0.003829 0.003782 + 7.915 0.002883 0.003828 0.003781 + 7.916 0.002882 0.003827 0.003781 + 7.917 0.002881 0.003826 0.003780 + 7.918 0.002881 0.003826 0.003779 + 7.919 0.002880 0.003825 0.003778 + 7.920 0.002880 0.003824 0.003777 + 7.921 0.002879 0.003823 0.003777 + 7.922 0.002878 0.003822 0.003776 + 7.923 0.002878 0.003822 0.003775 + 7.924 0.002877 0.003821 0.003774 + 7.925 0.002877 0.003820 0.003773 + 7.926 0.002876 0.003819 0.003773 + 7.927 0.002875 0.003818 0.003772 + 7.928 0.002875 0.003818 0.003771 + 7.929 0.002874 0.003817 0.003770 + 7.930 0.002873 0.003816 0.003770 + 7.931 0.002873 0.003815 0.003769 + 7.932 0.002872 0.003814 0.003768 + 7.933 0.002872 0.003814 0.003767 + 7.934 0.002871 0.003813 0.003766 + 7.935 0.002870 0.003812 0.003766 + 7.936 0.002870 0.003811 0.003765 + 7.937 0.002869 0.003810 0.003764 + 7.938 0.002869 0.003810 0.003763 + 7.939 0.002868 0.003809 0.003763 + 7.940 0.002867 0.003808 0.003762 + 7.941 0.002867 0.003807 0.003761 + 7.942 0.002866 0.003806 0.003760 + 7.943 0.002866 0.003806 0.003759 + 7.944 0.002865 0.003805 0.003759 + 7.945 0.002864 0.003804 0.003758 + 7.946 0.002864 0.003803 0.003757 + 7.947 0.002863 0.003802 0.003756 + 7.948 0.002863 0.003802 0.003755 + 7.949 0.002862 0.003801 0.003755 + 7.950 0.002861 0.003800 0.003754 + 7.951 0.002861 0.003799 0.003753 + 7.952 0.002860 0.003798 0.003752 + 7.953 0.002860 0.003798 0.003752 + 7.954 0.002859 0.003797 0.003751 + 7.955 0.002858 0.003796 0.003750 + 7.956 0.002858 0.003795 0.003749 + 7.957 0.002857 0.003794 0.003748 + 7.958 0.002857 0.003794 0.003748 + 7.959 0.002856 0.003793 0.003747 + 7.960 0.002855 0.003792 0.003746 + 7.961 0.002855 0.003791 0.003745 + 7.962 0.002854 0.003790 0.003745 + 7.963 0.002854 0.003790 0.003744 + 7.964 0.002853 0.003789 0.003743 + 7.965 0.002852 0.003788 0.003742 + 7.966 0.002852 0.003787 0.003741 + 7.967 0.002851 0.003786 0.003741 + 7.968 0.002851 0.003786 0.003740 + 7.969 0.002850 0.003785 0.003739 + 7.970 0.002850 0.003784 0.003738 + 7.971 0.002849 0.003783 0.003738 + 7.972 0.002848 0.003783 0.003737 + 7.973 0.002848 0.003782 0.003736 + 7.974 0.002847 0.003781 0.003735 + 7.975 0.002847 0.003780 0.003734 + 7.976 0.002846 0.003779 0.003734 + 7.977 0.002845 0.003779 0.003733 + 7.978 0.002845 0.003778 0.003732 + 7.979 0.002844 0.003777 0.003731 + 7.980 0.002844 0.003776 0.003731 + 7.981 0.002843 0.003775 0.003730 + 7.982 0.002842 0.003775 0.003729 + 7.983 0.002842 0.003774 0.003728 + 7.984 0.002841 0.003773 0.003728 + 7.985 0.002841 0.003772 0.003727 + 7.986 0.002840 0.003772 0.003726 + 7.987 0.002839 0.003771 0.003725 + 7.988 0.002839 0.003770 0.003724 + 7.989 0.002838 0.003769 0.003724 + 7.990 0.002838 0.003768 0.003723 + 7.991 0.002837 0.003768 0.003722 + 7.992 0.002836 0.003767 0.003721 + 7.993 0.002836 0.003766 0.003721 + 7.994 0.002835 0.003765 0.003720 + 7.995 0.002835 0.003764 0.003719 + 7.996 0.002834 0.003764 0.003718 + 7.997 0.002834 0.003763 0.003718 + 7.998 0.002833 0.003762 0.003717 + 7.999 0.002832 0.003761 0.003716 + 8.000 0.002832 0.003761 0.003715 + 8.001 0.002831 0.003760 0.003714 + 8.002 0.002831 0.003759 0.003714 + 8.003 0.002830 0.003758 0.003713 + 8.004 0.002829 0.003757 0.003712 + 8.005 0.002829 0.003757 0.003711 + 8.006 0.002828 0.003756 0.003711 + 8.007 0.002828 0.003755 0.003710 + 8.008 0.002827 0.003754 0.003709 + 8.009 0.002826 0.003754 0.003708 + 8.010 0.002826 0.003753 0.003708 + 8.011 0.002825 0.003752 0.003707 + 8.012 0.002825 0.003751 0.003706 + 8.013 0.002824 0.003750 0.003705 + 8.014 0.002824 0.003750 0.003705 + 8.015 0.002823 0.003749 0.003704 + 8.016 0.002822 0.003748 0.003703 + 8.017 0.002822 0.003747 0.003702 + 8.018 0.002821 0.003747 0.003701 + 8.019 0.002821 0.003746 0.003701 + 8.020 0.002820 0.003745 0.003700 + 8.021 0.002819 0.003744 0.003699 + 8.022 0.002819 0.003743 0.003698 + 8.023 0.002818 0.003743 0.003698 + 8.024 0.002818 0.003742 0.003697 + 8.025 0.002817 0.003741 0.003696 + 8.026 0.002816 0.003740 0.003695 + 8.027 0.002816 0.003740 0.003695 + 8.028 0.002815 0.003739 0.003694 + 8.029 0.002815 0.003738 0.003693 + 8.030 0.002814 0.003737 0.003692 + 8.031 0.002814 0.003736 0.003692 + 8.032 0.002813 0.003736 0.003691 + 8.033 0.002812 0.003735 0.003690 + 8.034 0.002812 0.003734 0.003689 + 8.035 0.002811 0.003733 0.003689 + 8.036 0.002811 0.003733 0.003688 + 8.037 0.002810 0.003732 0.003687 + 8.038 0.002809 0.003731 0.003686 + 8.039 0.002809 0.003730 0.003686 + 8.040 0.002808 0.003729 0.003685 + 8.041 0.002808 0.003729 0.003684 + 8.042 0.002807 0.003728 0.003683 + 8.043 0.002807 0.003727 0.003682 + 8.044 0.002806 0.003726 0.003682 + 8.045 0.002805 0.003726 0.003681 + 8.046 0.002805 0.003725 0.003680 + 8.047 0.002804 0.003724 0.003679 + 8.048 0.002804 0.003723 0.003679 + 8.049 0.002803 0.003723 0.003678 + 8.050 0.002803 0.003722 0.003677 + 8.051 0.002802 0.003721 0.003676 + 8.052 0.002801 0.003720 0.003676 + 8.053 0.002801 0.003719 0.003675 + 8.054 0.002800 0.003719 0.003674 + 8.055 0.002800 0.003718 0.003673 + 8.056 0.002799 0.003717 0.003673 + 8.057 0.002798 0.003716 0.003672 + 8.058 0.002798 0.003716 0.003671 + 8.059 0.002797 0.003715 0.003670 + 8.060 0.002797 0.003714 0.003670 + 8.061 0.002796 0.003713 0.003669 + 8.062 0.002796 0.003713 0.003668 + 8.063 0.002795 0.003712 0.003667 + 8.064 0.002794 0.003711 0.003667 + 8.065 0.002794 0.003710 0.003666 + 8.066 0.002793 0.003710 0.003665 + 8.067 0.002793 0.003709 0.003664 + 8.068 0.002792 0.003708 0.003664 + 8.069 0.002792 0.003707 0.003663 + 8.070 0.002791 0.003706 0.003662 + 8.071 0.002790 0.003706 0.003661 + 8.072 0.002790 0.003705 0.003661 + 8.073 0.002789 0.003704 0.003660 + 8.074 0.002789 0.003703 0.003659 + 8.075 0.002788 0.003703 0.003658 + 8.076 0.002787 0.003702 0.003658 + 8.077 0.002787 0.003701 0.003657 + 8.078 0.002786 0.003700 0.003656 + 8.079 0.002786 0.003700 0.003655 + 8.080 0.002785 0.003699 0.003655 + 8.081 0.002785 0.003698 0.003654 + 8.082 0.002784 0.003697 0.003653 + 8.083 0.002783 0.003697 0.003652 + 8.084 0.002783 0.003696 0.003652 + 8.085 0.002782 0.003695 0.003651 + 8.086 0.002782 0.003694 0.003650 + 8.087 0.002781 0.003694 0.003649 + 8.088 0.002781 0.003693 0.003649 + 8.089 0.002780 0.003692 0.003648 + 8.090 0.002779 0.003691 0.003647 + 8.091 0.002779 0.003690 0.003646 + 8.092 0.002778 0.003690 0.003646 + 8.093 0.002778 0.003689 0.003645 + 8.094 0.002777 0.003688 0.003644 + 8.095 0.002777 0.003687 0.003643 + 8.096 0.002776 0.003687 0.003643 + 8.097 0.002775 0.003686 0.003642 + 8.098 0.002775 0.003685 0.003641 + 8.099 0.002774 0.003684 0.003641 + 8.100 0.002774 0.003684 0.003640 + 8.101 0.002773 0.003683 0.003639 + 8.102 0.002773 0.003682 0.003638 + 8.103 0.002772 0.003681 0.003638 + 8.104 0.002771 0.003681 0.003637 + 8.105 0.002771 0.003680 0.003636 + 8.106 0.002770 0.003679 0.003635 + 8.107 0.002770 0.003678 0.003635 + 8.108 0.002769 0.003678 0.003634 + 8.109 0.002769 0.003677 0.003633 + 8.110 0.002768 0.003676 0.003632 + 8.111 0.002767 0.003675 0.003632 + 8.112 0.002767 0.003675 0.003631 + 8.113 0.002766 0.003674 0.003630 + 8.114 0.002766 0.003673 0.003629 + 8.115 0.002765 0.003672 0.003629 + 8.116 0.002765 0.003672 0.003628 + 8.117 0.002764 0.003671 0.003627 + 8.118 0.002764 0.003670 0.003626 + 8.119 0.002763 0.003669 0.003626 + 8.120 0.002762 0.003669 0.003625 + 8.121 0.002762 0.003668 0.003624 + 8.122 0.002761 0.003667 0.003624 + 8.123 0.002761 0.003666 0.003623 + 8.124 0.002760 0.003666 0.003622 + 8.125 0.002760 0.003665 0.003621 + 8.126 0.002759 0.003664 0.003621 + 8.127 0.002758 0.003663 0.003620 + 8.128 0.002758 0.003663 0.003619 + 8.129 0.002757 0.003662 0.003618 + 8.130 0.002757 0.003661 0.003618 + 8.131 0.002756 0.003660 0.003617 + 8.132 0.002756 0.003660 0.003616 + 8.133 0.002755 0.003659 0.003615 + 8.134 0.002754 0.003658 0.003615 + 8.135 0.002754 0.003657 0.003614 + 8.136 0.002753 0.003657 0.003613 + 8.137 0.002753 0.003656 0.003612 + 8.138 0.002752 0.003655 0.003612 + 8.139 0.002752 0.003654 0.003611 + 8.140 0.002751 0.003654 0.003610 + 8.141 0.002751 0.003653 0.003610 + 8.142 0.002750 0.003652 0.003609 + 8.143 0.002749 0.003651 0.003608 + 8.144 0.002749 0.003651 0.003607 + 8.145 0.002748 0.003650 0.003607 + 8.146 0.002748 0.003649 0.003606 + 8.147 0.002747 0.003648 0.003605 + 8.148 0.002747 0.003648 0.003604 + 8.149 0.002746 0.003647 0.003604 + 8.150 0.002745 0.003646 0.003603 + 8.151 0.002745 0.003645 0.003602 + 8.152 0.002744 0.003645 0.003601 + 8.153 0.002744 0.003644 0.003601 + 8.154 0.002743 0.003643 0.003600 + 8.155 0.002743 0.003642 0.003599 + 8.156 0.002742 0.003642 0.003599 + 8.157 0.002742 0.003641 0.003598 + 8.158 0.002741 0.003640 0.003597 + 8.159 0.002740 0.003639 0.003596 + 8.160 0.002740 0.003639 0.003596 + 8.161 0.002739 0.003638 0.003595 + 8.162 0.002739 0.003637 0.003594 + 8.163 0.002738 0.003636 0.003593 + 8.164 0.002738 0.003636 0.003593 + 8.165 0.002737 0.003635 0.003592 + 8.166 0.002737 0.003634 0.003591 + 8.167 0.002736 0.003634 0.003591 + 8.168 0.002735 0.003633 0.003590 + 8.169 0.002735 0.003632 0.003589 + 8.170 0.002734 0.003631 0.003588 + 8.171 0.002734 0.003631 0.003588 + 8.172 0.002733 0.003630 0.003587 + 8.173 0.002733 0.003629 0.003586 + 8.174 0.002732 0.003628 0.003585 + 8.175 0.002731 0.003628 0.003585 + 8.176 0.002731 0.003627 0.003584 + 8.177 0.002730 0.003626 0.003583 + 8.178 0.002730 0.003625 0.003583 + 8.179 0.002729 0.003625 0.003582 + 8.180 0.002729 0.003624 0.003581 + 8.181 0.002728 0.003623 0.003580 + 8.182 0.002728 0.003622 0.003580 + 8.183 0.002727 0.003622 0.003579 + 8.184 0.002726 0.003621 0.003578 + 8.185 0.002726 0.003620 0.003578 + 8.186 0.002725 0.003620 0.003577 + 8.187 0.002725 0.003619 0.003576 + 8.188 0.002724 0.003618 0.003575 + 8.189 0.002724 0.003617 0.003575 + 8.190 0.002723 0.003617 0.003574 + 8.191 0.002723 0.003616 0.003573 + 8.192 0.002722 0.003615 0.003572 + 8.193 0.002722 0.003614 0.003572 + 8.194 0.002721 0.003614 0.003571 + 8.195 0.002720 0.003613 0.003570 + 8.196 0.002720 0.003612 0.003570 + 8.197 0.002719 0.003611 0.003569 + 8.198 0.002719 0.003611 0.003568 + 8.199 0.002718 0.003610 0.003567 + 8.200 0.002718 0.003609 0.003567 + 8.201 0.002717 0.003609 0.003566 + 8.202 0.002717 0.003608 0.003565 + 8.203 0.002716 0.003607 0.003565 + 8.204 0.002715 0.003606 0.003564 + 8.205 0.002715 0.003606 0.003563 + 8.206 0.002714 0.003605 0.003562 + 8.207 0.002714 0.003604 0.003562 + 8.208 0.002713 0.003603 0.003561 + 8.209 0.002713 0.003603 0.003560 + 8.210 0.002712 0.003602 0.003560 + 8.211 0.002712 0.003601 0.003559 + 8.212 0.002711 0.003600 0.003558 + 8.213 0.002710 0.003600 0.003557 + 8.214 0.002710 0.003599 0.003557 + 8.215 0.002709 0.003598 0.003556 + 8.216 0.002709 0.003598 0.003555 + 8.217 0.002708 0.003597 0.003555 + 8.218 0.002708 0.003596 0.003554 + 8.219 0.002707 0.003595 0.003553 + 8.220 0.002707 0.003595 0.003552 + 8.221 0.002706 0.003594 0.003552 + 8.222 0.002706 0.003593 0.003551 + 8.223 0.002705 0.003592 0.003550 + 8.224 0.002704 0.003592 0.003550 + 8.225 0.002704 0.003591 0.003549 + 8.226 0.002703 0.003590 0.003548 + 8.227 0.002703 0.003590 0.003547 + 8.228 0.002702 0.003589 0.003547 + 8.229 0.002702 0.003588 0.003546 + 8.230 0.002701 0.003587 0.003545 + 8.231 0.002701 0.003587 0.003545 + 8.232 0.002700 0.003586 0.003544 + 8.233 0.002700 0.003585 0.003543 + 8.234 0.002699 0.003584 0.003542 + 8.235 0.002698 0.003584 0.003542 + 8.236 0.002698 0.003583 0.003541 + 8.237 0.002697 0.003582 0.003540 + 8.238 0.002697 0.003582 0.003540 + 8.239 0.002696 0.003581 0.003539 + 8.240 0.002696 0.003580 0.003538 + 8.241 0.002695 0.003579 0.003537 + 8.242 0.002695 0.003579 0.003537 + 8.243 0.002694 0.003578 0.003536 + 8.244 0.002694 0.003577 0.003535 + 8.245 0.002693 0.003577 0.003535 + 8.246 0.002692 0.003576 0.003534 + 8.247 0.002692 0.003575 0.003533 + 8.248 0.002691 0.003574 0.003533 + 8.249 0.002691 0.003574 0.003532 + 8.250 0.002690 0.003573 0.003531 + 8.251 0.002690 0.003572 0.003530 + 8.252 0.002689 0.003572 0.003530 + 8.253 0.002689 0.003571 0.003529 + 8.254 0.002688 0.003570 0.003528 + 8.255 0.002688 0.003569 0.003528 + 8.256 0.002687 0.003569 0.003527 + 8.257 0.002686 0.003568 0.003526 + 8.258 0.002686 0.003567 0.003525 + 8.259 0.002685 0.003566 0.003525 + 8.260 0.002685 0.003566 0.003524 + 8.261 0.002684 0.003565 0.003523 + 8.262 0.002684 0.003564 0.003523 + 8.263 0.002683 0.003564 0.003522 + 8.264 0.002683 0.003563 0.003521 + 8.265 0.002682 0.003562 0.003521 + 8.266 0.002682 0.003561 0.003520 + 8.267 0.002681 0.003561 0.003519 + 8.268 0.002681 0.003560 0.003518 + 8.269 0.002680 0.003559 0.003518 + 8.270 0.002679 0.003559 0.003517 + 8.271 0.002679 0.003558 0.003516 + 8.272 0.002678 0.003557 0.003516 + 8.273 0.002678 0.003556 0.003515 + 8.274 0.002677 0.003556 0.003514 + 8.275 0.002677 0.003555 0.003513 + 8.276 0.002676 0.003554 0.003513 + 8.277 0.002676 0.003554 0.003512 + 8.278 0.002675 0.003553 0.003511 + 8.279 0.002675 0.003552 0.003511 + 8.280 0.002674 0.003551 0.003510 + 8.281 0.002674 0.003551 0.003509 + 8.282 0.002673 0.003550 0.003509 + 8.283 0.002672 0.003549 0.003508 + 8.284 0.002672 0.003549 0.003507 + 8.285 0.002671 0.003548 0.003506 + 8.286 0.002671 0.003547 0.003506 + 8.287 0.002670 0.003546 0.003505 + 8.288 0.002670 0.003546 0.003504 + 8.289 0.002669 0.003545 0.003504 + 8.290 0.002669 0.003544 0.003503 + 8.291 0.002668 0.003544 0.003502 + 8.292 0.002668 0.003543 0.003502 + 8.293 0.002667 0.003542 0.003501 + 8.294 0.002667 0.003541 0.003500 + 8.295 0.002666 0.003541 0.003499 + 8.296 0.002665 0.003540 0.003499 + 8.297 0.002665 0.003539 0.003498 + 8.298 0.002664 0.003539 0.003497 + 8.299 0.002664 0.003538 0.003497 + 8.300 0.002663 0.003537 0.003496 + 8.301 0.002663 0.003537 0.003495 + 8.302 0.002662 0.003536 0.003495 + 8.303 0.002662 0.003535 0.003494 + 8.304 0.002661 0.003534 0.003493 + 8.305 0.002661 0.003534 0.003493 + 8.306 0.002660 0.003533 0.003492 + 8.307 0.002660 0.003532 0.003491 + 8.308 0.002659 0.003532 0.003490 + 8.309 0.002659 0.003531 0.003490 + 8.310 0.002658 0.003530 0.003489 + 8.311 0.002657 0.003529 0.003488 + 8.312 0.002657 0.003529 0.003488 + 8.313 0.002656 0.003528 0.003487 + 8.314 0.002656 0.003527 0.003486 + 8.315 0.002655 0.003527 0.003486 + 8.316 0.002655 0.003526 0.003485 + 8.317 0.002654 0.003525 0.003484 + 8.318 0.002654 0.003524 0.003484 + 8.319 0.002653 0.003524 0.003483 + 8.320 0.002653 0.003523 0.003482 + 8.321 0.002652 0.003522 0.003481 + 8.322 0.002652 0.003522 0.003481 + 8.323 0.002651 0.003521 0.003480 + 8.324 0.002651 0.003520 0.003479 + 8.325 0.002650 0.003520 0.003479 + 8.326 0.002649 0.003519 0.003478 + 8.327 0.002649 0.003518 0.003477 + 8.328 0.002648 0.003517 0.003477 + 8.329 0.002648 0.003517 0.003476 + 8.330 0.002647 0.003516 0.003475 + 8.331 0.002647 0.003515 0.003475 + 8.332 0.002646 0.003515 0.003474 + 8.333 0.002646 0.003514 0.003473 + 8.334 0.002645 0.003513 0.003472 + 8.335 0.002645 0.003513 0.003472 + 8.336 0.002644 0.003512 0.003471 + 8.337 0.002644 0.003511 0.003470 + 8.338 0.002643 0.003510 0.003470 + 8.339 0.002643 0.003510 0.003469 + 8.340 0.002642 0.003509 0.003468 + 8.341 0.002642 0.003508 0.003468 + 8.342 0.002641 0.003508 0.003467 + 8.343 0.002641 0.003507 0.003466 + 8.344 0.002640 0.003506 0.003466 + 8.345 0.002639 0.003506 0.003465 + 8.346 0.002639 0.003505 0.003464 + 8.347 0.002638 0.003504 0.003464 + 8.348 0.002638 0.003503 0.003463 + 8.349 0.002637 0.003503 0.003462 + 8.350 0.002637 0.003502 0.003461 + 8.351 0.002636 0.003501 0.003461 + 8.352 0.002636 0.003501 0.003460 + 8.353 0.002635 0.003500 0.003459 + 8.354 0.002635 0.003499 0.003459 + 8.355 0.002634 0.003499 0.003458 + 8.356 0.002634 0.003498 0.003457 + 8.357 0.002633 0.003497 0.003457 + 8.358 0.002633 0.003496 0.003456 + 8.359 0.002632 0.003496 0.003455 + 8.360 0.002632 0.003495 0.003455 + 8.361 0.002631 0.003494 0.003454 + 8.362 0.002631 0.003494 0.003453 + 8.363 0.002630 0.003493 0.003453 + 8.364 0.002629 0.003492 0.003452 + 8.365 0.002629 0.003492 0.003451 + 8.366 0.002628 0.003491 0.003451 + 8.367 0.002628 0.003490 0.003450 + 8.368 0.002627 0.003490 0.003449 + 8.369 0.002627 0.003489 0.003449 + 8.370 0.002626 0.003488 0.003448 + 8.371 0.002626 0.003487 0.003447 + 8.372 0.002625 0.003487 0.003446 + 8.373 0.002625 0.003486 0.003446 + 8.374 0.002624 0.003485 0.003445 + 8.375 0.002624 0.003485 0.003444 + 8.376 0.002623 0.003484 0.003444 + 8.377 0.002623 0.003483 0.003443 + 8.378 0.002622 0.003483 0.003442 + 8.379 0.002622 0.003482 0.003442 + 8.380 0.002621 0.003481 0.003441 + 8.381 0.002621 0.003481 0.003440 + 8.382 0.002620 0.003480 0.003440 + 8.383 0.002620 0.003479 0.003439 + 8.384 0.002619 0.003478 0.003438 + 8.385 0.002619 0.003478 0.003438 + 8.386 0.002618 0.003477 0.003437 + 8.387 0.002617 0.003476 0.003436 + 8.388 0.002617 0.003476 0.003436 + 8.389 0.002616 0.003475 0.003435 + 8.390 0.002616 0.003474 0.003434 + 8.391 0.002615 0.003474 0.003434 + 8.392 0.002615 0.003473 0.003433 + 8.393 0.002614 0.003472 0.003432 + 8.394 0.002614 0.003472 0.003432 + 8.395 0.002613 0.003471 0.003431 + 8.396 0.002613 0.003470 0.003430 + 8.397 0.002612 0.003470 0.003430 + 8.398 0.002612 0.003469 0.003429 + 8.399 0.002611 0.003468 0.003428 + 8.400 0.002611 0.003467 0.003428 + 8.401 0.002610 0.003467 0.003427 + 8.402 0.002610 0.003466 0.003426 + 8.403 0.002609 0.003465 0.003425 + 8.404 0.002609 0.003465 0.003425 + 8.405 0.002608 0.003464 0.003424 + 8.406 0.002608 0.003463 0.003423 + 8.407 0.002607 0.003463 0.003423 + 8.408 0.002607 0.003462 0.003422 + 8.409 0.002606 0.003461 0.003421 + 8.410 0.002606 0.003461 0.003421 + 8.411 0.002605 0.003460 0.003420 + 8.412 0.002605 0.003459 0.003419 + 8.413 0.002604 0.003459 0.003419 + 8.414 0.002604 0.003458 0.003418 + 8.415 0.002603 0.003457 0.003417 + 8.416 0.002602 0.003457 0.003417 + 8.417 0.002602 0.003456 0.003416 + 8.418 0.002601 0.003455 0.003415 + 8.419 0.002601 0.003454 0.003415 + 8.420 0.002600 0.003454 0.003414 + 8.421 0.002600 0.003453 0.003413 + 8.422 0.002599 0.003452 0.003413 + 8.423 0.002599 0.003452 0.003412 + 8.424 0.002598 0.003451 0.003411 + 8.425 0.002598 0.003450 0.003411 + 8.426 0.002597 0.003450 0.003410 + 8.427 0.002597 0.003449 0.003409 + 8.428 0.002596 0.003448 0.003409 + 8.429 0.002596 0.003448 0.003408 + 8.430 0.002595 0.003447 0.003407 + 8.431 0.002595 0.003446 0.003407 + 8.432 0.002594 0.003446 0.003406 + 8.433 0.002594 0.003445 0.003405 + 8.434 0.002593 0.003444 0.003405 + 8.435 0.002593 0.003444 0.003404 + 8.436 0.002592 0.003443 0.003403 + 8.437 0.002592 0.003442 0.003403 + 8.438 0.002591 0.003442 0.003402 + 8.439 0.002591 0.003441 0.003401 + 8.440 0.002590 0.003440 0.003401 + 8.441 0.002590 0.003439 0.003400 + 8.442 0.002589 0.003439 0.003399 + 8.443 0.002589 0.003438 0.003399 + 8.444 0.002588 0.003437 0.003398 + 8.445 0.002588 0.003437 0.003397 + 8.446 0.002587 0.003436 0.003397 + 8.447 0.002587 0.003435 0.003396 + 8.448 0.002586 0.003435 0.003395 + 8.449 0.002586 0.003434 0.003395 + 8.450 0.002585 0.003433 0.003394 + 8.451 0.002585 0.003433 0.003393 + 8.452 0.002584 0.003432 0.003393 + 8.453 0.002584 0.003431 0.003392 + 8.454 0.002583 0.003431 0.003391 + 8.455 0.002583 0.003430 0.003391 + 8.456 0.002582 0.003429 0.003390 + 8.457 0.002581 0.003429 0.003389 + 8.458 0.002581 0.003428 0.003389 + 8.459 0.002580 0.003427 0.003388 + 8.460 0.002580 0.003427 0.003387 + 8.461 0.002579 0.003426 0.003387 + 8.462 0.002579 0.003425 0.003386 + 8.463 0.002578 0.003425 0.003385 + 8.464 0.002578 0.003424 0.003385 + 8.465 0.002577 0.003423 0.003384 + 8.466 0.002577 0.003423 0.003383 + 8.467 0.002576 0.003422 0.003383 + 8.468 0.002576 0.003421 0.003382 + 8.469 0.002575 0.003421 0.003381 + 8.470 0.002575 0.003420 0.003381 + 8.471 0.002574 0.003419 0.003380 + 8.472 0.002574 0.003419 0.003380 + 8.473 0.002573 0.003418 0.003379 + 8.474 0.002573 0.003417 0.003378 + 8.475 0.002572 0.003417 0.003378 + 8.476 0.002572 0.003416 0.003377 + 8.477 0.002571 0.003415 0.003376 + 8.478 0.002571 0.003415 0.003376 + 8.479 0.002570 0.003414 0.003375 + 8.480 0.002570 0.003413 0.003374 + 8.481 0.002569 0.003413 0.003374 + 8.482 0.002569 0.003412 0.003373 + 8.483 0.002568 0.003411 0.003372 + 8.484 0.002568 0.003411 0.003372 + 8.485 0.002567 0.003410 0.003371 + 8.486 0.002567 0.003409 0.003370 + 8.487 0.002566 0.003409 0.003370 + 8.488 0.002566 0.003408 0.003369 + 8.489 0.002565 0.003407 0.003368 + 8.490 0.002565 0.003407 0.003368 + 8.491 0.002564 0.003406 0.003367 + 8.492 0.002564 0.003405 0.003366 + 8.493 0.002563 0.003405 0.003366 + 8.494 0.002563 0.003404 0.003365 + 8.495 0.002562 0.003403 0.003364 + 8.496 0.002562 0.003403 0.003364 + 8.497 0.002561 0.003402 0.003363 + 8.498 0.002561 0.003401 0.003362 + 8.499 0.002560 0.003401 0.003362 + 8.500 0.002560 0.003400 0.003361 + 8.501 0.002559 0.003399 0.003360 + 8.502 0.002559 0.003399 0.003360 + 8.503 0.002558 0.003398 0.003359 + 8.504 0.002558 0.003397 0.003359 + 8.505 0.002557 0.003397 0.003358 + 8.506 0.002557 0.003396 0.003357 + 8.507 0.002556 0.003395 0.003357 + 8.508 0.002556 0.003395 0.003356 + 8.509 0.002555 0.003394 0.003355 + 8.510 0.002555 0.003393 0.003355 + 8.511 0.002554 0.003393 0.003354 + 8.512 0.002554 0.003392 0.003353 + 8.513 0.002553 0.003391 0.003353 + 8.514 0.002553 0.003391 0.003352 + 8.515 0.002552 0.003390 0.003351 + 8.516 0.002552 0.003389 0.003351 + 8.517 0.002551 0.003389 0.003350 + 8.518 0.002551 0.003388 0.003349 + 8.519 0.002550 0.003387 0.003349 + 8.520 0.002550 0.003387 0.003348 + 8.521 0.002549 0.003386 0.003347 + 8.522 0.002549 0.003385 0.003347 + 8.523 0.002548 0.003385 0.003346 + 8.524 0.002548 0.003384 0.003346 + 8.525 0.002547 0.003383 0.003345 + 8.526 0.002547 0.003383 0.003344 + 8.527 0.002546 0.003382 0.003344 + 8.528 0.002546 0.003381 0.003343 + 8.529 0.002545 0.003381 0.003342 + 8.530 0.002545 0.003380 0.003342 + 8.531 0.002544 0.003379 0.003341 + 8.532 0.002544 0.003379 0.003340 + 8.533 0.002543 0.003378 0.003340 + 8.534 0.002543 0.003377 0.003339 + 8.535 0.002542 0.003377 0.003338 + 8.536 0.002542 0.003376 0.003338 + 8.537 0.002541 0.003375 0.003337 + 8.538 0.002541 0.003375 0.003336 + 8.539 0.002540 0.003374 0.003336 + 8.540 0.002540 0.003373 0.003335 + 8.541 0.002539 0.003373 0.003335 + 8.542 0.002539 0.003372 0.003334 + 8.543 0.002538 0.003371 0.003333 + 8.544 0.002538 0.003371 0.003333 + 8.545 0.002537 0.003370 0.003332 + 8.546 0.002537 0.003369 0.003331 + 8.547 0.002536 0.003369 0.003331 + 8.548 0.002536 0.003368 0.003330 + 8.549 0.002535 0.003368 0.003329 + 8.550 0.002535 0.003367 0.003329 + 8.551 0.002534 0.003366 0.003328 + 8.552 0.002534 0.003366 0.003327 + 8.553 0.002533 0.003365 0.003327 + 8.554 0.002533 0.003364 0.003326 + 8.555 0.002532 0.003364 0.003325 + 8.556 0.002532 0.003363 0.003325 + 8.557 0.002531 0.003362 0.003324 + 8.558 0.002531 0.003362 0.003324 + 8.559 0.002530 0.003361 0.003323 + 8.560 0.002530 0.003360 0.003322 + 8.561 0.002529 0.003360 0.003322 + 8.562 0.002529 0.003359 0.003321 + 8.563 0.002528 0.003358 0.003320 + 8.564 0.002528 0.003358 0.003320 + 8.565 0.002528 0.003357 0.003319 + 8.566 0.002527 0.003356 0.003318 + 8.567 0.002527 0.003356 0.003318 + 8.568 0.002526 0.003355 0.003317 + 8.569 0.002526 0.003354 0.003317 + 8.570 0.002525 0.003354 0.003316 + 8.571 0.002525 0.003353 0.003315 + 8.572 0.002524 0.003353 0.003315 + 8.573 0.002524 0.003352 0.003314 + 8.574 0.002523 0.003351 0.003313 + 8.575 0.002523 0.003351 0.003313 + 8.576 0.002522 0.003350 0.003312 + 8.577 0.002522 0.003349 0.003311 + 8.578 0.002521 0.003349 0.003311 + 8.579 0.002521 0.003348 0.003310 + 8.580 0.002520 0.003347 0.003309 + 8.581 0.002520 0.003347 0.003309 + 8.582 0.002519 0.003346 0.003308 + 8.583 0.002519 0.003345 0.003308 + 8.584 0.002518 0.003345 0.003307 + 8.585 0.002518 0.003344 0.003306 + 8.586 0.002517 0.003343 0.003306 + 8.587 0.002517 0.003343 0.003305 + 8.588 0.002516 0.003342 0.003304 + 8.589 0.002516 0.003341 0.003304 + 8.590 0.002515 0.003341 0.003303 + 8.591 0.002515 0.003340 0.003302 + 8.592 0.002514 0.003340 0.003302 + 8.593 0.002514 0.003339 0.003301 + 8.594 0.002513 0.003338 0.003301 + 8.595 0.002513 0.003338 0.003300 + 8.596 0.002512 0.003337 0.003299 + 8.597 0.002512 0.003336 0.003299 + 8.598 0.002511 0.003336 0.003298 + 8.599 0.002511 0.003335 0.003297 + 8.600 0.002510 0.003334 0.003297 + 8.601 0.002510 0.003334 0.003296 + 8.602 0.002509 0.003333 0.003296 + 8.603 0.002509 0.003332 0.003295 + 8.604 0.002508 0.003332 0.003294 + 8.605 0.002508 0.003331 0.003294 + 8.606 0.002507 0.003331 0.003293 + 8.607 0.002507 0.003330 0.003292 + 8.608 0.002507 0.003329 0.003292 + 8.609 0.002506 0.003329 0.003291 + 8.610 0.002506 0.003328 0.003290 + 8.611 0.002505 0.003327 0.003290 + 8.612 0.002505 0.003327 0.003289 + 8.613 0.002504 0.003326 0.003289 + 8.614 0.002504 0.003325 0.003288 + 8.615 0.002503 0.003325 0.003287 + 8.616 0.002503 0.003324 0.003287 + 8.617 0.002502 0.003323 0.003286 + 8.618 0.002502 0.003323 0.003285 + 8.619 0.002501 0.003322 0.003285 + 8.620 0.002501 0.003322 0.003284 + 8.621 0.002500 0.003321 0.003284 + 8.622 0.002500 0.003320 0.003283 + 8.623 0.002499 0.003320 0.003282 + 8.624 0.002499 0.003319 0.003282 + 8.625 0.002498 0.003318 0.003281 + 8.626 0.002498 0.003318 0.003280 + 8.627 0.002497 0.003317 0.003280 + 8.628 0.002497 0.003316 0.003279 + 8.629 0.002496 0.003316 0.003278 + 8.630 0.002496 0.003315 0.003278 + 8.631 0.002495 0.003314 0.003277 + 8.632 0.002495 0.003314 0.003277 + 8.633 0.002494 0.003313 0.003276 + 8.634 0.002494 0.003313 0.003275 + 8.635 0.002493 0.003312 0.003275 + 8.636 0.002493 0.003311 0.003274 + 8.637 0.002493 0.003311 0.003273 + 8.638 0.002492 0.003310 0.003273 + 8.639 0.002492 0.003309 0.003272 + 8.640 0.002491 0.003309 0.003272 + 8.641 0.002491 0.003308 0.003271 + 8.642 0.002490 0.003307 0.003270 + 8.643 0.002490 0.003307 0.003270 + 8.644 0.002489 0.003306 0.003269 + 8.645 0.002489 0.003306 0.003268 + 8.646 0.002488 0.003305 0.003268 + 8.647 0.002488 0.003304 0.003267 + 8.648 0.002487 0.003304 0.003267 + 8.649 0.002487 0.003303 0.003266 + 8.650 0.002486 0.003302 0.003265 + 8.651 0.002486 0.003302 0.003265 + 8.652 0.002485 0.003301 0.003264 + 8.653 0.002485 0.003300 0.003263 + 8.654 0.002484 0.003300 0.003263 + 8.655 0.002484 0.003299 0.003262 + 8.656 0.002483 0.003299 0.003262 + 8.657 0.002483 0.003298 0.003261 + 8.658 0.002482 0.003297 0.003260 + 8.659 0.002482 0.003297 0.003260 + 8.660 0.002481 0.003296 0.003259 + 8.661 0.002481 0.003295 0.003258 + 8.662 0.002481 0.003295 0.003258 + 8.663 0.002480 0.003294 0.003257 + 8.664 0.002480 0.003294 0.003257 + 8.665 0.002479 0.003293 0.003256 + 8.666 0.002479 0.003292 0.003255 + 8.667 0.002478 0.003292 0.003255 + 8.668 0.002478 0.003291 0.003254 + 8.669 0.002477 0.003290 0.003254 + 8.670 0.002477 0.003290 0.003253 + 8.671 0.002476 0.003289 0.003252 + 8.672 0.002476 0.003288 0.003252 + 8.673 0.002475 0.003288 0.003251 + 8.674 0.002475 0.003287 0.003250 + 8.675 0.002474 0.003287 0.003250 + 8.676 0.002474 0.003286 0.003249 + 8.677 0.002473 0.003285 0.003249 + 8.678 0.002473 0.003285 0.003248 + 8.679 0.002472 0.003284 0.003247 + 8.680 0.002472 0.003283 0.003247 + 8.681 0.002472 0.003283 0.003246 + 8.682 0.002471 0.003282 0.003245 + 8.683 0.002471 0.003282 0.003245 + 8.684 0.002470 0.003281 0.003244 + 8.685 0.002470 0.003280 0.003244 + 8.686 0.002469 0.003280 0.003243 + 8.687 0.002469 0.003279 0.003242 + 8.688 0.002468 0.003278 0.003242 + 8.689 0.002468 0.003278 0.003241 + 8.690 0.002467 0.003277 0.003241 + 8.691 0.002467 0.003277 0.003240 + 8.692 0.002466 0.003276 0.003239 + 8.693 0.002466 0.003275 0.003239 + 8.694 0.002465 0.003275 0.003238 + 8.695 0.002465 0.003274 0.003237 + 8.696 0.002464 0.003273 0.003237 + 8.697 0.002464 0.003273 0.003236 + 8.698 0.002463 0.003272 0.003236 + 8.699 0.002463 0.003271 0.003235 + 8.700 0.002463 0.003271 0.003234 + 8.701 0.002462 0.003270 0.003234 + 8.702 0.002462 0.003270 0.003233 + 8.703 0.002461 0.003269 0.003233 + 8.704 0.002461 0.003268 0.003232 + 8.705 0.002460 0.003268 0.003231 + 8.706 0.002460 0.003267 0.003231 + 8.707 0.002459 0.003267 0.003230 + 8.708 0.002459 0.003266 0.003229 + 8.709 0.002458 0.003265 0.003229 + 8.710 0.002458 0.003265 0.003228 + 8.711 0.002457 0.003264 0.003228 + 8.712 0.002457 0.003263 0.003227 + 8.713 0.002456 0.003263 0.003226 + 8.714 0.002456 0.003262 0.003226 + 8.715 0.002455 0.003262 0.003225 + 8.716 0.002455 0.003261 0.003225 + 8.717 0.002455 0.003260 0.003224 + 8.718 0.002454 0.003260 0.003223 + 8.719 0.002454 0.003259 0.003223 + 8.720 0.002453 0.003258 0.003222 + 8.721 0.002453 0.003258 0.003222 + 8.722 0.002452 0.003257 0.003221 + 8.723 0.002452 0.003257 0.003220 + 8.724 0.002451 0.003256 0.003220 + 8.725 0.002451 0.003255 0.003219 + 8.726 0.002450 0.003255 0.003218 + 8.727 0.002450 0.003254 0.003218 + 8.728 0.002449 0.003253 0.003217 + 8.729 0.002449 0.003253 0.003217 + 8.730 0.002448 0.003252 0.003216 + 8.731 0.002448 0.003252 0.003215 + 8.732 0.002448 0.003251 0.003215 + 8.733 0.002447 0.003250 0.003214 + 8.734 0.002447 0.003250 0.003214 + 8.735 0.002446 0.003249 0.003213 + 8.736 0.002446 0.003248 0.003212 + 8.737 0.002445 0.003248 0.003212 + 8.738 0.002445 0.003247 0.003211 + 8.739 0.002444 0.003247 0.003211 + 8.740 0.002444 0.003246 0.003210 + 8.741 0.002443 0.003245 0.003209 + 8.742 0.002443 0.003245 0.003209 + 8.743 0.002442 0.003244 0.003208 + 8.744 0.002442 0.003244 0.003208 + 8.745 0.002441 0.003243 0.003207 + 8.746 0.002441 0.003242 0.003206 + 8.747 0.002441 0.003242 0.003206 + 8.748 0.002440 0.003241 0.003205 + 8.749 0.002440 0.003240 0.003204 + 8.750 0.002439 0.003240 0.003204 + 8.751 0.002439 0.003239 0.003203 + 8.752 0.002438 0.003239 0.003203 + 8.753 0.002438 0.003238 0.003202 + 8.754 0.002437 0.003237 0.003201 + 8.755 0.002437 0.003237 0.003201 + 8.756 0.002436 0.003236 0.003200 + 8.757 0.002436 0.003236 0.003200 + 8.758 0.002435 0.003235 0.003199 + 8.759 0.002435 0.003234 0.003198 + 8.760 0.002434 0.003234 0.003198 + 8.761 0.002434 0.003233 0.003197 + 8.762 0.002434 0.003232 0.003197 + 8.763 0.002433 0.003232 0.003196 + 8.764 0.002433 0.003231 0.003195 + 8.765 0.002432 0.003231 0.003195 + 8.766 0.002432 0.003230 0.003194 + 8.767 0.002431 0.003229 0.003194 + 8.768 0.002431 0.003229 0.003193 + 8.769 0.002430 0.003228 0.003192 + 8.770 0.002430 0.003228 0.003192 + 8.771 0.002429 0.003227 0.003191 + 8.772 0.002429 0.003226 0.003191 + 8.773 0.002428 0.003226 0.003190 + 8.774 0.002428 0.003225 0.003189 + 8.775 0.002428 0.003225 0.003189 + 8.776 0.002427 0.003224 0.003188 + 8.777 0.002427 0.003223 0.003188 + 8.778 0.002426 0.003223 0.003187 + 8.779 0.002426 0.003222 0.003186 + 8.780 0.002425 0.003221 0.003186 + 8.781 0.002425 0.003221 0.003185 + 8.782 0.002424 0.003220 0.003185 + 8.783 0.002424 0.003220 0.003184 + 8.784 0.002423 0.003219 0.003183 + 8.785 0.002423 0.003218 0.003183 + 8.786 0.002423 0.003218 0.003182 + 8.787 0.002422 0.003217 0.003182 + 8.788 0.002422 0.003217 0.003181 + 8.789 0.002421 0.003216 0.003180 + 8.790 0.002421 0.003215 0.003180 + 8.791 0.002420 0.003215 0.003179 + 8.792 0.002420 0.003214 0.003179 + 8.793 0.002419 0.003214 0.003178 + 8.794 0.002419 0.003213 0.003177 + 8.795 0.002418 0.003212 0.003177 + 8.796 0.002418 0.003212 0.003176 + 8.797 0.002417 0.003211 0.003176 + 8.798 0.002417 0.003210 0.003175 + 8.799 0.002417 0.003210 0.003174 + 8.800 0.002416 0.003209 0.003174 + 8.801 0.002416 0.003209 0.003173 + 8.802 0.002415 0.003208 0.003173 + 8.803 0.002415 0.003207 0.003172 + 8.804 0.002414 0.003207 0.003171 + 8.805 0.002414 0.003206 0.003171 + 8.806 0.002413 0.003206 0.003170 + 8.807 0.002413 0.003205 0.003170 + 8.808 0.002412 0.003204 0.003169 + 8.809 0.002412 0.003204 0.003168 + 8.810 0.002412 0.003203 0.003168 + 8.811 0.002411 0.003203 0.003167 + 8.812 0.002411 0.003202 0.003167 + 8.813 0.002410 0.003201 0.003166 + 8.814 0.002410 0.003201 0.003166 + 8.815 0.002409 0.003200 0.003165 + 8.816 0.002409 0.003200 0.003164 + 8.817 0.002408 0.003199 0.003164 + 8.818 0.002408 0.003198 0.003163 + 8.819 0.002407 0.003198 0.003163 + 8.820 0.002407 0.003197 0.003162 + 8.821 0.002407 0.003197 0.003161 + 8.822 0.002406 0.003196 0.003161 + 8.823 0.002406 0.003195 0.003160 + 8.824 0.002405 0.003195 0.003160 + 8.825 0.002405 0.003194 0.003159 + 8.826 0.002404 0.003194 0.003158 + 8.827 0.002404 0.003193 0.003158 + 8.828 0.002403 0.003192 0.003157 + 8.829 0.002403 0.003192 0.003157 + 8.830 0.002402 0.003191 0.003156 + 8.831 0.002402 0.003191 0.003155 + 8.832 0.002402 0.003190 0.003155 + 8.833 0.002401 0.003189 0.003154 + 8.834 0.002401 0.003189 0.003154 + 8.835 0.002400 0.003188 0.003153 + 8.836 0.002400 0.003188 0.003153 + 8.837 0.002399 0.003187 0.003152 + 8.838 0.002399 0.003186 0.003151 + 8.839 0.002398 0.003186 0.003151 + 8.840 0.002398 0.003185 0.003150 + 8.841 0.002397 0.003185 0.003150 + 8.842 0.002397 0.003184 0.003149 + 8.843 0.002397 0.003183 0.003148 + 8.844 0.002396 0.003183 0.003148 + 8.845 0.002396 0.003182 0.003147 + 8.846 0.002395 0.003182 0.003147 + 8.847 0.002395 0.003181 0.003146 + 8.848 0.002394 0.003180 0.003145 + 8.849 0.002394 0.003180 0.003145 + 8.850 0.002393 0.003179 0.003144 + 8.851 0.002393 0.003179 0.003144 + 8.852 0.002392 0.003178 0.003143 + 8.853 0.002392 0.003177 0.003143 + 8.854 0.002392 0.003177 0.003142 + 8.855 0.002391 0.003176 0.003141 + 8.856 0.002391 0.003176 0.003141 + 8.857 0.002390 0.003175 0.003140 + 8.858 0.002390 0.003174 0.003140 + 8.859 0.002389 0.003174 0.003139 + 8.860 0.002389 0.003173 0.003138 + 8.861 0.002388 0.003173 0.003138 + 8.862 0.002388 0.003172 0.003137 + 8.863 0.002388 0.003171 0.003137 + 8.864 0.002387 0.003171 0.003136 + 8.865 0.002387 0.003170 0.003135 + 8.866 0.002386 0.003170 0.003135 + 8.867 0.002386 0.003169 0.003134 + 8.868 0.002385 0.003168 0.003134 + 8.869 0.002385 0.003168 0.003133 + 8.870 0.002384 0.003167 0.003133 + 8.871 0.002384 0.003167 0.003132 + 8.872 0.002384 0.003166 0.003131 + 8.873 0.002383 0.003165 0.003131 + 8.874 0.002383 0.003165 0.003130 + 8.875 0.002382 0.003164 0.003130 + 8.876 0.002382 0.003164 0.003129 + 8.877 0.002381 0.003163 0.003128 + 8.878 0.002381 0.003163 0.003128 + 8.879 0.002380 0.003162 0.003127 + 8.880 0.002380 0.003161 0.003127 + 8.881 0.002379 0.003161 0.003126 + 8.882 0.002379 0.003160 0.003126 + 8.883 0.002379 0.003160 0.003125 + 8.884 0.002378 0.003159 0.003124 + 8.885 0.002378 0.003158 0.003124 + 8.886 0.002377 0.003158 0.003123 + 8.887 0.002377 0.003157 0.003123 + 8.888 0.002376 0.003157 0.003122 + 8.889 0.002376 0.003156 0.003121 + 8.890 0.002375 0.003155 0.003121 + 8.891 0.002375 0.003155 0.003120 + 8.892 0.002375 0.003154 0.003120 + 8.893 0.002374 0.003154 0.003119 + 8.894 0.002374 0.003153 0.003119 + 8.895 0.002373 0.003152 0.003118 + 8.896 0.002373 0.003152 0.003117 + 8.897 0.002372 0.003151 0.003117 + 8.898 0.002372 0.003151 0.003116 + 8.899 0.002371 0.003150 0.003116 + 8.900 0.002371 0.003150 0.003115 + 8.901 0.002371 0.003149 0.003115 + 8.902 0.002370 0.003148 0.003114 + 8.903 0.002370 0.003148 0.003113 + 8.904 0.002369 0.003147 0.003113 + 8.905 0.002369 0.003147 0.003112 + 8.906 0.002368 0.003146 0.003112 + 8.907 0.002368 0.003145 0.003111 + 8.908 0.002367 0.003145 0.003110 + 8.909 0.002367 0.003144 0.003110 + 8.910 0.002367 0.003144 0.003109 + 8.911 0.002366 0.003143 0.003109 + 8.912 0.002366 0.003142 0.003108 + 8.913 0.002365 0.003142 0.003108 + 8.914 0.002365 0.003141 0.003107 + 8.915 0.002364 0.003141 0.003106 + 8.916 0.002364 0.003140 0.003106 + 8.917 0.002364 0.003140 0.003105 + 8.918 0.002363 0.003139 0.003105 + 8.919 0.002363 0.003138 0.003104 + 8.920 0.002362 0.003138 0.003104 + 8.921 0.002362 0.003137 0.003103 + 8.922 0.002361 0.003137 0.003102 + 8.923 0.002361 0.003136 0.003102 + 8.924 0.002360 0.003135 0.003101 + 8.925 0.002360 0.003135 0.003101 + 8.926 0.002360 0.003134 0.003100 + 8.927 0.002359 0.003134 0.003100 + 8.928 0.002359 0.003133 0.003099 + 8.929 0.002358 0.003133 0.003098 + 8.930 0.002358 0.003132 0.003098 + 8.931 0.002357 0.003131 0.003097 + 8.932 0.002357 0.003131 0.003097 + 8.933 0.002356 0.003130 0.003096 + 8.934 0.002356 0.003130 0.003096 + 8.935 0.002356 0.003129 0.003095 + 8.936 0.002355 0.003128 0.003094 + 8.937 0.002355 0.003128 0.003094 + 8.938 0.002354 0.003127 0.003093 + 8.939 0.002354 0.003127 0.003093 + 8.940 0.002353 0.003126 0.003092 + 8.941 0.002353 0.003126 0.003092 + 8.942 0.002353 0.003125 0.003091 + 8.943 0.002352 0.003124 0.003090 + 8.944 0.002352 0.003124 0.003090 + 8.945 0.002351 0.003123 0.003089 + 8.946 0.002351 0.003123 0.003089 + 8.947 0.002350 0.003122 0.003088 + 8.948 0.002350 0.003121 0.003088 + 8.949 0.002349 0.003121 0.003087 + 8.950 0.002349 0.003120 0.003086 + 8.951 0.002349 0.003120 0.003086 + 8.952 0.002348 0.003119 0.003085 + 8.953 0.002348 0.003119 0.003085 + 8.954 0.002347 0.003118 0.003084 + 8.955 0.002347 0.003117 0.003084 + 8.956 0.002346 0.003117 0.003083 + 8.957 0.002346 0.003116 0.003082 + 8.958 0.002346 0.003116 0.003082 + 8.959 0.002345 0.003115 0.003081 + 8.960 0.002345 0.003115 0.003081 + 8.961 0.002344 0.003114 0.003080 + 8.962 0.002344 0.003113 0.003080 + 8.963 0.002343 0.003113 0.003079 + 8.964 0.002343 0.003112 0.003078 + 8.965 0.002342 0.003112 0.003078 + 8.966 0.002342 0.003111 0.003077 + 8.967 0.002342 0.003110 0.003077 + 8.968 0.002341 0.003110 0.003076 + 8.969 0.002341 0.003109 0.003076 + 8.970 0.002340 0.003109 0.003075 + 8.971 0.002340 0.003108 0.003074 + 8.972 0.002339 0.003108 0.003074 + 8.973 0.002339 0.003107 0.003073 + 8.974 0.002339 0.003106 0.003073 + 8.975 0.002338 0.003106 0.003072 + 8.976 0.002338 0.003105 0.003072 + 8.977 0.002337 0.003105 0.003071 + 8.978 0.002337 0.003104 0.003070 + 8.979 0.002336 0.003104 0.003070 + 8.980 0.002336 0.003103 0.003069 + 8.981 0.002336 0.003102 0.003069 + 8.982 0.002335 0.003102 0.003068 + 8.983 0.002335 0.003101 0.003068 + 8.984 0.002334 0.003101 0.003067 + 8.985 0.002334 0.003100 0.003067 + 8.986 0.002333 0.003100 0.003066 + 8.987 0.002333 0.003099 0.003065 + 8.988 0.002333 0.003098 0.003065 + 8.989 0.002332 0.003098 0.003064 + 8.990 0.002332 0.003097 0.003064 + 8.991 0.002331 0.003097 0.003063 + 8.992 0.002331 0.003096 0.003063 + 8.993 0.002330 0.003096 0.003062 + 8.994 0.002330 0.003095 0.003061 + 8.995 0.002329 0.003094 0.003061 + 8.996 0.002329 0.003094 0.003060 + 8.997 0.002329 0.003093 0.003060 + 8.998 0.002328 0.003093 0.003059 + 8.999 0.002328 0.003092 0.003059 + 9.000 0.002327 0.003092 0.003058 + 9.001 0.002327 0.003091 0.003058 + 9.002 0.002326 0.003090 0.003057 + 9.003 0.002326 0.003090 0.003056 + 9.004 0.002326 0.003089 0.003056 + 9.005 0.002325 0.003089 0.003055 + 9.006 0.002325 0.003088 0.003055 + 9.007 0.002324 0.003088 0.003054 + 9.008 0.002324 0.003087 0.003054 + 9.009 0.002323 0.003086 0.003053 + 9.010 0.002323 0.003086 0.003052 + 9.011 0.002323 0.003085 0.003052 + 9.012 0.002322 0.003085 0.003051 + 9.013 0.002322 0.003084 0.003051 + 9.014 0.002321 0.003084 0.003050 + 9.015 0.002321 0.003083 0.003050 + 9.016 0.002320 0.003082 0.003049 + 9.017 0.002320 0.003082 0.003049 + 9.018 0.002320 0.003081 0.003048 + 9.019 0.002319 0.003081 0.003047 + 9.020 0.002319 0.003080 0.003047 + 9.021 0.002318 0.003080 0.003046 + 9.022 0.002318 0.003079 0.003046 + 9.023 0.002317 0.003078 0.003045 + 9.024 0.002317 0.003078 0.003045 + 9.025 0.002317 0.003077 0.003044 + 9.026 0.002316 0.003077 0.003044 + 9.027 0.002316 0.003076 0.003043 + 9.028 0.002315 0.003076 0.003042 + 9.029 0.002315 0.003075 0.003042 + 9.030 0.002314 0.003074 0.003041 + 9.031 0.002314 0.003074 0.003041 + 9.032 0.002314 0.003073 0.003040 + 9.033 0.002313 0.003073 0.003040 + 9.034 0.002313 0.003072 0.003039 + 9.035 0.002312 0.003072 0.003039 + 9.036 0.002312 0.003071 0.003038 + 9.037 0.002311 0.003071 0.003037 + 9.038 0.002311 0.003070 0.003037 + 9.039 0.002311 0.003069 0.003036 + 9.040 0.002310 0.003069 0.003036 + 9.041 0.002310 0.003068 0.003035 + 9.042 0.002309 0.003068 0.003035 + 9.043 0.002309 0.003067 0.003034 + 9.044 0.002308 0.003067 0.003034 + 9.045 0.002308 0.003066 0.003033 + 9.046 0.002308 0.003065 0.003032 + 9.047 0.002307 0.003065 0.003032 + 9.048 0.002307 0.003064 0.003031 + 9.049 0.002306 0.003064 0.003031 + 9.050 0.002306 0.003063 0.003030 + 9.051 0.002306 0.003063 0.003030 + 9.052 0.002305 0.003062 0.003029 + 9.053 0.002305 0.003061 0.003029 + 9.054 0.002304 0.003061 0.003028 + 9.055 0.002304 0.003060 0.003027 + 9.056 0.002303 0.003060 0.003027 + 9.057 0.002303 0.003059 0.003026 + 9.058 0.002303 0.003059 0.003026 + 9.059 0.002302 0.003058 0.003025 + 9.060 0.002302 0.003058 0.003025 + 9.061 0.002301 0.003057 0.003024 + 9.062 0.002301 0.003056 0.003024 + 9.063 0.002300 0.003056 0.003023 + 9.064 0.002300 0.003055 0.003022 + 9.065 0.002300 0.003055 0.003022 + 9.066 0.002299 0.003054 0.003021 + 9.067 0.002299 0.003054 0.003021 + 9.068 0.002298 0.003053 0.003020 + 9.069 0.002298 0.003053 0.003020 + 9.070 0.002297 0.003052 0.003019 + 9.071 0.002297 0.003051 0.003019 + 9.072 0.002297 0.003051 0.003018 + 9.073 0.002296 0.003050 0.003018 + 9.074 0.002296 0.003050 0.003017 + 9.075 0.002295 0.003049 0.003016 + 9.076 0.002295 0.003049 0.003016 + 9.077 0.002295 0.003048 0.003015 + 9.078 0.002294 0.003047 0.003015 + 9.079 0.002294 0.003047 0.003014 + 9.080 0.002293 0.003046 0.003014 + 9.081 0.002293 0.003046 0.003013 + 9.082 0.002292 0.003045 0.003013 + 9.083 0.002292 0.003045 0.003012 + 9.084 0.002292 0.003044 0.003011 + 9.085 0.002291 0.003044 0.003011 + 9.086 0.002291 0.003043 0.003010 + 9.087 0.002290 0.003042 0.003010 + 9.088 0.002290 0.003042 0.003009 + 9.089 0.002289 0.003041 0.003009 + 9.090 0.002289 0.003041 0.003008 + 9.091 0.002289 0.003040 0.003008 + 9.092 0.002288 0.003040 0.003007 + 9.093 0.002288 0.003039 0.003007 + 9.094 0.002287 0.003039 0.003006 + 9.095 0.002287 0.003038 0.003005 + 9.096 0.002287 0.003037 0.003005 + 9.097 0.002286 0.003037 0.003004 + 9.098 0.002286 0.003036 0.003004 + 9.099 0.002285 0.003036 0.003003 + 9.100 0.002285 0.003035 0.003003 + 9.101 0.002284 0.003035 0.003002 + 9.102 0.002284 0.003034 0.003002 + 9.103 0.002284 0.003034 0.003001 + 9.104 0.002283 0.003033 0.003001 + 9.105 0.002283 0.003032 0.003000 + 9.106 0.002282 0.003032 0.002999 + 9.107 0.002282 0.003031 0.002999 + 9.108 0.002282 0.003031 0.002998 + 9.109 0.002281 0.003030 0.002998 + 9.110 0.002281 0.003030 0.002997 + 9.111 0.002280 0.003029 0.002997 + 9.112 0.002280 0.003029 0.002996 + 9.113 0.002279 0.003028 0.002996 + 9.114 0.002279 0.003027 0.002995 + 9.115 0.002279 0.003027 0.002995 + 9.116 0.002278 0.003026 0.002994 + 9.117 0.002278 0.003026 0.002993 + 9.118 0.002277 0.003025 0.002993 + 9.119 0.002277 0.003025 0.002992 + 9.120 0.002277 0.003024 0.002992 + 9.121 0.002276 0.003024 0.002991 + 9.122 0.002276 0.003023 0.002991 + 9.123 0.002275 0.003023 0.002990 + 9.124 0.002275 0.003022 0.002990 + 9.125 0.002274 0.003021 0.002989 + 9.126 0.002274 0.003021 0.002989 + 9.127 0.002274 0.003020 0.002988 + 9.128 0.002273 0.003020 0.002988 + 9.129 0.002273 0.003019 0.002987 + 9.130 0.002272 0.003019 0.002986 + 9.131 0.002272 0.003018 0.002986 + 9.132 0.002272 0.003018 0.002985 + 9.133 0.002271 0.003017 0.002985 + 9.134 0.002271 0.003016 0.002984 + 9.135 0.002270 0.003016 0.002984 + 9.136 0.002270 0.003015 0.002983 + 9.137 0.002269 0.003015 0.002983 + 9.138 0.002269 0.003014 0.002982 + 9.139 0.002269 0.003014 0.002982 + 9.140 0.002268 0.003013 0.002981 + 9.141 0.002268 0.003013 0.002980 + 9.142 0.002267 0.003012 0.002980 + 9.143 0.002267 0.003012 0.002979 + 9.144 0.002267 0.003011 0.002979 + 9.145 0.002266 0.003010 0.002978 + 9.146 0.002266 0.003010 0.002978 + 9.147 0.002265 0.003009 0.002977 + 9.148 0.002265 0.003009 0.002977 + 9.149 0.002265 0.003008 0.002976 + 9.150 0.002264 0.003008 0.002976 + 9.151 0.002264 0.003007 0.002975 + 9.152 0.002263 0.003007 0.002975 + 9.153 0.002263 0.003006 0.002974 + 9.154 0.002262 0.003006 0.002973 + 9.155 0.002262 0.003005 0.002973 + 9.156 0.002262 0.003004 0.002972 + 9.157 0.002261 0.003004 0.002972 + 9.158 0.002261 0.003003 0.002971 + 9.159 0.002260 0.003003 0.002971 + 9.160 0.002260 0.003002 0.002970 + 9.161 0.002260 0.003002 0.002970 + 9.162 0.002259 0.003001 0.002969 + 9.163 0.002259 0.003001 0.002969 + 9.164 0.002258 0.003000 0.002968 + 9.165 0.002258 0.003000 0.002968 + 9.166 0.002258 0.002999 0.002967 + 9.167 0.002257 0.002998 0.002967 + 9.168 0.002257 0.002998 0.002966 + 9.169 0.002256 0.002997 0.002965 + 9.170 0.002256 0.002997 0.002965 + 9.171 0.002255 0.002996 0.002964 + 9.172 0.002255 0.002996 0.002964 + 9.173 0.002255 0.002995 0.002963 + 9.174 0.002254 0.002995 0.002963 + 9.175 0.002254 0.002994 0.002962 + 9.176 0.002253 0.002994 0.002962 + 9.177 0.002253 0.002993 0.002961 + 9.178 0.002253 0.002992 0.002961 + 9.179 0.002252 0.002992 0.002960 + 9.180 0.002252 0.002991 0.002960 + 9.181 0.002251 0.002991 0.002959 + 9.182 0.002251 0.002990 0.002959 + 9.183 0.002251 0.002990 0.002958 + 9.184 0.002250 0.002989 0.002957 + 9.185 0.002250 0.002989 0.002957 + 9.186 0.002249 0.002988 0.002956 + 9.187 0.002249 0.002988 0.002956 + 9.188 0.002249 0.002987 0.002955 + 9.189 0.002248 0.002986 0.002955 + 9.190 0.002248 0.002986 0.002954 + 9.191 0.002247 0.002985 0.002954 + 9.192 0.002247 0.002985 0.002953 + 9.193 0.002247 0.002984 0.002953 + 9.194 0.002246 0.002984 0.002952 + 9.195 0.002246 0.002983 0.002952 + 9.196 0.002245 0.002983 0.002951 + 9.197 0.002245 0.002982 0.002951 + 9.198 0.002244 0.002982 0.002950 + 9.199 0.002244 0.002981 0.002949 + 9.200 0.002244 0.002981 0.002949 + 9.201 0.002243 0.002980 0.002948 + 9.202 0.002243 0.002979 0.002948 + 9.203 0.002242 0.002979 0.002947 + 9.204 0.002242 0.002978 0.002947 + 9.205 0.002242 0.002978 0.002946 + 9.206 0.002241 0.002977 0.002946 + 9.207 0.002241 0.002977 0.002945 + 9.208 0.002240 0.002976 0.002945 + 9.209 0.002240 0.002976 0.002944 + 9.210 0.002240 0.002975 0.002944 + 9.211 0.002239 0.002975 0.002943 + 9.212 0.002239 0.002974 0.002943 + 9.213 0.002238 0.002974 0.002942 + 9.214 0.002238 0.002973 0.002942 + 9.215 0.002238 0.002972 0.002941 + 9.216 0.002237 0.002972 0.002940 + 9.217 0.002237 0.002971 0.002940 + 9.218 0.002236 0.002971 0.002939 + 9.219 0.002236 0.002970 0.002939 + 9.220 0.002236 0.002970 0.002938 + 9.221 0.002235 0.002969 0.002938 + 9.222 0.002235 0.002969 0.002937 + 9.223 0.002234 0.002968 0.002937 + 9.224 0.002234 0.002968 0.002936 + 9.225 0.002234 0.002967 0.002936 + 9.226 0.002233 0.002967 0.002935 + 9.227 0.002233 0.002966 0.002935 + 9.228 0.002232 0.002966 0.002934 + 9.229 0.002232 0.002965 0.002934 + 9.230 0.002232 0.002964 0.002933 + 9.231 0.002231 0.002964 0.002933 + 9.232 0.002231 0.002963 0.002932 + 9.233 0.002230 0.002963 0.002932 + 9.234 0.002230 0.002962 0.002931 + 9.235 0.002230 0.002962 0.002930 + 9.236 0.002229 0.002961 0.002930 + 9.237 0.002229 0.002961 0.002929 + 9.238 0.002228 0.002960 0.002929 + 9.239 0.002228 0.002960 0.002928 + 9.240 0.002228 0.002959 0.002928 + 9.241 0.002227 0.002959 0.002927 + 9.242 0.002227 0.002958 0.002927 + 9.243 0.002226 0.002958 0.002926 + 9.244 0.002226 0.002957 0.002926 + 9.245 0.002226 0.002956 0.002925 + 9.246 0.002225 0.002956 0.002925 + 9.247 0.002225 0.002955 0.002924 + 9.248 0.002224 0.002955 0.002924 + 9.249 0.002224 0.002954 0.002923 + 9.250 0.002224 0.002954 0.002923 + 9.251 0.002223 0.002953 0.002922 + 9.252 0.002223 0.002953 0.002922 + 9.253 0.002222 0.002952 0.002921 + 9.254 0.002222 0.002952 0.002921 + 9.255 0.002222 0.002951 0.002920 + 9.256 0.002221 0.002951 0.002920 + 9.257 0.002221 0.002950 0.002919 + 9.258 0.002220 0.002950 0.002918 + 9.259 0.002220 0.002949 0.002918 + 9.260 0.002220 0.002948 0.002917 + 9.261 0.002219 0.002948 0.002917 + 9.262 0.002219 0.002947 0.002916 + 9.263 0.002218 0.002947 0.002916 + 9.264 0.002218 0.002946 0.002915 + 9.265 0.002218 0.002946 0.002915 + 9.266 0.002217 0.002945 0.002914 + 9.267 0.002217 0.002945 0.002914 + 9.268 0.002216 0.002944 0.002913 + 9.269 0.002216 0.002944 0.002913 + 9.270 0.002216 0.002943 0.002912 + 9.271 0.002215 0.002943 0.002912 + 9.272 0.002215 0.002942 0.002911 + 9.273 0.002214 0.002942 0.002911 + 9.274 0.002214 0.002941 0.002910 + 9.275 0.002214 0.002941 0.002910 + 9.276 0.002213 0.002940 0.002909 + 9.277 0.002213 0.002940 0.002909 + 9.278 0.002212 0.002939 0.002908 + 9.279 0.002212 0.002938 0.002908 + 9.280 0.002212 0.002938 0.002907 + 9.281 0.002211 0.002937 0.002907 + 9.282 0.002211 0.002937 0.002906 + 9.283 0.002210 0.002936 0.002905 + 9.284 0.002210 0.002936 0.002905 + 9.285 0.002210 0.002935 0.002904 + 9.286 0.002209 0.002935 0.002904 + 9.287 0.002209 0.002934 0.002903 + 9.288 0.002208 0.002934 0.002903 + 9.289 0.002208 0.002933 0.002902 + 9.290 0.002208 0.002933 0.002902 + 9.291 0.002207 0.002932 0.002901 + 9.292 0.002207 0.002932 0.002901 + 9.293 0.002206 0.002931 0.002900 + 9.294 0.002206 0.002931 0.002900 + 9.295 0.002206 0.002930 0.002899 + 9.296 0.002205 0.002930 0.002899 + 9.297 0.002205 0.002929 0.002898 + 9.298 0.002204 0.002928 0.002898 + 9.299 0.002204 0.002928 0.002897 + 9.300 0.002204 0.002927 0.002897 + 9.301 0.002203 0.002927 0.002896 + 9.302 0.002203 0.002926 0.002896 + 9.303 0.002202 0.002926 0.002895 + 9.304 0.002202 0.002925 0.002895 + 9.305 0.002202 0.002925 0.002894 + 9.306 0.002201 0.002924 0.002894 + 9.307 0.002201 0.002924 0.002893 + 9.308 0.002200 0.002923 0.002893 + 9.309 0.002200 0.002923 0.002892 + 9.310 0.002200 0.002922 0.002892 + 9.311 0.002199 0.002922 0.002891 + 9.312 0.002199 0.002921 0.002891 + 9.313 0.002199 0.002921 0.002890 + 9.314 0.002198 0.002920 0.002889 + 9.315 0.002198 0.002920 0.002889 + 9.316 0.002197 0.002919 0.002888 + 9.317 0.002197 0.002919 0.002888 + 9.318 0.002197 0.002918 0.002887 + 9.319 0.002196 0.002918 0.002887 + 9.320 0.002196 0.002917 0.002886 + 9.321 0.002195 0.002916 0.002886 + 9.322 0.002195 0.002916 0.002885 + 9.323 0.002195 0.002915 0.002885 + 9.324 0.002194 0.002915 0.002884 + 9.325 0.002194 0.002914 0.002884 + 9.326 0.002193 0.002914 0.002883 + 9.327 0.002193 0.002913 0.002883 + 9.328 0.002193 0.002913 0.002882 + 9.329 0.002192 0.002912 0.002882 + 9.330 0.002192 0.002912 0.002881 + 9.331 0.002191 0.002911 0.002881 + 9.332 0.002191 0.002911 0.002880 + 9.333 0.002191 0.002910 0.002880 + 9.334 0.002190 0.002910 0.002879 + 9.335 0.002190 0.002909 0.002879 + 9.336 0.002189 0.002909 0.002878 + 9.337 0.002189 0.002908 0.002878 + 9.338 0.002189 0.002908 0.002877 + 9.339 0.002188 0.002907 0.002877 + 9.340 0.002188 0.002907 0.002876 + 9.341 0.002188 0.002906 0.002876 + 9.342 0.002187 0.002906 0.002875 + 9.343 0.002187 0.002905 0.002875 + 9.344 0.002186 0.002905 0.002874 + 9.345 0.002186 0.002904 0.002874 + 9.346 0.002186 0.002903 0.002873 + 9.347 0.002185 0.002903 0.002873 + 9.348 0.002185 0.002902 0.002872 + 9.349 0.002184 0.002902 0.002872 + 9.350 0.002184 0.002901 0.002871 + 9.351 0.002184 0.002901 0.002871 + 9.352 0.002183 0.002900 0.002870 + 9.353 0.002183 0.002900 0.002870 + 9.354 0.002182 0.002899 0.002869 + 9.355 0.002182 0.002899 0.002869 + 9.356 0.002182 0.002898 0.002868 + 9.357 0.002181 0.002898 0.002868 + 9.358 0.002181 0.002897 0.002867 + 9.359 0.002181 0.002897 0.002867 + 9.360 0.002180 0.002896 0.002866 + 9.361 0.002180 0.002896 0.002866 + 9.362 0.002179 0.002895 0.002865 + 9.363 0.002179 0.002895 0.002865 + 9.364 0.002179 0.002894 0.002864 + 9.365 0.002178 0.002894 0.002864 + 9.366 0.002178 0.002893 0.002863 + 9.367 0.002177 0.002893 0.002863 + 9.368 0.002177 0.002892 0.002862 + 9.369 0.002177 0.002892 0.002861 + 9.370 0.002176 0.002891 0.002861 + 9.371 0.002176 0.002891 0.002860 + 9.372 0.002176 0.002890 0.002860 + 9.373 0.002175 0.002890 0.002859 + 9.374 0.002175 0.002889 0.002859 + 9.375 0.002174 0.002889 0.002858 + 9.376 0.002174 0.002888 0.002858 + 9.377 0.002174 0.002888 0.002857 + 9.378 0.002173 0.002887 0.002857 + 9.379 0.002173 0.002887 0.002856 + 9.380 0.002172 0.002886 0.002856 + 9.381 0.002172 0.002885 0.002855 + 9.382 0.002172 0.002885 0.002855 + 9.383 0.002171 0.002884 0.002854 + 9.384 0.002171 0.002884 0.002854 + 9.385 0.002170 0.002883 0.002853 + 9.386 0.002170 0.002883 0.002853 + 9.387 0.002170 0.002882 0.002852 + 9.388 0.002169 0.002882 0.002852 + 9.389 0.002169 0.002881 0.002851 + 9.390 0.002169 0.002881 0.002851 + 9.391 0.002168 0.002880 0.002850 + 9.392 0.002168 0.002880 0.002850 + 9.393 0.002167 0.002879 0.002849 + 9.394 0.002167 0.002879 0.002849 + 9.395 0.002167 0.002878 0.002848 + 9.396 0.002166 0.002878 0.002848 + 9.397 0.002166 0.002877 0.002847 + 9.398 0.002165 0.002877 0.002847 + 9.399 0.002165 0.002876 0.002846 + 9.400 0.002165 0.002876 0.002846 + 9.401 0.002164 0.002875 0.002845 + 9.402 0.002164 0.002875 0.002845 + 9.403 0.002164 0.002874 0.002844 + 9.404 0.002163 0.002874 0.002844 + 9.405 0.002163 0.002873 0.002843 + 9.406 0.002162 0.002873 0.002843 + 9.407 0.002162 0.002872 0.002842 + 9.408 0.002162 0.002872 0.002842 + 9.409 0.002161 0.002871 0.002841 + 9.410 0.002161 0.002871 0.002841 + 9.411 0.002161 0.002870 0.002840 + 9.412 0.002160 0.002870 0.002840 + 9.413 0.002160 0.002869 0.002839 + 9.414 0.002159 0.002869 0.002839 + 9.415 0.002159 0.002868 0.002838 + 9.416 0.002159 0.002868 0.002838 + 9.417 0.002158 0.002867 0.002837 + 9.418 0.002158 0.002867 0.002837 + 9.419 0.002157 0.002866 0.002836 + 9.420 0.002157 0.002866 0.002836 + 9.421 0.002157 0.002865 0.002835 + 9.422 0.002156 0.002865 0.002835 + 9.423 0.002156 0.002864 0.002834 + 9.424 0.002156 0.002864 0.002834 + 9.425 0.002155 0.002863 0.002833 + 9.426 0.002155 0.002863 0.002833 + 9.427 0.002154 0.002862 0.002832 + 9.428 0.002154 0.002862 0.002832 + 9.429 0.002154 0.002861 0.002831 + 9.430 0.002153 0.002861 0.002831 + 9.431 0.002153 0.002860 0.002830 + 9.432 0.002153 0.002860 0.002830 + 9.433 0.002152 0.002859 0.002829 + 9.434 0.002152 0.002859 0.002829 + 9.435 0.002151 0.002858 0.002828 + 9.436 0.002151 0.002858 0.002828 + 9.437 0.002151 0.002857 0.002827 + 9.438 0.002150 0.002857 0.002827 + 9.439 0.002150 0.002856 0.002826 + 9.440 0.002149 0.002856 0.002826 + 9.441 0.002149 0.002855 0.002825 + 9.442 0.002149 0.002855 0.002825 + 9.443 0.002148 0.002854 0.002825 + 9.444 0.002148 0.002854 0.002824 + 9.445 0.002148 0.002853 0.002824 + 9.446 0.002147 0.002853 0.002823 + 9.447 0.002147 0.002852 0.002823 + 9.448 0.002146 0.002852 0.002822 + 9.449 0.002146 0.002851 0.002822 + 9.450 0.002146 0.002851 0.002821 + 9.451 0.002145 0.002850 0.002821 + 9.452 0.002145 0.002850 0.002820 + 9.453 0.002145 0.002849 0.002820 + 9.454 0.002144 0.002849 0.002819 + 9.455 0.002144 0.002848 0.002819 + 9.456 0.002143 0.002848 0.002818 + 9.457 0.002143 0.002847 0.002818 + 9.458 0.002143 0.002847 0.002817 + 9.459 0.002142 0.002846 0.002817 + 9.460 0.002142 0.002846 0.002816 + 9.461 0.002142 0.002845 0.002816 + 9.462 0.002141 0.002845 0.002815 + 9.463 0.002141 0.002844 0.002815 + 9.464 0.002140 0.002844 0.002814 + 9.465 0.002140 0.002843 0.002814 + 9.466 0.002140 0.002843 0.002813 + 9.467 0.002139 0.002842 0.002813 + 9.468 0.002139 0.002842 0.002812 + 9.469 0.002139 0.002841 0.002812 + 9.470 0.002138 0.002841 0.002811 + 9.471 0.002138 0.002840 0.002811 + 9.472 0.002137 0.002840 0.002810 + 9.473 0.002137 0.002839 0.002810 + 9.474 0.002137 0.002839 0.002809 + 9.475 0.002136 0.002838 0.002809 + 9.476 0.002136 0.002838 0.002808 + 9.477 0.002136 0.002837 0.002808 + 9.478 0.002135 0.002837 0.002807 + 9.479 0.002135 0.002836 0.002807 + 9.480 0.002134 0.002836 0.002806 + 9.481 0.002134 0.002835 0.002806 + 9.482 0.002134 0.002835 0.002805 + 9.483 0.002133 0.002834 0.002805 + 9.484 0.002133 0.002834 0.002804 + 9.485 0.002133 0.002833 0.002804 + 9.486 0.002132 0.002833 0.002803 + 9.487 0.002132 0.002832 0.002803 + 9.488 0.002131 0.002832 0.002802 + 9.489 0.002131 0.002831 0.002802 + 9.490 0.002131 0.002831 0.002801 + 9.491 0.002130 0.002830 0.002801 + 9.492 0.002130 0.002830 0.002800 + 9.493 0.002130 0.002829 0.002800 + 9.494 0.002129 0.002829 0.002799 + 9.495 0.002129 0.002828 0.002799 + 9.496 0.002128 0.002828 0.002798 + 9.497 0.002128 0.002827 0.002798 + 9.498 0.002128 0.002827 0.002798 + 9.499 0.002127 0.002826 0.002797 + 9.500 0.002127 0.002826 0.002797 + 9.501 0.002127 0.002825 0.002796 + 9.502 0.002126 0.002825 0.002796 + 9.503 0.002126 0.002824 0.002795 + 9.504 0.002125 0.002824 0.002795 + 9.505 0.002125 0.002823 0.002794 + 9.506 0.002125 0.002823 0.002794 + 9.507 0.002124 0.002822 0.002793 + 9.508 0.002124 0.002822 0.002793 + 9.509 0.002124 0.002821 0.002792 + 9.510 0.002123 0.002821 0.002792 + 9.511 0.002123 0.002820 0.002791 + 9.512 0.002122 0.002820 0.002791 + 9.513 0.002122 0.002819 0.002790 + 9.514 0.002122 0.002819 0.002790 + 9.515 0.002121 0.002818 0.002789 + 9.516 0.002121 0.002818 0.002789 + 9.517 0.002121 0.002817 0.002788 + 9.518 0.002120 0.002817 0.002788 + 9.519 0.002120 0.002816 0.002787 + 9.520 0.002119 0.002816 0.002787 + 9.521 0.002119 0.002815 0.002786 + 9.522 0.002119 0.002815 0.002786 + 9.523 0.002118 0.002814 0.002785 + 9.524 0.002118 0.002814 0.002785 + 9.525 0.002118 0.002813 0.002784 + 9.526 0.002117 0.002813 0.002784 + 9.527 0.002117 0.002812 0.002783 + 9.528 0.002116 0.002812 0.002783 + 9.529 0.002116 0.002811 0.002782 + 9.530 0.002116 0.002811 0.002782 + 9.531 0.002115 0.002810 0.002781 + 9.532 0.002115 0.002810 0.002781 + 9.533 0.002115 0.002809 0.002781 + 9.534 0.002114 0.002809 0.002780 + 9.535 0.002114 0.002808 0.002780 + 9.536 0.002114 0.002808 0.002779 + 9.537 0.002113 0.002807 0.002779 + 9.538 0.002113 0.002807 0.002778 + 9.539 0.002112 0.002806 0.002778 + 9.540 0.002112 0.002806 0.002777 + 9.541 0.002112 0.002805 0.002777 + 9.542 0.002111 0.002805 0.002776 + 9.543 0.002111 0.002804 0.002776 + 9.544 0.002111 0.002804 0.002775 + 9.545 0.002110 0.002803 0.002775 + 9.546 0.002110 0.002803 0.002774 + 9.547 0.002109 0.002803 0.002774 + 9.548 0.002109 0.002802 0.002773 + 9.549 0.002109 0.002802 0.002773 + 9.550 0.002108 0.002801 0.002772 + 9.551 0.002108 0.002801 0.002772 + 9.552 0.002108 0.002800 0.002771 + 9.553 0.002107 0.002800 0.002771 + 9.554 0.002107 0.002799 0.002770 + 9.555 0.002107 0.002799 0.002770 + 9.556 0.002106 0.002798 0.002769 + 9.557 0.002106 0.002798 0.002769 + 9.558 0.002105 0.002797 0.002769 + 9.559 0.002105 0.002797 0.002768 + 9.560 0.002105 0.002796 0.002768 + 9.561 0.002104 0.002796 0.002767 + 9.562 0.002104 0.002795 0.002767 + 9.563 0.002104 0.002795 0.002766 + 9.564 0.002103 0.002794 0.002766 + 9.565 0.002103 0.002794 0.002765 + 9.566 0.002103 0.002793 0.002765 + 9.567 0.002102 0.002793 0.002764 + 9.568 0.002102 0.002792 0.002764 + 9.569 0.002101 0.002792 0.002763 + 9.570 0.002101 0.002791 0.002763 + 9.571 0.002101 0.002791 0.002762 + 9.572 0.002100 0.002790 0.002762 + 9.573 0.002100 0.002790 0.002761 + 9.574 0.002100 0.002789 0.002761 + 9.575 0.002099 0.002789 0.002760 + 9.576 0.002099 0.002788 0.002760 + 9.577 0.002098 0.002788 0.002759 + 9.578 0.002098 0.002787 0.002759 + 9.579 0.002098 0.002787 0.002758 + 9.580 0.002097 0.002786 0.002758 + 9.581 0.002097 0.002786 0.002758 + 9.582 0.002097 0.002786 0.002757 + 9.583 0.002096 0.002785 0.002757 + 9.584 0.002096 0.002785 0.002756 + 9.585 0.002096 0.002784 0.002756 + 9.586 0.002095 0.002784 0.002755 + 9.587 0.002095 0.002783 0.002755 + 9.588 0.002094 0.002783 0.002754 + 9.589 0.002094 0.002782 0.002754 + 9.590 0.002094 0.002782 0.002753 + 9.591 0.002093 0.002781 0.002753 + 9.592 0.002093 0.002781 0.002752 + 9.593 0.002093 0.002780 0.002752 + 9.594 0.002092 0.002780 0.002751 + 9.595 0.002092 0.002779 0.002751 + 9.596 0.002092 0.002779 0.002750 + 9.597 0.002091 0.002778 0.002750 + 9.598 0.002091 0.002778 0.002749 + 9.599 0.002090 0.002777 0.002749 + 9.600 0.002090 0.002777 0.002749 + 9.601 0.002090 0.002776 0.002748 + 9.602 0.002089 0.002776 0.002748 + 9.603 0.002089 0.002775 0.002747 + 9.604 0.002089 0.002775 0.002747 + 9.605 0.002088 0.002774 0.002746 + 9.606 0.002088 0.002774 0.002746 + 9.607 0.002088 0.002773 0.002745 + 9.608 0.002087 0.002773 0.002745 + 9.609 0.002087 0.002772 0.002744 + 9.610 0.002087 0.002772 0.002744 + 9.611 0.002086 0.002772 0.002743 + 9.612 0.002086 0.002771 0.002743 + 9.613 0.002085 0.002771 0.002742 + 9.614 0.002085 0.002770 0.002742 + 9.615 0.002085 0.002770 0.002741 + 9.616 0.002084 0.002769 0.002741 + 9.617 0.002084 0.002769 0.002740 + 9.618 0.002084 0.002768 0.002740 + 9.619 0.002083 0.002768 0.002740 + 9.620 0.002083 0.002767 0.002739 + 9.621 0.002083 0.002767 0.002739 + 9.622 0.002082 0.002766 0.002738 + 9.623 0.002082 0.002766 0.002738 + 9.624 0.002081 0.002765 0.002737 + 9.625 0.002081 0.002765 0.002737 + 9.626 0.002081 0.002764 0.002736 + 9.627 0.002080 0.002764 0.002736 + 9.628 0.002080 0.002763 0.002735 + 9.629 0.002080 0.002763 0.002735 + 9.630 0.002079 0.002762 0.002734 + 9.631 0.002079 0.002762 0.002734 + 9.632 0.002079 0.002761 0.002733 + 9.633 0.002078 0.002761 0.002733 + 9.634 0.002078 0.002761 0.002732 + 9.635 0.002077 0.002760 0.002732 + 9.636 0.002077 0.002760 0.002732 + 9.637 0.002077 0.002759 0.002731 + 9.638 0.002076 0.002759 0.002731 + 9.639 0.002076 0.002758 0.002730 + 9.640 0.002076 0.002758 0.002730 + 9.641 0.002075 0.002757 0.002729 + 9.642 0.002075 0.002757 0.002729 + 9.643 0.002075 0.002756 0.002728 + 9.644 0.002074 0.002756 0.002728 + 9.645 0.002074 0.002755 0.002727 + 9.646 0.002074 0.002755 0.002727 + 9.647 0.002073 0.002754 0.002726 + 9.648 0.002073 0.002754 0.002726 + 9.649 0.002072 0.002753 0.002725 + 9.650 0.002072 0.002753 0.002725 + 9.651 0.002072 0.002752 0.002725 + 9.652 0.002071 0.002752 0.002724 + 9.653 0.002071 0.002752 0.002724 + 9.654 0.002071 0.002751 0.002723 + 9.655 0.002070 0.002751 0.002723 + 9.656 0.002070 0.002750 0.002722 + 9.657 0.002070 0.002750 0.002722 + 9.658 0.002069 0.002749 0.002721 + 9.659 0.002069 0.002749 0.002721 + 9.660 0.002069 0.002748 0.002720 + 9.661 0.002068 0.002748 0.002720 + 9.662 0.002068 0.002747 0.002719 + 9.663 0.002067 0.002747 0.002719 + 9.664 0.002067 0.002746 0.002718 + 9.665 0.002067 0.002746 0.002718 + 9.666 0.002066 0.002745 0.002718 + 9.667 0.002066 0.002745 0.002717 + 9.668 0.002066 0.002744 0.002717 + 9.669 0.002065 0.002744 0.002716 + 9.670 0.002065 0.002743 0.002716 + 9.671 0.002065 0.002743 0.002715 + 9.672 0.002064 0.002743 0.002715 + 9.673 0.002064 0.002742 0.002714 + 9.674 0.002064 0.002742 0.002714 + 9.675 0.002063 0.002741 0.002713 + 9.676 0.002063 0.002741 0.002713 + 9.677 0.002062 0.002740 0.002712 + 9.678 0.002062 0.002740 0.002712 + 9.679 0.002062 0.002739 0.002711 + 9.680 0.002061 0.002739 0.002711 + 9.681 0.002061 0.002738 0.002711 + 9.682 0.002061 0.002738 0.002710 + 9.683 0.002060 0.002737 0.002710 + 9.684 0.002060 0.002737 0.002709 + 9.685 0.002060 0.002736 0.002709 + 9.686 0.002059 0.002736 0.002708 + 9.687 0.002059 0.002735 0.002708 + 9.688 0.002059 0.002735 0.002707 + 9.689 0.002058 0.002735 0.002707 + 9.690 0.002058 0.002734 0.002706 + 9.691 0.002058 0.002734 0.002706 + 9.692 0.002057 0.002733 0.002705 + 9.693 0.002057 0.002733 0.002705 + 9.694 0.002056 0.002732 0.002705 + 9.695 0.002056 0.002732 0.002704 + 9.696 0.002056 0.002731 0.002704 + 9.697 0.002055 0.002731 0.002703 + 9.698 0.002055 0.002730 0.002703 + 9.699 0.002055 0.002730 0.002702 + 9.700 0.002054 0.002729 0.002702 + 9.701 0.002054 0.002729 0.002701 + 9.702 0.002054 0.002728 0.002701 + 9.703 0.002053 0.002728 0.002700 + 9.704 0.002053 0.002727 0.002700 + 9.705 0.002053 0.002727 0.002699 + 9.706 0.002052 0.002727 0.002699 + 9.707 0.002052 0.002726 0.002699 + 9.708 0.002052 0.002726 0.002698 + 9.709 0.002051 0.002725 0.002698 + 9.710 0.002051 0.002725 0.002697 + 9.711 0.002050 0.002724 0.002697 + 9.712 0.002050 0.002724 0.002696 + 9.713 0.002050 0.002723 0.002696 + 9.714 0.002049 0.002723 0.002695 + 9.715 0.002049 0.002722 0.002695 + 9.716 0.002049 0.002722 0.002694 + 9.717 0.002048 0.002721 0.002694 + 9.718 0.002048 0.002721 0.002694 + 9.719 0.002048 0.002720 0.002693 + 9.720 0.002047 0.002720 0.002693 + 9.721 0.002047 0.002720 0.002692 + 9.722 0.002047 0.002719 0.002692 + 9.723 0.002046 0.002719 0.002691 + 9.724 0.002046 0.002718 0.002691 + 9.725 0.002046 0.002718 0.002690 + 9.726 0.002045 0.002717 0.002690 + 9.727 0.002045 0.002717 0.002689 + 9.728 0.002045 0.002716 0.002689 + 9.729 0.002044 0.002716 0.002688 + 9.730 0.002044 0.002715 0.002688 + 9.731 0.002043 0.002715 0.002688 + 9.732 0.002043 0.002714 0.002687 + 9.733 0.002043 0.002714 0.002687 + 9.734 0.002042 0.002714 0.002686 + 9.735 0.002042 0.002713 0.002686 + 9.736 0.002042 0.002713 0.002685 + 9.737 0.002041 0.002712 0.002685 + 9.738 0.002041 0.002712 0.002684 + 9.739 0.002041 0.002711 0.002684 + 9.740 0.002040 0.002711 0.002683 + 9.741 0.002040 0.002710 0.002683 + 9.742 0.002040 0.002710 0.002683 + 9.743 0.002039 0.002709 0.002682 + 9.744 0.002039 0.002709 0.002682 + 9.745 0.002039 0.002708 0.002681 + 9.746 0.002038 0.002708 0.002681 + 9.747 0.002038 0.002707 0.002680 + 9.748 0.002038 0.002707 0.002680 + 9.749 0.002037 0.002707 0.002679 + 9.750 0.002037 0.002706 0.002679 + 9.751 0.002036 0.002706 0.002678 + 9.752 0.002036 0.002705 0.002678 + 9.753 0.002036 0.002705 0.002678 + 9.754 0.002035 0.002704 0.002677 + 9.755 0.002035 0.002704 0.002677 + 9.756 0.002035 0.002703 0.002676 + 9.757 0.002034 0.002703 0.002676 + 9.758 0.002034 0.002702 0.002675 + 9.759 0.002034 0.002702 0.002675 + 9.760 0.002033 0.002702 0.002674 + 9.761 0.002033 0.002701 0.002674 + 9.762 0.002033 0.002701 0.002673 + 9.763 0.002032 0.002700 0.002673 + 9.764 0.002032 0.002700 0.002673 + 9.765 0.002032 0.002699 0.002672 + 9.766 0.002031 0.002699 0.002672 + 9.767 0.002031 0.002698 0.002671 + 9.768 0.002031 0.002698 0.002671 + 9.769 0.002030 0.002697 0.002670 + 9.770 0.002030 0.002697 0.002670 + 9.771 0.002030 0.002696 0.002669 + 9.772 0.002029 0.002696 0.002669 + 9.773 0.002029 0.002696 0.002668 + 9.774 0.002029 0.002695 0.002668 + 9.775 0.002028 0.002695 0.002668 + 9.776 0.002028 0.002694 0.002667 + 9.777 0.002027 0.002694 0.002667 + 9.778 0.002027 0.002693 0.002666 + 9.779 0.002027 0.002693 0.002666 + 9.780 0.002026 0.002692 0.002665 + 9.781 0.002026 0.002692 0.002665 + 9.782 0.002026 0.002691 0.002664 + 9.783 0.002025 0.002691 0.002664 + 9.784 0.002025 0.002690 0.002664 + 9.785 0.002025 0.002690 0.002663 + 9.786 0.002024 0.002690 0.002663 + 9.787 0.002024 0.002689 0.002662 + 9.788 0.002024 0.002689 0.002662 + 9.789 0.002023 0.002688 0.002661 + 9.790 0.002023 0.002688 0.002661 + 9.791 0.002023 0.002687 0.002660 + 9.792 0.002022 0.002687 0.002660 + 9.793 0.002022 0.002686 0.002659 + 9.794 0.002022 0.002686 0.002659 + 9.795 0.002021 0.002685 0.002659 + 9.796 0.002021 0.002685 0.002658 + 9.797 0.002021 0.002685 0.002658 + 9.798 0.002020 0.002684 0.002657 + 9.799 0.002020 0.002684 0.002657 + 9.800 0.002020 0.002683 0.002656 + 9.801 0.002019 0.002683 0.002656 + 9.802 0.002019 0.002682 0.002655 + 9.803 0.002019 0.002682 0.002655 + 9.804 0.002018 0.002681 0.002655 + 9.805 0.002018 0.002681 0.002654 + 9.806 0.002018 0.002680 0.002654 + 9.807 0.002017 0.002680 0.002653 + 9.808 0.002017 0.002680 0.002653 + 9.809 0.002016 0.002679 0.002652 + 9.810 0.002016 0.002679 0.002652 + 9.811 0.002016 0.002678 0.002651 + 9.812 0.002015 0.002678 0.002651 + 9.813 0.002015 0.002677 0.002651 + 9.814 0.002015 0.002677 0.002650 + 9.815 0.002014 0.002676 0.002650 + 9.816 0.002014 0.002676 0.002649 + 9.817 0.002014 0.002675 0.002649 + 9.818 0.002013 0.002675 0.002648 + 9.819 0.002013 0.002675 0.002648 + 9.820 0.002013 0.002674 0.002647 + 9.821 0.002012 0.002674 0.002647 + 9.822 0.002012 0.002673 0.002646 + 9.823 0.002012 0.002673 0.002646 + 9.824 0.002011 0.002672 0.002646 + 9.825 0.002011 0.002672 0.002645 + 9.826 0.002011 0.002671 0.002645 + 9.827 0.002010 0.002671 0.002644 + 9.828 0.002010 0.002670 0.002644 + 9.829 0.002010 0.002670 0.002643 + 9.830 0.002009 0.002670 0.002643 + 9.831 0.002009 0.002669 0.002642 + 9.832 0.002009 0.002669 0.002642 + 9.833 0.002008 0.002668 0.002642 + 9.834 0.002008 0.002668 0.002641 + 9.835 0.002008 0.002667 0.002641 + 9.836 0.002007 0.002667 0.002640 + 9.837 0.002007 0.002666 0.002640 + 9.838 0.002007 0.002666 0.002639 + 9.839 0.002006 0.002666 0.002639 + 9.840 0.002006 0.002665 0.002638 + 9.841 0.002006 0.002665 0.002638 + 9.842 0.002005 0.002664 0.002638 + 9.843 0.002005 0.002664 0.002637 + 9.844 0.002005 0.002663 0.002637 + 9.845 0.002004 0.002663 0.002636 + 9.846 0.002004 0.002662 0.002636 + 9.847 0.002004 0.002662 0.002635 + 9.848 0.002003 0.002661 0.002635 + 9.849 0.002003 0.002661 0.002635 + 9.850 0.002003 0.002661 0.002634 + 9.851 0.002002 0.002660 0.002634 + 9.852 0.002002 0.002660 0.002633 + 9.853 0.002001 0.002659 0.002633 + 9.854 0.002001 0.002659 0.002632 + 9.855 0.002001 0.002658 0.002632 + 9.856 0.002000 0.002658 0.002631 + 9.857 0.002000 0.002657 0.002631 + 9.858 0.002000 0.002657 0.002631 + 9.859 0.001999 0.002657 0.002630 + 9.860 0.001999 0.002656 0.002630 + 9.861 0.001999 0.002656 0.002629 + 9.862 0.001998 0.002655 0.002629 + 9.863 0.001998 0.002655 0.002628 + 9.864 0.001998 0.002654 0.002628 + 9.865 0.001997 0.002654 0.002627 + 9.866 0.001997 0.002653 0.002627 + 9.867 0.001997 0.002653 0.002627 + 9.868 0.001996 0.002652 0.002626 + 9.869 0.001996 0.002652 0.002626 + 9.870 0.001996 0.002652 0.002625 + 9.871 0.001995 0.002651 0.002625 + 9.872 0.001995 0.002651 0.002624 + 9.873 0.001995 0.002650 0.002624 + 9.874 0.001994 0.002650 0.002623 + 9.875 0.001994 0.002649 0.002623 + 9.876 0.001994 0.002649 0.002623 + 9.877 0.001993 0.002648 0.002622 + 9.878 0.001993 0.002648 0.002622 + 9.879 0.001993 0.002648 0.002621 + 9.880 0.001992 0.002647 0.002621 + 9.881 0.001992 0.002647 0.002620 + 9.882 0.001992 0.002646 0.002620 + 9.883 0.001991 0.002646 0.002620 + 9.884 0.001991 0.002645 0.002619 + 9.885 0.001991 0.002645 0.002619 + 9.886 0.001990 0.002644 0.002618 + 9.887 0.001990 0.002644 0.002618 + 9.888 0.001990 0.002644 0.002617 + 9.889 0.001989 0.002643 0.002617 + 9.890 0.001989 0.002643 0.002616 + 9.891 0.001989 0.002642 0.002616 + 9.892 0.001988 0.002642 0.002616 + 9.893 0.001988 0.002641 0.002615 + 9.894 0.001988 0.002641 0.002615 + 9.895 0.001987 0.002640 0.002614 + 9.896 0.001987 0.002640 0.002614 + 9.897 0.001987 0.002640 0.002613 + 9.898 0.001986 0.002639 0.002613 + 9.899 0.001986 0.002639 0.002613 + 9.900 0.001986 0.002638 0.002612 + 9.901 0.001985 0.002638 0.002612 + 9.902 0.001985 0.002637 0.002611 + 9.903 0.001985 0.002637 0.002611 + 9.904 0.001984 0.002636 0.002610 + 9.905 0.001984 0.002636 0.002610 + 9.906 0.001984 0.002636 0.002609 + 9.907 0.001983 0.002635 0.002609 + 9.908 0.001983 0.002635 0.002609 + 9.909 0.001983 0.002634 0.002608 + 9.910 0.001982 0.002634 0.002608 + 9.911 0.001982 0.002633 0.002607 + 9.912 0.001982 0.002633 0.002607 + 9.913 0.001981 0.002632 0.002606 + 9.914 0.001981 0.002632 0.002606 + 9.915 0.001981 0.002632 0.002606 + 9.916 0.001980 0.002631 0.002605 + 9.917 0.001980 0.002631 0.002605 + 9.918 0.001980 0.002630 0.002604 + 9.919 0.001979 0.002630 0.002604 + 9.920 0.001979 0.002629 0.002603 + 9.921 0.001979 0.002629 0.002603 + 9.922 0.001978 0.002629 0.002603 + 9.923 0.001978 0.002628 0.002602 + 9.924 0.001978 0.002628 0.002602 + 9.925 0.001977 0.002627 0.002601 + 9.926 0.001977 0.002627 0.002601 + 9.927 0.001977 0.002626 0.002600 + 9.928 0.001976 0.002626 0.002600 + 9.929 0.001976 0.002625 0.002599 + 9.930 0.001976 0.002625 0.002599 + 9.931 0.001975 0.002625 0.002599 + 9.932 0.001975 0.002624 0.002598 + 9.933 0.001975 0.002624 0.002598 + 9.934 0.001974 0.002623 0.002597 + 9.935 0.001974 0.002623 0.002597 + 9.936 0.001974 0.002622 0.002596 + 9.937 0.001973 0.002622 0.002596 + 9.938 0.001973 0.002621 0.002596 + 9.939 0.001973 0.002621 0.002595 + 9.940 0.001972 0.002621 0.002595 + 9.941 0.001972 0.002620 0.002594 + 9.942 0.001972 0.002620 0.002594 + 9.943 0.001971 0.002619 0.002593 + 9.944 0.001971 0.002619 0.002593 + 9.945 0.001971 0.002618 0.002593 + 9.946 0.001970 0.002618 0.002592 + 9.947 0.001970 0.002618 0.002592 + 9.948 0.001970 0.002617 0.002591 + 9.949 0.001969 0.002617 0.002591 + 9.950 0.001969 0.002616 0.002590 + 9.951 0.001969 0.002616 0.002590 + 9.952 0.001968 0.002615 0.002590 + 9.953 0.001968 0.002615 0.002589 + 9.954 0.001968 0.002614 0.002589 + 9.955 0.001967 0.002614 0.002588 + 9.956 0.001967 0.002614 0.002588 + 9.957 0.001967 0.002613 0.002587 + 9.958 0.001966 0.002613 0.002587 + 9.959 0.001966 0.002612 0.002587 + 9.960 0.001966 0.002612 0.002586 + 9.961 0.001965 0.002611 0.002586 + 9.962 0.001965 0.002611 0.002585 + 9.963 0.001965 0.002611 0.002585 + 9.964 0.001964 0.002610 0.002584 + 9.965 0.001964 0.002610 0.002584 + 9.966 0.001964 0.002609 0.002584 + 9.967 0.001964 0.002609 0.002583 + 9.968 0.001963 0.002608 0.002583 + 9.969 0.001963 0.002608 0.002582 + 9.970 0.001963 0.002607 0.002582 + 9.971 0.001962 0.002607 0.002581 + 9.972 0.001962 0.002607 0.002581 + 9.973 0.001962 0.002606 0.002581 + 9.974 0.001961 0.002606 0.002580 + 9.975 0.001961 0.002605 0.002580 + 9.976 0.001961 0.002605 0.002579 + 9.977 0.001960 0.002604 0.002579 + 9.978 0.001960 0.002604 0.002578 + 9.979 0.001960 0.002604 0.002578 + 9.980 0.001959 0.002603 0.002578 + 9.981 0.001959 0.002603 0.002577 + 9.982 0.001959 0.002602 0.002577 + 9.983 0.001958 0.002602 0.002576 + 9.984 0.001958 0.002601 0.002576 + 9.985 0.001958 0.002601 0.002575 + 9.986 0.001957 0.002601 0.002575 + 9.987 0.001957 0.002600 0.002575 + 9.988 0.001957 0.002600 0.002574 + 9.989 0.001956 0.002599 0.002574 + 9.990 0.001956 0.002599 0.002573 + 9.991 0.001956 0.002598 0.002573 + 9.992 0.001955 0.002598 0.002572 + 9.993 0.001955 0.002598 0.002572 + 9.994 0.001955 0.002597 0.002572 + 9.995 0.001954 0.002597 0.002571 + 9.996 0.001954 0.002596 0.002571 + 9.997 0.001954 0.002596 0.002570 + 9.998 0.001953 0.002595 0.002570 + 9.999 0.001953 0.002595 0.002569 +10.000 0.001953 0.002594 0.002569 diff --git a/docs/source/user/turbsim/examples/TurbSim_User.timeSeriesInput b/docs/source/user/turbsim/examples/TurbSim_User.timeSeriesInput new file mode 100644 index 0000000000..ad7cec199b --- /dev/null +++ b/docs/source/user/turbsim/examples/TurbSim_User.timeSeriesInput @@ -0,0 +1,75 @@ +--------------TurbSim v2.00.* User Time Series Input File----------------------- +Time series input from Y:/wind/windweb/MetData/135mData/M4Twr/20Hz/mat/2014/01/13/01134_16_40_00_013.mat. Using rotated series +-------------------------------------------------------------------------------- + 3 nComp - Number of velocity components in the file (1=u component only; 2=u & v components; 3=u,v,w) [if < 3 other components will be generated using values from input file] + 5 nPoints - Number of time series points contained in this file (-) + 4 RefPtID - Index of the reference point (1-nPoints) +Pointyi Pointzi ! listed in order of increasing height + (m) (m) + 0.00000 15.00000 + 0.00000 30.00000 + 0.00000 50.00000 + 0.00000 76.00000 + 0.00000 102.00000 ! 0.00000 131.00000 +--------Time Series------------------------------------------------------------- + Elapsed Time Point01u_015m Point01v_015m Point01w_015m Point02u_030m Point02v_030m Point02w_030m Point03u_050m Point03v_050m Point03w_050m Point04u_076m Point04v_076m Point04w_076m Point05u_100m Point05v_100m Point05w_100m + (s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) (m/s) + 0.0000 10.0239 -6.5673 0.1700 10.7104 -4.3265 -0.2657 7.5121 -5.5683 0.7229 8.5538 1.8554 2.7886 7.0625 -2.1336 -0.2311 + 0.0500 9.8543 -6.6871 0.2014 10.5539 -4.5656 -0.1635 8.2209 -5.4902 0.7691 8.9743 2.5509 3.3407 7.7085 -2.3617 -0.6188 + 0.1000 9.6866 -6.9837 -0.0274 10.6105 -4.1738 -0.1907 8.3543 -5.4594 0.8359 8.6827 2.7908 3.1656 7.8472 -2.9253 -0.6418 + 0.1500 9.7324 -7.0552 -0.0051 10.6691 -4.4155 -0.0675 8.1870 -5.3004 0.9976 8.4674 2.6578 2.9444 7.7456 -2.1933 -0.0762 + 0.2000 10.6893 -6.8507 -0.9577 10.3897 -4.9771 0.2487 8.0996 -5.2680 1.9644 8.9458 3.0094 1.8673 7.6701 -2.2987 0.2604 + 0.2500 9.9231 -7.3007 0.7656 10.4993 -4.6568 0.1041 7.3927 -5.6227 1.8984 8.9012 2.8845 1.6848 7.3964 -2.1423 0.5068 + 0.3000 10.6087 -7.4602 1.1109 10.6404 -4.6216 0.4016 7.8551 -5.8079 1.7017 7.8978 2.7014 1.8440 7.5993 -2.1448 0.7674 + 0.3500 10.7004 -6.5530 1.5361 10.6060 -5.0307 0.2697 8.0539 -5.2520 1.5816 7.5469 2.3478 2.0364 7.5398 -2.6146 1.1950 + 0.4000 10.6239 -6.5870 0.9715 10.2804 -5.5762 0.2131 9.0905 -5.1252 1.2239 7.1627 2.1428 2.4274 7.6807 -2.6597 1.6527 + 0.4500 10.3173 -6.9557 0.7657 9.7826 -5.9725 0.4581 9.4540 -4.3138 1.3725 7.9526 2.5129 2.2073 7.9318 -2.2922 1.9459 + 0.5000 10.1416 -7.2209 0.7567 10.0303 -4.9716 0.6309 9.8407 -3.7520 0.7614 8.4600 2.4350 0.6511 7.1259 -2.6972 1.2240 + 0.5500 10.5047 -6.7512 0.6150 9.2657 -4.9317 0.3516 10.2811 -3.3267 -0.2976 9.9670 1.6305 1.0282 8.6704 -2.5493 1.6831 + 0.6000 10.7474 -6.2916 1.0679 9.8545 -4.6793 0.9724 9.2865 -3.1312 -0.3782 8.8298 1.9777 2.6725 8.5316 -2.3025 0.8950 + 0.6500 10.0867 -7.4206 0.5036 9.7205 -4.9432 1.1458 9.9069 -2.8483 0.4944 7.9273 2.2319 2.3362 8.2093 -3.3990 0.9988 + 0.7000 9.8459 -7.4542 -1.2710 8.9698 -4.7850 1.0775 9.6954 -2.6462 -0.0771 8.6383 2.1842 2.0920 8.2936 -3.7892 1.0731 + 0.7500 9.6427 -7.2455 -1.4315 9.3917 -4.6785 1.1891 9.1673 -2.7193 0.3366 8.9427 2.3911 1.6469 8.2266 -3.3263 0.7393 + 0.8000 9.5695 -7.7153 -0.7343 9.5739 -4.4328 1.1584 9.0573 -2.6535 0.1908 8.3292 2.2472 2.0362 7.8194 -3.7072 0.5483 + 0.8500 10.2921 -6.9918 -0.9979 9.6578 -4.3620 1.2127 8.9479 -3.1538 0.7260 8.3102 2.6701 1.7449 7.8589 -3.7135 1.0110 + 0.9000 9.8191 -6.6210 0.3998 9.8743 -4.2941 1.0936 9.6018 -2.5313 1.0496 8.2451 2.9574 2.1521 8.2243 -3.4065 0.9394 + 0.9500 10.0563 -6.9999 0.2417 10.3157 -4.2559 1.1260 8.5548 -1.6788 0.2954 9.0907 3.7919 2.0049 7.9246 -3.4823 1.1144 + 1.0000 9.2220 -5.9308 0.8000 9.9854 -4.1755 1.2094 8.5202 -2.2213 0.1535 9.0511 3.9090 2.2632 7.8068 -3.8460 1.2086 + 1.0500 10.0784 -5.5374 2.1954 9.5217 -4.6836 0.8753 7.3394 -3.3442 0.5039 9.6810 2.8990 2.8360 7.9015 -3.3869 0.9430 + 1.1000 9.5813 -5.8415 2.4204 10.2011 -4.7455 0.9099 8.3667 -3.6501 1.0368 9.2322 2.6666 3.0034 8.0554 -4.2803 0.4702 + 1.1500 10.1393 -5.7391 1.2873 9.5294 -5.2682 0.6955 8.8540 -3.1497 1.1417 9.4119 3.0706 2.5219 7.4228 -4.3461 0.8886 + 1.2000 10.3018 -6.1910 0.7048 9.3079 -5.5758 0.5641 8.2826 -3.4260 -0.1190 8.6405 4.2058 1.3511 7.4680 -3.3188 1.0912 + 1.2500 10.4492 -6.5951 1.0127 9.5492 -6.0838 0.6965 9.3215 -3.4758 1.0654 8.4973 4.2717 1.8545 6.9824 -3.1717 1.1065 + 1.3000 9.7664 -7.2437 0.7676 9.8434 -6.0361 1.7628 9.8312 -4.2205 1.2115 10.6266 4.3021 2.0330 6.5258 -3.8663 0.4524 + 1.3500 8.8919 -7.6760 -0.0979 10.1855 -5.7703 2.1307 10.8853 -4.1283 1.0649 10.8756 4.4807 1.9956 6.9195 -3.3237 1.6040 + 1.4000 8.5238 -7.3008 -0.3770 10.8332 -4.6349 1.7131 12.1108 -4.8969 1.1674 10.6947 3.9128 1.6159 8.4642 -2.8396 0.9717 + 1.4500 8.8623 -7.0775 -0.9606 11.0740 -3.6287 1.5952 11.4015 -5.6323 1.0211 10.5890 3.2867 1.8309 9.5736 -0.5216 0.7578 + 1.5000 8.9728 -7.6597 -1.1552 10.7549 -4.2620 1.7992 10.7991 -5.3671 2.0018 9.5452 2.8431 1.5174 10.6925 -0.3945 0.5945 + 1.5500 8.8930 -7.7153 -1.7600 10.7559 -5.3923 1.5490 10.0907 -5.4767 1.8856 10.2371 3.6055 1.6828 10.8529 -0.9786 1.0433 + 1.6000 8.1438 -7.3152 -1.3176 11.2665 -5.4384 1.8053 10.3574 -5.0149 2.0594 9.6361 3.1687 1.3117 10.7002 -0.6667 0.8452 + 1.6500 8.1903 -6.4505 -1.0248 11.5024 -5.7717 2.0776 11.9254 -4.4893 2.8001 9.9311 2.9386 1.3768 10.7060 -0.7470 0.8856 + 1.7000 9.0474 -6.7787 -0.8811 11.3869 -6.0596 1.5911 12.0853 -4.2717 4.3402 9.8545 2.1151 1.6933 10.7079 -0.8640 1.3663 + 1.7500 10.0716 -8.2431 -1.1994 11.3583 -6.2625 1.4395 11.0410 -4.7577 3.0154 9.6239 2.1524 1.4212 10.3019 -0.8535 0.4244 + 1.8000 10.3520 -8.2542 -1.4154 10.8857 -6.4505 1.4755 12.1790 -6.3834 3.3937 10.0146 2.5972 1.2509 9.5056 -0.0165 -0.3471 + 1.8500 10.2673 -8.4203 -0.8290 11.2969 -5.1986 1.5565 11.6385 -6.3633 3.2360 9.8851 2.9320 1.7049 9.8463 0.3261 -1.3010 + 1.9000 9.9709 -8.1295 -0.9342 11.0247 -5.4012 1.7529 9.7081 -6.9237 2.1064 9.9010 2.3647 1.0849 10.2883 -0.1628 -0.7578 + 1.9500 9.5836 -7.5340 -0.4032 11.1866 -6.0114 1.6810 9.7360 -7.2981 0.1954 10.0995 1.7221 1.0449 10.7854 -1.2740 -0.1517 + 2.0000 9.5896 -7.2660 0.5083 11.2579 -6.3094 2.0051 11.3014 -5.7867 0.2450 9.9340 1.9320 1.1467 11.1319 -1.6288 -0.3444 + 2.0500 9.3882 -6.8663 0.8786 11.3524 -6.3428 1.7095 11.2813 -6.4390 -1.7085 9.5712 2.6001 1.2784 11.2306 -1.7141 0.1113 + 2.1000 8.7823 -6.7390 1.5286 10.9909 -6.1085 1.5209 11.4142 -6.7184 -1.8720 9.4923 2.8418 1.5547 11.2806 -1.3214 -0.5971 + 2.1500 8.9461 -6.7526 1.5970 11.3461 -6.2745 1.5290 13.2924 -4.9391 -0.6849 9.5288 3.3245 0.9158 10.8063 -1.1277 -1.2120 + 2.2000 8.9624 -6.6657 1.6980 11.1410 -6.3087 1.6787 13.4706 -5.0622 -0.6158 10.1418 1.8111 0.8268 11.1688 -0.9472 1.1495 + 2.2500 8.8499 -6.0401 2.1428 11.4928 -5.4539 2.2674 12.8181 -4.6727 -1.2197 10.2068 1.6660 1.2006 11.4231 0.4246 1.3627 + 2.3000 9.1016 -5.9852 1.9954 11.3350 -5.4306 2.0391 12.0135 -5.0135 -0.8402 11.1153 1.2957 1.1267 10.9777 0.8571 1.3400 + 2.3500 9.1675 -5.7344 2.0088 11.4377 -5.2459 1.8240 11.4657 -6.7320 0.4036 10.6081 1.8950 0.7705 11.2355 0.5694 1.5834 + +[*** lines skipped ***] + + 599.6000 21.6444 0.7256 -0.5400 20.4558 0.5259 0.9114 19.1770 -0.8751 0.3857 24.4937 -6.3154 -4.5203 21.0207 -4.2703 -2.0237 + 599.6500 22.1481 1.2154 0.0964 20.6350 1.5186 -0.9619 19.2215 -1.6973 -0.6734 25.4836 -6.1009 -4.3497 21.4399 -3.2808 -1.7420 + 599.7000 21.2232 1.4231 0.6101 20.7161 1.5255 -0.1667 19.8549 -2.0380 0.0898 24.9724 -5.9289 -4.3457 20.6534 -3.4699 -2.7933 + 599.7500 21.6185 1.3266 0.5301 20.7629 1.8099 0.4765 19.4575 -1.3570 0.2398 24.8527 -5.4890 -4.7523 20.1542 -3.2187 -2.3682 + 599.8000 20.6428 2.2662 0.6105 20.6605 2.0787 0.8918 19.3609 -1.1687 -1.1169 24.2970 -5.2672 -4.9008 19.5841 -3.2314 -3.0080 + 599.8500 20.0781 2.4219 1.1325 20.0819 2.0141 1.2528 19.7549 -0.9027 0.0447 24.7932 -5.3731 -5.1058 20.8291 -3.4064 -2.4940 + 599.9000 19.9940 1.8457 1.7090 20.2872 2.2371 1.4736 19.2907 0.3054 0.9823 24.2658 -6.3314 -5.0125 21.3521 -3.2908 -1.7865 + 599.9500 20.6705 2.1299 2.4844 20.4711 2.0164 1.8634 19.2943 -1.0680 -0.8599 25.2163 -6.0627 -4.7138 21.4276 -2.9413 -1.3921 diff --git a/docs/source/user/turbsim/index.rst b/docs/source/user/turbsim/index.rst new file mode 100644 index 0000000000..9a54a22ec4 --- /dev/null +++ b/docs/source/user/turbsim/index.rst @@ -0,0 +1,14 @@ +TurbSim Users Guide Placeholder +====================================== + +.. only:: html + + This is a placeholder for the TurbSim documentation that has not yet been converted to readTheDocs. + +.. toctree:: + :maxdepth: 2 + + output.rst + appendix.rst + + diff --git a/docs/source/user/turbsim/output.rst b/docs/source/user/turbsim/output.rst new file mode 100644 index 0000000000..4ec6bf6087 --- /dev/null +++ b/docs/source/user/turbsim/output.rst @@ -0,0 +1,33 @@ +.. _TurbSim_output: + +Output Files +============ + + +HAWC Full-Field Files +--------------------------------------------------- + +When TurbSim is requested to write HAWC-formatted output files (``WrHAWCFF=TRUE``), it will generate four files. ``-u.bin``, +``-v.bin``, and ``-w.bin`` are binary files that contain the full-field turbulence data for the 3 wind-speed components. +``.HAWC`` is a text summary file that indicates the number of points in the binary files and how they should be scaled. The data +in this file is written in a format that can be copied into a HAWC2 input file. + + +Notes: + +1. The ``factor_scaling`` values in the summary file indicate the inverse of the values TurbSim used to scale the data in the HAWC files. + ``factor_scaling`` can theoretically be used in HAWC2 to obtain the original data generated by TurbSim. + TurbSim scales the data so that HAWC2 will obtain the standard-deviation ratios of 1.0 (u/u), 0.8 (v/u), and 0.5 (w/u) as a work-around for + an issue in how HAWC2 scales turbulence files. Please note that these ratios may not work well with non-IEC turbulence models. + +2. HAWC-formatted files are always periodic, so all of the analysis time steps are written. + +3. The u-component wind speed files have the mean *hub-height* wind speed removed, so they will contain any shear that was defined. + +4. For HAWC2 simulations, it is recommended that TurbSim be run without shear (``PLExp=0``) and without any mean flow angles (``VFlowAng=0``, + ``HFlowAng=0``). These values can instead be added in the HAWC2 input file or in the InflowWind input file for OpenFAST. + + + + + diff --git a/glue-codes/fast-farm/CMakeLists.txt b/glue-codes/fast-farm/CMakeLists.txt index 40507fc30c..c6ad9ffc75 100644 --- a/glue-codes/fast-farm/CMakeLists.txt +++ b/glue-codes/fast-farm/CMakeLists.txt @@ -44,12 +44,16 @@ set_property(TARGET FAST.Farm PROPERTY LINKER_LANGUAGE Fortran) string(TOUPPER ${CMAKE_Fortran_COMPILER_ID} _compiler_id) string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type) -if (${_compiler_id} STREQUAL "GNU" AND ${_build_type} STREQUAL "RELEASE") +if (${_compiler_id} STREQUAL "GNU" AND NOT ${VARIABLE_TRACKING}) # With variable tracking enabled, the compile step frequently aborts on large modules and - # restarts with this option off. Disabling in Release mode avoids this problem when compiling with - # full optimizations, but leaves it enabled for RelWithDebInfo which adds both -O2 and -g flags. + # restarts with this option off. Disabling avoids this problem when compiling with + # full optimizations. However, variable tracking should be enabled when actively debugging + # for better runtime debugging output. # https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html - set_source_files_properties(src/FAST_Farm_Types.f90 src/FASTWrapper_Types.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") + set_source_files_properties(src/FAST_Farm_Types.f90 src/FASTWrapper_Types.f90 src/FASTWrapper.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") + set_source_files_properties(src/FAST_Farm_IO.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") + set_source_files_properties(src/FAST_Farm_Subs.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") + set_source_files_properties(src/FAST_Farm.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") endif() if (${_compiler_id} MATCHES "^INTEL" AND ${_build_type} STREQUAL "RELEASE" AND NOT WIN32) # Compilation hangs on FAST_Farm_Types.f90 with -O3 on linux (on some hardware) diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 218f2b3017..6bcae36bee 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -2202,9 +2202,18 @@ subroutine FARM_CalcOutput(t, farm, ErrStat, ErrMsg) call Transfer_WD_to_AWAE(farm) + if ( farm%p%UseSC ) then + + !-------------------- + ! 3a. Transfer y_F to u_SC, at n+1 + do nt = 1,farm%p%NumTurbines + + farm%SC%uInputs%toSC( (nt-1)*farm%SC%p%NumCtrl2SC + 1 : nt*farm%SC%p%NumCtrl2SC ) = farm%FWrap(nt)%y%toSC + + end do + !-------------------- ! 2. call SC_CO and transfer y_SC to u_F, at n+1 - if ( farm%p%UseSC ) then call SC_CalcOutput(t, farm%SC%uInputs, farm%SC%p, farm%SC%x, farm%SC%xd, farm%SC%z, & farm%SC%OtherState, farm%SC%y, farm%SC%m, ErrStat2, ErrMsg2 ) @@ -2212,9 +2221,6 @@ subroutine FARM_CalcOutput(t, farm, ErrStat, ErrMsg) farm%FWrap(nt)%u%fromSCglob = farm%SC%y%fromSCglob farm%FWrap(nt)%u%fromSC = farm%SC%y%fromSC( (nt-1)*farm%SC%p%NumSC2Ctrl + 1 : nt*farm%SC%p%NumSC2Ctrl ) - !-------------------- - ! 3a. Transfer y_F to u_SC, at n+1 - farm%SC%uInputs%toSC( (nt-1)*farm%SC%p%NumCtrl2SC + 1 : nt*farm%SC%p%NumCtrl2SC ) = farm%FWrap(nt)%y%toSC end do diff --git a/glue-codes/openfast-cpp/src/OpenFAST.cpp b/glue-codes/openfast-cpp/src/OpenFAST.cpp index 78dc5cbadd..8a415ced2c 100644 --- a/glue-codes/openfast-cpp/src/OpenFAST.cpp +++ b/glue-codes/openfast-cpp/src/OpenFAST.cpp @@ -7,7 +7,7 @@ int fast::OpenFAST::AbortErrLev = ErrID_Fatal; // abort error level; compare with NWTC Library -//Constructor +//Constructor fast::fastInputs::fastInputs(): nTurbinesGlob(0), dryRun(false), @@ -40,8 +40,8 @@ timeZero(false) fast::OpenFAST::~OpenFAST(){ } inline bool fast::OpenFAST::checkFileExists(const std::string& name) { - struct stat buffer; - return (stat (name.c_str(), &buffer) == 0); + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); } void fast::OpenFAST::init() { @@ -93,7 +93,7 @@ void fast::OpenFAST::init() { } break ; - + case fast::init: sc.init(scio, nTurbinesProc); @@ -204,6 +204,10 @@ void fast::OpenFAST::init() { timeZero = true; numVelPtsTwr[iTurb] = cDriver_Output_to_FAST[iTurb].u_Len - numBlades[iTurb]*numVelPtsBlade[iTurb] - 1; + if(numVelPtsTwr[iTurb] == 0) { + numForcePtsTwr[iTurb] = 0; + std::cout << "Aerodyn doesn't want to calculate forces on the tower. All actuator points on the tower are turned off for turbine " << turbineMapProcToGlob[iTurb] << "." << std::endl ; + } int nfpts = get_numForcePtsLoc(iTurb); forceNodeVel[iTurb].resize(nfpts); @@ -217,7 +221,7 @@ void fast::OpenFAST::init() { } int nTimesteps; - + if (nTurbinesProc > 0) { readVelocityData(ntStart); } @@ -240,7 +244,7 @@ void fast::OpenFAST::init() { case fast::simStartType_END: break; - + } } } @@ -276,12 +280,12 @@ void fast::OpenFAST::solution0() { void fast::OpenFAST::step() { /* ****************************** - set inputs from this code and call FAST: + set inputs from this code and call FAST: ********************************* */ for (int iTurb=0; iTurb < nTurbinesProc; iTurb++) { - // set wind speeds at original locations + // set wind speeds at original locations // setOutputsToFAST(cDriver_Input_from_FAST[iTurb], cDriver_Output_to_FAST[iTurb]); // this advances the states, calls CalcOutput, and solves for next inputs. Predictor-corrector loop is imbeded here: @@ -299,7 +303,7 @@ void fast::OpenFAST::step() { } fastcpp_velocity_file.close() ; } - + FAST_OpFM_Step(&iTurb, &ErrStat, ErrMsg); checkError(ErrStat, ErrMsg); @@ -307,18 +311,18 @@ void fast::OpenFAST::step() { // greater than zero if (nacelle_cd[iTurb]>0.) { calc_nacelle_force ( - cDriver_Output_to_FAST[iTurb].u[0], - cDriver_Output_to_FAST[iTurb].v[0], - cDriver_Output_to_FAST[iTurb].w[0], - nacelle_cd[iTurb], - nacelle_area[iTurb], - air_density[iTurb], - cDriver_Input_from_FAST[iTurb].fx[0], - cDriver_Input_from_FAST[iTurb].fy[0], + cDriver_Output_to_FAST[iTurb].u[0], + cDriver_Output_to_FAST[iTurb].v[0], + cDriver_Output_to_FAST[iTurb].w[0], + nacelle_cd[iTurb], + nacelle_area[iTurb], + air_density[iTurb], + cDriver_Input_from_FAST[iTurb].fx[0], + cDriver_Input_from_FAST[iTurb].fy[0], cDriver_Input_from_FAST[iTurb].fz[0] ); } - + if ( isDebug() ) { std::ofstream actuatorForcesFile; actuatorForcesFile.open("actuator_forces.csv") ; @@ -337,14 +341,13 @@ void fast::OpenFAST::step() { // sc.fastSCInputOutput(); } - nt_global = nt_global + 1; if(scStatus) { std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; // sc.advanceTime(); // Advance states, inputs and outputs from 'n' to 'n+1' } - + if ( (((nt_global - ntStart) % nEveryCheckPoint) == 0 ) && (nt_global != ntStart) ) { // Use default FAST naming convention for checkpoint file // . @@ -365,18 +368,17 @@ void fast::OpenFAST::step() { // } } } - } void fast::OpenFAST::stepNoWrite() { /* ****************************** - set inputs from this code and call FAST: + set inputs from this code and call FAST: ********************************* */ for (int iTurb=0; iTurb < nTurbinesProc; iTurb++) { - // set wind speeds at original locations + // set wind speeds at original locations // setOutputsToFAST(cDriver_Input_from_FAST[iTurb], cDriver_Output_to_FAST[iTurb]); // this advances the states, calls CalcOutput, and solves for next inputs. Predictor-corrector loop is imbeded here: @@ -386,25 +388,24 @@ void fast::OpenFAST::stepNoWrite() { } - if(scStatus) { - std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; - // sc.updateStates( nt_global * dtFAST); // Predict state at 'n+1' based on inputs - // sc.calcOutputs_np1( (nt_global+1) * dtFAST); - // sc.fastSCInputOutput(); - } - - nt_global = nt_global + 1; - - if(scStatus) { - std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; - // sc.advanceTime(); // Advance states, inputs and outputs from 'n' to 'n+1' - } - + if(scStatus) { + std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; + // sc.updateStates( nt_global * dtFAST); // Predict state at 'n+1' based on inputs + // sc.calcOutputs_np1( (nt_global+1) * dtFAST); + // sc.fastSCInputOutput(); + } + + nt_global = nt_global + 1; + + if(scStatus) { + std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; + // sc.advanceTime(); // Advance states, inputs and outputs from 'n' to 'n+1' + } } void fast::OpenFAST::calc_nacelle_force(const float & u, const float & v, const float & w, const float & cd, const float & area, const float & rho, float & fx, float & fy, float & fz) { - // Calculate the force on the nacelle (fx,fy,fz) given the - // velocity sampled at the nacelle point (u,v,w), + // Calculate the force on the nacelle (fx,fy,fz) given the + // velocity sampled at the nacelle point (u,v,w), // drag coefficient 'cd' and nacelle area 'area' // The velocity magnitude @@ -412,7 +413,7 @@ void fast::OpenFAST::calc_nacelle_force(const float & u, const float & v, const // Velocity correction based on Martinez-Tossas PhD Thesis 2017 // The correction samples the velocity at the center of the - // Gaussian kernel and scales it to obtain the inflow velocity + // Gaussian kernel and scales it to obtain the inflow velocity float epsilon_d = std::sqrt(2.0 / M_PI * cd * area); float correction = 1. / (1.0 - cd * area / (4.0 * M_PI * epsilon_d * epsilon_d)); @@ -507,7 +508,7 @@ void fast::OpenFAST::getHubShftDir(double* hubShftVec, int iTurbGlob, int nSize) void fast::OpenFAST::getVelNodeCoordinates(double* currentCoords, int iNode, int iTurbGlob, int nSize) { assert(nSize==3); - // Set coordinates at current node of current turbine + // Set coordinates at current node of current turbine int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numVelPtsLoc(iTurbLoc); currentCoords[0] = cDriver_Input_from_FAST[iTurbLoc].pxVel[iNode] + TurbineBasePos[iTurbLoc][0] ; @@ -526,7 +527,7 @@ void fast::OpenFAST::getForceNodeCoordinates(double* currentCoords, int iNode, i void fast::OpenFAST::getForceNodeOrientation(double* currentOrientation, int iNode, int iTurbGlob, int nSize) { assert(nSize==9); - // Set orientation at current node of current turbine + // Set orientation at current node of current turbine int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numForcePtsLoc(iTurbLoc); for(int i=0;i<9;i++) { @@ -547,7 +548,7 @@ void fast::OpenFAST::getRelativeVelForceNode(double* currentVelocity, int iNode, void fast::OpenFAST::getForce(double* currentForce, int iNode, int iTurbGlob, int nSize) { assert(nSize==3); - // Set forces at current node of current turbine + // Set forces at current node of current turbine int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numForcePtsLoc(iTurbLoc); currentForce[0] = -cDriver_Input_from_FAST[iTurbLoc].fx[iNode] ; @@ -556,7 +557,7 @@ void fast::OpenFAST::getForce(double* currentForce, int iNode, int iTurbGlob, in } double fast::OpenFAST::getChord(int iNode, int iTurbGlob) { - // Return blade chord/tower diameter at current node of current turbine + // Return blade chord/tower diameter at current node of current turbine int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numForcePtsLoc(iTurbLoc); return cDriver_Input_from_FAST[iTurbLoc].forceNodesChord[iNode] ; @@ -564,7 +565,7 @@ double fast::OpenFAST::getChord(int iNode, int iTurbGlob) { void fast::OpenFAST::setVelocity(double* currentVelocity, int iNode, int iTurbGlob, int nSize) { assert(nSize==3); - // Set velocity at current node of current turbine - + // Set velocity at current node of current turbine - int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numVelPtsLoc(iTurbLoc); cDriver_Output_to_FAST[iTurbLoc].u[iNode] = currentVelocity[0]; @@ -574,7 +575,7 @@ void fast::OpenFAST::setVelocity(double* currentVelocity, int iNode, int iTurbGl void fast::OpenFAST::setVelocityForceNode(double* currentVelocity, int iNode, int iTurbGlob, int nSize) { assert(nSize==3); - // Set velocity at current node of current turbine - + // Set velocity at current node of current turbine - int iTurbLoc = get_localTurbNo(iTurbGlob); for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numForcePtsLoc(iTurbLoc); @@ -611,9 +612,9 @@ void fast::OpenFAST::interpolateVel_ForceToVelNodes() { for(int j=0; j < nForcePtsBlade; j++) { int iNodeForce = 1 + iBlade * nForcePtsBlade + j ; //The number of actuator force points is always the same for all blades rDistForce[j] = std::sqrt( - (cDriver_Input_from_FAST[iTurb].pxForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pxForce[0])*(cDriver_Input_from_FAST[iTurb].pxForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pxForce[0]) - + (cDriver_Input_from_FAST[iTurb].pyForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pyForce[0])*(cDriver_Input_from_FAST[iTurb].pyForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pyForce[0]) - + (cDriver_Input_from_FAST[iTurb].pzForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pzForce[0])*(cDriver_Input_from_FAST[iTurb].pzForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pzForce[0]) + (cDriver_Input_from_FAST[iTurb].pxForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pxForce[0])*(cDriver_Input_from_FAST[iTurb].pxForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pxForce[0]) + + (cDriver_Input_from_FAST[iTurb].pyForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pyForce[0])*(cDriver_Input_from_FAST[iTurb].pyForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pyForce[0]) + + (cDriver_Input_from_FAST[iTurb].pzForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pzForce[0])*(cDriver_Input_from_FAST[iTurb].pzForce[iNodeForce] - cDriver_Input_from_FAST[iTurb].pzForce[0]) ); } @@ -622,9 +623,9 @@ void fast::OpenFAST::interpolateVel_ForceToVelNodes() { for(int j=0; j < nVelPtsBlade; j++) { int iNodeVel = 1 + iBlade * nVelPtsBlade + j ; //Assumes the same number of velocity (Aerodyn) nodes for all blades double rDistVel = std::sqrt( - (cDriver_Input_from_FAST[iTurb].pxVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pxVel[0])*(cDriver_Input_from_FAST[iTurb].pxVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pxVel[0]) - + (cDriver_Input_from_FAST[iTurb].pyVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pyVel[0])*(cDriver_Input_from_FAST[iTurb].pyVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pyVel[0]) - + (cDriver_Input_from_FAST[iTurb].pzVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pzVel[0])*(cDriver_Input_from_FAST[iTurb].pzVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pzVel[0]) + (cDriver_Input_from_FAST[iTurb].pxVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pxVel[0])*(cDriver_Input_from_FAST[iTurb].pxVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pxVel[0]) + + (cDriver_Input_from_FAST[iTurb].pyVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pyVel[0])*(cDriver_Input_from_FAST[iTurb].pyVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pyVel[0]) + + (cDriver_Input_from_FAST[iTurb].pzVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pzVel[0])*(cDriver_Input_from_FAST[iTurb].pzVel[iNodeVel] - cDriver_Input_from_FAST[iTurb].pzVel[0]) ); //Find nearest two force nodes int jForceLower = 0; @@ -669,7 +670,7 @@ void fast::OpenFAST::interpolateVel_ForceToVelNodes() { while ( (hDistForce[jForceLower+1] < hDistVel) && ( jForceLower < (nForcePtsTower-2)) ) { jForceLower = jForceLower + 1; } - int iNodeForceLower = iNodeBotTowerForce + jForceLower ; + int iNodeForceLower = iNodeBotTowerForce + jForceLower ; double rInterp = (hDistVel - hDistForce[jForceLower])/(hDistForce[jForceLower+1]-hDistForce[jForceLower]); cDriver_Output_to_FAST[iTurb].u[iNodeVel] = forceNodeVel[iTurb][iNodeForceLower][0] + rInterp * (forceNodeVel[iTurb][iNodeForceLower+1][0] - forceNodeVel[iTurb][iNodeForceLower][0] ); cDriver_Output_to_FAST[iTurb].v[iNodeVel] = forceNodeVel[iTurb][iNodeForceLower][1] + rInterp * (forceNodeVel[iTurb][iNodeForceLower+1][1] - forceNodeVel[iTurb][iNodeForceLower][1] ); @@ -685,8 +686,8 @@ void fast::OpenFAST::computeTorqueThrust(int iTurbGlob, std::vector & to std::vector relLoc(3,0.0); std::vector rPerpShft(3); thrust[0] = 0.0; thrust[1] = 0.0; thrust[2] = 0.0; - torque[0] = 0.0; torque[1] = 0.0; torque[2] = 0.0; - + torque[0] = 0.0; torque[1] = 0.0; torque[2] = 0.0; + std::vector hubShftVec(3); getHubShftDir(hubShftVec, iTurbGlob); @@ -699,9 +700,9 @@ void fast::OpenFAST::computeTorqueThrust(int iTurbGlob, std::vector & to thrust[1] = thrust[1] + cDriver_Input_from_FAST[iTurbLoc].fy[iNode] ; thrust[2] = thrust[2] + cDriver_Input_from_FAST[iTurbLoc].fz[iNode] ; - relLoc[0] = cDriver_Input_from_FAST[iTurbLoc].pxForce[iNode] - cDriver_Input_from_FAST[iTurbLoc].pxForce[0] ; + relLoc[0] = cDriver_Input_from_FAST[iTurbLoc].pxForce[iNode] - cDriver_Input_from_FAST[iTurbLoc].pxForce[0]; relLoc[1] = cDriver_Input_from_FAST[iTurbLoc].pyForce[iNode] - cDriver_Input_from_FAST[iTurbLoc].pyForce[0]; - relLoc[2] = cDriver_Input_from_FAST[iTurbLoc].pzForce[iNode] - cDriver_Input_from_FAST[iTurbLoc].pzForce[0]; + relLoc[2] = cDriver_Input_from_FAST[iTurbLoc].pzForce[iNode] - cDriver_Input_from_FAST[iTurbLoc].pzForce[0]; double rDotHubShftVec = relLoc[0]*hubShftVec[0] + relLoc[1]*hubShftVec[1] + relLoc[2]*hubShftVec[2]; for (int j=0; j < 3; j++) rPerpShft[j] = relLoc[j] - rDotHubShftVec * hubShftVec[j]; @@ -714,7 +715,7 @@ void fast::OpenFAST::computeTorqueThrust(int iTurbGlob, std::vector & to } fast::ActuatorNodeType fast::OpenFAST::getVelNodeType(int iTurbGlob, int iNode) { - // Return the type of velocity node for the given node number. The node ordering (from FAST) is + // Return the type of velocity node for the given node number. The node ordering (from FAST) is // Node 0 - Hub node // Blade 1 nodes // Blade 2 nodes @@ -725,17 +726,17 @@ fast::ActuatorNodeType fast::OpenFAST::getVelNodeType(int iTurbGlob, int iNode) for(int j=0; j < iTurbLoc; j++) iNode = iNode - get_numVelPtsLoc(iTurbGlob); if (iNode) { if ( (iNode + 1 - (get_numVelPts(iTurbLoc) - get_numVelPtsTwr(iTurbLoc)) ) > 0 ) { - return TOWER; + return TOWER; } else { return BLADE; } } else { - return HUB; + return HUB; } } fast::ActuatorNodeType fast::OpenFAST::getForceNodeType(int iTurbGlob, int iNode) { - // Return the type of actuator force node for the given node number. The node ordering (from FAST) is + // Return the type of actuator force node for the given node number. The node ordering (from FAST) is // Node 0 - Hub node // Blade 1 nodes // Blade 2 nodes @@ -811,7 +812,7 @@ void fast::OpenFAST::allocateMemory() { numVelPtsBlade.resize(nTurbinesProc); numVelPtsTwr.resize(nTurbinesProc); forceNodeVel.resize(nTurbinesProc); - + for (int iTurb=0; iTurb < nTurbinesProc; iTurb++) { TurbineBasePos[iTurb].resize(3); @@ -832,7 +833,7 @@ void fast::OpenFAST::allocateMemory() { // Allocate memory for Turbine datastructure for all turbines FAST_AllocateTurbines(&nTurbinesProc, &ErrStat, ErrMsg); - + // Allocate memory for OpFM Input types in FAST cDriver_Input_from_FAST.resize(nTurbinesProc) ; cDriver_Output_to_FAST.resize(nTurbinesProc) ; @@ -851,7 +852,6 @@ void fast::OpenFAST::allocateTurbinesToProcsSimple() { } void fast::OpenFAST::end() { - // Deallocate types we allocated earlier if (nTurbinesProc > 0) closeVelocityDataFile(nt_global, velNodeDataFile); @@ -888,7 +888,7 @@ void fast::OpenFAST::readVelocityData(int nTimesteps) { H5Aclose(attr); } - // Allocate memory and read the velocity data. + // Allocate memory and read the velocity data. velNodeData.resize(nTurbines); for (int iTurb=0; iTurb < nTurbines; iTurb++) { int nVelPts = get_numVelPtsLoc(iTurb) ; @@ -898,7 +898,7 @@ void fast::OpenFAST::readVelocityData(int nTimesteps) { hsize_t start[3]; start[1] = 0; start[2] = 0; hsize_t count[3]; count[0] = 1; count[1] = nVelPts; count[2] = 6; - hid_t mspace_id = H5Screate_simple(3, count, NULL); + hid_t mspace_id = H5Screate_simple(3, count, NULL); for (int iStep=0; iStep < nTimesteps; iStep++) { start[0] = iStep; @@ -945,7 +945,7 @@ hid_t fast::OpenFAST::openVelocityDataFile(bool createFile) { H5Pset_chunk(dcpl_id, 3, chunk_dims); hid_t dataSpace = H5Screate_simple(3, dims, NULL); - hid_t dataSet = H5Dcreate(velDataFile, ("/turbine" + std::to_string(iTurb)).c_str(), H5T_NATIVE_DOUBLE, dataSpace, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + hid_t dataSet = H5Dcreate(velDataFile, ("/turbine" + std::to_string(iTurb)).c_str(), H5T_NATIVE_DOUBLE, dataSpace, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); herr_t status = H5Pclose(dcpl_id); status = H5Dclose(dataSet); @@ -969,7 +969,7 @@ herr_t fast::OpenFAST::closeVelocityDataFile(int nt_global, hid_t velDataFile) { void fast::OpenFAST::backupVelocityDataFile(int curTimeStep, hid_t & velDataFile) { closeVelocityDataFile(curTimeStep, velDataFile); - + std::ifstream source("velDatafile." + std::to_string(worldMPIRank) + ".h5", std::ios::binary); std::ofstream dest("velDatafile." + std::to_string(worldMPIRank) + ".h5." + std::to_string(curTimeStep) + ".bak", std::ios::binary); @@ -1001,7 +1001,7 @@ void fast::OpenFAST::writeVelocityData(hid_t h5File, int iTurb, int iTimestep, O hid_t dset_id = H5Dopen2(h5File, ("/turbine" + std::to_string(iTurb)).c_str(), H5P_DEFAULT); hid_t dspace_id = H5Dget_space(dset_id); H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, start, NULL, count, NULL); - hid_t mspace_id = H5Screate_simple(3, count, NULL); + hid_t mspace_id = H5Screate_simple(3, count, NULL); H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mspace_id, dspace_id, H5P_DEFAULT, tmpVelData.data()); H5Dclose(dset_id); @@ -1017,7 +1017,7 @@ void fast::OpenFAST::writeVelocityData(hid_t h5File, int iTurb, int iTimestep, O void fast::OpenFAST::applyVelocityData(int iPrestart, int iTurb, OpFM_OutputType_t cDriver_Output_to_FAST, std::vector & velData) { int nVelPts = get_numVelPtsLoc(iTurb); for (int j = 0; j < nVelPts; j++){ - cDriver_Output_to_FAST.u[j] = velData[(iPrestart*nVelPts+j)*6 + 3]; + cDriver_Output_to_FAST.u[j] = velData[(iPrestart*nVelPts+j)*6 + 3]; cDriver_Output_to_FAST.v[j] = velData[(iPrestart*nVelPts+j)*6 + 4]; cDriver_Output_to_FAST.w[j] = velData[(iPrestart*nVelPts+j)*6 + 5]; } @@ -1029,11 +1029,8 @@ void fast::OpenFAST::loadSuperController(const fast::fastInputs & fi) { std::cout << "Use of Supercontroller is not supported through the C++ API right now" << std::endl; // scStatus = fi.scStatus; // sc.load(fi.nTurbinesGlob, fi.scLibFile, scio); - + } else { - scStatus = false; } - } - diff --git a/glue-codes/openfast/CMakeLists.txt b/glue-codes/openfast/CMakeLists.txt index f4e4e4485a..5fe7c78227 100644 --- a/glue-codes/openfast/CMakeLists.txt +++ b/glue-codes/openfast/CMakeLists.txt @@ -14,19 +14,27 @@ # limitations under the License. # +set (CMAKE_CXX_STANDARD 11) + add_executable(openfast src/FAST_Prog.f90) target_link_libraries(openfast openfast_postlib foamfastlib) set_property(TARGET openfast PROPERTY LINKER_LANGUAGE Fortran) +include_directories(${CMAKE_SOURCE_DIR}/modules/openfast-library/src/) +include_directories(${CMAKE_BINARY_DIR}/modules/openfoam/) +include_directories(${CMAKE_BINARY_DIR}/modules/supercontroller/) +add_executable(openfast_cpp src/FAST_Prog.cpp src/FastLibAPI.cpp) +target_link_libraries(openfast_cpp openfastlib) + string(TOUPPER ${CMAKE_Fortran_COMPILER_ID} _compiler_id) -string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type) -if (${_compiler_id} STREQUAL "GNU" AND ${_build_type} STREQUAL "RELEASE") +if (${_compiler_id} STREQUAL "GNU" AND NOT ${VARIABLE_TRACKING}) # With variable tracking enabled, the compile step frequently aborts on large modules and - # restarts with this option off. Disabling in Release mode avoids this problem when compiling with - # full optimizations, but leaves it enabled for RelWithDebInfo which adds both -O2 and -g flags. + # restarts with this option off. Disabling avoids this problem when compiling with + # full optimizations. However, variable tracking should be enabled when actively debugging + # for better runtime debugging output. # https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html set_source_files_properties(src/FAST_Prog.f90 PROPERTIES COMPILE_FLAGS "-fno-var-tracking -fno-var-tracking-assignments") endif() -install(TARGETS openfast +install(TARGETS openfast openfast_cpp RUNTIME DESTINATION bin) diff --git a/glue-codes/openfast/src/FAST_Prog.c b/glue-codes/openfast/src/FAST_Prog.c deleted file mode 100644 index 998218021c..0000000000 --- a/glue-codes/openfast/src/FAST_Prog.c +++ /dev/null @@ -1,185 +0,0 @@ - -#include "FAST_Library.h" -#include "stdio.h" -#include -#include -#include -#include - -int checkError(const int ErrStat, const char * ErrMsg); -void setOutputsToFAST(OpFM_InputType_t* OpFM_Input_from_FAST, OpFM_OutputType_t* OpFM_Output_to_FAST); - - -int -main(int argc, char *argv[], char *env[]) -{ - double dt; - double TMax=10.0; - float TurbinePos[3]; - int TurbID; - int ErrStat = 0; - char ErrMsg[INTERFACE_STRING_LENGTH]; // make sure this is the same size as IntfStrLen in FAST_Library.f90 - char InputFileName[INTERFACE_STRING_LENGTH]; // make sure this is the same size as IntfStrLen in FAST_Library.f90 - char CheckpointFileRoot[INTERFACE_STRING_LENGTH]; // make sure this is the same size as IntfStrLen in FAST_Library.f90 - - OpFM_InputType_t* OpFM_Input_from_FAST = NULL; - OpFM_OutputType_t* OpFM_Output_to_FAST = NULL; - - int n_t_global = -2; - int i = 0; - int j = 0; - int k = 0; - int n_t_global_start = 0; - int NumBlades = 0; - int NumElementsPerBlade = 0; - int NumTwrElements = 0; - int n_checkpoint = 10; - int NumScOutputs = 4; // 5; // # outputs from the supercontroller == # inputs to the controller == NumSC2Ctrl - int NumScInputs = 2; // 2; // # inputs to the supercontroller == # outputs from the controller == NumCtrl2SC - - OpFM_Input_from_FAST = malloc(sizeof(OpFM_InputType_t)); - OpFM_Output_to_FAST = malloc(sizeof(OpFM_OutputType_t)); - if (OpFM_Input_from_FAST == NULL || OpFM_Output_to_FAST == NULL) { - fprintf(stderr, "Error allocating space for OpFM interface types.\n"); - return 1; - } - - - - if (0){ // restart from checkpoint file - - /* ****************************** - restart - ********************************* */ - /* note that this will set n_t_global inside the FAST library */ - strcpy(CheckpointFileRoot, "../../../CertTest/Test18.1200"); - FAST_OpFM_Restart(CheckpointFileRoot, &AbortErrLev, &dt, &NumBlades, &NumElementsPerBlade, &n_t_global_start, OpFM_Input_from_FAST, OpFM_Output_to_FAST, &ErrStat, ErrMsg); - if (checkError(ErrStat, ErrMsg)) return 1; - - } - else{ - /* ****************************** - initialization - ********************************* */ - - // this calls the Init() routines of each module - strcpy(InputFileName, "../../../CertTest/Test18.fst"); - TurbID = 1; - TurbinePos[0] = 0.0; // x location of turbine - TurbinePos[1] = 0.0; // y location of turbine - TurbinePos[2] = 0.0; // z location of turbine - - FAST_OpFM_Init(&TMax, InputFileName, &TurbID, &NumScOutputs, &NumScInputs, TurbinePos, &AbortErrLev, &dt, &NumBlades, &NumElementsPerBlade, - OpFM_Input_from_FAST, OpFM_Output_to_FAST, &ErrStat, ErrMsg); - if (checkError(ErrStat, ErrMsg)) return 1; - - NumTwrElements = OpFM_Output_to_FAST->u_Len - NumBlades*NumElementsPerBlade - 1; - - - // set wind speeds at initial locations - setOutputsToFAST(OpFM_Input_from_FAST, OpFM_Output_to_FAST); - - FAST_OpFM_Solution0(&ErrStat, ErrMsg); - if (checkError(ErrStat, ErrMsg)) return 1; - - } - - // determine subcycling number - - /* ****************************** - call FAST once per time step - ********************************* */ - - for (n_t_global = n_t_global_start; n_t_global < 20; n_t_global++){ - - /* ****************************** - if you want to create a checkpoint file: - ********************************* */ - if (n_t_global == n_checkpoint){ - //sprintf(CheckpointFileRoot, "../../CertTest/Test18.%d", n_t_global); - sprintf(CheckpointFileRoot, " "); // if blank, it will use FAST convention .n_t_global - FAST_CreateCheckpoint(CheckpointFileRoot, &ErrStat, ErrMsg); - checkError(ErrStat, ErrMsg); - } - - - /* ****************************** - set inputs from this code and call FAST: - ********************************* */ - - // set wind speeds at original locations - setOutputsToFAST(OpFM_Input_from_FAST, OpFM_Output_to_FAST); - - - // this advances the states, calls CalcOutput, and solves for next inputs. Predictor-corrector loop is imbeded here: - // (note OpenFOAM could do subcycling around this step) - FAST_OpFM_Step(&ErrStat, ErrMsg); - if (checkError(ErrStat, ErrMsg)) return 1; - - - // do something with - //OpFM_Input_from_FAST->px[j] - //OpFM_Input_from_FAST->py[j] - //OpFM_Input_from_FAST->pz[j] - //OpFM_Input_from_FAST->fx[j] - //OpFM_Input_from_FAST->fy[j] - //OpFM_Input_from_FAST->fz[j] - //OpFM_Input_from_FAST->SuperController[j] - } - - /* ****************************** - End the program - ********************************* */ - - FAST_End(); - - // deallocate types we allocated earlier - if (OpFM_Input_from_FAST != NULL) { - free(OpFM_Input_from_FAST); - OpFM_Input_from_FAST = NULL; - } - if (OpFM_Output_to_FAST != NULL) { - free(OpFM_Output_to_FAST); - OpFM_Output_to_FAST = NULL; - } - -} - -int -checkError(const int ErrStat, const char * ErrMsg){ - - if (ErrStat != ErrID_None){ - fprintf(stderr, "%s\n", ErrMsg); - - if (ErrStat >= AbortErrLev){ - FAST_End(); - return 1; - } - - } - - return 0; - -} - -void -setOutputsToFAST(OpFM_InputType_t* OpFM_Input_from_FAST, OpFM_OutputType_t* OpFM_Output_to_FAST){ - int j; - - // routine sets the u-v-w wind speeds used in FAST and the SuperController inputs - - for (j = 0; j < OpFM_Output_to_FAST->u_Len; j++){ - OpFM_Output_to_FAST->u[j] = (float) 10.0*pow((OpFM_Input_from_FAST->pz[j] / 90.0), 0.2); // 0.2 power law wind profile using reference 10 m/s at 90 meters - OpFM_Output_to_FAST->v[j] = 0.0; - OpFM_Output_to_FAST->w[j] = 0.0; - } - - // call supercontroller - - for (j = 0; j < OpFM_Output_to_FAST->SuperController_Len; j++){ - OpFM_Output_to_FAST->SuperController[j] = (float) j; // set it somehow.... (would be set from the SuperController outputs) - } - - - return; -} diff --git a/glue-codes/openfast/src/FAST_Prog.cpp b/glue-codes/openfast/src/FAST_Prog.cpp new file mode 100644 index 0000000000..2ac629867d --- /dev/null +++ b/glue-codes/openfast/src/FAST_Prog.cpp @@ -0,0 +1,33 @@ + +#include "stdio.h" +#include +#include +#include +#include "FastLibAPI.h" + +int main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "Incorrect syntax. Expected syntax is `openfast_cpp input.fst`" << std::endl; + return 1; + } + + std::string input_file_name = argv[1]; + + FastLibAPI fastlib = FastLibAPI(input_file_name); + fastlib.fast_run(); + + // // Get the hub position + // float absolute_position[3] = {}; + // float rotational_velocity[3] = {}; + // double orientation_dcm[9] = {}; + + // fastlib.get_hub_position(absolute_position, rotational_velocity, orientation_dcm); + + // printf("%f %f %f\n", absolute_position[0], absolute_position[1], absolute_position[2]); + // printf("%f %f %f\n", rotational_velocity[0], rotational_velocity[1], rotational_velocity[2]); + // printf("%f %f %f\n", orientation_dcm[0], orientation_dcm[1], orientation_dcm[2]); + // printf("%f %f %f\n", orientation_dcm[3], orientation_dcm[4], orientation_dcm[5]); + // printf("%f %f %f\n", orientation_dcm[6], orientation_dcm[7], orientation_dcm[8]); + + return 0; +} diff --git a/glue-codes/openfast/src/FastLibAPI.cpp b/glue-codes/openfast/src/FastLibAPI.cpp new file mode 100644 index 0000000000..98c47ed647 --- /dev/null +++ b/glue-codes/openfast/src/FastLibAPI.cpp @@ -0,0 +1,180 @@ + +#include "FastLibAPI.h" +#include +#include +#include +#include +#include +#include + + +FastLibAPI::FastLibAPI(std::string input_file): +n_turbines(1), +i_turb(0), +dt(0.0), +t_max(0.0), +abort_error_level(4), +end_early(false), +num_outs(0), +num_inputs(NumFixedInputs), +ended(false) +{ + input_file_name = input_file; +} + +FastLibAPI::~FastLibAPI() { + fast_deinit(); +} + +bool FastLibAPI::fatal_error(int error_status) { + return error_status >= abort_error_level; +} + +void FastLibAPI::fast_init() { + int _error_status = 0; + char _error_message[INTERFACE_STRING_LENGTH]; + + std::cout << input_file_name; + + FAST_AllocateTurbines( + &n_turbines, + &_error_status, + _error_message + ); + if (fatal_error(_error_status)) { + throw std::runtime_error( "Error " + std::to_string(_error_status) + ": " + _error_message ); + } + + FAST_Sizes( + &i_turb, + input_file_name.c_str(), + &abort_error_level, + &num_outs, + &dt, + &t_max, + &_error_status, + _error_message, + channel_names + ); + if (fatal_error(_error_status)) { + throw std::runtime_error( "Error " + std::to_string(_error_status) + ": " + _error_message ); + } + + // Allocate the data for the outputs + + // Create a dynamic array of pointers + // Then, create a row for every pointer and initialize all elements to 0.0 + output_values = new double *[total_time_steps()]; + for (int i=0; i +#include +#include + +class FastLibAPI { + + private: + std::string input_file_name; + + int n_turbines; + int i_turb; + double dt; + double t_max; + int abort_error_level; + bool end_early; + int num_outs; + char channel_names[MAXIMUM_OUTPUTS * CHANNEL_LENGTH + 1]; + bool ended; + + // The inputs are meant to be from Simulink. + // If < NumFixedInputs, FAST_SetExternalInputs simply returns, + // but this behavior may change to an error + // MAKE THIS NumFixedInputs + int num_inputs; + double inp_array[NumFixedInputs] = {}; + + // These arrays hold the outputs from OpenFAST + // output_array is a 1D vector for the values from a single step + // output_values is a 2D array for the values from all steps in the simulation + std::vector output_array; + double **output_values; + + public: + + // Constructor + FastLibAPI(std::string input_file); + + // Destructor + ~FastLibAPI(); + + bool fatal_error(int error_status); + void fast_init(); + void fast_sim(); + void fast_deinit(); + void fast_run(); + int total_time_steps(); + std::string output_channel_names(); + void get_hub_position(float *absolute_position, float *rotational_velocity, double *orientation_dcm); +}; + +#endif diff --git a/glue-codes/python/OpenFAST.py b/glue-codes/python/OpenFAST.py new file mode 100644 index 0000000000..6e7e25df30 --- /dev/null +++ b/glue-codes/python/OpenFAST.py @@ -0,0 +1,48 @@ + +import openfast_library + +project_root = '/Users/rmudafor/Development/weis' +library_path = project_root + '/build/modules/openfast-library/libopenfastlib.dylib' + +def serial(input_file): + input_file_name = input_file # "/Users/rmudafor/Development/weis/reg_tests/r-test/glue-codes/openfast/AOC_YFix_WSt/AOC_YFix_WSt.fst" + openfastlib = openfast_library.FastLibAPI(library_path, input_file_name) + openfastlib.fast_run() + + # Display the outputs + # for i, c in enumerate(openfastlib.output_channel_names): + # print(i, c) + # print(openfastlib.output_channel_names) + # print(openfastlib.output_values) + # print(openfastlib.output_values[:,0]) # Prints the time steps + +def parallel(): + ## Parallel with MPI + from mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + + if rank == 0: + input_file_name = "{}/reg_tests/r-test/glue-codes/openfast/AOC_WSt/AOC_WSt.fst".format(project_root) + openfastlib = openfast_library.FastLibAPI(library_path, input_file_name) + openfastlib.fast_run() + elif rank == 1: + input_file_name = "{}/reg_tests/r-test/glue-codes/openfast/AOC_YFix_WSt/AOC_YFix_WSt.fst".format(project_root) + openfastlib = openfast_library.FastLibAPI(library_path, input_file_name) + openfastlib.fast_run() + elif rank == 2: + input_file_name = "{}/reg_tests/r-test/glue-codes/openfast/AOC_YFree_WTurb/AOC_YFree_WTurb.fst".format(project_root) + openfastlib = openfast_library.FastLibAPI(library_path, input_file_name) + openfastlib.fast_run() + elif rank == 3: + input_file_name = "{}/reg_tests/r-test/glue-codes/openfast/AWT_YFix_WSt/AWT_YFix_WSt.fst".format(project_root) + openfastlib = openfast_library.FastLibAPI(library_path, input_file_name) + openfastlib.fast_run() + +if __name__=="__main__": + import sys + if len(sys.argv) > 1: + input_file = sys.argv[1] + serial(input_file) + else: + print("No cases run. Check the driver code.") diff --git a/glue-codes/python/openfast_library.py b/glue-codes/python/openfast_library.py new file mode 100644 index 0000000000..234e213612 --- /dev/null +++ b/glue-codes/python/openfast_library.py @@ -0,0 +1,277 @@ +from ctypes import ( + CDLL, + POINTER, + create_string_buffer, + byref, + c_int, + c_double, + c_float, + c_char, + c_bool +) +import os +from typing import List, Tuple +import numpy as np +import math + + +IntfStrLen = 1025 # FAST_Library global +NumFixedInputs = 51 # FAST_Library global + + +class FastLibAPI(CDLL): + + def __init__(self, library_path: str, input_file_name: str): + super().__init__(library_path) + self.library_path = library_path + self.input_file_name = create_string_buffer(os.path.abspath(input_file_name).encode('utf-8')) + + self._initialize_routines() + + # Create buffers for class data + self.n_turbines = c_int(1) + self.i_turb = c_int(0) + self.dt = c_double(0.0) + self.t_max = c_double(0.0) + self.abort_error_level = c_int(4) # Initialize to 4 (ErrID_Fatal) and reset to user-given value in FAST_Sizes + self.end_early = c_bool(False) + self.num_outs = c_int(0) + self.channel_names = create_string_buffer(20 * 4000) + self.ended = False + + # The inputs are meant to be from Simulink. + # If < 51, FAST_SetExternalInputs simply returns, + # but this behavior may change to an error + ### MAKE THIS 51 + self.num_inputs = c_int(NumFixedInputs) + # inp_array is initialized with 0. See FAST_Library.FAST_SetExternalInputs for usage. + self.inp_array = (c_double * self.num_inputs.value)(0.0, ) + + # These arrays hold the outputs from OpenFAST + # output_array is a 1D array for the values from a single step + # output_values is a 2D array for the values from all steps in the simulation + self.output_array = None + self.output_values = None + + + def _initialize_routines(self) -> None: + self.FAST_AllocateTurbines.argtypes = [ + POINTER(c_int), + POINTER(c_int), + POINTER(c_char) + ] + self.FAST_AllocateTurbines.restype = c_int + + self.FAST_Sizes.argtype = [ + POINTER(c_int), # iTurb IN + POINTER(c_char), # InputFileName_c IN + POINTER(c_int), # AbortErrLev_c OUT + POINTER(c_int), # NumOuts_c OUT + POINTER(c_double), # dt_c OUT + POINTER(c_double), # tmax_c OUT + POINTER(c_int), # ErrStat_c OUT + POINTER(c_char), # ErrMsg_c OUT + POINTER(c_char), # ChannelNames_c OUT + POINTER(c_double), # TMax OPTIONAL IN + POINTER(c_double) # InitInpAry OPTIONAL IN + ] + self.FAST_Sizes.restype = c_int + + self.FAST_Start.argtype = [ + POINTER(c_int), # iTurb IN + POINTER(c_int), # NumInputs_c IN + POINTER(c_int), # NumOutputs_c IN + POINTER(c_double), # InputAry IN + POINTER(c_double), # OutputAry OUT + POINTER(c_int), # ErrStat_c OUT + POINTER(c_char) # ErrMsg_c OUT + ] + self.FAST_Start.restype = c_int + + self.FAST_Update.argtype = [ + POINTER(c_int), # iTurb IN + POINTER(c_int), # NumInputs_c IN + POINTER(c_int), # NumOutputs_c IN + POINTER(c_double), # InputAry IN + POINTER(c_double), # OutputAry OUT + POINTER(c_bool), # EndSimulationEarly OUT + POINTER(c_int), # ErrStat_c OUT + POINTER(c_char) # ErrMsg_c OUT + ] + self.FAST_Update.restype = c_int + + self.FAST_DeallocateTurbines.argtypes = [ + POINTER(c_int), # ErrStat_c OUT + POINTER(c_char), # ErrMsg_c OUT + ] + self.FAST_DeallocateTurbines.restype = c_int + + self.FAST_End.argtypes = [ + POINTER(c_int), # iTurb IN + POINTER(c_bool), # StopTheProgram IN + ] + self.FAST_End.restype = c_int + + self.FAST_HubPosition.argtypes = [ + POINTER(c_int), # iTurb IN + POINTER(c_float), # AbsPosition_c(3) OUT + POINTER(c_float), # RotationalVel_c(3) OUT + POINTER(c_double), # Orientation_c(9) OUT + POINTER(c_int), # ErrStat_c OUT + POINTER(c_char) # ErrMsg_c OUT + ] + self.FAST_HubPosition.restype = c_int + + + def fatal_error(self, error_status) -> bool: + return error_status.value >= self.abort_error_level.value + + + def fast_init(self) -> None: + _error_status = c_int(0) + _error_message = create_string_buffer(IntfStrLen) + + self.FAST_AllocateTurbines( + byref(self.n_turbines), + byref(_error_status), + _error_message + ) + if self.fatal_error(_error_status): + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + + self.FAST_Sizes( + byref(self.i_turb), + self.input_file_name, + byref(self.abort_error_level), + byref(self.num_outs), + byref(self.dt), + byref(self.t_max), + byref(_error_status), + _error_message, + self.channel_names, + None, # Optional arguments must pass C-Null pointer; with ctypes, use None. + None # Optional arguments must pass C-Null pointer; with ctypes, use None. + ) + if self.fatal_error(_error_status): + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + + # Allocate the data for the outputs + # NOTE: The ctypes array allocation (output_array) must be after the output_values + # allocation, or otherwise seg fault. + self.output_values = np.empty( (self.total_time_steps, self.num_outs.value) ) + self.output_array = (c_double * self.num_outs.value)(0.0, ) + + + def fast_sim(self) -> None: + _error_status = c_int(0) + _error_message = create_string_buffer(IntfStrLen) + + self.FAST_Start( + byref(self.i_turb), + byref(self.num_inputs), + byref(self.num_outs), + byref(self.inp_array), + byref(self.output_array), + byref(_error_status), + _error_message + ) + self.output_values[0] = self.output_array[:] + if self.fatal_error(_error_status): + self.fast_deinit() + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + + for i in range( 1, self.total_time_steps ): + self.FAST_Update( + byref(self.i_turb), + byref(self.num_inputs), + byref(self.num_outs), + byref(self.inp_array), + byref(self.output_array), + byref(self.end_early), + byref(_error_status), + _error_message + ) + self.output_values[i] = self.output_array[:] + if self.fatal_error(_error_status): + self.fast_deinit() + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + if self.end_early: + break + + + def fast_deinit(self) -> None: + _error_status = c_int(0) + _error_message = create_string_buffer(IntfStrLen) + + if not self.ended: + self.ended = True + + # Deallocate all the internal variables and allocatable arrays + # Despite the name, this does not actually end the program + self.FAST_End( + byref(self.i_turb), + byref(c_bool(False)) + ) + + # Deallocate the Turbine array + self.FAST_DeallocateTurbines( + byref(_error_status), + _error_message + ) + if self.fatal_error(_error_status): + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + + + def fast_run(self) -> None: + self.fast_init() + self.fast_sim() + self.fast_deinit() + + + @property + def total_time_steps(self) -> int: + # From FAST_Subs FAST_Init: + # p%n_TMax_m1 = CEILING( ( (p%TMax - t_initial) / p%DT ) ) - 1 ! We're going to go from step 0 to n_TMax (thus the -1 here) + # Then in FAST_Prog: + # TIME_STEP_LOOP: DO n_t_global = Restart_step, Turbine(1)%p_FAST%n_TMax_m1 + # + # Note that Fortran indexing starts at 1 and includes the upper bound + # Python indexing starts at 0 and does not include the upper bound + # The for-loop in this interface begins at 1 (there's an init step before) + # and that's why we have the +1 below + # + # We assume here t_initial is always 0 + return math.ceil( self.t_max.value / self.dt.value) + 1 + + + @property + def output_channel_names(self) -> List: + if len(self.channel_names.value.split()) == 0: + return [] + output_channel_names = self.channel_names.value.split() + output_channel_names = [n.decode('UTF-8') for n in output_channel_names] + return output_channel_names + + + def get_hub_position(self) -> Tuple: + _error_status = c_int(0) + _error_message = create_string_buffer(IntfStrLen) + + # Data buffers + absolute_position = (c_float * 3)(0.0, ) + rotational_velocity = (c_float * 3)(0.0, ) + orientation_dcm = (c_double * 9)(0.0, ) + + # Get hub position from the fast library + self.FAST_HubPosition( + byref(self.i_turb), + absolute_position, + rotational_velocity, + orientation_dcm, + byref(_error_status), + _error_message + ) + if self.fatal_error(_error_status): + raise RuntimeError(f"Error {_error_status.value}: {_error_message.value}") + + return absolute_position, rotational_velocity, orientation_dcm diff --git a/glue-codes/simulink/README.md b/glue-codes/simulink/README.md new file mode 100644 index 0000000000..a6509128b9 --- /dev/null +++ b/glue-codes/simulink/README.md @@ -0,0 +1,5 @@ +OpenFAST expects a set of channels passed from Simulink to the library. The number channels may change between OpenFAST releases. + +For list of control channels, see comments at end of source file modules/openfast-library/src/FAST_Library.h + +The examples included here inclue all the channels listed in the FAST_Library.h file. diff --git a/glue-codes/simulink/src/FAST_SFunc.c b/glue-codes/simulink/src/FAST_SFunc.c index 21e0a1c98a..b03d689a99 100644 --- a/glue-codes/simulink/src/FAST_SFunc.c +++ b/glue-codes/simulink/src/FAST_SFunc.c @@ -49,6 +49,7 @@ static double TMax = 0; static int NumInputs = NumFixedInputs; static int NumAddInputs = 0; // number of additional inputs static int NumOutputs = 1; +static bool EndEarly = false; static int ErrStat = 0; static char ErrMsg[INTERFACE_STRING_LENGTH]; // make sure this is the same size as IntfStrLen in FAST_Library.f90 static int ErrStat2 = 0; @@ -83,12 +84,7 @@ checkError(SimStruct *S){ if (ErrStat >= AbortErrLev) { ssPrintf("\n"); - if (ErrStat > ErrID_Fatal) { // in case we've reached a trim solution - ssPrintf("%s\n", ErrMsg); - } - else { - ssSetErrorStatus(S, ErrMsg); - } + ssSetErrorStatus(S, ErrMsg); mdlTerminate(S); // terminate on error (in case Simulink doesn't do so itself) return 1; } @@ -207,7 +203,7 @@ static void mdlInitializeSizes(SimStruct *S) FAST_AllocateTurbines(&nTurbines, &ErrStat, ErrMsg); if (checkError(S)) return; - FAST_Sizes(&iTurb, &TMax, InitInputAry, InputFileName, &AbortErrLev, &NumOutputs, &dt, &ErrStat, ErrMsg, ChannelNames); + FAST_Sizes(&iTurb, InputFileName, &AbortErrLev, &NumOutputs, &dt, &TMax, &ErrStat, ErrMsg, ChannelNames, &TMax, InitInputAry); n_t_global = -1; if (checkError(S)) return; @@ -430,9 +426,16 @@ static void mdlUpdate(SimStruct *S, int_T tid) /* ==== Call the Fortran routine (args are pass-by-reference) */ - FAST_Update(&iTurb, &NumInputs, &NumOutputs, InputAry, OutputAry, &ErrStat, ErrMsg); + FAST_Update(&iTurb, &NumInputs, &NumOutputs, InputAry, OutputAry, &EndEarly, &ErrStat, ErrMsg); n_t_global = n_t_global + 1; + // For trim solution or any other reason to end early when there is no error + if (EndEarly) { + mdlTerminate(S); // terminate after simulation completes (in case Simulink doesn't do so itself) + return; + } + + // Handle errors if (checkError(S)) return; setOutputs(S, OutputAry); diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index e8facc7c4f..2a5b1c4784 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -276,7 +276,7 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut if (Failed()) return; NumBlades(iR) = InitInp%rotors(iR)%NumBlades p%rotors(iR)%NumBlades = InitInp%rotors(iR)%NumBlades - if (size(InitInp%rotors)>1) then + if (nRotors > 1) then p%rotors(iR)%RootName = TRIM(InitInp%RootName)//'.AD.R'//trim(num2lstr(iR)) else p%rotors(iR)%RootName = TRIM(InitInp%RootName)//'.AD' @@ -325,6 +325,7 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! set the rest of the parameters + p%SkewMod = InputFileData%SkewMod do iR = 1, nRotors p%rotors(iR)%AeroProjMod = InitInp%rotors(iR)%AeroProjMod call SetParameters( InitInp, InputFileData, InputFileData%rotors(iR), p%rotors(iR), p, ErrStat2, ErrMsg2 ) @@ -1160,7 +1161,8 @@ subroutine AD_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) TYPE(AD_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 - integer :: iW + + integer :: iW @@ -1382,6 +1384,9 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif + ! Cavitation check + call AD_CavtCrit(u, p, m, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) !------------------------------------------------------- ! get values to output to file: @@ -1476,47 +1481,59 @@ subroutine RotCalcOutput( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, Er call ADTwr_CalcOutput(p, u, m, y, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif - - call AD_CavtCrit(u, p, m, errStat2, errMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine RotCalcOutput subroutine AD_CavtCrit(u, p, m, errStat, errMsg) - TYPE(RotInputType), INTENT(IN ) :: u !< Inputs at Time t - TYPE(RotParameterType), INTENT(IN ) :: p !< Parameters - TYPE(RotMiscVarType), INTENT(INOUT) :: m !< Misc/optimization variables - !! nectivity information does not have to be recalculated) + TYPE(AD_InputType), INTENT(IN ) :: u !< Inputs at time t + TYPE(AD_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(AD_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 - integer :: i,j - real(ReKi) :: SigmaCavitCrit, SigmaCavit + + ! Local variables + integer :: i, j + integer(intKi) :: iR, iW + real(ReKi) :: SigmaCavitCrit, SigmaCavit + real(ReKi) :: Vreltemp + real(ReKi) :: Cpmintemp errStat = ErrID_None errMsg = '' - if ( p%CavitCheck ) then ! Calculate the cavitation number for the airfoil at the node in quesiton, and compare to the critical cavitation number based on the vapour pressure and submerged depth - do j = 1,p%numBlades ! Loop through all blades - do i = 1,p%NumBlNds ! Loop through all nodes + do iR = 1,size(p%rotors) + if ( p%rotors(iR)%CavitCheck ) then ! Calculate the cavitation number for the airfoil at the node in quesiton, and compare to the critical cavitation number based on the vapour pressure and submerged depth + do j = 1,p%rotors(iR)%numBlades ! Loop through all blades + do i = 1,p%rotors(iR)%NumBlNds ! Loop through all nodes - if ( EqualRealNos( m%BEMT_y%Vrel(i,j), 0.0_ReKi ) ) call SetErrStat( ErrID_Fatal, 'Vrel cannot be zero to do a cavitation check', ErrStat, ErrMsg, 'AD_CavtCrit') - if (ErrStat >= AbortErrLev) return + if ( p%WakeMod == WakeMod_BEMT .or. p%WakeMod == WakeMod_DBEMT ) then + Vreltemp = m%rotors(iR)%BEMT_y%Vrel(i,j) + Cpmintemp = m%rotors(iR)%BEMT_y%Cpmin(i,j) + else if ( p%WakeMod == WakeMod_FVW ) then + iW = p%FVW%Bld2Wings(iR,j) + Vreltemp = m%FVW%W(iW)%BN_Vrel(i) + Cpmintemp = m%FVW%W(iW)%BN_Cpmin(i) + end if + + if ( EqualRealNos( Vreltemp, 0.0_ReKi ) ) call SetErrStat( ErrID_Fatal, 'Vrel cannot be zero to do a cavitation check', ErrStat, ErrMsg, 'AD_CavtCrit' ) + if ( ErrStat >= AbortErrLev ) return - SigmaCavit= -1* m%BEMT_y%Cpmin(i,j) ! Local cavitation number on node j - SigmaCavitCrit= ( ( p%Patm + ( p%Gravity * (p%WtrDpth - ( u%HubMotion%Position(3,1)+u%HubMotion%TranslationDisp(3,1) ) - ( u%BladeMotion(j)%Position(3,i) + u%BladeMotion(j)%TranslationDisp(3,i) - u%HubMotion%Position(3,1))) * p%airDens) - p%Pvap ) / ( 0.5_ReKi * p%airDens * m%BEMT_y%Vrel(i,j)**2)) ! Critical value of Sigma, cavitation occurs if local cavitation number is greater than this + SigmaCavit = -1 * Cpmintemp ! Local cavitation number on node j + SigmaCavitCrit = ( p%rotors(iR)%Patm + ( p%rotors(iR)%Gravity * ( p%rotors(iR)%WtrDpth - ( u%rotors(iR)%BladeMotion(j)%Position(3,i) + u%rotors(iR)%BladeMotion(j)%TranslationDisp(3,i) ) ) * p%rotors(iR)%airDens ) - p%rotors(iR)%Pvap ) / ( 0.5_ReKi * p%rotors(iR)%airDens * Vreltemp**2 ) ! Critical value of Sigma, cavitation occurs if local cavitation number is greater than this - if ( (SigmaCavitCrit < SigmaCavit) .and. (.not. (m%CavitWarnSet(i,j)) ) ) then - call WrScr( NewLine//'Cavitation occurred at blade '//trim(num2lstr(j))//' and node '//trim(num2lstr(i))//'.' ) - m%CavitWarnSet(i,j) = .true. + if ( ( SigmaCavitCrit < SigmaCavit ) .and. ( .not. ( m%rotors(iR)%CavitWarnSet(i,j) ) ) ) then + call WrScr( NewLine//'Cavitation occurred at blade '//trim(num2lstr(j))//' and node '//trim(num2lstr(i))//'.' ) + m%rotors(iR)%CavitWarnSet(i,j) = .true. end if - m%SigmaCavit(i,j)= SigmaCavit - m%SigmaCavitCrit(i,j)=SigmaCavitCrit + m%rotors(iR)%SigmaCavit(i,j) = SigmaCavit + m%rotors(iR)%SigmaCavitCrit(i,j) = SigmaCavitCrit - end do ! p%NumBlNds - end do ! p%numBlades - end if ! Cavitation check + end do ! p%NumBlNds + end do ! p%numBlades + end if ! Cavitation check + end do ! p%numRotors end subroutine AD_CavtCrit !---------------------------------------------------------------------------------------------------------------------------------- @@ -1659,7 +1676,7 @@ subroutine SetInputs(p, p_AD, u, m, indx, errStat, errMsg) ErrMsg = "" ! Disturbed inflow on blade (if tower shadow present) - call SetDisturbedInflow(p, u, m, errStat, errMsg) + call SetDisturbedInflow(p, p_AD, u, m, errStat, errMsg) if (p_AD%WakeMod /= WakeMod_FVW) then ! This needs to extract the inputs from the AD data types (mesh) and massage them for the BEMT module @@ -1668,14 +1685,18 @@ subroutine SetInputs(p, p_AD, u, m, indx, errStat, errMsg) endif end subroutine SetInputs +!---------------------------------------------------------------------------------------------------------------------------------- !> Disturbed inflow on the blade if tower shadow or tower influence are enabled -subroutine SetDisturbedInflow(p, u, m, errStat, errMsg) +subroutine SetDisturbedInflow(p, p_AD, u, m, errStat, errMsg) type(RotParameterType), intent(in ) :: p !< AD parameters + type(AD_ParameterType), intent(in ) :: p_AD !< AD parameters type(RotInputType), intent(in ) :: u !< AD Inputs at Time type(RotMiscVarType), 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 + real(R8Ki) :: x_hat_disk(3) + integer(intKi) :: j,k integer(intKi) :: errStat2 character(ErrMsgLen) :: errMsg2 character(*), parameter :: RoutineName = 'SetDisturbedInflow' @@ -1688,6 +1709,16 @@ subroutine SetDisturbedInflow(p, u, m, errStat, errMsg) m%DisturbedInflow = u%InflowOnBlade end if + if (p_AD%SkewMod == SkewMod_Orthogonal) then + x_hat_disk = u%HubMotion%Orientation(1,:,1) + + do k=1,p%NumBlades + do j=1,p%NumBlNds + m%DisturbedInflow(:,j,k) = dot_product( m%DisturbedInflow(:,j,k), x_hat_disk ) * x_hat_disk + enddo + enddo + endif + end subroutine SetDisturbedInflow @@ -1798,8 +1829,10 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%BEMT_u(indx)%UserProp = u%UserProp - ! ................ TSR ..................... + !.......................... + ! TSR + !.......................... if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then m%BEMT_u(indx)%TSR = 0.0_ReKi else @@ -2016,7 +2049,7 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) endif do iR =1, size(p%rotors) ! Disturbed inflow for UA on Lifting line Mesh Points - call SetDisturbedInflow(p%rotors(iR), u(tIndx)%rotors(iR), m%rotors(iR), errStat, errMsg) + call SetDisturbedInflow(p%rotors(iR), p, u(tIndx)%rotors(iR), m%rotors(iR), errStat, errMsg) do k=1,p%rotors(iR)%NumBlades iW=p%FVW%Bld2Wings(iR,k) m%FVW_u(tIndx)%W(iW)%Vwnd_LL(1:3,:) = m%rotors(iR)%DisturbedInflow(1:3,:,k) @@ -2139,7 +2172,7 @@ subroutine SetOutputsFromFVW(t, u, p, OtherState, x, xd, m, y, ErrStat, ErrMsg) type(AFI_OutputType) :: AFI_interp ! Resulting values from lookup table real(ReKi) :: UrelWind_s(3) ! Relative wind (wind+str) in section coords real(ReKi) :: Cx, Cy - real(ReKi) :: Cl_Static, Cd_Static, Cm_Static + real(ReKi) :: Cl_Static, Cd_Static, Cm_Static, Cpmin real(ReKi) :: Cl_dyn, Cd_dyn, Cm_dyn type(UA_InputType), pointer :: u_UA ! Alias to shorten notations integer(IntKi), parameter :: InputIndex=1 ! we will always use values at t in this routine @@ -2173,6 +2206,7 @@ subroutine SetOutputsFromFVW(t, u, p, OtherState, x, xd, m, y, ErrStat, ErrMsg) Cl_Static = AFI_interp%Cl Cd_Static = AFI_interp%Cd Cm_Static = AFI_interp%Cm + Cpmin = AFI_interp%Cpmin ! Set dynamic to the (will be same as static if UA_Flag is false) Cl_dyn = AFI_interp%Cl @@ -2227,6 +2261,7 @@ subroutine SetOutputsFromFVW(t, u, p, OtherState, x, xd, m, y, ErrStat, ErrMsg) m%FVW%W(iW)%BN_Cl_Static(j) = Cl_Static m%FVW%W(iW)%BN_Cd_Static(j) = Cd_Static m%FVW%W(iW)%BN_Cm_Static(j) = Cm_Static + m%FVW%W(iW)%BN_Cpmin(j) = Cpmin m%FVW%W(iW)%BN_Cl(j) = Cl_dyn m%FVW%W(iW)%BN_Cd(j) = Cd_dyn m%FVW%W(iW)%BN_Cm(j) = Cm_dyn @@ -2336,7 +2371,7 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) if ( InputFileData%IndToler < 0.0 .or. EqualRealNos(InputFileData%IndToler, 0.0_ReKi) ) & call SetErrStat( ErrID_Fatal, 'IndToler must be greater than 0.', ErrStat, ErrMsg, RoutineName ) - if ( InputFileData%SkewMod /= SkewMod_Uncoupled .and. InputFileData%SkewMod /= SkewMod_PittPeters) & ! .and. InputFileData%SkewMod /= SkewMod_Coupled ) + if ( InputFileData%SkewMod /= SkewMod_Orthogonal .and. InputFileData%SkewMod /= SkewMod_Uncoupled .and. InputFileData%SkewMod /= SkewMod_PittPeters) & ! .and. InputFileData%SkewMod /= SkewMod_Coupled ) call SetErrStat( ErrID_Fatal, 'SkewMod must be 1, or 2. Option 3 will be implemented in a future version.', ErrStat, ErrMsg, RoutineName ) end if !BEMT/DBEMT checks @@ -5464,7 +5499,7 @@ SUBROUTINE Perturb_u( p, n, perturb_sign, u, du ) CASE ( 1) !Module/Mesh/Field: u%TowerMotion%TranslationDisp = 1; u%TowerMotion%TranslationDisp( fieldIndx,node) = u%TowerMotion%TranslationDisp( fieldIndx,node) + du * perturb_sign CASE ( 2) !Module/Mesh/Field: u%TowerMotion%Orientation = 2; - CALL PerturbOrientationMatrix( u%TowerMotion%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%TowerMotion%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 3) !Module/Mesh/Field: u%TowerMotion%TranslationVel = 3; u%TowerMotion%TranslationVel( fieldIndx,node ) = u%TowerMotion%TranslationVel( fieldIndx,node) + du * perturb_sign diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index 7110eeb837..7918e878f4 100644 --- a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 @@ -1046,8 +1046,7 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx DO IdxBlade=1,p%BldNd_BladesOut iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes -!NOT available in FVW yet - y%WriteOutput( OutIdx ) = 0.0_ReKi + y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cpmin(IdxNode) OutIdx = OutIdx + 1 ENDDO ENDDO @@ -1392,7 +1391,6 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, p_AD, ErrStat, ErrMsg ) ! The following are invalid for free vortex wake InvalidOutput( BldNd_Chi ) = .true. InvalidOutput( BldNd_Curve ) = .true. - InvalidOutput( BldNd_CpMin ) = .true. InvalidOutput( BldNd_GeomPhi ) = .true. ! applies only to BEM endif diff --git a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt index 7603a7c0fd..ca84d6e9e8 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt @@ -45,7 +45,8 @@ typedef ^ ^ character(25) Fmt_a typedef ^ ^ character(1) delim - - - "column delimiter" "-" typedef ^ ^ character(20) outFmt - - - "Format specifier" "-" typedef ^ ^ IntKi fileFmt - - - "Output format 1=Text, 2=Binary, 3=Both" "-" -typedef ^ ^ IntKi wrVTK - - - "0= no vtk, 1=animation" "-" +typedef ^ ^ IntKi wrVTK - - - "0= no vtk, 1=init only, 2=animation" "-" +typedef ^ ^ IntKi WrVTK_Type - - - "Flag for VTK output type (1=surface, 2=line, 3=both)" - typedef ^ ^ character(1024) Root - - - "Output file rootname" "-" typedef ^ ^ character(1024) VTK_OutFileRoot - - - "Output file rootname for vtk" "-" typedef ^ ^ character(ChanLen) WriteOutputHdr {:} - - "Channel headers" "-" @@ -121,6 +122,7 @@ typedef ^ ^ ReKi yawAcc typedef ^ ^ character(1024) motionFileName - - - "" - typedef ^ ^ ReKi motion :: - - "" "-" typedef ^ ^ MeshType ptMesh - - - "Point mesh for origin motion" "-" +typedef ^ ^ MeshMapType ED_P_2_AD_P_N - - - "Mesh mapping from nacelle to AD nacelle motion" typedef ^ ^ MeshMapType map2hubPt - - - "Mesh mapping from Nacelle to hub" # ... Tower data ............................................................................................................ diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 816b9e8ffe..184055d32b 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -86,16 +86,15 @@ subroutine Dvr_Init(dvr, AD, IW, errStat,errMsg ) ! --- Driver initialization CALL NWTC_Init( ProgNameIN=version%Name ) + InputFile = "" ! initialize to empty string to make sure it's input from the command line CALL CheckArgs( InputFile, Flag=FlagArg ) IF ( LEN( TRIM(FlagArg) ) > 0 ) CALL NormStop() - ! 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 ) - + + ! Display the copyright notice and compile info: + CALL DispCopyrightLicense( version%Name ) + CALL DispCompileRuntimeInfo( version%Name ) + ! Read the AeroDyn driver input file call Dvr_ReadInputFile(inputFile, dvr, errStat2, errMsg2 ); if(Failed()) return @@ -278,12 +277,17 @@ subroutine Dvr_TimeStep(nt, dvr, AD, IW, errStat, errMsg) ! VTK outputs - if (dvr%out%WrVTK==1 .and. nt==1) then + if ((dvr%out%WrVTK>=1 .and. nt==1) .or. (dvr%out%WrVTK==2)) then ! Init only - call WrVTK_Surfaces(time, dvr, dvr%out, nt-1, AD) - else if (dvr%out%WrVTK==2) then - ! Animation - call WrVTK_Surfaces(time, dvr, dvr%out, nt-1, AD) + select case (dvr%out%WrVTK_Type) + case (1) ! surfaces + call WrVTK_Surfaces(time, dvr, dvr%out, nt-1, AD) + case (2) ! lines + call WrVTK_Lines( time, dvr, dvr%out, nt-1, AD) + case (3) ! both + call WrVTK_Surfaces(time, dvr, dvr%out, nt-1, AD) + call WrVTK_Lines( time, dvr, dvr%out, nt-1, AD) + end select endif ! Get state variables at next step: INPUT at step nt - 1, OUTPUT at step nt @@ -731,6 +735,9 @@ subroutine Init_ADMeshMap(dvr, uAD, errStat, errMsg) ! hub 2 hubAD call MeshMapCreate(wt%hub%ptMesh, uAD%rotors(iWT)%hubMotion, wt%hub%ED_P_2_AD_P_H, errStat2, errMsg2); if(Failed())return + ! nac 2 nacAD + call MeshMapCreate(wt%nac%ptMesh, uAD%rotors(iWT)%nacelleMotion, wt%nac%ED_P_2_AD_P_N, errStat2, errMsg2); if(Failed())return + ! bldroot 2 bldroot AD do iB = 1, wt%numBlades call MeshMapCreate(wt%bld(iB)%ptMesh, uAD%rotors(iWT)%BladeRootMotion(iB), wt%bld(iB)%ED_P_2_AD_P_R, errStat2, errMsg2); if(Failed())return @@ -1065,6 +1072,9 @@ subroutine Set_AD_Inputs(nt,dvr,AD,IW,errStat,errMsg) ! Hub 2 Hub AD call Transfer_Point_to_Point(wt%hub%ptMesh, AD%u(1)%rotors(iWT)%hubMotion, wt%hub%ED_P_2_AD_P_H, errStat2, errMsg2); if(Failed()) return + ! Nac 2 Nac AD + call Transfer_Point_to_Point(wt%nac%ptMesh, AD%u(1)%rotors(iWT)%nacelleMotion, wt%nac%ED_P_2_AD_P_N, errStat2, errMsg2); if(Failed()) return + ! Blade root to blade root AD do iB = 1,wt%numBlades call Transfer_Point_to_Point(wt%bld(iB)%ptMesh, AD%u(1)%rotors(iWT)%BladeRootMotion(iB), wt%bld(iB)%ED_P_2_AD_P_R, errStat2, errMsg2); if(Failed()) return @@ -1582,6 +1592,7 @@ subroutine Dvr_ReadInputFile(fileName, dvr, errStat, errMsg ) call ParseVar(FileInfo_In, CurLine, 'outFmt' , dvr%out%outFmt , errStat2, errMsg2, unEc); if(Failed()) return call ParseVar(FileInfo_In, CurLine, 'outFileFmt' , dvr%out%fileFmt , errStat2, errMsg2, unEc); if(Failed()) return call ParseVar(FileInfo_In, CurLine, 'WrVTK' , dvr%out%WrVTK , errStat2, errMsg2, unEc); if(Failed()) return + call ParseVar(FileInfo_In, CurLine, 'WrVTK_Type' , dvr%out%WrVTK_Type , errStat2, errMsg2, unEc); if(Failed()) return call ParseVar(FileInfo_In, CurLine, 'VTKHubRad' , hubRad_ReKi , errStat2, errMsg2, unEc); if(Failed()) return call ParseAry(FileInfo_In, CurLine, 'VTKNacDim' , dvr%out%VTKNacDim, 6, errStat2, errMsg2, unEc); if(Failed()) return dvr%out%VTKHubRad = real(hubRad_ReKi,SiKi) @@ -1698,6 +1709,12 @@ subroutine ValidateInputs(dvr, errStat, errMsg) !if ( FmtWidth < MinChanLen ) call SetErrStat( ErrID_Warn, 'OutFmt produces a column less than '//trim(num2lstr(MinChanLen))//' characters wide ('// & ! TRIM(Num2LStr(FmtWidth))//'), which may be too small.', ErrStat, ErrMsg, RoutineName ) + if (Check((dvr%out%WrVTK<0 .or. dvr%out%WrVTK>2 ), 'WrVTK must be 0 (none), 1 (initialization only), 2 (animation), or 3 (mode shapes).')) then + return + else + if (Check((dvr%out%WrVTK_Type<1 .or. dvr%out%WrVTK_Type>3), 'VTK_type must be 1 (surfaces), 2 (lines/points), or 3 (both).')) return + endif + contains logical function Check(Condition, ErrMsg_in) @@ -1895,9 +1912,9 @@ subroutine Dvr_CalcOutputDriver(dvr, y_Ifw, errStat, errMsg) ! 6 base DOF rotations = EulerExtract(dvr%WT(iWT)%ptMesh%Orientation(:,:,1)); - arr(k) = dvr%WT(iWT)%ptMesh%Position(1,1)+dvr%WT(iWT)%ptMesh%TranslationDisp(1,1); k=k+1 ! surge - arr(k) = dvr%WT(iWT)%ptMesh%Position(2,1)+dvr%WT(iWT)%ptMesh%TranslationDisp(2,1); k=k+1 ! sway - arr(k) = dvr%WT(iWT)%ptMesh%Position(3,1)+dvr%WT(iWT)%ptMesh%TranslationDisp(3,1); k=k+1 ! heave + arr(k) = dvr%WT(iWT)%ptMesh%TranslationDisp(1,1); k=k+1 ! surge + arr(k) = dvr%WT(iWT)%ptMesh%TranslationDisp(2,1); k=k+1 ! sway + arr(k) = dvr%WT(iWT)%ptMesh%TranslationDisp(3,1); k=k+1 ! heave arr(k) = rotations(1) * R2D ; k=k+1 ! roll arr(k) = rotations(2) * R2D ; k=k+1 ! pitch arr(k) = rotations(3) * R2D ; k=k+1 ! yaw @@ -2119,8 +2136,8 @@ SUBROUTINE SetVTKParameters(p_FAST, dvr, InitOutData_AD, AD, ErrStat, ErrMsg) allocate(p_FAST%VTK_Surface(dvr%numTurbines)) ! --- Find dimensions for all objects to determine "Ground" and typical dimensions - WorldBoxMax(2) =-HUGE(1.0_SiKi) - WorldBoxMin(2) = HUGE(1.0_SiKi) + WorldBoxMax =-HUGE(1.0_SiKi) + WorldBoxMin = HUGE(1.0_SiKi) MaxBladeLength=0 MaxTwrLength=0 do iWT=1,dvr%numTurbines @@ -2295,7 +2312,7 @@ SUBROUTINE WrVTK_Surfaces(t_global, dvr, p_FAST, VTK_count, AD) end do if (p_FAST%WrVTK>1) then - ! --- Debug outputs + ! --- animations ! Tower base call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, wt%twr%ptMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseSurface', & VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth , & @@ -2319,6 +2336,59 @@ SUBROUTINE WrVTK_Surfaces(t_global, dvr, p_FAST, VTK_count, AD) end if END SUBROUTINE WrVTK_Surfaces !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine writes a minimal subset of meshes with surfaces to VTK-formatted files. It doesn't bother with +!! returning an error code. +SUBROUTINE WrVTK_Lines(t_global, dvr, p_FAST, VTK_count, AD) + use FVW_IO, only: WrVTK_FVW + REAL(DbKi), INTENT(IN ) :: t_global !< Current global time + type(Dvr_SimData), target, intent(inout) :: dvr ! intent(out) only so that we can save FmtWidth in dvr%out%ActualChanLen + TYPE(Dvr_Outputs), INTENT(IN ) :: p_FAST !< Parameters for the glue code + INTEGER(IntKi) , INTENT(IN ) :: VTK_count + TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data + logical, parameter :: OutputFields = .FALSE. ! due to confusion about what fields mean on a surface, we are going to just output the basic meshes if people ask for fields + INTEGER(IntKi) :: k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + CHARACTER(*), PARAMETER :: RoutineName = 'WrVTK_Lines' + integer(IntKi) :: iWT + type(WTData), pointer :: wt ! Alias to shorten notation + character(10) :: sWT + + do iWT = 1, size(dvr%WT) + sWT = '.T'//trim(num2lstr(iWT)) + wt=>dvr%WT(iWT) + + ! Tower motions + if (AD%u(2)%rotors(iWT)%TowerMotion%nNodes>0) then + call MeshWrVTK(p_FAST%VTKRefPoint, AD%u(2)%rotors(iWT)%TowerMotion, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.Tower', & + VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + + if (wt%numBlades>0) then + ! Nacelle + call MeshWrVTK(p_FAST%VTKRefPoint, wt%nac%ptMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.Nacelle', & + VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + + ! Hub + call MeshWrVTK(p_FAST%VTKRefPoint, AD%u(2)%rotors(iWT)%HubMotion, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.Hub', & + VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + + ! Blades + do K=1,wt%numBlades + call MeshWrVTK(p_FAST%VTKRefPoint, AD%u(2)%rotors(iWT)%BladeMotion(K), trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(k)), & + VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, Sib=AD%y%rotors(iWT)%BladeLoad(k) ) + end do + enddo + + ! Free wake (only write this here if doing line meshes only -- FVW is written with surface outputs) + if (allocated(AD%m%FVW_u) .and. dvr%out%WrVTK_Type==2) then + if (allocated(AD%m%FVW_u(1)%WingsMesh)) then + call WrVTK_FVW(AD%p%FVW, AD%x%FVW, AD%z%FVW, AD%m%FVW, trim(p_FAST%VTK_OutFileRoot)//'.FVW', VTK_count, p_FAST%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + end if + end if +END SUBROUTINE WrVTK_Lines +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes the ground or seabed reference surface information in VTK format. !! see VTK file information format for XML, here: http://www.vtk.org/wp-content/uploads/2015/04/file-formats.pdf SUBROUTINE WrVTK_Ground ( RefPoint, HalfLengths, FileRootName, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 index ce2000033d..61b1087629 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 @@ -76,7 +76,8 @@ MODULE AeroDyn_Driver_Types character(1) :: delim !< column delimiter [-] character(20) :: outFmt !< Format specifier [-] INTEGER(IntKi) :: fileFmt !< Output format 1=Text, 2=Binary, 3=Both [-] - INTEGER(IntKi) :: wrVTK !< 0= no vtk, 1=animation [-] + INTEGER(IntKi) :: wrVTK !< 0= no vtk, 1=init only, 2=animation [-] + INTEGER(IntKi) :: WrVTK_Type !< Flag for VTK output type (1=surface, 2=line, 3=both) [-] character(1024) :: Root !< Output file rootname [-] character(1024) :: VTK_OutFileRoot !< Output file rootname for vtk [-] character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Channel headers [-] @@ -162,6 +163,7 @@ MODULE AeroDyn_Driver_Types character(1024) :: motionFileName !< [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: motion !< [-] TYPE(MeshType) :: ptMesh !< Point mesh for origin motion [-] + TYPE(MeshMapType) :: ED_P_2_AD_P_N !< Mesh mapping from nacelle to AD nacelle motion [-] TYPE(MeshMapType) :: map2hubPt !< Mesh mapping from Nacelle to hub [-] END TYPE NacData ! ======================= @@ -1035,6 +1037,7 @@ SUBROUTINE AD_Dvr_CopyDvr_Outputs( SrcDvr_OutputsData, DstDvr_OutputsData, CtrlC DstDvr_OutputsData%outFmt = SrcDvr_OutputsData%outFmt DstDvr_OutputsData%fileFmt = SrcDvr_OutputsData%fileFmt DstDvr_OutputsData%wrVTK = SrcDvr_OutputsData%wrVTK + DstDvr_OutputsData%WrVTK_Type = SrcDvr_OutputsData%WrVTK_Type DstDvr_OutputsData%Root = SrcDvr_OutputsData%Root DstDvr_OutputsData%VTK_OutFileRoot = SrcDvr_OutputsData%VTK_OutFileRoot IF (ALLOCATED(SrcDvr_OutputsData%WriteOutputHdr)) THEN @@ -1211,6 +1214,7 @@ SUBROUTINE AD_Dvr_PackDvr_Outputs( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Int_BufSz = Int_BufSz + 1*LEN(InData%outFmt) ! outFmt Int_BufSz = Int_BufSz + 1 ! fileFmt Int_BufSz = Int_BufSz + 1 ! wrVTK + Int_BufSz = Int_BufSz + 1 ! WrVTK_Type Int_BufSz = Int_BufSz + 1*LEN(InData%Root) ! Root Int_BufSz = Int_BufSz + 1*LEN(InData%VTK_OutFileRoot) ! VTK_OutFileRoot Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no @@ -1355,6 +1359,8 @@ SUBROUTINE AD_Dvr_PackDvr_Outputs( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%wrVTK Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%WrVTK_Type + Int_Xferred = Int_Xferred + 1 DO I = 1, LEN(InData%Root) IntKiBuf(Int_Xferred) = ICHAR(InData%Root(I:I), IntKi) Int_Xferred = Int_Xferred + 1 @@ -1605,6 +1611,8 @@ SUBROUTINE AD_Dvr_UnPackDvr_Outputs( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta Int_Xferred = Int_Xferred + 1 OutData%wrVTK = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%WrVTK_Type = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 DO I = 1, LEN(OutData%Root) OutData%Root(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 @@ -4648,6 +4656,9 @@ SUBROUTINE AD_Dvr_CopyNacData( SrcNacDataData, DstNacDataData, CtrlCode, ErrStat CALL MeshCopy( SrcNacDataData%ptMesh, DstNacDataData%ptMesh, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL NWTC_Library_Copymeshmaptype( SrcNacDataData%ED_P_2_AD_P_N, DstNacDataData%ED_P_2_AD_P_N, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN CALL NWTC_Library_Copymeshmaptype( SrcNacDataData%map2hubPt, DstNacDataData%map2hubPt, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN @@ -4666,6 +4677,7 @@ SUBROUTINE AD_Dvr_DestroyNacData( NacDataData, ErrStat, ErrMsg ) DEALLOCATE(NacDataData%motion) ENDIF CALL MeshDestroy( NacDataData%ptMesh, ErrStat, ErrMsg ) + CALL NWTC_Library_Destroymeshmaptype( NacDataData%ED_P_2_AD_P_N, ErrStat, ErrMsg ) CALL NWTC_Library_Destroymeshmaptype( NacDataData%map2hubPt, ErrStat, ErrMsg ) END SUBROUTINE AD_Dvr_DestroyNacData @@ -4734,6 +4746,23 @@ SUBROUTINE AD_Dvr_PackNacData( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! ED_P_2_AD_P_N: size of buffers for each call to pack subtype + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%ED_P_2_AD_P_N, ErrStat2, ErrMsg2, .TRUE. ) ! ED_P_2_AD_P_N + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! ED_P_2_AD_P_N + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! ED_P_2_AD_P_N + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! ED_P_2_AD_P_N + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF Int_BufSz = Int_BufSz + 3 ! map2hubPt: size of buffers for each call to pack subtype CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%map2hubPt, ErrStat2, ErrMsg2, .TRUE. ) ! map2hubPt CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -4820,6 +4849,34 @@ SUBROUTINE AD_Dvr_PackNacData( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%ED_P_2_AD_P_N, ErrStat2, ErrMsg2, OnlySize ) ! ED_P_2_AD_P_N + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + IF(ALLOCATED(Re_Buf)) THEN IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf @@ -4982,6 +5039,46 @@ SUBROUTINE AD_Dvr_UnPackNacData( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackmeshmaptype( Re_Buf, Db_Buf, Int_Buf, OutData%ED_P_2_AD_P_N, ErrStat2, ErrMsg2 ) ! ED_P_2_AD_P_N + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 9273b345ec..6f266d5c25 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -22,7 +22,7 @@ MODULE AeroDyn_IO use NWTC_Library use AeroDyn_Types - use BEMTUncoupled, only : SkewMod_Uncoupled, SkewMod_PittPeters, VelocityIsZero + use BEMTUncoupled, only : SkewMod_Orthogonal, SkewMod_Uncoupled, SkewMod_PittPeters, VelocityIsZero use FVW_Subs, only : FVW_AeroOuts USE AeroDyn_AllBldNdOuts_IO @@ -1656,87 +1656,95 @@ END FUNCTION Calc_Chi0 !---------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE Calc_WriteOutput( p, p_AD, u, m, m_AD, y, OtherState, xd, indx, iRot, ErrStat, ErrMsg ) - TYPE(RotParameterType), INTENT(IN ) :: p ! The rotor parameters - TYPE(AD_ParameterType), INTENT(IN ) :: p_AD ! The module parameters - TYPE(RotInputType), INTENT(IN ) :: u ! inputs - TYPE(RotMiscVarType), INTENT(INOUT) :: m ! misc variables - TYPE(AD_MiscVarType), INTENT(INOUT) :: m_AD ! misc variables - TYPE(RotOutputType), INTENT(IN ) :: y ! outputs - TYPE(RotOtherStateType), INTENT(IN ) :: OtherState ! other states at t (for DBEMT and UA) - TYPE(RotDiscreteStateType),INTENT(IN ) :: xd ! Discrete states - integer, intent(in ) :: indx ! index into m%BEMT_u(indx) array; 1=t and 2=t+dt (but not checked here) - integer, intent(in ) :: iRot ! Rotor index, needed for FVW - INTEGER(IntKi), INTENT( OUT) :: ErrStat ! The error status code - CHARACTER(*), INTENT( OUT) :: ErrMsg ! The error message, if an error occurred + TYPE(RotParameterType), INTENT(IN ) :: p ! The rotor parameters + TYPE(AD_ParameterType), INTENT(IN ) :: p_AD ! The module parameters + TYPE(RotInputType), INTENT(IN ) :: u ! inputs + TYPE(RotMiscVarType), INTENT(INOUT) :: m ! misc variables + TYPE(AD_MiscVarType), INTENT(INOUT) :: m_AD ! misc variables + TYPE(RotOutputType), INTENT(IN ) :: y ! outputs + TYPE(RotOtherStateType), INTENT(IN ) :: OtherState ! other states at t (for DBEMT and UA) + TYPE(RotDiscreteStateType), INTENT(IN ) :: xd ! Discrete states + integer, intent(in ) :: indx ! index into m%BEMT_u(indx) array; 1=t and 2=t+dt (but not checked here) + integer, intent(in ) :: iRot ! Rotor index, needed for FVW + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! The error status code + CHARACTER(*), INTENT( OUT) :: ErrMsg ! The error message, if an error occurred ! local variables - CHARACTER(*), PARAMETER :: RoutineName = 'Calc_WriteOutput' - INTEGER(intKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - - INTEGER(IntKi) :: j,k,beta - REAL(ReKi) :: tmp(3) - REAL(ReKi) :: force(3) - REAL(ReKi) :: moment(3) - REAL(ReKi) :: denom, rmax - REAL(ReKi) :: ct, st ! cosine, sine of theta - REAL(ReKi) :: cp, sp ! cosine, sine of phi - + CHARACTER(*), PARAMETER :: RoutineName = 'Calc_WriteOutput' + INTEGER(intKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + INTEGER(IntKi) :: j,k,beta + REAL(ReKi) :: tmp(3) + REAL(ReKi) :: force(3) + REAL(ReKi) :: moment(3) + REAL(ReKi) :: denom, rmax, omega + REAL(ReKi) :: ct, st ! cosine, sine of theta + REAL(ReKi) :: cp, sp ! cosine, sine of phi + ! start routine: ErrStat = ErrID_None ErrMsg = "" - ! tower outputs - do beta=1,p%NTwOuts - j = p%TwOutNd(beta) - - tmp = matmul( u%TowerMotion%Orientation(:,:,j) , u%InflowOnTower(:,j) ) - m%AllOuts( TwNVUnd(:,beta) ) = tmp - - tmp = matmul( u%TowerMotion%Orientation(:,:,j) , u%TowerMotion%TranslationVel(:,j) ) - m%AllOuts( TwNSTV(:,beta) ) = tmp - - m%AllOuts( TwNVrel(beta) ) = m%W_Twr(j) ! relative velocity - m%AllOuts( TwNDynP(beta) ) = 0.5 * p%AirDens * m%W_Twr(j)**2 ! dynamic pressure - m%AllOuts( TwNRe( beta) ) = p%TwrDiam(j) * m%W_Twr(j) / p%KinVisc / 1.0E6 ! reynolds number (in millions) - m%AllOuts( TwNM( beta) ) = m%W_Twr(j) / p%SpdSound ! Mach number - m%AllOuts( TwNFdx( beta) ) = m%X_Twr(j) - m%AllOuts( TwNFdy( beta) ) = m%Y_Twr(j) - - end do ! out nodes + ! Compute max radius and rotor speed if (p_AD%WakeMod /= WakeMod_FVW) then - call Calc_WriteOutput_BEMT + rmax = 0.0_ReKi + do k=1,p%NumBlades + do j=1,p%NumBlNds + rmax = max(rmax, m%BEMT_u(indx)%rLocal(j,k) ) + end do !j=nodes + end do !k=blades + +! rmax = p%BEMT%rTipFixMax + omega = m%BEMT_u(indx)%omega else - call Calc_WriteOutput_FVW + rmax = Calc_MaxRadius(p, u) + omega = Calc_Omega(u) endif + + call Calc_WriteOutput_AD() ! need to call this before calling the BEMT vs FVW versions of outputs so that the integrated output quantities are known + + if (p_AD%WakeMod /= WakeMod_FVW) then + call Calc_WriteOutput_BEMT() + else + call Calc_WriteOutput_FVW() + endif - ! blade node tower clearance (requires tower influence calculation): - if (p%TwrPotent /= TwrPotent_none .or. p%TwrShadow /= TwrShadow_none) then - do k=1,p%numBlades - do beta=1,p%NBlOuts - j=p%BlOutNd(beta) - m%AllOuts( BNClrnc( beta,k) ) = m%TwrClrnc(j,k) - end do - end do - end if + ! set these for debugging +! m%AllOuts( Debug1 ) = 0.0_ReKi !TwoNorm( m%BEMT%u_SkewWake(1)%v_qsw ) +! m%AllOuts( Debug2 ) = 0.0_ReKi !TwoNorm( x%BEMT%v_w ) +! m%AllOuts( Debug3 ) = 0.0_ReKi CONTAINS !.......................................................................................... - subroutine Calc_WriteOutput_BEMT - real(ReKi) :: omega - omega = m%BEMT_u(indx)%omega + subroutine Calc_WriteOutput_AD() + + ! tower outputs + do beta=1,p%NTwOuts + j = p%TwOutNd(beta) + + tmp = matmul( u%TowerMotion%Orientation(:,:,j) , u%InflowOnTower(:,j) ) + m%AllOuts( TwNVUnd(:,beta) ) = tmp + + tmp = matmul( u%TowerMotion%Orientation(:,:,j) , u%TowerMotion%TranslationVel(:,j) ) + m%AllOuts( TwNSTV(:,beta) ) = tmp + + m%AllOuts( TwNVrel(beta) ) = m%W_Twr(j) ! relative velocity + m%AllOuts( TwNDynP(beta) ) = 0.5 * p%AirDens * m%W_Twr(j)**2 ! dynamic pressure + m%AllOuts( TwNRe( beta) ) = p%TwrDiam(j) * m%W_Twr(j) / p%KinVisc / 1.0E6 ! reynolds number (in millions) + m%AllOuts( TwNM( beta) ) = m%W_Twr(j) / p%SpdSound ! Mach number + m%AllOuts( TwNFdx( beta) ) = m%X_Twr(j) + m%AllOuts( TwNFdy( beta) ) = m%Y_Twr(j) + + end do ! out nodes + ! blade outputs do k=1,min(p%numBlades,3) ! limit this - m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi(k)*R2D, 360.0_ReKi ) - ! m%AllOuts( BPitch( k) ) = calculated in SetInputsForBEMT - do beta=1,p%NBlOuts - j=p%BlOutNd(beta) tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%InflowOnBlade(:,j,k) ) @@ -1753,72 +1761,39 @@ subroutine Calc_WriteOutput_BEMT m%AllOuts( BNSTVx( beta,k) ) = tmp(1) m%AllOuts( BNSTVy( beta,k) ) = tmp(2) m%AllOuts( BNSTVz( beta,k) ) = tmp(3) - - m%AllOuts( BNVrel( beta,k) ) = m%BEMT_y%Vrel(j,k) - m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m%BEMT_y%Vrel(j,k)**2 - m%AllOuts( BNRe( beta,k) ) = p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) / p%KinVisc / 1.0E6 - m%AllOuts( BNM( beta,k) ) = m%BEMT_y%Vrel(j,k) / p%SpdSound - - m%AllOuts( BNVIndx(beta,k) ) = - m%BEMT_u(indx)%Vx(j,k) * m%BEMT_y%axInduction( j,k) - m%AllOuts( BNVIndy(beta,k) ) = m%BEMT_u(indx)%Vy(j,k) * m%BEMT_y%tanInduction(j,k) - - m%AllOuts( BNAxInd(beta,k) ) = m%BEMT_y%axInduction(j,k) - m%AllOuts( BNTnInd(beta,k) ) = m%BEMT_y%tanInduction(j,k) - - m%AllOuts( BNAlpha(beta,k) ) = Rad2M180to180Deg( m%BEMT_y%phi(j,k) - m%BEMT_u(indx)%theta(j,k) ) - m%AllOuts( BNTheta(beta,k) ) = m%BEMT_u(indx)%theta(j,k)*R2D - m%AllOuts( BNPhi( beta,k) ) = m%BEMT_y%phi(j,k)*R2D + m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D - - !m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cl(j,k) - !m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cd(j,k) - - m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(j,k) + m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) - cp=cos(m%BEMT_y%phi(j,k)) - sp=sin(m%BEMT_y%phi(j,k)) - m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cx(j,k)*cp + m%BEMT_y%Cy(j,k)*sp - m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cx(j,k)*sp - m%BEMT_y%Cy(j,k)*cp - m%AllOuts( BNCm( beta,k) ) = m%BEMT_y%Cm(j,k) - m%AllOuts( BNCx( beta,k) ) = m%BEMT_y%Cx(j,k) - m%AllOuts( BNCy( beta,k) ) = m%BEMT_y%Cy(j,k) - - ct=cos(m%BEMT_u(indx)%theta(j,k)) - st=sin(m%BEMT_u(indx)%theta(j,k)) - m%AllOuts( BNCn( beta,k) ) = m%BEMT_y%Cx(j,k)*ct + m%BEMT_y%Cy(j,k)*st - m%AllOuts( BNCt( beta,k) ) =-m%BEMT_y%Cx(j,k)*st + m%BEMT_y%Cy(j,k)*ct - - m%AllOuts( BNFl( beta,k) ) = m%X(j,k)*cp - m%Y(j,k)*sp - m%AllOuts( BNFd( beta,k) ) = m%X(j,k)*sp + m%Y(j,k)*cp - m%AllOuts( BNMm( beta,k) ) = m%M(j,k) - m%AllOuts( BNFx( beta,k) ) = m%X(j,k) - m%AllOuts( BNFy( beta,k) ) = -m%Y(j,k) - m%AllOuts( BNFn( beta,k) ) = m%X(j,k)*ct - m%Y(j,k)*st - m%AllOuts( BNFt( beta,k) ) = -m%X(j,k)*st - m%Y(j,k)*ct - - m%AllOuts( BNGam( beta,k) ) = 0.5_ReKi * p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) * m%BEMT_y%Cl(j,k) ! "Gam" [m^2/s] end do ! nodes end do ! blades + - ! rotor outputs: - rmax = 0.0_ReKi - do k=1,p%NumBlades - do j=1,p%NumBlNds - rmax = max(rmax, m%BEMT_u(indx)%rLocal(j,k) ) - end do !j=nodes - end do !k=blades - m%AllOuts( RtSpeed ) = m%BEMT_u(indx)%omega*RPS2RPM - m%AllOuts( RtArea ) = pi*rmax**2 + ! blade node tower clearance (requires tower influence calculation): + if (p%TwrPotent /= TwrPotent_none .or. p%TwrShadow /= TwrShadow_none) then + do k=1,p%numBlades + do beta=1,p%NBlOuts + j=p%BlOutNd(beta) + m%AllOuts( BNClrnc( beta,k) ) = m%TwrClrnc(j,k) + end do + end do + end if + + + + m%AllOuts( RtSpeed ) = omega*RPS2RPM + m%AllOuts( RtArea ) = pi * rmax**2 + tmp = matmul( u%HubMotion%Orientation(:,:,1), m%V_DiskAvg ) m%AllOuts( RtVAvgxh ) = tmp(1) m%AllOuts( RtVAvgyh ) = tmp(2) m%AllOuts( RtVAvgzh ) = tmp(3) - m%AllOuts( RtSkew ) = m%BEMT_u(indx)%chi0*R2D + ! integrate force/moments over blades by performing mesh transfer to hub point: force = 0.0_ReKi @@ -1827,76 +1802,155 @@ subroutine Calc_WriteOutput_BEMT call Transfer_Line2_to_Point( y%BladeLoad(k), m%HubLoad, m%B_L_2_H_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%HubMotion ) force = force + m%HubLoad%force( :,1) moment = moment + m%HubLoad%moment(:,1) - - if (k<=4) then + + if (k<=size(BAeroFxg)) then ! Power contribution of blade wrt hub tmp = matmul( u%HubMotion%Orientation(:,:,1), m%HubLoad%moment(:,1) ) - m%AllOuts( BAeroPwr(k) ) = omega * tmp(1) - - ! In global, wrt hub! + m%AllOuts( BAeroPwr(k) ) = omega * tmp(1) + + ! In global, wrt hub! m%AllOuts( BAeroFxg(k) ) = m%HubLoad%force(1,1) m%AllOuts( BAeroFyg(k) ) = m%HubLoad%force(2,1) m%AllOuts( BAeroFzg(k) ) = m%HubLoad%force(3,1) m%AllOuts( BAeroMxg(k) ) = m%HubLoad%moment(1,1) m%AllOuts( BAeroMyg(k) ) = m%HubLoad%moment(2,1) m%AllOuts( BAeroMzg(k) ) = m%HubLoad%moment(3,1) - - endif + end if end do - ! In global + + ! In global m%AllOuts( RtAeroFxg ) = force(1) m%AllOuts( RtAeroFyg ) = force(2) m%AllOuts( RtAeroFzg ) = force(3) m%AllOuts( RtAeroMxg ) = moment(1) m%AllOuts( RtAeroMyg ) = moment(2) m%AllOuts( RtAeroMzg ) = moment(3) - ! In hub coord tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) m%AllOuts( RtAeroFxh ) = tmp(1) m%AllOuts( RtAeroFyh ) = tmp(2) m%AllOuts( RtAeroFzh ) = tmp(3) - + tmp = matmul( u%HubMotion%Orientation(:,:,1), moment ) m%AllOuts( RtAeroMxh ) = tmp(1) m%AllOuts( RtAeroMyh ) = tmp(2) m%AllOuts( RtAeroMzh ) = tmp(3) - - m%AllOuts( RtAeroPwr ) = m%BEMT_u(indx)%omega * m%AllOuts( RtAeroMxh ) - - - - m%AllOuts( RtTSR ) = m%BEMT_u(indx)%TSR - - if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then - m%AllOuts( RtTSR ) = 0.0_ReKi - m%AllOuts( RtAeroCp ) = 0.0_ReKi - m%AllOuts( RtAeroCq ) = 0.0_ReKi - m%AllOuts( RtAeroCt ) = 0.0_ReKi - else - denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 - m%AllOuts( RtTSR ) = m%BEMT_u(indx)%omega * rmax / m%V_dot_x - - m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) - m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) - m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom - end if + + m%AllOuts( RtAeroPwr ) = omega * m%AllOuts( RtAeroMxh ) + + ! Integrate force/moments over blades by performing mesh transfer to blade root points: - do k=1,min(p%NumBlades,4) ! Temporary hack for at least one more blae outputs + do k=1,p%NumBlades call Transfer_Line2_to_Point( y%BladeLoad(k), m%BladeRootLoad(k), m%B_L_2_R_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%BladeRootMotion(k) ) + end do + do k=1,min(p%NumBlades,size(BAeroFx)) ! Transform force vector to blade root coordinate system tmp = matmul( u%BladeRootMotion(k)%Orientation(:,:,1), m%BladeRootLoad(k)%force( :,1) ) m%AllOuts( BAeroFx(k) ) = tmp(1) m%AllOuts( BAeroFy(k) ) = tmp(2) m%AllOuts( BAeroFz(k) ) = tmp(3) + ! Transform moment vector to blade root coordinate system tmp = matmul( u%BladeRootMotion(k)%Orientation(:,:,1), m%BladeRootLoad(k)%moment( :,1) ) m%AllOuts( BAeroMx(k) ) = tmp(1) m%AllOuts( BAeroMy(k) ) = tmp(2) m%AllOuts( BAeroMz(k) ) = tmp(3) - end do ! k=blades + end do ! k=blades + + ! rotor outputs + if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then + m%AllOuts( RtTSR ) = 0.0_ReKi + m%AllOuts( RtAeroCp ) = 0.0_ReKi + m%AllOuts( RtAeroCq ) = 0.0_ReKi + m%AllOuts( RtAeroCt ) = 0.0_ReKi + else + m%AllOuts( RtTSR ) = omega * rmax / m%V_dot_x + + denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 + m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) + m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax ) + m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom + end if + + + end subroutine Calc_WriteOutput_AD + !.......................................................................................... + subroutine Calc_WriteOutput_BEMT() + REAL(R8Ki) :: orient(3,3) + REAL(R8Ki) :: theta(3) + REAL(ReKi) :: denom !, rmax + REAL(ReKi) :: ct, st ! cosine, sine of theta + REAL(ReKi) :: cp, sp ! cosine, sine of phi + + + + + ! blade outputs + do k=1,min(p%numBlades,size(BAzimuth) ) ! limit this + m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi(k)*R2D, 360.0_ReKi ) + ! m%AllOuts( BPitch( k) ) = calculated in SetInputsForBEMT + + do beta=1,p%NBlOuts + + j=p%BlOutNd(beta) + + m%AllOuts( BNVrel( beta,k) ) = m%BEMT_y%Vrel(j,k) + m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m%BEMT_y%Vrel(j,k)**2 + m%AllOuts( BNRe( beta,k) ) = p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) / p%KinVisc / 1.0E6 + m%AllOuts( BNM( beta,k) ) = m%BEMT_y%Vrel(j,k) / p%SpdSound + + m%AllOuts( BNVIndx(beta,k) ) = - m%BEMT_u(indx)%Vx(j,k) * m%BEMT_y%axInduction( j,k) + m%AllOuts( BNVIndy(beta,k) ) = m%BEMT_u(indx)%Vy(j,k) * m%BEMT_y%tanInduction(j,k) + + m%AllOuts( BNAxInd(beta,k) ) = m%BEMT_y%axInduction(j,k) + m%AllOuts( BNTnInd(beta,k) ) = m%BEMT_y%tanInduction(j,k) + + m%AllOuts( BNAlpha(beta,k) ) = Rad2M180to180Deg( m%BEMT_y%phi(j,k) - m%BEMT_u(indx)%theta(j,k) ) + m%AllOuts( BNTheta(beta,k) ) = m%BEMT_u(indx)%theta(j,k)*R2D + m%AllOuts( BNPhi( beta,k) ) = m%BEMT_y%phi(j,k)*R2D + + ! m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D + + m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(j,k) + ! m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) + ! m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) + + !m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cl(j,k) + !m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cd(j,k) + cp=cos(m%BEMT_y%phi(j,k)) + sp=sin(m%BEMT_y%phi(j,k)) + m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cx(j,k)*cp + m%BEMT_y%Cy(j,k)*sp + m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cx(j,k)*sp - m%BEMT_y%Cy(j,k)*cp + m%AllOuts( BNCm( beta,k) ) = m%BEMT_y%Cm(j,k) + m%AllOuts( BNCx( beta,k) ) = m%BEMT_y%Cx(j,k) + m%AllOuts( BNCy( beta,k) ) = m%BEMT_y%Cy(j,k) + + ct=cos(m%BEMT_u(indx)%theta(j,k)) + st=sin(m%BEMT_u(indx)%theta(j,k)) + m%AllOuts( BNCn( beta,k) ) = m%BEMT_y%Cx(j,k)*ct + m%BEMT_y%Cy(j,k)*st + m%AllOuts( BNCt( beta,k) ) =-m%BEMT_y%Cx(j,k)*st + m%BEMT_y%Cy(j,k)*ct + + m%AllOuts( BNFl( beta,k) ) = m%X(j,k)*cp - m%Y(j,k)*sp + m%AllOuts( BNFd( beta,k) ) = m%X(j,k)*sp + m%Y(j,k)*cp + m%AllOuts( BNMm( beta,k) ) = m%M(j,k) + m%AllOuts( BNFx( beta,k) ) = m%X(j,k) + m%AllOuts( BNFy( beta,k) ) = -m%Y(j,k) + m%AllOuts( BNFn( beta,k) ) = m%X(j,k)*ct - m%Y(j,k)*st + m%AllOuts( BNFt( beta,k) ) = -m%X(j,k)*st - m%Y(j,k)*ct + + m%AllOuts( BNGam( beta,k) ) = 0.5_ReKi * p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) * m%BEMT_y%Cl(j,k) ! "Gam" [m^2/s] + + end do ! nodes + end do ! blades + + + ! rotor outputs: + + m%AllOuts( RtSkew ) = m%BEMT_u(indx)%chi0*R2D +! m%AllOuts( RtTSR ) = m%BEMT_u(indx)%TSR m%AllOuts( DBEMTau1 ) = OtherState%BEMT%DBEMT%tau1 + end subroutine Calc_WriteOutput_BEMT @@ -1907,11 +1961,6 @@ end subroutine Calc_WriteOutput_BEMT !! Make sure these are set! subroutine Calc_WriteOutput_FVW integer :: iW - real(ReKi) :: rmax, omega - - ! Compute max radius and rotor speed - rmax = Calc_MaxRadius(p, u) - omega = Calc_Omega(u) ! blade outputs do k=1,min(p%numBlades,3) @@ -1920,22 +1969,6 @@ subroutine Calc_WriteOutput_FVW do beta=1,p%NBlOuts j=p%BlOutNd(beta) - ! --- Setting AD outputs - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%InflowOnBlade(:,j,k) ) - m%AllOuts( BNVUndx(beta,k) ) = tmp(1) - m%AllOuts( BNVUndy(beta,k) ) = tmp(2) - m%AllOuts( BNVUndz(beta,k) ) = tmp(3) - - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), m%DisturbedInflow(:,j,k) ) - m%AllOuts( BNVDisx(beta,k) ) = tmp(1) - m%AllOuts( BNVDisy(beta,k) ) = tmp(2) - m%AllOuts( BNVDisz(beta,k) ) = tmp(3) - - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%BladeMotion(k)%TranslationVel(:,j) ) - m%AllOuts( BNSTVx( beta,k) ) = tmp(1) - m%AllOuts( BNSTVy( beta,k) ) = tmp(2) - m%AllOuts( BNSTVz( beta,k) ) = tmp(3) - m%AllOuts( BNVrel( beta,k) ) = m_AD%FVW%W(iW)%BN_Vrel(j) m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m_AD%FVW%W(iW)%BN_Vrel(j)**2 m%AllOuts( BNRe( beta,k) ) = m_AD%FVW%W(iW)%BN_Re(j) / 1.0E6 @@ -1952,10 +1985,7 @@ subroutine Calc_WriteOutput_FVW m%AllOuts( BNPhi( beta,k) ) = m_AD%FVW%W(iW)%BN_phi(j)*R2D ! m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D ! TODO -! m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(jk) ! TODO - m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) - m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) - + m%AllOuts( BNCpmin(beta,k) ) = m_AD%FVW%W(iW)%BN_Cpmin(j) m%AllOuts( BNCl( beta,k) ) = m_AD%FVW%W(iW)%BN_Cl(j) m%AllOuts( BNCd( beta,k) ) = m_AD%FVW%W(iW)%BN_Cd(j) m%AllOuts( BNCm( beta,k) ) = m_AD%FVW%W(iW)%BN_Cm(j) @@ -1982,84 +2012,10 @@ subroutine Calc_WriteOutput_FVW end do ! blades - m%AllOuts( RtSpeed ) = omega*RPS2RPM - m%AllOuts( RtArea ) = pi*rmax**2 ! TODO vertical axis - - tmp = matmul( u%HubMotion%Orientation(:,:,1), m%V_DiskAvg ) - m%AllOuts( RtVAvgxh ) = tmp(1) - m%AllOuts( RtVAvgyh ) = tmp(2) - m%AllOuts( RtVAvgzh ) = tmp(3) - +! m%AllOuts( RtArea ) = pi*rmax**2 ! TODO vertical axis m%AllOuts( RtSkew ) = Calc_Chi0(m%V_diskAvg, m%V_dot_x) * R2D - ! integrate force/moments over blades by performing mesh transfer to hub point: - force = 0.0_ReKi - moment = 0.0_ReKi - do k=1,p%NumBlades - call Transfer_Line2_to_Point( y%BladeLoad(k), m%HubLoad, m%B_L_2_H_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%HubMotion ) - force = force + m%HubLoad%force( :,1) - moment = moment + m%HubLoad%moment(:,1) - - if (k<=4) then - ! Power contribution of blade wrt hub - tmp = matmul( u%HubMotion%Orientation(:,:,1), m%HubLoad%moment(:,1) ) - m%AllOuts( BAeroPwr(k) ) = omega * tmp(1) - ! In global, wrt hub! - m%AllOuts( BAeroFxg(k) ) = m%HubLoad%force(1,1) - m%AllOuts( BAeroFyg(k) ) = m%HubLoad%force(2,1) - m%AllOuts( BAeroFzg(k) ) = m%HubLoad%force(3,1) - m%AllOuts( BAeroMxg(k) ) = m%HubLoad%moment(1,1) - m%AllOuts( BAeroMyg(k) ) = m%HubLoad%moment(2,1) - m%AllOuts( BAeroMzg(k) ) = m%HubLoad%moment(3,1) - endif - end do - ! In global - m%AllOuts( RtAeroFxg ) = force(1) - m%AllOuts( RtAeroFyg ) = force(2) - m%AllOuts( RtAeroFzg ) = force(3) - m%AllOuts( RtAeroMxg ) = moment(1) - m%AllOuts( RtAeroMyg ) = moment(2) - m%AllOuts( RtAeroMzg ) = moment(3) - ! In hub coord - tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) - m%AllOuts( RtAeroFxh ) = tmp(1) - m%AllOuts( RtAeroFyh ) = tmp(2) - m%AllOuts( RtAeroFzh ) = tmp(3) - - tmp = matmul( u%HubMotion%Orientation(:,:,1), moment ) - m%AllOuts( RtAeroMxh ) = tmp(1) - m%AllOuts( RtAeroMyh ) = tmp(2) - m%AllOuts( RtAeroMzh ) = tmp(3) - - m%AllOuts( RtAeroPwr ) = omega * m%AllOuts( RtAeroMxh ) - - if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then - m%AllOuts( RtTSR ) = 0.0_ReKi - m%AllOuts( RtAeroCp ) = 0.0_ReKi - m%AllOuts( RtAeroCq ) = 0.0_ReKi - m%AllOuts( RtAeroCt ) = 0.0_ReKi - else - denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 - m%AllOuts( RtTSR ) = omega * rmax / m%V_dot_x - m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) - m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) - m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom - end if - - ! Integrate force/moments over blades by performing mesh transfer to blade root points: - do k=1,min(p%NumBlades,4) - call Transfer_Line2_to_Point( y%BladeLoad(k), m%BladeRootLoad(k), m%B_L_2_R_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%BladeRootMotion(k) ) - ! Transform force vector to blade root coordinate system - tmp = matmul( u%BladeRootMotion(k)%Orientation(:,:,1), m%BladeRootLoad(k)%force( :,1) ) - m%AllOuts( BAeroFx(k) ) = tmp(1) - m%AllOuts( BAeroFy(k) ) = tmp(2) - m%AllOuts( BAeroFz(k) ) = tmp(3) - ! Transform moment vector to blade root coordinate system - tmp = matmul( u%BladeRootMotion(k)%Orientation(:,:,1), m%BladeRootLoad(k)%moment( :,1) ) - m%AllOuts( BAeroMx(k) ) = tmp(1) - m%AllOuts( BAeroMy(k) ) = tmp(2) - m%AllOuts( BAeroMz(k) ) = tmp(3) - end do ! k=blades +! m%AllOuts( DBEMTau1 ) = 0.0_ReKi ! not valid with FVW end subroutine Calc_WriteOutput_FVW @@ -2744,6 +2700,8 @@ SUBROUTINE AD_PrintSum( InputFileData, p, p_AD, u, y, ErrStat, ErrMsg ) ! SkewMod select case (InputFileData%SkewMod) + case (SkewMod_Orthogonal) + Msg = 'orthogonal' case (SkewMod_Uncoupled) Msg = 'uncoupled' case (SkewMod_PittPeters) diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index c196e6b733..3b32ea94f2 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -124,7 +124,7 @@ typedef ^ AD_InputFile ReKi KinVisc - - - "Kinematic air viscosity" m^2/s typedef ^ AD_InputFile ReKi Patm - - - "Atmospheric pressure" Pa typedef ^ AD_InputFile ReKi Pvap - - - "Vapour pressure" Pa typedef ^ AD_InputFile ReKi SpdSound - - - "Speed of sound" m/s -typedef ^ AD_InputFile IntKi SkewMod - - - "Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0]" - +typedef ^ AD_InputFile IntKi SkewMod - - - "Type of skewed-wake correction model {0=orthogonal, 1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0]" - typedef ^ AD_InputFile ReKi SkewModFactor - - - "Constant used in Pitt/Peters skewed wake model (default is 15*pi/32)" - typedef ^ AD_InputFile LOGICAL TipLoss - - - "Use the Prandtl tip-loss model? [unused when WakeMod=0]" flag typedef ^ AD_InputFile LOGICAL HubLoss - - - "Use the Prandtl hub-loss model? [unused when WakeMod=0]" flag @@ -284,6 +284,7 @@ typedef ^ ParameterType RotParameterType rotors {:} - - "Parameter types for typedef ^ ParameterType DbKi DT - - - "Time step for continuous state integration & discrete state update" seconds typedef ^ ParameterType CHARACTER(1024) RootName - - - "RootName for writing output files" - typedef ^ ParameterType AFI_ParameterType AFI {:} - - "AirfoilInfo parameters" +typedef ^ ParameterType IntKi SkewMod - - - "Type of skewed-wake correction model {0=orthogonal, 1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0]" - typedef ^ ParameterType IntKi WakeMod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW}" - typedef ^ ParameterType FVW_ParameterType FVW - - - "Parameters for FVW module" typedef ^ ParameterType LOGICAL UA_Flag - - - "logical flag indicating whether to use UnsteadyAero" - diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 8fe6792526..677430d4ca 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -152,7 +152,7 @@ MODULE AeroDyn_Types REAL(ReKi) :: Patm !< Atmospheric pressure [Pa] REAL(ReKi) :: Pvap !< Vapour pressure [Pa] REAL(ReKi) :: SpdSound !< Speed of sound [m/s] - INTEGER(IntKi) :: SkewMod !< Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0] [-] + INTEGER(IntKi) :: SkewMod !< Type of skewed-wake correction model {0=orthogonal, 1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0] [-] REAL(ReKi) :: SkewModFactor !< Constant used in Pitt/Peters skewed wake model (default is 15*pi/32) [-] LOGICAL :: TipLoss !< Use the Prandtl tip-loss model? [unused when WakeMod=0] [flag] LOGICAL :: HubLoss !< Use the Prandtl hub-loss model? [unused when WakeMod=0] [flag] @@ -328,6 +328,7 @@ MODULE AeroDyn_Types REAL(DbKi) :: DT !< Time step for continuous state integration & discrete state update [seconds] CHARACTER(1024) :: RootName !< RootName for writing output files [-] TYPE(AFI_ParameterType) , DIMENSION(:), ALLOCATABLE :: AFI !< AirfoilInfo parameters [-] + INTEGER(IntKi) :: SkewMod !< Type of skewed-wake correction model {0=orthogonal, 1=uncoupled, 2=Pitt/Peters, 3=coupled} [unused when WakeMod=0] [-] INTEGER(IntKi) :: WakeMod !< Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW} [-] TYPE(FVW_ParameterType) :: FVW !< Parameters for FVW module [-] LOGICAL :: UA_Flag !< logical flag indicating whether to use UnsteadyAero [-] @@ -11174,6 +11175,7 @@ SUBROUTINE AD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) IF (ErrStat>=AbortErrLev) RETURN ENDDO ENDIF + DstParamData%SkewMod = SrcParamData%SkewMod DstParamData%WakeMod = SrcParamData%WakeMod CALL FVW_CopyParam( SrcParamData%FVW, DstParamData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) @@ -11289,6 +11291,7 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si END IF END DO END IF + Int_BufSz = Int_BufSz + 1 ! SkewMod Int_BufSz = Int_BufSz + 1 ! WakeMod Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype CALL FVW_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW @@ -11423,6 +11426,8 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si ENDIF END DO END IF + IntKiBuf(Int_Xferred) = InData%SkewMod + Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%WakeMod Int_Xferred = Int_Xferred + 1 CALL FVW_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW @@ -11602,6 +11607,8 @@ SUBROUTINE AD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END DO END IF + OutData%SkewMod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 OutData%WakeMod = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 Buf_size=IntKiBuf( Int_Xferred ) diff --git a/modules/aerodyn/src/BEMTUncoupled.f90 b/modules/aerodyn/src/BEMTUncoupled.f90 index ea760fd74e..1107f48aa6 100644 --- a/modules/aerodyn/src/BEMTUncoupled.f90 +++ b/modules/aerodyn/src/BEMTUncoupled.f90 @@ -30,6 +30,7 @@ module BEMTUnCoupled implicit none + integer(IntKi), public, parameter :: SkewMod_Orthogonal = 0 ! Inflow orthogonal to rotor [-] integer(IntKi), public, parameter :: SkewMod_Uncoupled = 1 ! Uncoupled (no correction) [-] integer(IntKi), public, parameter :: SkewMod_PittPeters = 2 ! Pitt/Peters [-] integer(IntKi), public, parameter :: SkewMod_Coupled = 3 ! Coupled [-] diff --git a/modules/aerodyn/src/FVW.f90 b/modules/aerodyn/src/FVW.f90 index 1e0b97173f..64aecb29c7 100644 --- a/modules/aerodyn/src/FVW.f90 +++ b/modules/aerodyn/src/FVW.f90 @@ -240,6 +240,7 @@ subroutine FVW_InitMiscVars( p, m, ErrStat, ErrMsg ) call AllocAry( m%W(iW)%BN_Cl_Static , p%W(iW)%nSpan+1 , 'Coefficient lift - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cl_Static = -999999_ReKi; call AllocAry( m%W(iW)%BN_Cd_Static , p%W(iW)%nSpan+1 , 'Coefficient drag - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cd_Static = -999999_ReKi; call AllocAry( m%W(iW)%BN_Cm_Static , p%W(iW)%nSpan+1 , 'Coefficient moment - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cm_Static = -999999_ReKi; + call AllocAry( m%W(iW)%BN_Cpmin , p%W(iW)%nSpan+1 , 'Coefficient minimum pressure - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cpmin = -999999_ReKi; call AllocAry( m%W(iW)%BN_Cl , p%W(iW)%nSpan+1 , 'Coefficient lift - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cl = -999999_ReKi; call AllocAry( m%W(iW)%BN_Cd , p%W(iW)%nSpan+1 , 'Coefficient drag - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cd = -999999_ReKi; call AllocAry( m%W(iW)%BN_Cm , p%W(iW)%nSpan+1 , 'Coefficient moment - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%W(iW)%BN_Cm = -999999_ReKi; diff --git a/modules/aerodyn/src/FVW_Registry.txt b/modules/aerodyn/src/FVW_Registry.txt index 4b820161e3..6083c2609d 100644 --- a/modules/aerodyn/src/FVW_Registry.txt +++ b/modules/aerodyn/src/FVW_Registry.txt @@ -165,6 +165,7 @@ typedef ^ ^ ReKi typedef ^ ^ ReKi BN_Cl_Static : - - "Coefficient lift, excluding unsteady aero effects" - typedef ^ ^ ReKi BN_Cd_Static : - - "Coefficient drag. excluding unsteady aero effects" - typedef ^ ^ ReKi BN_Cm_Static : - - "Coefficient moment, excluding unsteady aero effects" - +typedef ^ ^ ReKi BN_Cpmin : - - "Coefficient minimum pressure, excluding unsteady aero effects" - typedef ^ ^ ReKi BN_Cl : - - "Coefficient lift, including unsteady aero effects" - typedef ^ ^ ReKi BN_Cd : - - "Coefficient drag, including unsteady aero effects" - typedef ^ ^ ReKi BN_Cm : - - "Coefficient moment, including unsteady aero effects" - diff --git a/modules/aerodyn/src/FVW_Subs.f90 b/modules/aerodyn/src/FVW_Subs.f90 index 96b8be25ad..676f5ee445 100644 --- a/modules/aerodyn/src/FVW_Subs.f90 +++ b/modules/aerodyn/src/FVW_Subs.f90 @@ -1453,8 +1453,16 @@ subroutine FVW_AeroOuts( M_sg, M_ag, PitchAndTwist, Vstr_g, Vind_g, Vwnd_g, Kin Vwnd_s = matmul(M_sg, Vwnd_g) Urel_s = Vwnd_s - Vstr_s ! relative wind Vtot_s = Vwnd_s - Vstr_s + Vind_s - AxInd = -Vind_s(1)/Urel_s(1) - TanInd = Vind_s(2)/Urel_s(2) + if (EqualRealNos(Urel_s(1),0.0_ReKi)) then + AxInd = 0.0_ReKi + else + AxInd = -Vind_s(1)/Urel_s(1) + endif + if (EqualRealNos(Urel_s(2),0.0_ReKi)) then + TanInd = 0.0_ReKi + else + TanInd = Vind_s(2)/Urel_s(2) + end if phi = atan2( Vtot_s(1), Vtot_s(2) ) ! flow angle if(.false.) print*,PitchAndTwist ! just to avoid unused var for now diff --git a/modules/aerodyn/src/FVW_Types.f90 b/modules/aerodyn/src/FVW_Types.f90 index 72df451fa7..6f287de750 100644 --- a/modules/aerodyn/src/FVW_Types.f90 +++ b/modules/aerodyn/src/FVW_Types.f90 @@ -194,6 +194,7 @@ MODULE FVW_Types REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cl_Static !< Coefficient lift, excluding unsteady aero effects [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cd_Static !< Coefficient drag. excluding unsteady aero effects [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cm_Static !< Coefficient moment, excluding unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cpmin !< Coefficient minimum pressure, excluding unsteady aero effects [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cl !< Coefficient lift, including unsteady aero effects [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cd !< Coefficient drag, including unsteady aero effects [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BN_Cm !< Coefficient moment, including unsteady aero effects [-] @@ -4070,6 +4071,18 @@ SUBROUTINE FVW_CopyWng_MiscVarType( SrcWng_MiscVarTypeData, DstWng_MiscVarTypeDa END IF DstWng_MiscVarTypeData%BN_Cm_Static = SrcWng_MiscVarTypeData%BN_Cm_Static ENDIF +IF (ALLOCATED(SrcWng_MiscVarTypeData%BN_Cpmin)) THEN + i1_l = LBOUND(SrcWng_MiscVarTypeData%BN_Cpmin,1) + i1_u = UBOUND(SrcWng_MiscVarTypeData%BN_Cpmin,1) + IF (.NOT. ALLOCATED(DstWng_MiscVarTypeData%BN_Cpmin)) THEN + ALLOCATE(DstWng_MiscVarTypeData%BN_Cpmin(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstWng_MiscVarTypeData%BN_Cpmin.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstWng_MiscVarTypeData%BN_Cpmin = SrcWng_MiscVarTypeData%BN_Cpmin +ENDIF IF (ALLOCATED(SrcWng_MiscVarTypeData%BN_Cl)) THEN i1_l = LBOUND(SrcWng_MiscVarTypeData%BN_Cl,1) i1_u = UBOUND(SrcWng_MiscVarTypeData%BN_Cl,1) @@ -4248,6 +4261,9 @@ SUBROUTINE FVW_DestroyWng_MiscVarType( Wng_MiscVarTypeData, ErrStat, ErrMsg ) IF (ALLOCATED(Wng_MiscVarTypeData%BN_Cm_Static)) THEN DEALLOCATE(Wng_MiscVarTypeData%BN_Cm_Static) ENDIF +IF (ALLOCATED(Wng_MiscVarTypeData%BN_Cpmin)) THEN + DEALLOCATE(Wng_MiscVarTypeData%BN_Cpmin) +ENDIF IF (ALLOCATED(Wng_MiscVarTypeData%BN_Cl)) THEN DEALLOCATE(Wng_MiscVarTypeData%BN_Cl) ENDIF @@ -4539,6 +4555,11 @@ SUBROUTINE FVW_PackWng_MiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Int_BufSz = Int_BufSz + 2*1 ! BN_Cm_Static upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%BN_Cm_Static) ! BN_Cm_Static END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cpmin allocated yes/no + IF ( ALLOCATED(InData%BN_Cpmin) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! BN_Cpmin upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cpmin) ! BN_Cpmin + END IF Int_BufSz = Int_BufSz + 1 ! BN_Cl allocated yes/no IF ( ALLOCATED(InData%BN_Cl) ) THEN Int_BufSz = Int_BufSz + 2*1 ! BN_Cl upper/lower bounds for each dimension @@ -5320,6 +5341,21 @@ SUBROUTINE FVW_PackWng_MiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( .NOT. ALLOCATED(InData%BN_Cpmin) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cpmin,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cpmin,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%BN_Cpmin,1), UBOUND(InData%BN_Cpmin,1) + ReKiBuf(Re_Xferred) = InData%BN_Cpmin(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( .NOT. ALLOCATED(InData%BN_Cl) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -6302,6 +6338,24 @@ SUBROUTINE FVW_UnPackWng_MiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSt Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cpmin not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%BN_Cpmin)) DEALLOCATE(OutData%BN_Cpmin) + ALLOCATE(OutData%BN_Cpmin(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cpmin.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%BN_Cpmin,1), UBOUND(OutData%BN_Cpmin,1) + OutData%BN_Cpmin(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cl not allocated Int_Xferred = Int_Xferred + 1 ELSE diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index c1e6151630..1c8421c14f 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -348,9 +348,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ real(ReKi) :: q_minus1 ! real(ReKi) :: q_f_minus1 real(ReKi) :: Cn_pot_minus1 ! - real(ReKi) :: K3prime_q ! real(ReKi) :: k_mq ! - real(ReKi) :: Kprimeprime_q ! real(ReKi) :: dynamicFilterCutoffHz ! find frequency based on reduced frequency of k = BL_p%filtCutOff real(ReKi) :: LowPassConst @@ -512,19 +510,19 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%Cn_q_circ = 0.0_ReKi end if - K3prime_q = Get_ExpEqn( BL_p%b5*beta_M_Sqrd*KC%ds, 1.0_ReKi, xd%K3prime_q_minus1(i,j), BL_p%A5*(KC%q_f_cur - q_f_minus1), 0.0_ReKi ) ! Eqn 1.26 - KC%Cm_q_circ = -BL_p%C_nalpha*(KC%q_f_cur - K3prime_q)*p%c(i,j)/(16.0_ReKi*beta_M*u%U) ! Eqn 1.25 + KC%K3prime_q = Get_ExpEqn( BL_p%b5*beta_M_Sqrd*KC%ds, 1.0_ReKi, xd%K3prime_q_minus1(i,j), BL_p%A5*(KC%q_f_cur - q_f_minus1), 0.0_ReKi ) ! Eqn 1.26 + KC%Cm_q_circ = -BL_p%C_nalpha*(KC%q_f_cur - KC%K3prime_q)*p%c(i,j)/(16.0_ReKi*beta_M*u%U) ! Eqn 1.25 KC%Cn_pot = KC%Cn_alpha_q_circ + KC%Cn_alpha_q_nc ! Eqn 1.20 [2a] k_mq = 7.0_ReKi / (15.0_ReKi*(1.0_ReKi-M) + 1.5_ReKi * BL_p%C_nalpha * BL_p%A5 * BL_p%b5 * beta_M * M**2) ! Eqn 1.29 [2] ! CHECK THAT DENOM ISN'T ZERO! - Kprimeprime_q = Get_ExpEqn( real(p%dt,ReKi), k_mq**2*T_I , xd%Kprimeprime_q_minus1(i,j) , KC%Kq_f , Kq_f_minus1 ) ! Eqn 1.29 [3] + KC%Kprimeprime_q = Get_ExpEqn( real(p%dt,ReKi), k_mq**2*T_I , xd%Kprimeprime_q_minus1(i,j) , KC%Kq_f , Kq_f_minus1 ) ! Eqn 1.29 [3] ! Compute Cm_q_nc if ( p%UAMod == UA_MinnemaPierce ) then - KC%Cm_q_nc = -1.0_ReKi * KC%Cn_q_nc / 4.0_ReKi - (KC%k_alpha**2) * T_I * (KC%Kq_f - Kprimeprime_q) / (3.0_ReKi*M) ! Eqn 1.31 + KC%Cm_q_nc = -1.0_ReKi * KC%Cn_q_nc / 4.0_ReKi - (KC%k_alpha**2) * T_I * (KC%Kq_f - KC%Kprimeprime_q) / (3.0_ReKi*M) ! Eqn 1.31 else - KC%Cm_q_nc = -7.0_ReKi * (k_mq**2) * T_I * (KC%Kq_f - Kprimeprime_q) / (12.0_ReKi*M) ! Eqn 1.29 [1] + KC%Cm_q_nc = -7.0_ReKi * (k_mq**2) * T_I * (KC%Kq_f - KC%Kprimeprime_q) / (12.0_ReKi*M) ! Eqn 1.29 [1] end if if ( p%UAMod == UA_Gonzalez ) then @@ -2074,6 +2072,8 @@ subroutine UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrSt xd%X4_minus1(i,j) = KC%X4 xd%Kprime_alpha_minus1(i,j) = KC%Kprime_alpha xd%Kprime_q_minus1(i,j) = KC%Kprime_q + xd%K3prime_q_minus1(i,j) = KC%K3prime_q + xd%Kprimeprime_q_minus1(i,j)= KC%Kprimeprime_q xd%Dp_minus1(i,j) = KC%Dp xd%Cn_pot_minus1(i,j) = KC%Cn_pot xd%Cn_prime_minus1(i,j) = KC%Cn_prime diff --git a/modules/aerodyn/src/UnsteadyAero_Registry.txt b/modules/aerodyn/src/UnsteadyAero_Registry.txt index 613b543a81..733a4b46b3 100644 --- a/modules/aerodyn/src/UnsteadyAero_Registry.txt +++ b/modules/aerodyn/src/UnsteadyAero_Registry.txt @@ -69,6 +69,8 @@ typedef ^ UA_KelvinChainType ReKi typedef ^ UA_KelvinChainType ReKi X4 - - - "" - typedef ^ UA_KelvinChainType ReKi Kprime_alpha - - - "" - typedef ^ UA_KelvinChainType ReKi Kprime_q - - - "" - +typedef ^ UA_KelvinChainType ReKi K3prime_q - - - "" - +typedef ^ UA_KelvinChainType ReKi Kprimeprime_q - - - "" - typedef ^ UA_KelvinChainType ReKi Dp - - - "" - typedef ^ UA_KelvinChainType ReKi Cn_pot - - - "" - typedef ^ UA_KelvinChainType ReKi Cc_pot - - - "" - diff --git a/modules/aerodyn/src/UnsteadyAero_Types.f90 b/modules/aerodyn/src/UnsteadyAero_Types.f90 index d970c878be..48c47a9ffd 100644 --- a/modules/aerodyn/src/UnsteadyAero_Types.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Types.f90 @@ -83,6 +83,8 @@ MODULE UnsteadyAero_Types REAL(ReKi) :: X4 !< [-] REAL(ReKi) :: Kprime_alpha !< [-] REAL(ReKi) :: Kprime_q !< [-] + REAL(ReKi) :: K3prime_q !< [-] + REAL(ReKi) :: Kprimeprime_q !< [-] REAL(ReKi) :: Dp !< [-] REAL(ReKi) :: Cn_pot !< [-] REAL(ReKi) :: Cc_pot !< [-] @@ -950,6 +952,8 @@ SUBROUTINE UA_CopyKelvinChainType( SrcKelvinChainTypeData, DstKelvinChainTypeDat DstKelvinChainTypeData%X4 = SrcKelvinChainTypeData%X4 DstKelvinChainTypeData%Kprime_alpha = SrcKelvinChainTypeData%Kprime_alpha DstKelvinChainTypeData%Kprime_q = SrcKelvinChainTypeData%Kprime_q + DstKelvinChainTypeData%K3prime_q = SrcKelvinChainTypeData%K3prime_q + DstKelvinChainTypeData%Kprimeprime_q = SrcKelvinChainTypeData%Kprimeprime_q DstKelvinChainTypeData%Dp = SrcKelvinChainTypeData%Dp DstKelvinChainTypeData%Cn_pot = SrcKelvinChainTypeData%Cn_pot DstKelvinChainTypeData%Cc_pot = SrcKelvinChainTypeData%Cc_pot @@ -1047,6 +1051,8 @@ SUBROUTINE UA_PackKelvinChainType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_BufSz = Re_BufSz + 1 ! X4 Re_BufSz = Re_BufSz + 1 ! Kprime_alpha Re_BufSz = Re_BufSz + 1 ! Kprime_q + Re_BufSz = Re_BufSz + 1 ! K3prime_q + Re_BufSz = Re_BufSz + 1 ! Kprimeprime_q Re_BufSz = Re_BufSz + 1 ! Dp Re_BufSz = Re_BufSz + 1 ! Cn_pot Re_BufSz = Re_BufSz + 1 ! Cc_pot @@ -1140,6 +1146,10 @@ SUBROUTINE UA_PackKelvinChainType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%Kprime_q Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%K3prime_q + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Kprimeprime_q + Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%Dp Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%Cn_pot @@ -1266,6 +1276,10 @@ SUBROUTINE UA_UnPackKelvinChainType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta Re_Xferred = Re_Xferred + 1 OutData%Kprime_q = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%K3prime_q = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Kprimeprime_q = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 OutData%Dp = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%Cn_pot = ReKiBuf(Re_Xferred) diff --git a/modules/aerodyn14/CMakeLists.txt b/modules/aerodyn14/CMakeLists.txt index be1846cc91..58741a9281 100644 --- a/modules/aerodyn14/CMakeLists.txt +++ b/modules/aerodyn14/CMakeLists.txt @@ -45,7 +45,7 @@ set(DWM_SOURCES ) add_executable(dwm_driver_wind_farm ${DWM_SOURCES}) -target_link_libraries(dwm_driver_wind_farm aerodyn14lib) +target_link_libraries(dwm_driver_wind_farm aerodyn14lib versioninfolib) install(TARGETS dwm_driver_wind_farm RUNTIME DESTINATION bin diff --git a/modules/aerodyn14/src/DWM_driver_wind_farm_sub.f90 b/modules/aerodyn14/src/DWM_driver_wind_farm_sub.f90 index dae5c1a2da..b2492b0462 100644 --- a/modules/aerodyn14/src/DWM_driver_wind_farm_sub.f90 +++ b/modules/aerodyn14/src/DWM_driver_wind_farm_sub.f90 @@ -1,5 +1,6 @@ MODULE DWM_driver_wind_farm_sub USE NWTC_Library + USE VersionInfo IMPLICIT NONE !PUBLIC SUBROUTINES diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index 260a937899..4eaddf4b38 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -562,6 +562,8 @@ subroutine InitializeNodalLocations(member_total,kp_member,kp_coordinate,p,GLL_n else qfit = nkp ! if points-per-element more that number of keypoints, fit to LSFE with order (nkp-1) endif + + if (qfit .gt. 7) qfit = 7 call AllocAry(least_sq_gll, qfit, "least-squares GLL nodes",ErrStat2, ErrMsg2) @@ -6517,7 +6519,7 @@ SUBROUTINE BD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat END SUBROUTINE BD_JacobianPConstrState !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !> Routine to pack the data structures representing the operating points into arrays for linearization. -SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedLogMap ) +SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedPackedOrient ) REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(BD_InputType), INTENT(INOUT) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) @@ -6536,7 +6538,7 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, 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 - LOGICAL, OPTIONAL, INTENT(IN ) :: NeedLogMap !< whether a y_op values should contain log maps instead of full orientation matrices + LOGICAL, OPTIONAL, INTENT(IN ) :: NeedPackedOrient !< whether a y_op values should contain 3-value representation instead of full orientation matrices INTEGER(IntKi) :: index, i, dof INTEGER(IntKi) :: nu @@ -6545,7 +6547,7 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'BD_GetOP' LOGICAL :: FieldMask(FIELDMASK_SIZE) - LOGICAL :: ReturnLogMap + LOGICAL :: ReturnSmallAngle TYPE(BD_ContinuousStateType) :: dx ! derivative of continuous states at operating point @@ -6582,10 +6584,11 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, IF ( PRESENT( y_op ) ) THEN - if (present(NeedLogMap)) then - ReturnLogMap = NeedLogMap + ! Only the y operating points need to potentially return a smaller array than the "normal" call to this return. In the trim solution, we use a smaller array for y. + if (present(NeedPackedOrient)) then + ReturnSmallAngle = NeedPackedOrient else - ReturnLogMap = .false. + ReturnSmallAngle = .false. end if if (.not. allocated(y_op)) then @@ -6596,6 +6599,7 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, if (ErrStat >= AbortErrLev) return end if + if (ReturnSmallAngle) y_op = 0.0_ReKi ! initialize in case we are returning packed orientations and don't fill the entire array index = 1 call PackLoadMesh(y%ReactionForce, y_op, index) @@ -6607,7 +6611,7 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, FieldMask(MASKID_RotationVel) = .true. FieldMask(MASKID_TranslationAcc) = .true. FieldMask(MASKID_RotationAcc) = .true. - call PackMotionMesh(y%BldMotion, y_op, index, FieldMask=FieldMask, UseLogMaps=ReturnLogMap) + call PackMotionMesh(y%BldMotion, y_op, index, FieldMask=FieldMask, UseSmlAngle=ReturnSmallAngle) index = index - 1 do i=1,p%NumOuts + p%BldNd_TotNumOuts diff --git a/modules/beamdyn/src/BeamDyn_IO.f90 b/modules/beamdyn/src/BeamDyn_IO.f90 index 92af5a918c..c497b3f198 100644 --- a/modules/beamdyn/src/BeamDyn_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_IO.f90 @@ -2481,7 +2481,7 @@ SUBROUTINE Perturb_u( p, n, perturb_sign, u, du ) CASE ( 1) !Module/Mesh/Field: u%RootMotion%TranslationDisp = 1; u%RootMotion%TranslationDisp( fieldIndx,node) = u%RootMotion%TranslationDisp( fieldIndx,node) + du * perturb_sign CASE ( 2) !Module/Mesh/Field: u%RootMotion%Orientation = 2; - CALL PerturbOrientationMatrix( u%RootMotion%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%RootMotion%Orientation(:,:,node), du * perturb_sign, fieldIndx ) ! NOTE: call not using DCM_logmap CASE ( 3) !Module/Mesh/Field: u%RootMotion%TranslationVel = 3; u%RootMotion%TranslationVel( fieldIndx,node) = u%RootMotion%TranslationVel( fieldIndx,node) + du * perturb_sign CASE ( 4) !Module/Mesh/Field: u%RootMotion%RotationVel = 4; @@ -2561,8 +2561,8 @@ SUBROUTINE Perturb_x( p, fieldIndx, node, dof, perturb_sign, x, dx ) call BD_CrvMatrixR( x%q( 4:6, node ), rotation ) ! returns the rotation matrix (transpose of DCM) that was stored in the state as a w-m parameter orientation = transpose(rotation) - CALL PerturbOrientationMatrix( orientation, dx * perturb_sign, dof-3 ) - + CALL PerturbOrientationMatrix( orientation, dx * perturb_sign, dof-3 ) ! NOTE: call not using DCM_logmap + rotation = transpose(orientation) call BD_CrvExtractCrv( rotation, x%q( 4:6, node ), ErrStat2, ErrMsg2 ) ! return the w-m parameters of the new orientation end if diff --git a/modules/elastodyn/src/ElastoDyn.f90 b/modules/elastodyn/src/ElastoDyn.f90 index 753ae6ca21..ffb058a9fb 100644 --- a/modules/elastodyn/src/ElastoDyn.f90 +++ b/modules/elastodyn/src/ElastoDyn.f90 @@ -1812,7 +1812,10 @@ SUBROUTINE ED_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) y%NcIMURAxs = m%AllOuts(NcIMURAxs)*D2R ! Nacelle roll acceleration (rad/s^2) -- this is in the shaft (tilted) coordinate system, instead of the nacelle (nontilted) coordinate system y%NcIMURAys = m%AllOuts(NcIMURAys)*D2R ! Nacelle nodding acceleration (rad/s^2) y%NcIMURAzs = m%AllOuts(NcIMURAzs)*D2R ! Nacelle yaw acceleration (rad/s^2) -- this is in the shaft (tilted) coordinate system, instead of the nacelle (nontilted) coordinate system - + y%LSShftFxa = m%AllOuts(LSShftFxa)*1000. ! Rotating low-speed shaft force x (GL co-ords) (N) + y%LSShftFys = m%AllOuts(LSShftFys)*1000. ! Nonrotating low-speed shaft force y (GL co-ords) (N) + y%LSShftFzs = m%AllOuts(LSShftFzs)*1000. ! Nonrotating low-speed shaft force z (GL co-ords) (N) + RETURN @@ -11643,9 +11646,9 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta, dY) end do end if - call PackMotionMesh_dY(y_p%PlatformPtMesh, y_m%PlatformPtMesh, dY, indx_first) - call PackMotionMesh_dY(y_p%TowerLn2Mesh, y_m%TowerLn2Mesh, dY, indx_first) - call PackMotionMesh_dY(y_p%HubPtMotion, y_m%HubPtMotion, dY, indx_first, FieldMask=Mask) + call PackMotionMesh_dY(y_p%PlatformPtMesh, y_m%PlatformPtMesh, dY, indx_first, UseSmlAngle=.true.) + call PackMotionMesh_dY(y_p%TowerLn2Mesh, y_m%TowerLn2Mesh, dY, indx_first, UseSmlAngle=.true.) + call PackMotionMesh_dY(y_p%HubPtMotion, y_m%HubPtMotion, dY, indx_first, FieldMask=Mask) do k=1,p%NumBl call PackMotionMesh_dY(y_p%BladeRootMotion(k), y_m%BladeRootMotion(k), dY, indx_first) end do @@ -11665,7 +11668,7 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta, dY) END SUBROUTINE Compute_dY !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to pack the data structures representing the operating points into arrays for linearization. -SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedLogMap ) +SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedPackedOrient ) REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(ED_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) @@ -11684,7 +11687,7 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, 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 - LOGICAL, OPTIONAL, INTENT(IN ) :: NeedLogMap !< whether a y_op values should contain log maps instead of full orientation matrices + LOGICAL, OPTIONAL, INTENT(IN ) :: NeedPackedOrient !< whether a y_op values should contain 3-value representation instead of full orientation matrices @@ -11744,8 +11747,8 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, !.................................. IF ( PRESENT( y_op ) ) THEN - if (present(NeedLogMap)) then - ReturnLogMap = NeedLogMap + if (present(NeedPackedOrient)) then + ReturnLogMap = NeedPackedOrient else ReturnLogMap = .false. end if @@ -11771,7 +11774,8 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, if (ErrStat>=AbortErrLev) return end if - + if (ReturnLogMap) y_op = 0.0_ReKi ! initialize in case we are returning packed orientations and don't fill the entire array + Mask = .false. Mask(MASKID_TRANSLATIONDISP) = .true. @@ -11781,16 +11785,16 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, index = 1 if (allocated(y%BladeLn2Mesh)) then do k=1,p%NumBl - call PackMotionMesh(y%BladeLn2Mesh(k), y_op, index, UseLogMaps=ReturnLogMap) + call PackMotionMesh(y%BladeLn2Mesh(k), y_op, index, UseSmlAngle=ReturnLogMap) end do end if - call PackMotionMesh(y%PlatformPtMesh, y_op, index, UseLogMaps=ReturnLogMap) - call PackMotionMesh(y%TowerLn2Mesh, y_op, index, UseLogMaps=ReturnLogMap) - call PackMotionMesh(y%HubPtMotion, y_op, index, FieldMask=Mask, UseLogMaps=ReturnLogMap) + call PackMotionMesh(y%PlatformPtMesh, y_op, index, UseSmlAngle=ReturnLogMap) + call PackMotionMesh(y%TowerLn2Mesh, y_op, index, UseSmlAngle=ReturnLogMap) + call PackMotionMesh(y%HubPtMotion, y_op, index, FieldMask=Mask, UseSmlAngle=ReturnLogMap) do k=1,p%NumBl - call PackMotionMesh(y%BladeRootMotion(k), y_op, index, UseLogMaps=ReturnLogMap) + call PackMotionMesh(y%BladeRootMotion(k), y_op, index, UseSmlAngle=ReturnLogMap) end do - call PackMotionMesh(y%NacelleMotion, y_op, index, UseLogMaps=ReturnLogMap) + call PackMotionMesh(y%NacelleMotion, y_op, index, UseSmlAngle=ReturnLogMap) y_op(index) = y%Yaw ; index = index + 1 y_op(index) = y%YawRate ; index = index + 1 diff --git a/modules/elastodyn/src/ElastoDyn_Registry.txt b/modules/elastodyn/src/ElastoDyn_Registry.txt index f747ea5cc2..b6f348bba7 100644 --- a/modules/elastodyn/src/ElastoDyn_Registry.txt +++ b/modules/elastodyn/src/ElastoDyn_Registry.txt @@ -875,3 +875,6 @@ typedef ^ OutputType ReKi NcIMURAxs - - - "Nacelle inertial measurement unit ang typedef ^ OutputType ReKi NcIMURAys - - - "Nacelle inertial measurement unit angular (rotational) acceleration (absolute)" rad/s^2 typedef ^ OutputType ReKi NcIMURAzs - - - "Nacelle inertial measurement unit angular (rotational) acceleration (absolute)" rad/s^2 typedef ^ OutputType ReKi RotPwr - - - "Rotor power (this is equivalent to the low-speed shaft power)" W +typedef ^ OutputType ReKi LSShftFxa - - - "Rotating low-speed shaft force x" N +typedef ^ OutputType ReKi LSShftFys - - - "Nonrotating low-speed shaft force y" N +typedef ^ OutputType ReKi LSShftFzs - - - "Nonrotating low-speed shaft force z" N diff --git a/modules/elastodyn/src/ElastoDyn_Types.f90 b/modules/elastodyn/src/ElastoDyn_Types.f90 index 6fd3d21ea6..03ba6296e4 100644 --- a/modules/elastodyn/src/ElastoDyn_Types.f90 +++ b/modules/elastodyn/src/ElastoDyn_Types.f90 @@ -873,6 +873,9 @@ MODULE ElastoDyn_Types REAL(ReKi) :: NcIMURAys !< Nacelle inertial measurement unit angular (rotational) acceleration (absolute) [rad/s^2] REAL(ReKi) :: NcIMURAzs !< Nacelle inertial measurement unit angular (rotational) acceleration (absolute) [rad/s^2] REAL(ReKi) :: RotPwr !< Rotor power (this is equivalent to the low-speed shaft power) [W] + REAL(ReKi) :: LSShftFxa !< Rotating low-speed shaft force x [N] + REAL(ReKi) :: LSShftFys !< Nonrotating low-speed shaft force y [N] + REAL(ReKi) :: LSShftFzs !< Nonrotating low-speed shaft force z [N] END TYPE ED_OutputType ! ======================= CONTAINS @@ -23519,6 +23522,9 @@ SUBROUTINE ED_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMs DstOutputData%NcIMURAys = SrcOutputData%NcIMURAys DstOutputData%NcIMURAzs = SrcOutputData%NcIMURAzs DstOutputData%RotPwr = SrcOutputData%RotPwr + DstOutputData%LSShftFxa = SrcOutputData%LSShftFxa + DstOutputData%LSShftFys = SrcOutputData%LSShftFys + DstOutputData%LSShftFzs = SrcOutputData%LSShftFzs END SUBROUTINE ED_CopyOutput SUBROUTINE ED_DestroyOutput( OutputData, ErrStat, ErrMsg ) @@ -23809,6 +23815,9 @@ SUBROUTINE ED_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Re_BufSz = Re_BufSz + 1 ! NcIMURAys Re_BufSz = Re_BufSz + 1 ! NcIMURAzs Re_BufSz = Re_BufSz + 1 ! RotPwr + Re_BufSz = Re_BufSz + 1 ! LSShftFxa + Re_BufSz = Re_BufSz + 1 ! LSShftFys + Re_BufSz = Re_BufSz + 1 ! LSShftFzs IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -24222,6 +24231,12 @@ SUBROUTINE ED_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%RotPwr Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFxa + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFys + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFzs + Re_Xferred = Re_Xferred + 1 END SUBROUTINE ED_PackOutput SUBROUTINE ED_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -24773,6 +24788,12 @@ SUBROUTINE ED_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Re_Xferred = Re_Xferred + 1 OutData%RotPwr = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%LSShftFxa = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFys = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFzs = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 END SUBROUTINE ED_UnPackOutput @@ -25205,6 +25226,12 @@ SUBROUTINE ED_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg y_out%NcIMURAzs = y1%NcIMURAzs + b * ScaleFactor b = -(y1%RotPwr - y2%RotPwr) y_out%RotPwr = y1%RotPwr + b * ScaleFactor + b = -(y1%LSShftFxa - y2%LSShftFxa) + y_out%LSShftFxa = y1%LSShftFxa + b * ScaleFactor + b = -(y1%LSShftFys - y2%LSShftFys) + y_out%LSShftFys = y1%LSShftFys + b * ScaleFactor + b = -(y1%LSShftFzs - y2%LSShftFzs) + y_out%LSShftFzs = y1%LSShftFzs + b * ScaleFactor END SUBROUTINE ED_Output_ExtrapInterp1 @@ -25369,6 +25396,15 @@ SUBROUTINE ED_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, Err b = (t(3)**2*(y1%RotPwr - y2%RotPwr) + t(2)**2*(-y1%RotPwr + y3%RotPwr))* scaleFactor c = ( (t(2)-t(3))*y1%RotPwr + t(3)*y2%RotPwr - t(2)*y3%RotPwr ) * scaleFactor y_out%RotPwr = y1%RotPwr + b + c * t_out + b = (t(3)**2*(y1%LSShftFxa - y2%LSShftFxa) + t(2)**2*(-y1%LSShftFxa + y3%LSShftFxa))* scaleFactor + c = ( (t(2)-t(3))*y1%LSShftFxa + t(3)*y2%LSShftFxa - t(2)*y3%LSShftFxa ) * scaleFactor + y_out%LSShftFxa = y1%LSShftFxa + b + c * t_out + b = (t(3)**2*(y1%LSShftFys - y2%LSShftFys) + t(2)**2*(-y1%LSShftFys + y3%LSShftFys))* scaleFactor + c = ( (t(2)-t(3))*y1%LSShftFys + t(3)*y2%LSShftFys - t(2)*y3%LSShftFys ) * scaleFactor + y_out%LSShftFys = y1%LSShftFys + b + c * t_out + b = (t(3)**2*(y1%LSShftFzs - y2%LSShftFzs) + t(2)**2*(-y1%LSShftFzs + y3%LSShftFzs))* scaleFactor + c = ( (t(2)-t(3))*y1%LSShftFzs + t(3)*y2%LSShftFzs - t(2)*y3%LSShftFzs ) * scaleFactor + y_out%LSShftFzs = y1%LSShftFzs + b + c * t_out END SUBROUTINE ED_Output_ExtrapInterp2 END MODULE ElastoDyn_Types diff --git a/modules/feamooring/CMakeLists.txt b/modules/feamooring/CMakeLists.txt index c9009c443d..42411802d3 100644 --- a/modules/feamooring/CMakeLists.txt +++ b/modules/feamooring/CMakeLists.txt @@ -33,7 +33,7 @@ install(TARGETS feamlib LIBRARY DESTINATION lib) add_executable(feam_driver src/FEAM_Driver.f90) -target_link_libraries(feam_driver feamlib) +target_link_libraries(feam_driver feamlib versioninfolib) install(TARGETS feam_driver EXPORT "${CMAKE_PROJECT_NAME}Libraries" diff --git a/modules/hydrodyn/CMakeLists.txt b/modules/hydrodyn/CMakeLists.txt index 3c10213253..ccf0a80cad 100644 --- a/modules/hydrodyn/CMakeLists.txt +++ b/modules/hydrodyn/CMakeLists.txt @@ -59,6 +59,13 @@ set(HYDRODYN_SOURCES add_library(hydrodynlib ${HYDRODYN_SOURCES}) target_link_libraries(hydrodynlib nwtclibs) +# c-bindings interface library +add_library(hydrodyn_c_binding SHARED src/HydroDyn_C_Binding.f90) +target_link_libraries(hydrodyn_c_binding hydrodynlib) +if(APPLE OR UNIX) + target_compile_definitions(hydrodyn_c_binding PUBLIC -DIMPLICIT_DLLEXPORT) +endif() + add_executable(hydrodyn_driver src/HydroDyn_DriverCode.f90) target_link_libraries(hydrodyn_driver hydrodynlib nwtclibs versioninfolib) @@ -66,7 +73,7 @@ target_link_libraries(hydrodyn_driver hydrodynlib nwtclibs versioninfolib) # src/SS_Radiation_DriverCode.f90) #target_link_libraries(ss_radiation hydrodynlib nwtclibs) -install(TARGETS hydrodynlib hydrodyn_driver +install(TARGETS hydrodynlib hydrodyn_driver hydrodyn_c_binding EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/modules/hydrodyn/python-lib/hydrodyn_library.py b/modules/hydrodyn/python-lib/hydrodyn_library.py new file mode 100644 index 0000000000..b52e2eb74f --- /dev/null +++ b/modules/hydrodyn/python-lib/hydrodyn_library.py @@ -0,0 +1,621 @@ +#********************************************************************************************************************************** +# LICENSING +# Copyright (C) 2021 National Renewable Energy Laboratory +# +# This file is part of HydroDyn. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#********************************************************************************************************************************** +# +# This is the Python-C interface library for HydroDyn. This may be used +# directly with Python based codes to call and run HydroDyn. An example of +# using this library from Python is given in the accompanying Python driver +# program. Additional notes and information on the interfacing is included +# there. +# +# Note on angles: +# All angles passed in are assumed to be given in radians as an Euler +# angle sequence R(z)*R(y)*R(x) (notice the order as this important when +# passing angles in). Written in matrix form as (doxygen formatted): +# +# \f{eqnarray*}{ +# M & = & R(\theta_z) R(\theta_y) R(\theta_x) \\ +# & = & \begin{bmatrix} \cos(\theta_z) & \sin(\theta_z) & 0 \\ +# -\sin(\theta_z) & \cos(\theta_z) & 0 \\ +# 0 & 0 & 1 \end{bmatrix} +# \begin{bmatrix} \cos(\theta_y) & 0 & -\sin(\theta_y) \\ +# 0 & 1 & 0 \\ +# \sin(\theta_y) & 0 & \cos(\theta_y) \end{bmatrix} +# \begin{bmatrix} 1 & 0 & 0 \\ +# 0 & \cos(\theta_x) & \sin(\theta_x) \\ +# 0 & -\sin(\theta_x) & \cos(\theta_x) \end{bmatrix} \\ +# & = & \begin{bmatrix} +# \cos(\theta_y)\cos(\theta_z) & \cos(\theta_x)\sin(\theta_z)+\sin(\theta_x)\sin(\theta_y)\cos(\theta_z) & +# \sin(\theta_x)\sin(\theta_z)-\cos(\theta_x)\sin(\theta_y)\cos(\theta_z) \\ +# -\cos(\theta_y)\sin(\theta_z) & \cos(\theta_x)\cos(\theta_z)-\sin(\theta_x)\sin(\theta_y)\sin(\theta_z) & +# \sin(\theta_x)\cos(\theta_z)+\cos(\theta_x)\sin(\theta_y)\sin(\theta_z) \\ +# \sin(\theta_y) & -\sin(\theta_x)\cos(\theta_y) & \cos(\theta_x)\cos(\theta_y) \\ +# \end{bmatrix} +# \f} +# +# When passed into the Fortran library, this Euler angle set is converted +# into a DCM (direction cosine matrix) and stored on the input mesh. All +# calculations internally in HD are then performed using the DCM form of +# the input angles. +# +# It should be noted that a small angle assumption when returning the +# outputs for the platform roll, pitch, and yaw. These angles are +# assumed to be small enough that treating them as independent angles +# does not introduce significant error in the output channels. This may +# yield a small discrepency between the values passed in and the returned +# output channel values. These output channels should not be directly +# used -- they are only for reporting purposes. +# +from ctypes import ( + CDLL, + POINTER, + create_string_buffer, + byref, + c_int, + c_double, + c_float, + c_char, + c_char_p, +) +import numpy as np +import datetime + +class HydroDynLib(CDLL): + # Human readable error levels from IfW. + error_levels = { + 0: "None", + 1: "Info", + 2: "Warning", + 3: "Severe Error", + 4: "Fatal Error" + } + + # NOTE: the error message length in Fortran is controlled by the + # ErrMsgLen variable in the NWTC_Base.f90 file. If that ever + # changes, it may be necessary to update the corresponding size + # here. + error_msg_c_len = 1025 + + # NOTE: the length of the name used for any output file written by the + # HD Fortran code is 1025. + default_str_c_len = 1025 + + def __init__(self, library_path): + super().__init__(library_path) + self.library_path = library_path + + self._initialize_routines() + self.ended = False # For error handling at end + + + # Create buffers for class data + self.abort_error_level = 4 + self.error_status_c = c_int(0) + self.error_message_c = create_string_buffer(self.error_msg_c_len) + + # This is not sufficient for HD + #FIXME: ChanLen may not always be 20 -- could be as much as 256 + # Possible fix is to pass this length over to Fortran side. + # Also may want to convert this at some point to C_NULL_CHAR + # delimeter instead of fixed width. Future problem though. + # Number of channel names may exceeed 5000 + self._channel_names_c = create_string_buffer(20 * 4000) + self._channel_units_c = create_string_buffer(20 * 4000) + + # Initial environmental conditions + self.gravity = 9.80665 # Gravity (m/s^2) + self.defWtrDens = 1025.0 # Water density (kg/m^3) + self.defWtrDpth = 200.0 # Water depth (m) + self.defMSL2SWL = 0.0 # Offset between still-water level and mean sea level (m) [positive upward] + + # Interpolation order (must be 1: linear, or 2: quadratic) + self.InterpOrder = 1 # default of linear interpolation + + # Initial time related variables + self.dt = 0.1 # typical default for HD + self.t_start = 0.0 # initial time + self.tmax = 600.0 # typical default for HD waves FFT + #FIXME: check tmax/total_time and note exactly what is different between them. + self.total_time = 0.0 # may be longer than tmax + self.numTimeSteps = 0 + + self.numChannels = 0 # Number of channels returned + + # Number of bodies and initial reference point + # The initial position is only set as (X,Y). The Z value and + # orientation is set by HD and will be returned along with the full + # set of numBodies where it is expecting loads inputs. + self.ptfmRefPt_x = 0.0 + self.ptfmRefPt_y = 0.0 + + # Nodes + # The number of nodes must be constant throughout simulation. The + # initial position is given in the initNodePos array (resize as + # needed, should be Nx6). + # Rotations are given in radians assuming small angles. See note at + # top of this file. + self.numNodePts = 1 # Single ptfm attachment point for floating rigid + self.initNodePos = np.zeros((self.numNodePts,6)) # N x 6 array [x,y,z,Rx,Ry,Rz] + + # OutRootName + # If HD writes a file (echo, summary, or other), use this for the + # root of the file name. + self.outRootName = "Output_HDlib_default" + + # _initialize_routines() ------------------------------------------------------------------------------------------------------------ + def _initialize_routines(self): + self.HydroDyn_C_Init.argtypes = [ + POINTER(c_char), # OutRootName + POINTER(c_char_p), # input file string + POINTER(c_int), # input file string length + POINTER(c_float), # gravity + POINTER(c_float), # defWtrDens + POINTER(c_float), # defWtrDpth + POINTER(c_float), # defMSL2SWL + POINTER(c_float), # PtfmRefPt_X + POINTER(c_float), # PtfmRefPt_Y + POINTER(c_int), # numNodePts -- number of points expecting motions/loads + POINTER(c_float), # initNodePos -- initial node positions in flat array of 6*numNodePts + POINTER(c_int), # InterpOrder + POINTER(c_double), # t_initial + POINTER(c_double), # dt + POINTER(c_double), # tmax + POINTER(c_int), # number of channels + POINTER(c_char), # output channel names + POINTER(c_char), # output channel units + POINTER(c_int), # ErrStat_C + POINTER(c_char) # ErrMsg_C + ] + self.HydroDyn_C_Init.restype = c_int + + self.HydroDyn_C_CalcOutput.argtypes = [ + POINTER(c_double), # Time_C + POINTER(c_int), # numNodePts -- number of points expecting motions/loads + POINTER(c_float), # nodePos -- node positions in flat array of 6*numNodePts + POINTER(c_float), # nodeVel -- node velocities in flat array of 6*numNodePts + POINTER(c_float), # nodeAcc -- node accelerations in flat array of 6*numNodePts + POINTER(c_float), # nodeFrc -- node forces/moments in flat array of 6*numNodePts + POINTER(c_float), # Output Channel Values + POINTER(c_int), # ErrStat_C + POINTER(c_char) # ErrMsg_C + ] + self.HydroDyn_C_CalcOutput.restype = c_int + + self.HydroDyn_C_UpdateStates.argtypes = [ + POINTER(c_double), # Time_C + POINTER(c_double), # TimeNext_C + POINTER(c_int), # numNodePts -- number of points expecting motions/loads + POINTER(c_float), # nodePos -- node positions in flat array of 6*numNodePts + POINTER(c_float), # nodeVel -- node velocities in flat array of 6*numNodePts + POINTER(c_float), # nodeAcc -- node accelerations in flat array of 6*numNodePts + POINTER(c_int), # ErrStat_C + POINTER(c_char) # ErrMsg_C + ] + self.HydroDyn_C_UpdateStates.restype = c_int + + self.HydroDyn_C_End.argtypes = [ + POINTER(c_int), # ErrStat_C + POINTER(c_char) # ErrMsg_C + ] + self.HydroDyn_C_End.restype = c_int + + # hydrodyn_init ------------------------------------------------------------------------------------------------------------ + def hydrodyn_init(self, input_string_array): + # nodePositions -- N x 6 array -- position info as [x1,y1,z1,Rx1,Ry1,Rz1] + + # Primary input file will be passed as a single string joined by + # C_NULL_CHAR. + input_string = '\x00'.join(input_string_array) + input_string = input_string.encode('utf-8') + input_string_length = len(input_string) + + self._numChannels_c = c_int(0) + + # Rootname for HD output files (echo etc). + _outRootName_c = create_string_buffer((self.outRootName.ljust(self.default_str_c_len)).encode('utf-8')) + + # store initial number of node points for error handling at calls + self._initNumNodePts = self.numNodePts + + # initNodePos + # Verify that the shape of initNodePos is correct + if self.initNodePos.shape[1] != 6: + print("Expecting a Nx6 array of initial node locations (initNodePos) with second index for [x,y,z,Rx,Ry,Rz]") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + if self.initNodePos.shape[0] != self.numNodePts: + print("Expecting a Nx6 array of initial node locations (initNodePos) with first index for node number.") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + #FIXME: for now we only allow for a single rigid motion platform. If + # multiple nodes are allowed for substructure coupling or + # flexible floating platforms, then remove this check and verify + # the fortran side works as expected (theoretically should, but + # it is untested). + if self.numNodePts != 1: + print(f"HydroDyn C interface does not currently support flexible structures ({self.numNodePts} input motion points were requested, but only 1 is currently supported).") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + + # Make a flat 1D array of position info: + # [x2,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...] + nodeInitLoc_flat = [pp for p in self.initNodePos for pp in p] + nodeInitLoc_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodeInitLoc_flat): + nodeInitLoc_flat_c[i] = c_float(p) + + + # call HydroDyn_C_Init + self.HydroDyn_C_Init( + _outRootName_c, # IN: rootname for HD file writing + c_char_p(input_string), # IN: input file string + byref(c_int(input_string_length)), # IN: input file string length + byref(c_float(self.gravity)), # IN: gravity + byref(c_float(self.defWtrDens)), # IN: default water density + byref(c_float(self.defWtrDpth)), # IN: default water depth + byref(c_float(self.defMSL2SWL)), # IN: default offset between still-water level and mean sea level + byref(c_float(self.ptfmRefPt_x)), # IN: Platform initial position (X) + byref(c_float(self.ptfmRefPt_y)), # IN: Platform initial position (Y) + byref(c_int(self.numNodePts)), # IN: number of attachment points expected (where motions are transferred into HD) + nodeInitLoc_flat_c, # IN: initNodePos -- initial node positions in flat array of 6*numNodePts + byref(c_int(self.InterpOrder)), # IN: InterpOrder (1: linear, 2: quadratic) + byref(c_double(self.t_start)), # IN: time initial + byref(c_double(self.dt)), # IN: time step (dt) + byref(c_double(self.tmax)), # IN: tmax + byref(self._numChannels_c), # OUT: number of channels + self._channel_names_c, # OUT: output channel names + self._channel_units_c, # OUT: output channel units + byref(self.error_status_c), # OUT: ErrStat_C + self.error_message_c # OUT: ErrMsg_C + ) + + self.check_error() + + # Initialize output channels + self.numChannels = self._numChannels_c.value + + + # hydrodyn_calcOutput ------------------------------------------------------------------------------------------------------------ + def hydrodyn_calcOutput(self, time, nodePos, nodeVel, nodeAcc, nodeFrcMom, outputChannelValues): + + # Check input motion info + self.check_input_motions(nodePos,nodeVel,nodeAcc) + + # set flat arrays for inputs of motion + # Position -- [x2,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...] + nodePos_flat = [pp for p in nodePos for pp in p] + nodePos_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodePos_flat): + nodePos_flat_c[i] = c_float(p) + + # Velocity -- [Vx2,Vy1,Vz1,RVx1,RVy1,RVz1, Vx2,Vy2,Vz2,RVx2,RVy2,RVz2 ...] + nodeVel_flat = [pp for p in nodeVel for pp in p] + nodeVel_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodeVel_flat): + nodeVel_flat_c[i] = c_float(p) + + # Acceleration -- [Ax1,Ay1,Az1,RAx1,RAy1,RAz1, Ax2,Ay2,Az2,RAx2,RAy2,RAz2 ...] + nodeAcc_flat = [pp for p in nodeAcc for pp in p] + nodeAcc_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodeAcc_flat): + nodeAcc_flat_c[i] = c_float(p) + + # Resulting Forces/moments -- [Fx1,Fy1,Fz1,Mx1,My1,Mz1, Fx2,Fy2,Fz2,Mx2,My2,Mz2 ...] + nodeFrc_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + + # Set up output channels + outputChannelValues_c = (c_float * self.numChannels)(0.0,) + + # Run HydroDyn_C_CalcOutput + self.HydroDyn_C_CalcOutput( + byref(c_double(time)), # IN: time at which to calculate output forces + byref(c_int(self.numNodePts)), # IN: number of attachment points expected (where motions are transferred into HD) + nodePos_flat_c, # IN: positions - specified by user + nodeVel_flat_c, # IN: velocities at desired positions + nodeAcc_flat_c, # IN: accelerations at desired positions + nodeFrc_flat_c, # OUT: resulting forces/moments array + 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 + ) + + self.check_error() + + ## Reshape Force/Moment into [N,6] + count = 0 + for j in range(0,self.numNodePts): + nodeFrcMom[j,0] = nodeFrc_flat_c[count] + nodeFrcMom[j,1] = nodeFrc_flat_c[count+1] + nodeFrcMom[j,2] = nodeFrc_flat_c[count+2] + nodeFrcMom[j,3] = nodeFrc_flat_c[count+3] + nodeFrcMom[j,4] = nodeFrc_flat_c[count+4] + nodeFrcMom[j,5] = nodeFrc_flat_c[count+5] + count = count + 6 + + # Convert output channel values back into python + for k in range(0,self.numChannels): + outputChannelValues[k] = float(outputChannelValues_c[k]) + + # hydrodyn_updateStates ------------------------------------------------------------------------------------------------------------ + def hydrodyn_updateStates(self, time, timeNext, nodePos, nodeVel, nodeAcc, nodeFrcMom): + + # Check input motion info + self.check_input_motions(nodePos,nodeVel,nodeAcc) + + # set flat arrays for inputs of motion + # Position -- [x2,y1,z1,Rx1,Ry1,Rz1, x2,y2,z2,Rx2,Ry2,Rz2 ...] + nodePos_flat = [pp for p in nodePos for pp in p] + nodePos_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodePos_flat): + nodePos_flat_c[i] = c_float(p) + + # Velocity -- [Vx2,Vy1,Vz1,RVx1,RVy1,RVz1, Vx2,Vy2,Vz2,RVx2,RVy2,RVz2 ...] + nodeVel_flat = [pp for p in nodeVel for pp in p] + nodeVel_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodeVel_flat): + nodeVel_flat_c[i] = c_float(p) + + # Acceleration -- [Ax1,Ay1,Az1,RAx1,RAy1,RAz1, Ax2,Ay2,Az2,RAx2,RAy2,RAz2 ...] + nodeAcc_flat = [pp for p in nodeAcc for pp in p] + nodeAcc_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + for i, p in enumerate(nodeAcc_flat): + nodeAcc_flat_c[i] = c_float(p) + + # Resulting Forces/moments -- [Fx1,Fy1,Fz1,Mx1,My1,Mz1, Fx2,Fy2,Fz2,Mx2,My2,Mz2 ...] + nodeFrc_flat_c = (c_float * (6 * self.numNodePts))(0.0,) + + # Run HydroDyn_UpdateStates_c + self.HydroDyn_C_UpdateStates( + 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(c_int(self.numNodePts)), # IN: number of attachment points expected (where motions are transferred into HD) + nodePos_flat_c, # IN: positions - specified by user + nodeVel_flat_c, # IN: velocities at desired positions + nodeAcc_flat_c, # IN: accelerations at desired positions + byref(self.error_status_c), # OUT: ErrStat_C + self.error_message_c # OUT: ErrMsg_C + ) + + self.check_error() + + # hydrodyn_end ------------------------------------------------------------------------------------------------------------ + def hydrodyn_end(self): + if not self.ended: + self.ended = True + # Run HydroDyn_C_End + self.HydroDyn_C_End( + byref(self.error_status_c), + self.error_message_c + ) + + self.check_error() + + # other functions ---------------------------------------------------------------------------------------------------------- + def check_error(self): + if self.error_status_c.value == 0: + return + elif self.error_status_c.value < self.abort_error_level: + print(f"HydroDyn error status: {self.error_levels[self.error_status_c.value]}: {self.error_message_c.value.decode('ascii')}") + else: + print(f"HydroDyn error status: {self.error_levels[self.error_status_c.value]}: {self.error_message_c.value.decode('ascii')}") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + + + def check_input_motions(self,nodePos,nodeVel,nodeAcc): + # make sure number of nodes didn't change for some reason + if self._initNumNodePts != self.numNodePts: + print(f"At time {time}, the number of node points changed from initial value of {self._initNumNodePts}. This is not permitted during the simulation.") + self.hydrodyn_end() + raise Exception("\nError in calling HydroDyn library.") + + # Verify that the shape of positions array is correct + if nodePos.shape[1] != 6: + print("Expecting a Nx6 array of node positions (nodePos) with second index for [x,y,z,Rx,Ry,Rz]") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + if nodePos.shape[0] != self.numNodePts: + print("Expecting a Nx6 array of node positions (nodePos) with first index for node number.") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + + + # Verify that the shape of velocities array is correct + if nodeVel.shape[1] != 6: + print("Expecting a Nx6 array of node velocities (nodeVel) with second index for [x,y,z,Rx,Ry,Rz]") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + if nodeVel.shape[0] != self.numNodePts: + print("Expecting a Nx6 array of node velocities (nodeVel) with first index for node number.") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + + + # Verify that the shape of accelerations array is correct + if nodeAcc.shape[1] != 6: + print("Expecting a Nx6 array of node accelerations (nodeAcc) with second index for [x,y,z,Rx,Ry,Rz]") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + if nodeAcc.shape[0] != self.numNodePts: + print("Expecting a Nx6 array of node accelerations (nodeAcc) with first index for node number.") + self.hydrodyn_end() + raise Exception("\nHydroDyn terminated prematurely.") + + + + @property + def output_channel_names(self): + if len(self._channel_names_c.value.split()) == 0: + return [] + output_channel_names = self._channel_names_c.value.split() + output_channel_names = [n.decode('UTF-8') for n in output_channel_names] + return output_channel_names + + @property + def output_channel_units(self): + if len(self._channel_units_c.value.split()) == 0: + return [] + output_channel_units = self._channel_units_c.value.split() + output_channel_units = [n.decode('UTF-8') for n in output_channel_units] + return output_channel_units + + +#=============================================================================== +# Helper class for debugging the interface. This will write out all the +# input position/orientation, velocities, accelerations, and the resulting +# forces and moments at each input node. If all is functioning correctly, +# this will be identical to the corresponding values in the HydroDyn output +# channels. + +class DriverDbg(): + """ + This is only for debugging purposes only. The input motions and resulting + forces can be written to file with this class to verify the data I/O to the + Fortran library. + When coupled to another code, the force/moment array would be passed back + to the calling code for use in the structural solver. + """ + def __init__(self,filename,numNodePts): + self.DbgFile=open(filename,'wt') # open output file and write header info + self.numNodePts=numNodePts + # write file header + t_string=datetime.datetime.now() + dt_string=datetime.date.today() + self.DbgFile.write(f"## This file was generated by hydrodyn_c_lib on {dt_string.strftime('%b-%d-%Y')} at {t_string.strftime('%H:%M:%S')}\n") + self.DbgFile.write(f"## This file contains the resulting forces/moments at each of {self.numNodePts} node(s) passed into the hydrodyn_c_lib\n") + self.DbgFile.write("#\n") + f_string = "{:^25s}" + self.DbgFile.write("# T ") + for i in range(1,self.numNodePts+1): + f_num = "N{0:04d}_".format(i) + self.DbgFile.write(f_string.format(f_num+"x" )) + self.DbgFile.write(f_string.format(f_num+"y" )) + self.DbgFile.write(f_string.format(f_num+"z" )) + self.DbgFile.write(f_string.format(f_num+"Rx" )) + self.DbgFile.write(f_string.format(f_num+"Ry" )) + self.DbgFile.write(f_string.format(f_num+"Rz" )) + self.DbgFile.write(f_string.format(f_num+"Vx" )) + self.DbgFile.write(f_string.format(f_num+"Vy" )) + self.DbgFile.write(f_string.format(f_num+"Vz" )) + self.DbgFile.write(f_string.format(f_num+"RVx")) + self.DbgFile.write(f_string.format(f_num+"RVy")) + self.DbgFile.write(f_string.format(f_num+"RVz")) + self.DbgFile.write(f_string.format(f_num+"Ax" )) + self.DbgFile.write(f_string.format(f_num+"Ay" )) + self.DbgFile.write(f_string.format(f_num+"Az" )) + self.DbgFile.write(f_string.format(f_num+"RAx")) + self.DbgFile.write(f_string.format(f_num+"RAy")) + self.DbgFile.write(f_string.format(f_num+"RAz")) + self.DbgFile.write(f_string.format(f_num+"Fx" )) + self.DbgFile.write(f_string.format(f_num+"Fy" )) + self.DbgFile.write(f_string.format(f_num+"Fz" )) + self.DbgFile.write(f_string.format(f_num+"Mx" )) + self.DbgFile.write(f_string.format(f_num+"My" )) + self.DbgFile.write(f_string.format(f_num+"Mz" )) + self.DbgFile.write("\n") + self.DbgFile.write("# (s) ") + for i in range(1,self.numNodePts+1): + self.DbgFile.write(f_string.format("(m)" )) + self.DbgFile.write(f_string.format("(m)" )) + self.DbgFile.write(f_string.format("(m)" )) + self.DbgFile.write(f_string.format("(rad)" )) + self.DbgFile.write(f_string.format("(rad)" )) + self.DbgFile.write(f_string.format("(rad)" )) + self.DbgFile.write(f_string.format("(m/s)" )) + self.DbgFile.write(f_string.format("(m/s)" )) + self.DbgFile.write(f_string.format("(m/s)" )) + self.DbgFile.write(f_string.format("(rad/s)" )) + self.DbgFile.write(f_string.format("(rad/s)" )) + self.DbgFile.write(f_string.format("(rad/s)" )) + self.DbgFile.write(f_string.format("(m/s^2)" )) + self.DbgFile.write(f_string.format("(m/s^2)" )) + self.DbgFile.write(f_string.format("(m/s^2)" )) + self.DbgFile.write(f_string.format("(rad/s^2)")) + self.DbgFile.write(f_string.format("(rad/s^2)")) + self.DbgFile.write(f_string.format("(rad/s^2)")) + self.DbgFile.write(f_string.format("(N)" )) + self.DbgFile.write(f_string.format("(N)" )) + self.DbgFile.write(f_string.format("(N)" )) + self.DbgFile.write(f_string.format("(N-m)" )) + self.DbgFile.write(f_string.format("(N-m)" )) + self.DbgFile.write(f_string.format("(N-m)" )) + self.DbgFile.write("\n") + self.opened = True + + def write(self,t,nodePos,nodeVel,nodeAcc,nodeFrc): + t_string = "{:10.4f}" + f_string = "{:25.7f}"*6 + self.DbgFile.write(t_string.format(t)) + for i in range(0,self.numNodePts): + self.DbgFile.write(f_string.format(*nodePos[i,:])) + self.DbgFile.write(f_string.format(*nodeVel[i,:])) + self.DbgFile.write(f_string.format(*nodeAcc[i,:])) + self.DbgFile.write(f_string.format(*nodeFrc[i,:])) + self.DbgFile.write("\n") + + def end(self): + if self.opened: + self.DbgFile.close() + self.opened = False + + +#=============================================================================== +# Helper class for writing channels to file. +# for the regression testing to mirror the output from the InfowWind Fortran +# driver. This may also have value for debugging the interfacing to IfW. + +class WriteOutChans(): + """ + This is only for testing purposes. Since we are not returning the + output channels to anything, we will write them to file. When coupled to + another code, this data would be passed back for inclusion the any output + file there. + """ + def __init__(self,filename,chan_names,chan_units): + chan_names.insert(0,'Time') # add time index header + chan_units.insert(0,'(s)') # add time index unit + self.OutFile=open(filename,'wt') # open output file and write header info + # write file header + t_string=datetime.datetime.now() + dt_string=datetime.date.today() + self.OutFile.write(f"## This file was generated by InflowWind_Driver on {dt_string.strftime('%b-%d-%Y')} at {t_string.strftime('%H:%M:%S')}\n") + self.OutFile.write(f"## This file contains output channels requested from the OutList section of the input file") + self.OutFile.write(f"{filename}\n") + self.OutFile.write("#\n") + self.OutFile.write("#\n") + self.OutFile.write("#\n") + self.OutFile.write("#\n") + l = len(chan_names) + f_string = "{:^15s}"+" {:^20s} "*(l-1) + self.OutFile.write(f_string.format(*chan_names) + '\n') + self.OutFile.write(f_string.format(*chan_units) + '\n') + self.opened = True + + def write(self,chan_data): + l = chan_data.shape[1] + f_string = "{:10.4f}"+"{:25.7f}"*(l-1) + for i in range(0,chan_data.shape[0]): + self.OutFile.write(f_string.format(*chan_data[i,:]) + '\n') + #if i==0: + # print(f"{chan_data[i,:]}") + + def end(self): + if self.opened: + self.OutFile.close() + self.opened = False diff --git a/modules/hydrodyn/src/HydroDyn.f90 b/modules/hydrodyn/src/HydroDyn.f90 index 5b0e990a3b..1f8cedf0ee 100644 --- a/modules/hydrodyn/src/HydroDyn.f90 +++ b/modules/hydrodyn/src/HydroDyn.f90 @@ -1793,52 +1793,47 @@ SUBROUTINE HydroDyn_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message + CHARACTER(*), PARAMETER :: RoutineName = 'HydroDyn_End' ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" - - ! Place any last minute operations or calculations here: - - ! Write the HydroDyn-level output file data if the user requested module-level output ! and the current time has advanced since the last stored time step. - IF ( p%OutSwtch == 1 .OR. p%OutSwtch == 3) THEN - CALL HDOut_WriteOutputs( m%LastOutTime, y, p, m%Decimate, ErrStat, ErrMsg ) + CALL HDOut_WriteOutputs( m%LastOutTime, y, p, m%Decimate, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF ! Close files here: - CALL HDOut_CloseOutput( p, ErrStat, ErrMsg ) + CALL HDOut_CloseOutput( p, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! Destroy the input data: - - CALL HydroDyn_DestroyInput( u, ErrStat, ErrMsg ) + ! Destroy the input data: (ignore errors) + CALL HydroDyn_DestroyInput( u, ErrStat2, ErrMsg2 ) - ! Destroy the parameter data: - - CALL HydroDyn_DestroyParam( p, ErrStat, ErrMsg ) + ! Destroy the parameter data: (ignore errors) + CALL HydroDyn_DestroyParam( p, ErrStat2, ErrMsg2 ) - ! Destroy the state data: + ! Destroy the state data: (ignore errors) + CALL HydroDyn_DestroyContState( x, ErrStat2, ErrMsg2 ) + CALL HydroDyn_DestroyDiscState( xd, ErrStat2, ErrMsg2 ) + CALL HydroDyn_DestroyConstrState( z, ErrStat2, ErrMsg2 ) + CALL HydroDyn_DestroyOtherState( OtherState, ErrStat2, ErrMsg2 ) - CALL HydroDyn_DestroyContState( x, ErrStat, ErrMsg ) - CALL HydroDyn_DestroyDiscState( xd, ErrStat, ErrMsg ) - CALL HydroDyn_DestroyConstrState( z, ErrStat, ErrMsg ) - CALL HydroDyn_DestroyOtherState( OtherState, ErrStat, ErrMsg ) - - ! Destroy misc variables: - - CALL HydroDyn_DestroyMisc( m, ErrStat, ErrMsg ) + ! Destroy misc variables: (ignore errors) + CALL HydroDyn_DestroyMisc( m, ErrStat2, ErrMsg2 ) - ! Destroy the output data: - - CALL HydroDyn_DestroyOutput( y, ErrStat, ErrMsg ) + ! Destroy the output data: (ignore errors) + CALL HydroDyn_DestroyOutput( y, ErrStat2, ErrMsg2 ) END SUBROUTINE HydroDyn_End @@ -2579,8 +2574,6 @@ SUBROUTINE HD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM ! For the case where either RdtnMod=0 and ExtcnMod=0 and hence %SS_Rdtn data or %SS_Exctn data is not valid then we do not have states, so simply return ! The key here is to never allocate the dXdu and related state Jacobian arrays because then the glue-code will behave properly - if ( p%totalStates == 0 ) return - ! Calculate the partial derivative of the continuous state functions (X) with respect to the inputs (u) here: ! allocate dXdu if necessary @@ -2753,8 +2746,6 @@ SUBROUTINE HD_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrStat = ErrID_None ErrMsg = '' - if ( p%totalStates == 0 ) return - ! Calculate the partial derivative of the output functions (Y) with respect to the continuous states (x) here: @@ -3454,7 +3445,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 1) !Module/Mesh/Field: u%Morison%Mesh%TranslationDisp = 1 u%Morison%Mesh%TranslationDisp (fieldIndx,node) = u%Morison%Mesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE ( 2) !Module/Mesh/Field: u%Morison%Mesh%Orientation = 2 - CALL PerturbOrientationMatrix( u%Morison%Mesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%Morison%Mesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 3) !Module/Mesh/Field: u%Morison%Mesh%TranslationVel = 3 u%Morison%Mesh%TranslationVel( fieldIndx,node) = u%Morison%Mesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE ( 4) !Module/Mesh/Field: u%Morison%Mesh%RotationVel = 4 @@ -3469,7 +3460,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 7) !Module/Mesh/Field: u%WAMITMesh%TranslationDisp = 7 u%WAMITMesh%TranslationDisp (fieldIndx,node) = u%WAMITMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE ( 8) !Module/Mesh/Field: u%WAMITMesh%Orientation = 8 - CALL PerturbOrientationMatrix( u%WAMITMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%WAMITMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 9) !Module/Mesh/Field: u%WAMITMesh%TranslationVel = 9 u%WAMITMesh%TranslationVel( fieldIndx,node) = u%WAMITMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE (10) !Module/Mesh/Field: u%WAMITMesh%RotationVel = 10 @@ -3483,7 +3474,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE (13) !Module/Mesh/Field: u%PRPMesh%TranslationDisp = 13 u%PRPMesh%TranslationDisp (fieldIndx,node) = u%PRPMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE (14) !Module/Mesh/Field: u%PRPMesh%Orientation = 14 - CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE (15) !Module/Mesh/Field: u%PRPMesh%TranslationVel = 15 u%PRPMesh%TranslationVel( fieldIndx,node) = u%PRPMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE (16) !Module/Mesh/Field: u%PRPMesh%RotationVel = 16 @@ -3498,7 +3489,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 7) !Module/Mesh/Field: u%PRPMesh%TranslationDisp = 7 u%PRPMesh%TranslationDisp (fieldIndx,node) = u%PRPMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE ( 8) !Module/Mesh/Field: u%PRPMesh%Orientation = 8 - CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 9) !Module/Mesh/Field: u%PRPMesh%TranslationVel = 9 u%PRPMesh%TranslationVel( fieldIndx,node) = u%PRPMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE (10) !Module/Mesh/Field: u%PRPMesh%RotationVel = 10 @@ -3514,7 +3505,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE (1) !Module/Mesh/Field: u%WAMITMesh%TranslationDisp = 1 u%WAMITMesh%TranslationDisp (fieldIndx,node) = u%WAMITMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE (2) !Module/Mesh/Field: u%WAMITMesh%Orientation = 2 - CALL PerturbOrientationMatrix( u%WAMITMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%WAMITMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE (3) !Module/Mesh/Field: u%WAMITMesh%TranslationVel = 3 u%WAMITMesh%TranslationVel( fieldIndx,node) = u%WAMITMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE (4) !Module/Mesh/Field: u%WAMITMesh%RotationVel = 4 @@ -3528,7 +3519,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 7) !Module/Mesh/Field: u%PRPMesh%TranslationDisp = 7 u%PRPMesh%TranslationDisp (fieldIndx,node) = u%PRPMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE ( 8) !Module/Mesh/Field: u%PRPMesh%Orientation = 8 - CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 9) !Module/Mesh/Field: u%PRPMesh%TranslationVel = 9 u%PRPMesh%TranslationVel( fieldIndx,node) = u%PRPMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE (10) !Module/Mesh/Field: u%PRPMesh%RotationVel = 10 @@ -3543,7 +3534,7 @@ SUBROUTINE HD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 1) !Module/Mesh/Field: u%PRPMesh%TranslationDisp = 1 u%PRPMesh%TranslationDisp (fieldIndx,node) = u%PRPMesh%TranslationDisp (fieldIndx,node) + du * perturb_sign CASE ( 2) !Module/Mesh/Field: u%PRPMesh%Orientation = 2 - CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%PRPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 3) !Module/Mesh/Field: u%PRPMesh%TranslationVel = 3 u%PRPMesh%TranslationVel( fieldIndx,node) = u%PRPMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE ( 4) !Module/Mesh/Field: u%PRPMesh%RotationVel = 4 diff --git a/modules/hydrodyn/src/HydroDyn_C_Binding.f90 b/modules/hydrodyn/src/HydroDyn_C_Binding.f90 new file mode 100644 index 0000000000..d4cda71634 --- /dev/null +++ b/modules/hydrodyn/src/HydroDyn_C_Binding.f90 @@ -0,0 +1,1032 @@ +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2021 National Renewable Energy Lab +! +! This file is part of HydroDyn. +! +! 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 HydroDyn_C_BINDING + + USE ISO_C_BINDING + USE HydroDyn + USE HydroDyn_Types + USE NWTC_Library + + IMPLICIT NONE + + PUBLIC :: HydroDyn_C_Init + PUBLIC :: HydroDyn_C_CalcOutput + PUBLIC :: HydroDyn_C_UpdateStates + PUBLIC :: HydroDyn_C_End + + !------------------------------------------------------------------------------------ + ! Error handling + ! This must exactly match the value in the python-lib. If ErrMsgLen changes at + ! some point in the nwtc-library, this should be updated, but the logic exists + ! to correctly handle different lengths of the strings + integer(IntKi), parameter :: ErrMsgLen_C = 1025 + integer(IntKi), parameter :: IntfStrLen = 1025 ! length of other strings through the C interface + + !------------------------------------------------------------------------------------ + ! Potential issues + ! - if MaxHDOutputs is sufficiently large, we may overrun the buffer on the Python + ! side (OutputChannelNames_C,OutputChannelUnits_C). Don't have a good method to + ! check this in code yet. Might be best to pass the max length over to Init and + ! do some checks here. May also want to convert this to C_NULL_CHAR delimiter + ! instead of fixed width. + + !------------------------------------------------------------------------------------ + ! Data storage + ! All HydroDyn data is stored within the following data structures inside this + ! module. No data is stored within HydroDyn itself, but is instead passed in + ! from this module. This data is not available to the calling code unless + ! explicitly passed through the interface (derived types such as these are + ! non-trivial to pass through the c-bindings). + !------------------------------ + ! Extrapolation and interpolation + ! For the solver in HD, previous timesteps input must be stored for extrapolation + ! to the t+dt timestep. This can be either linear (1) quadratic (2). The + ! InterpOrder variable tracks what this is and sets the size of the inputs `u` + ! passed into HD. Inputs `u` will be sized as follows: + ! linear interp u(2) with inputs at T,T-dt + ! quadratic interp u(3) with inputs at T,T-dt,T-2*dt + integer(IntKi) :: InterpOrder + !------------------------------ + ! Primary HD derived data types + type(HydroDyn_InputType), allocatable :: u(:) !< Inputs at T, T-dt, T-2*dt (history kept for updating states) + type(HydroDyn_InitInputType) :: InitInp !< Initialization data + type(HydroDyn_InitOutputType) :: InitOutData !< Initial output data -- Names, units, and version info. + type(HydroDyn_ParameterType) :: p !< Parameters + type(HydroDyn_ContinuousStateType) :: x(0:2) !< continuous states at Time t and t+dt (predicted) + type(HydroDyn_DiscreteStateType) :: xd(0:2) !< discrete states at Time t and t+dt (predicted) + type(HydroDyn_ConstraintStateType) :: z(0:2) !< Constraint states at Time t and t+dt (predicted) + type(HydroDyn_OtherStateType) :: OtherStates(0:2) !< Initial other/optimization states + type(HydroDyn_OutputType) :: y !< Initial output (outputs are not calculated; only the output mesh is initialized) + type(HydroDyn_MiscVarType) :: m !< Misc variables for optimization (not copied in glue code) + !------------------------------ + ! Time tracking + ! When we are performing a correction step, time information of previous + ! calls is needed to decide how to apply correction logic or cycle the inputs + ! and resave the previous timestep states. + ! Correction steps + ! OpenFAST has the ability to perform correction steps. During a correction + ! step, new input values are passed in but the timestep remains the same. + ! When this occurs the new input data at time t is used with the state + ! information from the previous timestep (t) to calculate new state values + ! time t+dt in the UpdateStates routine. In OpenFAST this is all handled by + ! the glue code. However, here we do not pass state information through the + ! interface and therefore must store it here analogously to how it is handled + ! in the OpenFAST glue code. + real(DbKi) :: dT_Global ! dT of the code calling this module + integer(IntKi) :: N_Global ! global timestep + real(DbKi) :: T_Initial ! initial Time of simulation + real(DbKi), allocatable :: InputTimes(:) ! input times corresponding to u(:) array + 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) + integer(IntKi), parameter :: STATE_CURR = 1 ! Index for current state + integer(IntKi), parameter :: STATE_PRED = 2 ! Index for predicted state + ! Note the indexing is different on inputs (no clue why, but thats how OF handles it) + integer(IntKi), parameter :: INPUT_LAST = 3 ! Index for previous input at t-dt + integer(IntKi), parameter :: INPUT_CURR = 2 ! Index for current input at t + integer(IntKi), parameter :: INPUT_PRED = 1 ! Index for predicted input at t+dt + !------------------------------------------------------------------------------------ + + + + !------------------------------------------------------------------------------------ + ! Meshes for motions and loads + ! Meshes are used within HD to handle all motions and loads. Rather than directly + ! map to those nodes, we will create a mapping to go between the array of node + ! positions passed into this module and what is used inside HD. This is done + ! through a pair of meshes for the motion and loads corresponding to the node + ! positions passed in. + !------------------------------ + ! Meshes for external nodes + ! These point meshes are merely used to simplify the mapping of motions/loads + ! to/from HD using the library mesh mapping routines. These meshes may contain + ! one or multiple points. + ! - 1 point -- rigid floating body assumption + ! - N points -- flexible structure (either floating or fixed bottom) + integer(IntKi) :: NumNodePts ! Number of mesh points we are interfacing motions/loads to/from HD + type(MeshType) :: HD_MotionMesh ! mesh for motions of external nodes + type(MeshType) :: HD_LoadMesh ! mesh for loads for external nodes + type(MeshType) :: HD_LoadMesh_tmp ! mesh for loads for external nodes -- temporary + !------------------------------ + ! Mesh mapping: motions + ! The mapping of motions from the nodes passed in to the corresponding HD meshes + type(MeshMapType) :: Map_Motion_2_HD_PRP_P ! Mesh mapping between input motion mesh and PRP + type(MeshMapType) :: Map_Motion_2_HD_WB_P ! Mesh mapping between input motion mesh and WAMIT body(ies) mesh + type(MeshMapType) :: Map_Motion_2_HD_Mo_P ! Mesh mapping between input motion mesh and Morison mesh + !------------------------------ + ! Mesh mapping: loads + ! The mapping of loads from the HD meshes to the corresponding external nodes + type(MeshMapType) :: Map_HD_WB_P_2_Load ! Mesh mapping between HD output WAMIT body loads mesh and external nodes mesh + type(MeshMapType) :: Map_HD_Mo_P_2_Load ! Mesh mapping between HD output Morison loads mesh and external nodes mesh + ! Meshes -- helper stuff + real(R8Ki) :: theta(3) ! mesh creation helper data + ! Motions input (so we don't have to reallocate all the time + real(ReKi), allocatable :: tmpNodePos(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. + real(ReKi), allocatable :: tmpNodeVel(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. + real(ReKi), allocatable :: tmpNodeAcc(:,:) ! temp array. Probably don't need this, but makes conversion from C clearer. + real(ReKi), allocatable :: tmpNodeFrc(:,:) ! temp array. Probably don't need this, but makes conversion to C clearer. + !------------------------------------------------------------------------------------ + + +CONTAINS + +!> This routine sets the error status in C_CHAR for export to calling code. +!! Make absolutely certain that we do not overrun the end of ErrMsg_C. That is hard coded to 1025, +!! but ErrMsgLen is set in the nwtc_library, and could change without updates here. We don't want an +!! inadvertant buffer overrun -- that can lead to bad things. +subroutine SetErr(ErrStat, ErrMsg, ErrStat_C, ErrMsg_C) + integer, intent(in ) :: ErrStat !< aggregated error message (fortran type) + character(ErrMsgLen), intent(in ) :: ErrMsg !< aggregated error message (fortran type) + integer(c_int), intent( out) :: ErrStat_C + character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) + integer :: i + ErrStat_C = ErrStat ! We will send back the same error status that is used in OpenFAST + if (ErrMsgLen > ErrMsgLen_C-1) then ! If ErrMsgLen is > the space in ErrMsg_C, do not copy everything over + ErrMsg_C = TRANSFER( trim(ErrMsg(1:ErrMsgLen_C-1))//C_NULL_CHAR, ErrMsg_C ) + else + ErrMsg_C = TRANSFER( trim(ErrMsg)//C_NULL_CHAR, ErrMsg_C ) + endif +end subroutine SetErr + + +!=============================================================================================================== +!--------------------------------------------- HydroDyn Init---------------------------------------------------- +!=============================================================================================================== +SUBROUTINE HydroDyn_C_Init( OutRootName_C, InputFileString_C, InputFileStringLength_C, & + Gravity_C, defWtrDens_C, defWtrDpth_C, defMSL2SWL_C, & + PtfmRefPtPositionX_C, PtfmRefPtPositionY_C, & + NumNodePts_C, InitNodePositions_C, & + !NumWaveElev_C, WaveElevXY_C & !Placeholder for later + InterpOrder_C, T_initial_C, DT_C, TMax_C, & + NumChannels_C, OutputChannelNames_C, OutputChannelUnits_C, & + ErrStat_C, ErrMsg_C) BIND (C, NAME='HydroDyn_C_Init') + implicit none +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_Init +!GCC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_Init +#endif + + character(kind=c_char), intent(in ) :: OutRootName_C(IntfStrLen) !< Root name to use for echo files and other + type(c_ptr), intent(in ) :: InputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR + integer(c_int), intent(in ) :: InputFileStringLength_C !< lenght of the input file string + real(c_float), intent(in ) :: Gravity_C !< Gravitational constant (set by calling code) + real(c_float), intent(in ) :: defWtrDens_C !< Default value for water density (may be overridden by input file) + real(c_float), intent(in ) :: defWtrDpth_C !< Default value for water density (may be overridden by input file) + real(c_float), intent(in ) :: defMSL2SWL_C !< Default Offset between still-water level and mean sea level (m) [positive upward] (may be overridden by input file) + real(c_float), intent(in ) :: PtfmRefPtPositionX_C !< Initial position in wave field + real(c_float), intent(in ) :: PtfmRefPtPositionY_C !< Initial position in wave field + integer(c_int), intent(in ) :: NumNodePts_C !< Number of mesh points we are transfering motions to and output loads to + real(c_float), intent(in ) :: InitNodePositions_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [x,y,z,Rx,Ry,Rz] + !NOTE: not setting up the WaveElev at this point. Leaving placeholder for future + !integer(c_int), intent(in ) :: NumWaveElev_C !< Number of mesh points we are transfering motions to and output loads to + !real(c_float), intent(in ) :: WaveElevXY_C !< A 2xNumWaveElev_C array [x,y] + real(c_double), intent(in ) :: T_initial_C + integer(c_int), intent(in ) :: InterpOrder_C !< Interpolation order to use (must be 1 or 2) + real(c_double), intent(in ) :: DT_C !< Timestep used with HD for stepping forward from t to t+dt. Must be constant. + real(c_double), intent(in ) :: TMax_C !< Maximum time for simulation (used to set arrays for wave kinematics) + 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*MaxHDOutputs+1) !< NOTE: if MaxHDOutputs is sufficiently large, we may overrun the buffer on the Python side. + character(kind=c_char), intent( out) :: OutputChannelUnits_C(ChanLen*MaxHDOutputs+1) + 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 Variables + character(IntfStrLen) :: OutRootName !< Root name to use for echo files and other + character(kind=C_char, len=InputFileStringLength_C), pointer :: InputFileString !< Input file as a single string with NULL chracter separating lines + + real(DbKi) :: TimeInterval !< timestep for HD + integer(IntKi) :: ErrStat !< aggregated error message + 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 + character(*), parameter :: RoutineName = 'HydroDyn_C_Init' !< for error handling + + ! Initialize error handling + ErrStat = ErrID_None + ErrMsg = "" + + ! Sanity checks on values passed + InterpOrder = int(InterpOrder_C, IntKi) + if ( InterpOrder < 1_IntKi .or. InterpOrder > 2_IntKi ) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "InterpOrder passed into HydroDyn_C must be 1 (linear) or 2 (quadratic)" + if (Failed()) return + endif + + ! Get fortran pointer to C_NULL_CHAR deliniated input file as a string + call C_F_pointer(InputFileString_C, InputFileString) + + ! Get the data to pass to HD_Init + call InitFileInfo(InputFileString, InitInp%PassedFileData, ErrStat2, ErrMsg2); if (Failed()) return + + ! For diagnostic purposes, the following can be used to display the contents + ! of the InFileInfo data structure. + ! CU is the screen -- system dependent. + !call Print_FileInfo_Struct( CU, InitInp%PassedFileData ) + + ! Set other inputs for calling HydroDyn_Init + InitInp%InputFile = "passed_hd_file" ! dummy + InitInp%UseInputFile = .FALSE. ! this probably should be passed in + InitInp%HasIce = .FALSE. ! Always keep at false unless interfacing to ice modules + ! Linearization + ! for now, set linearization to false. Pass this in later when interface supports it + ! Note: we may want to linearize at T=0 for added mass effects, but that might be + ! special case + InitInp%Linearize = .FALSE. + + ! RootName -- for output of echo or other files + OutRootName = TRANSFER( OutRootName_C, OutRootName ) + i = INDEX(OutRootName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... + if ( i > 0 ) OutRootName = OutRootName(1:I) ! remove it + InitInp%OutRootName = trim(OutRootName) + + ! Values passed in + InitInp%Gravity = REAL(Gravity_C, ReKi) + InitInp%defWtrDens = REAL(defWtrDens_C, ReKi) + InitInp%defWtrDpth = REAL(defWtrDpth_C, ReKi) + InitInp%defMSL2SWL = REAL(defMSL2SWL_C, ReKi) + TimeInterval = REAL(DT_C, DbKi) + dT_Global = TimeInterval ! Assume this DT is constant for all simulation + N_Global = 0_IntKi ! Assume we are on timestep 0 at start + t_initial = REAL(T_Initial_C, DbKi) + InitInp%TMax = REAL(TMax_C, DbKi) + + ! Number of bodies and initial positions + ! - NumNodePts is the number of interface Mesh points we are expecting on the python + ! side. Will validate this against what HD reads from the initialization info. + NumNodePts = int(NumNodePts_C, IntKi) + if (NumNodePts < 1) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "At least one node point must be specified" + if (Failed()) return + endif + ! Allocate temporary arrays to simplify data conversions + call AllocAry( tmpNodePos, 6, NumNodePts, "tmpNodePos", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( tmpNodeVel, 6, NumNodePts, "tmpNodeVel", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( tmpNodeAcc, 6, NumNodePts, "tmpNodeAcc", ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( tmpNodeFrc, 6, NumNodePts, "tmpNodeFrc", ErrStat2, ErrMsg2 ); if (Failed()) return + tmpNodePos(1:6,1:NumNodePts) = reshape( real(InitNodePositions_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + + ! Platform reference position + ! The HD model uses this for building the moddel. This is only specified as an (X,Y) + ! position (no Z). + InitInp%PtfmLocationX = REAL(PtfmRefPtPositionX_C, ReKi) + InitInp%PtfmLocationY = REAL(PtfmRefPtPositionY_C, ReKi) + + + ! Wave eleveation output + ! Wave elevations can be exported for a set of points (grid or any other layout). + ! This feature is used only in the driver codes for exporting for visualization + ! and could be added to this inteface. + ! Skipping this for now. Maybe add later. + !InitInp%WaveElevXY + + + !---------------------------------------------------- + ! Allocate input array u and corresponding InputTimes + !---------------------------------------------------- + ! These inputs are used in the time stepping algorithm within HD_UpdateStates + ! For quadratic interpolation (InterpOrder==2), 3 timesteps are used. For + ! linear (InterOrder==1), 2 timesteps (the HD code can handle either). + ! u(1) inputs at t + ! u(2) inputs at t - dt + ! u(3) inputs at t - 2*dt ! quadratic only + allocate(u(InterpOrder+1), STAT=ErrStat2) + if (ErrStat2 /= 0) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "Could not allocate inuput" + if (Failed()) return + endif + call AllocAry( InputTimes, InterpOrder+1, "InputTimes", ErrStat2, ErrMsg2 ); if (Failed()) return + + + ! Call the main subroutine HydroDyn_Init + ! TimeInterval and InitInp are passed into HD_Init, all the rest are set by HD_Init + ! + ! NOTE: Pass u(1) only (this is empty and will be set inside Init). We will copy + ! this to u(2) and u(3) afterwards + call HydroDyn_Init( InitInp, u(1), p, x(STATE_CURR), xd(STATE_CURR), z(STATE_CURR), OtherStates(STATE_CURR), y, m, TimeInterval, InitOutData, ErrStat2, ErrMsg2 ) + if (Failed()) return + + + !------------------------------------------------------------- + ! Sanity checks + !------------------------------------------------------------- + call CheckDepth(ErrStat2,ErrMsg2); if (Failed()) return + call CheckNodes(ErrStat2,ErrMsg2); if (Failed()) return + + + !------------------------------------------------------------- + ! Set the interface meshes for motion inputs and loads output + !------------------------------------------------------------- + call SetMotionLoadsInterfaceMeshes(ErrStat2,ErrMsg2); if (Failed()) return + + + !------------------------------------------------------------- + ! Setup other prior timesteps + ! We fill InputTimes with negative times, but the Input values are identical for each of those times; this allows + ! us to use, e.g., quadratic interpolation that effectively acts as a zeroth-order extrapolation and first-order extrapolation + ! for the first and second time steps. (The interpolation order in the ExtrapInput routines are determined as + ! order = SIZE(Input) + !------------------------------------------------------------- + do i=2,InterpOrder+1 + call HydroDyn_CopyInput (u(1), u(i), MESH_NEWCOPY, Errstat2, ErrMsg2) + if (Failed()) return + enddo + do i = 1, InterpOrder + 1 + InputTimes(i) = t_initial - (i - 1) * dT_Global + enddo + InputTimePrev = InputTimes(1) - dT_Global ! Initialize for UpdateStates + + + !------------------------------------------------------------- + ! Initial setup of other pieces of x,xd,z,OtherStates + !------------------------------------------------------------- + CALL HydroDyn_CopyContState ( x( STATE_CURR), x( STATE_PRED), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState ( xd( STATE_CURR), xd( STATE_PRED), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState( z( STATE_CURR), z( STATE_PRED), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState ( OtherStates(STATE_CURR), OtherStates(STATE_PRED), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + + !------------------------------------------------------------- + ! Setup the previous timestep copies of states + !------------------------------------------------------------- + CALL HydroDyn_CopyContState ( x( STATE_CURR), x( STATE_LAST), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState ( xd( STATE_CURR), xd( STATE_LAST), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState( z( STATE_CURR), z( STATE_LAST), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState ( OtherStates(STATE_CURR), OtherStates(STATE_LAST), MESH_NEWCOPY, Errstat2, ErrMsg2); if (Failed()) return + +!TODO +! Is there any other InitOutData should be returned +! Any additional warnings or error handling necessary + + + !------------------------------------------------- + ! Set output channel information for driver code + !------------------------------------------------- + + ! Number of channels + NumChannels_C = size(InitOutData%WriteOutputHdr) + + ! transfer the output channel names and units to c_char arrays for returning + ! Upgrade idea: use C_NULL_CHAR as delimiters. Requires rework of Python + ! side of code. + k=1 + do i=1,NumChannels_C + do j=1,ChanLen ! max length of channel name. Same for units + OutputChannelNames_C(k)=InitOutData%WriteOutputHdr(i)(j:j) + OutputChannelUnits_C(k)=InitOutData%WriteOutputUnt(i)(j:j) + k=k+1 + enddo + enddo + + ! null terminate the string + OutputChannelNames_C(k) = C_NULL_CHAR + OutputChannelUnits_C(k) = C_NULL_CHAR + + + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + +CONTAINS + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) then + call FailCleanup() + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + endif + end function Failed + + subroutine FailCleanup() + if (allocated(tmpNodePos)) deallocate(tmpNodePos) + if (allocated(tmpNodeVel)) deallocate(tmpNodeVel) + if (allocated(tmpNodeAcc)) deallocate(tmpNodeAcc) + if (allocated(tmpNodeFrc)) deallocate(tmpNodeFrc) + end subroutine FailCleanup + + !> This subroutine sets the interface meshes to map to the input motions to the HD + !! meshes for WAMIT and Morison. This subroutine also sets the meshes for the + !! output loads. + subroutine SetMotionLoadsInterfaceMeshes(ErrStat3,ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 !< temporary error status + character(ErrMsgLen), intent( out) :: ErrMsg3 !< temporary error message + integer(IntKi) :: iNode + real(ReKi) :: InitPos(3) + real(R8Ki) :: theta(3) + real(R8Ki) :: Orient(3,3) + !------------------------------------------------------------- + ! Set the interface meshes for motion inputs and loads output + !------------------------------------------------------------- + ! Motion mesh + ! This point mesh may contain more than one point. Mapping will be used to map + ! this to the input meshes for WAMIT and Morison. + call MeshCreate( HD_MotionMesh , & + IOS = COMPONENT_INPUT , & + Nnodes = NumNodePts , & + ErrStat = ErrStat3 , & + ErrMess = ErrMsg3 , & + TranslationDisp = .TRUE., Orientation = .TRUE., & + TranslationVel = .TRUE., RotationVel = .TRUE., & + TranslationAcc = .TRUE., RotationAcc = .TRUE. ) + if (ErrStat3 >= AbortErrLev) return + + do iNode=1,NumNodePts + ! initial position and orientation of node + InitPos = tmpNodePos(1:3,iNode) + theta = real(tmpNodePos(4:6,iNode),DbKi) ! convert ReKi to DbKi to avoid roundoff + CALL SmllRotTrans( 'InputRotation', theta(1), theta(2), theta(3), Orient, 'Orient', ErrStat, ErrMsg ) + call MeshPositionNode( HD_MotionMesh , & + iNode , & + InitPos , & ! position + ErrStat3, ErrMsg3 , & + Orient ) ! orientation + if (ErrStat3 >= AbortErrLev) return + + call MeshConstructElement ( HD_MotionMesh, ELEMENT_POINT, ErrStat3, ErrMsg3, iNode ) + if (ErrStat3 >= AbortErrLev) return + enddo + + call MeshCommit ( HD_MotionMesh, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + + HD_MotionMesh%RemapFlag = .TRUE. + + ! For checking the mesh, uncomment this. + ! note: CU is is output unit (platform dependent). + !call MeshPrintInfo( CU, HD_MotionMesh ) + + !------------------------------------------------------------- + ! Loads mesh + ! This point mesh may contain more than one point. Mapping will be used to map + ! the loads from output meshes for WAMIT and Morison. + ! Output mesh for loads at each WAMIT body + CALL MeshCopy( SrcMesh = HD_MotionMesh ,& + DestMesh = HD_LoadMesh ,& + CtrlCode = MESH_SIBLING ,& + IOS = COMPONENT_OUTPUT ,& + ErrStat = ErrStat3 ,& + ErrMess = ErrMsg3 ,& + Force = .TRUE. ,& + Moment = .TRUE. ) + if (ErrStat3 >= AbortErrLev) return + + HD_LoadMesh%RemapFlag = .TRUE. + + ! For checking the mesh, uncomment this. + ! note: CU is is output unit (platform dependent). + !call MeshPrintInfo( CU, HD_LoadMesh ) + + !------------------------------------------------------------- + ! Loads mesh + ! This point mesh may contain more than one point. Mapping will be used to map + ! the loads from output meshes for WAMIT and Morison. + ! Output mesh for loads at each WAMIT body + CALL MeshCopy( SrcMesh = HD_LoadMesh ,& + DestMesh = HD_LoadMesh_tmp ,& + CtrlCode = MESH_COUSIN ,& + IOS = COMPONENT_OUTPUT ,& + ErrStat = ErrStat3 ,& + ErrMess = ErrMsg3 ,& + Force = .TRUE. ,& + Moment = .TRUE. ) + if (ErrStat3 >= AbortErrLev) return + + HD_LoadMesh_tmp%RemapFlag = .TRUE. + + ! For checking the mesh, uncomment this. + ! note: CU is is output unit (platform dependent). + !call MeshPrintInfo( CU, HD_LoadMesh_tmp ) + + !------------------------------------------------------------- + ! Set the mapping meshes + ! PRP - principle reference point + call MeshMapCreate( HD_MotionMesh, u(1)%PRPMesh, Map_Motion_2_HD_PRP_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + ! WAMIT - floating bodies using potential flow + if ( u(1)%WAMITMesh%Committed ) then ! input motions + call MeshMapCreate( HD_MotionMesh, u(1)%WAMITMesh, Map_Motion_2_HD_WB_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif + if ( y%WAMITMesh%Committed ) then ! output loads + call MeshMapCreate( y%WAMITMesh, HD_LoadMesh, Map_HD_WB_P_2_Load, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif + ! Morison - nodes for strip theory + if ( u(1)%Morison%Mesh%Committed ) then ! input motions + call MeshMapCreate( HD_MotionMesh, u(1)%Morison%Mesh, Map_Motion_2_HD_Mo_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif + if ( y%Morison%Mesh%Committed ) then ! output loads + call MeshMapCreate( y%Morison%Mesh, HD_LoadMesh, Map_HD_Mo_P_2_Load, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif + + end subroutine SetMotionLoadsInterfaceMeshes + + !------------------------------------------------------------- + !> Sanity check the nodes + !! If more than one input node was passed in, but only a single HD node + !! exits (single Morison or single WAMIT), then give error that too many + !! nodes passed. + subroutine CheckNodes(ErrStat3,ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 !< temporary error status + character(ErrMsgLen), intent( out) :: ErrMsg3 !< temporary error message + ErrStat3 = ErrID_None + ErrMsg3 = "" + if ( NumNodePts > 1 ) then + if ( u(1)%Morison%Mesh%Committed .and. u(1)%WAMITMesh%Committed ) then + if ( (u(1)%Morison%Mesh%Nnodes + u(1)%WAMITMesh%Nnodes) < NumNodePts ) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = "More nodes passed into library than exist in HydroDyn model" + endif + elseif ( u(1)%Morison%Mesh%Committed ) then ! No WAMIT + if ( u(1)%Morison%Mesh%Nnodes < NumNodePts ) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = "More nodes passed into library than exist in HydroDyn model Morison mesh" + endif + elseif ( u(1)%WAMITMesh%Committed ) then ! No Morison + if ( u(1)%WAMITMesh%Nnodes < NumNodePts ) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = "More nodes passed into library than exist in HydroDyn model WAMIT mesh" + endif + endif + endif + end subroutine CheckNodes + + !------------------------------------------------------------- + !> Sanity check the Morison mesh + !! If the Morison mesh has points near the bottom of the waterdepth, + !! then we could have some very strange results with only a single mesh + !! point for the HD_MotionMesh. All WAMIT mesh points should be near + !! the surface, so no checking is necessary. + subroutine CheckDepth(ErrStat3,ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 !< temporary error status + character(ErrMsgLen), intent( out) :: ErrMsg3 !< temporary error message + real(ReKi) :: tmpZpos !< temporary z-position + ErrStat3 = ErrID_None + ErrMsg3 = "" + tmpZpos=-0.001_ReKi*abs(p%WtrDpth) ! Initial comparison value close to surface + if ( NumNodePts == 1 .and. u(1)%Morison%Mesh%Committed ) then + do i=1,u(1)%Morison%Mesh%Nnodes + ! Find lowest Morison node + if (u(1)%Morison%Mesh%Position(3,i) < tmpZpos) then + tmpZpos = u(1)%Morison%Mesh%Position(3,i) + endif + enddo + if (tmpZpos < -abs(p%WtrDpth)*0.9_ReKi) then ! within 10% of the seafloor + ErrStat3 = ErrID_Severe + ErrMsg3 = "Inconsistent model"//NewLine//" -- Single library input node for simulating rigid floating structure."// & + NewLine//" -- Lowest Morison node is is in lowest 10% of water depth indicating fixed bottom structure from HydroDyn."// & + NewLine//" ---- Results may not make physical sense ----" + endif + endif + end subroutine CheckDepth + +END SUBROUTINE HydroDyn_C_Init + + +!=============================================================================================================== +!--------------------------------------------- HydroDyn CalcOutput --------------------------------------------- +!=============================================================================================================== + +SUBROUTINE HydroDyn_C_CalcOutput(Time_C, NumNodePts_C, NodePos_C, NodeVel_C, NodeAcc_C, & + NodeFrc_C, OutputChannelValues_C, ErrStat_C, ErrMsg_C) BIND (C, NAME='HydroDyn_C_CalcOutput') + implicit none +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_CalcOutput +!GCC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_CalcOutput +#endif + real(c_double), intent(in ) :: Time_C + integer(c_int), intent(in ) :: NumNodePts_C !< Number of mesh points we are transfering motions to and output loads to + real(c_float), intent(in ) :: NodePos_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [x,y,z,Rx,Ry,Rz] -- positions (global) + real(c_float), intent(in ) :: NodeVel_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [Vx,Vy,Vz,RVx,RVy,RVz] -- velocities (global) + real(c_float), intent(in ) :: NodeAcc_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [Ax,Ay,Az,RAx,RAy,RAz] -- accelerations (global) + real(c_float), intent( out) :: NodeFrc_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [Fx,Fy,Fz,Mx,My,Mz] -- forces and moments (global) + real(c_float), intent( out) :: OutputChannelValues_C(p%NumOuts) + integer(c_int), intent( out) :: ErrStat_C + character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) + + ! Local variables + real(DbKi) :: Time + integer(IntKi) :: iNode + integer(IntKi) :: ErrStat !< aggregated error status + character(ErrMsgLen) :: ErrMsg !< aggregated error message + integer(IntKi) :: ErrStat2 !< temporary error status from a call + character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call + character(*), parameter :: RoutineName = 'HydroDyn_C_CalcOutput' !< for error handling + + ! Initialize error handling + ErrStat = ErrID_None + ErrMsg = "" + + ! Sanity check -- number of node points cannot change + if ( NumNodePts /= int(NumNodePts_C, IntKi) ) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "Number of node points passed in changed. This must be constant throughout simulation" + if (Failed()) return + endif + + ! Convert the inputs from C to Fortrn + Time = REAL(Time_C,DbKi) + + ! Reshape position, velocity, acceleration + tmpNodePos(1:6,1:NumNodePts) = reshape( real(NodePos_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + tmpNodeVel(1:6,1:NumNodePts) = reshape( real(NodeVel_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + tmpNodeAcc(1:6,1:NumNodePts) = reshape( real(NodeAcc_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + + + ! Transfer motions to input meshes + call Set_MotionMesh( ErrStat2, ErrMsg2 ) ! update motion mesh with input motion arrays + if (Failed()) return + call HD_SetInputMotion( u(1), ErrStat2, ErrMsg2 ) ! transfer input motion mesh to u(1) meshes + if (Failed()) return + + + ! Call the main subroutine HydroDyn_CalcOutput to get the resulting forces and moments at time T + CALL HydroDyn_CalcOutput( Time, u(1), p, x(STATE_CURR), xd(STATE_CURR), z(STATE_CURR), OtherStates(STATE_CURR), y, m, ErrStat2, ErrMsg2 ) + if (Failed()) return + + + ! Transfer resulting load meshes to intermediate mesh + call HD_TransferLoads( u(1), y, ErrStat2, ErrMsg2 ) + if (Failed()) return + + + ! Set output force/moment array + call Set_OutputLoadArray( ) + ! Reshape for return + NodeFrc_C(1:6*NumNodePts) = reshape( real(tmpNodeFrc(1:6,1:NumNodePts), c_float), (/6*NumNodePts/) ) + + ! Get the output channel info out of y + OutputChannelValues_C = REAL(y%WriteOutput, C_FLOAT) + + ! Set error status + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + +CONTAINS + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + end function Failed +END SUBROUTINE HydroDyn_C_CalcOutput + +!=============================================================================================================== +!--------------------------------------------- HydroDyn UpdateStates ------------------------------------------- +!=============================================================================================================== +!> This routine updates the states from Time_C to TimeNext_C. It is assumed that the inputs are given for +!! TimeNext_C, but will be checked against the previous timestep values. +!! Since we don't really know if we are doing correction steps or not, we will track the previous state and +!! reset to those if we are repeating a timestep (normally this would be handled by the OF glue code, but since +!! the states are not passed across the interface, we must handle them here). +SUBROUTINE HydroDyn_C_UpdateStates( Time_C, TimeNext_C, NumNodePts_C, NodePos_C, NodeVel_C, NodeAcc_C, & + ErrStat_C, ErrMsg_C) BIND (C, NAME='HydroDyn_C_UpdateStates') + implicit none +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_UpdateStates +!GCC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_UpdateStates +#endif + real(c_double), intent(in ) :: Time_C + real(c_double), intent(in ) :: TimeNext_C + integer(c_int), intent(in ) :: NumNodePts_C !< Number of mesh points we are transfering motions to and output loads to + real(c_float), intent(in ) :: NodePos_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [x,y,z,Rx,Ry,Rz] -- positions (global) + real(c_float), intent(in ) :: NodeVel_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [Vx,Vy,Vz,RVx,RVy,RVz] -- velocities (global) + real(c_float), intent(in ) :: NodeAcc_C( 6*NumNodePts_C ) !< A 6xNumNodePts_C array [Ax,Ay,Az,RAx,RAy,RAz] -- accelerations (global) + integer(c_int), intent( out) :: ErrStat_C + character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) + + ! Local variables + logical :: CorrectionStep ! if we are repeating a timestep in UpdateStates, don't update the inputs array + integer(IntKi) :: iNode + integer(IntKi) :: ErrStat !< aggregated error status + character(ErrMsgLen) :: ErrMsg !< aggregated error message + integer(IntKi) :: ErrStat2 !< temporary error status from a call + character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call + character(*), parameter :: RoutineName = 'HydroDyn_C_UpdateStates' !< for error handling + + ! Initialize error handling + ErrStat = ErrID_None + ErrMsg = "" + CorrectionStep = .false. + + ! Sanity check -- number of node points cannot change + if ( NumNodePts /= int(NumNodePts_C, IntKi) ) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "Number of node points passed in changed. This must be constant throughout simulation" + if (Failed()) return + endif + + + !------------------------------------------------------- + ! Check the time for current timestep and next timestep + !------------------------------------------------------- + ! These inputs are used in the time stepping algorithm within HD_UpdateStates + ! For quadratic interpolation (InterpOrder==2), 3 timesteps are used. For + ! linear (InterOrder==1), 2 timesteps (the HD code can handle either). + ! u(1) inputs at t + dt ! Next timestep + ! u(2) inputs at t ! This timestep + ! u(3) inputs at t - dt ! previous timestep (quadratic only) + ! + ! NOTE: Within HD, the Radiation calculations can be done at an integer multiple of the + ! timestep. This is checked at each UpdateStates call. However, if we compile + ! in double precision, the values of Time_C and TimeNext_C are in double precison, + ! but InputTimes is in DbKi (which is promoted quad precision when compiling in + ! double precision) and the check may fail. So we are going to set the times we + ! we pass over to UpdateStates using the global timestep and the stored DbKi value + ! for the timestep rather than the lower precision (when compiled double) time + ! values passed in. It is a bit of a clumsy workaround for this precision loss, + ! but should not affect any results. + + ! Check if we are repeating an UpdateStates call (for example in a predictor/corrector loop) + if ( EqualRealNos( real(Time_C,DbKi), InputTimePrev ) ) then + CorrectionStep = .true. + else ! Setup time input times array + InputTimePrev = real(Time_C,DbKi) ! Store for check next time + if (InterpOrder>1) then ! quadratic, so keep the old time + InputTimes(INPUT_LAST) = ( N_Global - 1 ) * dT_Global ! u(3) at T-dT + endif + InputTimes(INPUT_CURR) = N_Global * dT_Global ! u(2) at T + InputTimes(INPUT_PRED) = ( N_Global + 1 ) * dT_Global ! u(1) at T+dT + N_Global = N_Global + 1_IntKi ! increment counter to T+dT + endif + + + if (CorrectionStep) then + ! Step back to previous state because we are doing a correction step + ! -- repeating the T -> T+dt update with new inputs at T+dt + ! -- the STATE_CURR contains states at T+dt from the previous call, so revert those + CALL HydroDyn_CopyContState (x( STATE_LAST), x( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState (xd( STATE_LAST), xd( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState (z( STATE_LAST), z( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState (OtherStates(STATE_LAST), OtherStates(STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + else + ! Cycle inputs back one timestep since we are moving forward in time. + if (InterpOrder>1) then ! quadratic, so keep the old time + call HydroDyn_CopyInput( u(INPUT_CURR), u(INPUT_LAST), MESH_UPDATECOPY, ErrStat2, ErrMsg2); if (Failed()) return + endif + ! Move inputs from previous t+dt (now t) to t + call HydroDyn_CopyInput( u(INPUT_PRED), u(INPUT_CURR), MESH_UPDATECOPY, ErrStat2, ErrMsg2); if (Failed()) return + endif + + !------------------------------------------------------- + ! Set inputs for time T+dt -- u(1) + !------------------------------------------------------- + ! Reshape position, velocity, acceleration + tmpNodePos(1:6,1:NumNodePts) = reshape( real(NodePos_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + tmpNodeVel(1:6,1:NumNodePts) = reshape( real(NodeVel_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + tmpNodeAcc(1:6,1:NumNodePts) = reshape( real(NodeAcc_C(1:6*NumNodePts),ReKi), (/6,NumNodePts/) ) + + ! Transfer motions to input meshes + call Set_MotionMesh( ErrStat2, ErrMsg2 ) ! update motion mesh with input motion arrays + if (Failed()) return + call HD_SetInputMotion( u(INPUT_PRED), ErrStat2, ErrMsg2 ) ! transfer input motion mesh to u(1) meshes + if (Failed()) return + + + ! Set copy the current state over to the predicted state for sending to UpdateStates + ! -- The STATE_PREDicted will get updated in the call. + ! -- The UpdateStates routine expects this to contain states at T at the start of the call (history not passed in) + CALL HydroDyn_CopyContState (x( STATE_CURR), x( STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState (xd( STATE_CURR), xd( STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState (z( STATE_CURR), z( STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState (OtherStates(STATE_CURR), OtherStates(STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + + + ! Call the main subroutine HydroDyn_UpdateStates to get the velocities + CALL HydroDyn_UpdateStates( InputTimes(INPUT_CURR), N_Global, u, InputTimes, p, x(STATE_PRED), xd(STATE_PRED), z(STATE_PRED), OtherStates(STATE_PRED), m, ErrStat2, ErrMsg2 ) + if (Failed()) return + + + !------------------------------------------------------- + ! cycle the states + !------------------------------------------------------- + ! move current state at T to previous state at T-dt + ! -- STATE_LAST now contains info at time T + ! -- this allows repeating the T --> T+dt update + CALL HydroDyn_CopyContState (x( STATE_CURR), x( STATE_LAST), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState (xd( STATE_CURR), xd( STATE_LAST), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState (z( STATE_CURR), z( STATE_LAST), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState (OtherStates(STATE_CURR), OtherStates(STATE_LAST), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + ! Update the predicted state as the new current state + ! -- we have now advanced from T to T+dt. This allows calling with CalcOuput to get the outputs at T+dt + CALL HydroDyn_CopyContState (x( STATE_PRED), x( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyDiscState (xd( STATE_PRED), xd( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyConstrState (z( STATE_PRED), z( STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + CALL HydroDyn_CopyOtherState (OtherStates(STATE_PRED), OtherStates(STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2); if (Failed()) return + + + + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + end function Failed +END SUBROUTINE HydroDyn_C_UpdateStates + +!=============================================================================================================== +!--------------------------------------------------- HydroDyn End----------------------------------------------- +!=============================================================================================================== +! NOTE: the error handling in this routine is slightly different than the other routines + +SUBROUTINE HydroDyn_C_End(ErrStat_C,ErrMsg_C) BIND (C, NAME='HydroDyn_C_End') + implicit none +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_End +!GCC$ ATTRIBUTES DLLEXPORT :: HydroDyn_C_End +#endif + integer(c_int), intent( out) :: ErrStat_C + character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) + + ! Local variables + integer(IntKi) :: i !< generic loop counter + integer :: ErrStat !< aggregated error status + 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 = 'HydroDyn_End_c' !< for error handling + + ! Initialize error handling + ErrStat = ErrID_None + ErrMsg = "" + + ! clear out any globably allocated helper arrays + if (allocated(tmpNodePos)) deallocate(tmpNodePos) + if (allocated(tmpNodeVel)) deallocate(tmpNodeVel) + if (allocated(tmpNodeAcc)) deallocate(tmpNodeAcc) + if (allocated(tmpNodeFrc)) deallocate(tmpNodeFrc) + + + ! Call the main subroutine HydroDyn_End + ! If u is not allocated, then we didn't get far at all in initialization, + ! or HD_C_End got called before Init. We don't want a segfault, so check + ! for allocation. + if (allocated(u)) then + call HydroDyn_End( u(1), p, x(STATE_CURR), xd(STATE_CURR), z(STATE_CURR), OtherStates(STATE_CURR), y, m, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + endif + + ! NOTE: HydroDyn_End only takes 1 instance of u, not the array. So extra + ! logic is required here (this isn't necessary in the fortran driver + ! or in openfast, but may be when this code is called from C, Python, + ! or some other code using the c-bindings. + if (allocated(u)) then + do i=2,size(u) + call HydroDyn_DestroyInput( u(i), ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + enddo + if (allocated(u)) deallocate(u) + endif + + ! Destroy any other copies of states (rerun on (STATE_CURR) is ok) + call HydroDyn_DestroyContState( x( STATE_LAST), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyDiscState( xd( STATE_LAST), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyConstrState( z( STATE_LAST), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyOtherState( OtherStates(STATE_LAST), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyContState( x( STATE_CURR), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyDiscState( xd( STATE_CURR), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyConstrState( z( STATE_CURR), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyOtherState( OtherStates(STATE_CURR), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyContState( x( STATE_PRED), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyDiscState( xd( STATE_PRED), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyConstrState( z( STATE_PRED), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call HydroDyn_DestroyOtherState( OtherStates(STATE_PRED), ErrStat2, ErrMsg2 ); call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + + ! if deallocate other items now + if (allocated(InputTimes)) deallocate(InputTimes) + + ! Clear out mesh related data storage + call ClearMesh() + + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) +CONTAINS + !> Don't leave junk in memory. So destroy meshes and mappings. + subroutine ClearMesh() + ! Destroy connection meshes + call MeshDestroy( HD_MotionMesh, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call MeshDestroy( HD_LoadMesh, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ! Destroy mesh mappings + call NWTC_Library_Destroymeshmaptype( Map_Motion_2_HD_PRP_P, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call NWTC_Library_Destroymeshmaptype( Map_Motion_2_HD_WB_P , ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call NWTC_Library_Destroymeshmaptype( Map_Motion_2_HD_Mo_P , ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call NWTC_Library_Destroymeshmaptype( Map_HD_WB_P_2_Load , ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call NWTC_Library_Destroymeshmaptype( Map_HD_Mo_P_2_Load , ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + end subroutine ClearMesh +END SUBROUTINE HydroDyn_C_End + + +!> This routine is operating on module level data, hence few inputs +subroutine Set_MotionMesh(ErrStat3, ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: iNode + real(R8Ki) :: theta(3) + real(R8Ki) :: Orient(3,3) + ! Set mesh corresponding to input motions + do iNode=1,NumNodePts + theta = real(tmpNodePos(4:6,iNode),DbKi) ! convert ReKi to DbKi to avoid roundoff + CALL SmllRotTrans( 'InputRotation', theta(1), theta(2), theta(3), Orient, 'Orient', ErrStat3, ErrMsg3 ) + HD_MotionMesh%TranslationDisp(1:3,iNode) = tmpNodePos(1:3,iNode) - HD_MotionMesh%Position(1:3,iNode) ! relative displacement only + HD_MotionMesh%Orientation(1:3,1:3,iNode) = Orient + HD_MotionMesh%TranslationVel( 1:3,iNode) = tmpNodeVel(1:3,iNode) + HD_MotionMesh%RotationVel( 1:3,iNode) = tmpNodeVel(4:6,iNode) + HD_MotionMesh%TranslationAcc( 1:3,iNode) = tmpNodeAcc(1:3,iNode) + HD_MotionMesh%RotationAcc( 1:3,iNode) = tmpNodeAcc(4:6,iNode) + enddo +end subroutine Set_MotionMesh + +!> Map the motion of the intermediate input mesh over to the input meshes +!! This routine is operating on module level data, hence few inputs +subroutine HD_SetInputMotion( u_local, ErrStat3, ErrMsg3 ) + type(HydroDyn_InputType), intent(inout) :: u_local ! Only one input (probably at T) + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + ! Principle reference point + CALL Transfer_Point_to_Point( HD_MotionMesh, u_local%PRPMesh, Map_Motion_2_HD_PRP_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + ! WAMIT mesh + if ( u_local%WAMITMesh%Committed ) then + call Transfer_Point_to_Point( HD_MotionMesh, u_local%WAMITMesh, Map_Motion_2_HD_WB_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif + ! Morison mesh + if ( u_local%Morison%Mesh%Committed ) then + call Transfer_Point_to_Point( HD_MotionMesh, u_local%Morison%Mesh, Map_Motion_2_HD_Mo_P, ErrStat3, ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + endif +end subroutine HD_SetInputMotion + + +!> Map the loads of the output meshes to the intermediate output mesh. Since +!! we are mapping two meshes over to a single one, we use an intermediate +!! temporary mesh -- prevents accidental overwrite of WAMIT loads on HD_LoadMesh +!! with the mapping of the Morison loads. +!! This routine is operating on module level data, hence few inputs +subroutine HD_TransferLoads( u_local, y_local, ErrStat3, ErrMsg3 ) + type(HydroDyn_InputType), intent(in ) :: u_local ! Only one input (probably at T) + type(HydroDyn_OutputType), intent(in ) :: y_local ! Only one input (probably at T) + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + + HD_LoadMesh%Force = 0.0_ReKi + HD_LoadMesh%Moment = 0.0_ReKi + + ! WAMIT mesh + if ( y_local%WAMITMesh%Committed ) then + HD_LoadMesh_tmp%Force = 0.0_ReKi + HD_LoadMesh_tmp%Moment = 0.0_ReKi + call Transfer_Point_to_Point( y_local%WAMITMesh, HD_LoadMesh_tmp, Map_HD_WB_P_2_Load, ErrStat3, ErrMsg3, u_local%WAMITMesh, HD_MotionMesh ) + if (ErrStat3 >= AbortErrLev) return + HD_LoadMesh%Force = HD_LoadMesh%Force + HD_LoadMesh_tmp%Force + HD_LoadMesh%Moment = HD_LoadMesh%Moment + HD_LoadMesh_tmp%Moment + endif + ! Morison mesh + if ( y_local%Morison%Mesh%Committed ) then + HD_LoadMesh_tmp%Force = 0.0_ReKi + HD_LoadMesh_tmp%Moment = 0.0_ReKi + call Transfer_Point_to_Point( y_local%Morison%Mesh, HD_LoadMesh_tmp, Map_HD_Mo_P_2_Load, ErrStat3, ErrMsg3, u_local%Morison%Mesh, HD_MotionMesh ) + if (ErrStat3 >= AbortErrLev) return + HD_LoadMesh%Force = HD_LoadMesh%Force + HD_LoadMesh_tmp%Force + HD_LoadMesh%Moment = HD_LoadMesh%Moment + HD_LoadMesh_tmp%Moment + endif +end subroutine HD_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() + integer(IntKi) :: iNode + ! Set mesh corresponding to input motions + do iNode=1,NumNodePts + tmpNodeFrc(1:3,iNode) = HD_LoadMesh%Force (1:3,iNode) + tmpNodeFrc(4:6,iNode) = HD_LoadMesh%Moment(1:3,iNode) + enddo +end subroutine Set_OutputLoadArray + +END MODULE HydroDyn_C_BINDING diff --git a/modules/hydrodyn/src/HydroDyn_DriverCode.f90 b/modules/hydrodyn/src/HydroDyn_DriverCode.f90 index 2e186d5bca..6312fb010c 100644 --- a/modules/hydrodyn/src/HydroDyn_DriverCode.f90 +++ b/modules/hydrodyn/src/HydroDyn_DriverCode.f90 @@ -165,12 +165,9 @@ PROGRAM HydroDynDriver CALL CheckArgs( drvrFilename, Flag=FlagArg ) IF ( LEN( TRIM(FlagArg) ) > 0 ) CALL NormStop() - ! Display the copyright notice + ! Display the copyright notice and compile info: 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 DispCompileRuntimeInfo( version%Name ) ! Parse the driver input file and run the simulation based on that file CALL ReadDriverInputFile( drvrFilename, drvrInitInp, ErrStat, ErrMsg ) diff --git a/modules/hydrodyn/src/HydroDyn_Output.f90 b/modules/hydrodyn/src/HydroDyn_Output.f90 index 465797a7ce..fc1c73e6bc 100644 --- a/modules/hydrodyn/src/HydroDyn_Output.f90 +++ b/modules/hydrodyn/src/HydroDyn_Output.f90 @@ -1231,6 +1231,8 @@ SUBROUTINE HDOut_WriteOutputs( Time, y, p, Decimate, ErrStat, ErrMsg ) ! Local variables INTEGER :: I ! Generic loop counter CHARACTER(200) :: Frmt ! a string to hold a format statement + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 IF (p%UnOutFile < 0 ) RETURN @@ -1268,7 +1270,7 @@ SUBROUTINE HDOut_WriteOutputs( Time, y, p, Decimate, ErrStat, ErrMsg ) WRITE(p%UnOutFile,Frmt,ADVANCE='no') ( p%Delim, y%WriteOutput(I) , I=1,p%NumTotalOuts ) END IF - WRITE (p%UnOutFile,'()', IOSTAT=ErrStat) ! write the line return + WRITE (p%UnOutFile,'()', IOSTAT=ErrStat2) ! write the line return -- ignore error status ELSE Decimate = Decimate + 1 diff --git a/modules/hydrodyn/src/WAMIT2.f90 b/modules/hydrodyn/src/WAMIT2.f90 index 5559dd89f7..fad0873cea 100644 --- a/modules/hydrodyn/src/WAMIT2.f90 +++ b/modules/hydrodyn/src/WAMIT2.f90 @@ -4221,12 +4221,12 @@ SUBROUTINE Read_DataFile3D( InitInp, Filename3D, Data3D, ErrStat, Errmsg ) IF ( EqualRealNos( Data3D%WvDir1(J), Data3D%WvDir2(J) ) .AND. & EqualRealNos( Data3D%WvDir1(K), Data3D%WvDir2(K) ) ) THEN - ! Check if not filled - IF ( .NOT. Data3D%DataMask( I, J, K, L ) ) THEN + ! Check if filled + IF ( Data3D%DataMask( I, J, K, L ) ) THEN ! See if the diagonal mirror one (WvDir2,WvDir1) value is not filled, ! and fill it if empty - IF ( Data3D%DataMask( I, K, J, L ) ) THEN + IF ( .NOT. Data3D%DataMask( I, K, J, L ) ) THEN Data3D%DataSet ( I, K, J, L ) = Data3D%DataSet( I, J, K, L ) Data3D%DataMask( I, K, J, L ) = .TRUE. ENDIF diff --git a/modules/icefloe/CMakeLists.txt b/modules/icefloe/CMakeLists.txt index 67306c750f..12fc293ac0 100644 --- a/modules/icefloe/CMakeLists.txt +++ b/modules/icefloe/CMakeLists.txt @@ -38,7 +38,7 @@ set(ICEFLOE_LIBS_SOURCES ) add_library(icefloelib ${ICEFLOE_LIBS_SOURCES}) -target_link_libraries(icefloelib nwtclibs) +target_link_libraries(icefloelib nwtclibs versioninfolib) install(TARGETS icefloelib EXPORT "${CMAKE_PROJECT_NAME}Libraries" diff --git a/modules/inflowwind/CMakeLists.txt b/modules/inflowwind/CMakeLists.txt index abc3f26313..1dea2c8dbe 100644 --- a/modules/inflowwind/CMakeLists.txt +++ b/modules/inflowwind/CMakeLists.txt @@ -53,7 +53,7 @@ target_link_libraries(ifwlib nwtclibs) # C-bound interface library add_library(ifw_c_binding SHARED src/IfW_C_Binding.f90) -target_link_libraries(ifw_c_binding ifwlib) +target_link_libraries(ifw_c_binding ifwlib versioninfolib) if(APPLE OR UNIX) target_compile_definitions(ifw_c_binding PUBLIC -DIMPLICIT_DLLEXPORT) endif() @@ -65,7 +65,7 @@ set(IFW_DRIVER_SOURCES ) add_executable(inflowwind_driver ${IFW_DRIVER_SOURCES}) -target_link_libraries(inflowwind_driver ifwlib ${CMAKE_DL_LIBS}) +target_link_libraries(inflowwind_driver ifwlib versioninfolib ${CMAKE_DL_LIBS}) install(TARGETS inflowwind_driver ifwlib ifw_c_binding EXPORT "${CMAKE_PROJECT_NAME}Libraries" diff --git a/modules/inflowwind/src/IfW_BladedFFWind.f90 b/modules/inflowwind/src/IfW_BladedFFWind.f90 index 7f8998fbc2..47f17c7927 100644 --- a/modules/inflowwind/src/IfW_BladedFFWind.f90 +++ b/modules/inflowwind/src/IfW_BladedFFWind.f90 @@ -99,6 +99,7 @@ SUBROUTINE IfW_BladedFFWind_Init(InitInp, ParamData, MiscVars, InitOutData, ErrS if (InitInp%NativeBladedFmt) then ParamData%FF%InterpTower = .true. + ParamData%FF%AddMeanAfterInterp = .true. ! Validate scaling data if we've got native-Bladed format CALL FFWind_ValidateInput(FF_InitInp, ParamData%FF%NFFComp, TmpErrStat, TmpErrMsg) @@ -111,7 +112,7 @@ SUBROUTINE IfW_BladedFFWind_Init(InitInp, ParamData, MiscVars, InitOutData, ErrS IF (ErrStat >= AbortErrLev) RETURN ! Add the mean wind speed to the u component. - call AddMeanVelocity(FF_InitInp, ParamData%FF%GridBase, 1.0_ReKi/ParamData%FF%InvFFZD, ParamData%FF%FFData) + if (.not. ParamData%FF%AddMeanAfterInterp) call AddMeanVelocity(FF_InitInp, ParamData%FF%GridBase, 1.0_ReKi/ParamData%FF%InvFFZD, ParamData%FF%FFData) else ParamData%FF%InterpTower = .false. end if @@ -525,6 +526,7 @@ SUBROUTINE Read_Summary_FF ( UnitWind, FileName, CWise, ZCenter, TI, UBar, RefHt RefHt = 0.0 Periodic = .FALSE. LHR = .FALSE. + CWise = .FALSE. ! default value, in case it is not in this file !---------------------------------------------------------------------------------------------- ! Open summary file. @@ -540,7 +542,7 @@ SUBROUTINE Read_Summary_FF ( UnitWind, FileName, CWise, ZCenter, TI, UBar, RefHt !---------------------------------------------------------------------------------------------- ! Here are the strings we're looking for, in this order: - ! 1) 'CLOCKWISE' + ! 1) 'CLOCKWISE' (optional) ! 2) 'HUB HEIGHT' ! 3) (unused; decided we didn't need to read data also stored in the binary file) ! 4) 'UBAR' @@ -557,7 +559,8 @@ SUBROUTINE Read_Summary_FF ( UnitWind, FileName, CWise, ZCenter, TI, UBar, RefHt IF ( TmpErrStat /= 0 ) THEN ! the "HEIGHT OFFSET", "PERIODIC", and "BLADED LEFT-HAND RULE" parameters are not necessary. We'll assume they are zero/false if we didn't find it. - IF ( StrNeeded(1) .OR. StrNeeded(2) .OR. StrNeeded(4) ) THEN + ! We will also assume "CLOCKWISE" is false if we didn't find it. + IF ( StrNeeded(2) .OR. StrNeeded(4) ) THEN CALL SetErrStat( ErrID_Fatal, ' Error reading line #'//TRIM(Num2LStr(LineCount))//' of the summary file, "'// & TRIM(FileName)//'". Could not find all of the required parameters.', ErrStat, ErrMsg, RoutineName ) RETURN @@ -570,36 +573,39 @@ SUBROUTINE Read_Summary_FF ( UnitWind, FileName, CWise, ZCenter, TI, UBar, RefHt CALL Conv2UC ( LINE ) - IF ( StrNeeded(1) ) THEN + IF ( StrNeeded(2) ) THEN ! if "CLOCKWISE" (StrNeeded(1)) is in the file, we would have already read it. If not, it's not in this file. - !------------------------------------------------------------------------------------------- - ! #1: Get the rotation direction, using the string "CLOCKWISE" - !------------------------------------------------------------------------------------------- + IF ( StrNeeded(1) ) THEN - IF ( INDEX( LINE, 'CLOCKWISE' ) > 0 ) THEN + !------------------------------------------------------------------------------------------- + ! #1: Get the rotation direction, using the string "CLOCKWISE" + !------------------------------------------------------------------------------------------- - READ (LINE, *, IOSTAT = TmpErrStat) CWise ! Look for True/False values + IF ( INDEX( LINE, 'CLOCKWISE' ) > 0 ) THEN - IF ( TmpErrStat /= 0 ) THEN ! Look for Yes/No values instead + READ (LINE, *, IOSTAT = TmpErrStat) CWise ! Look for True/False values - LINE = ADJUSTL ( LINE ) ! Remove leading spaces from input line + IF ( TmpErrStat /= 0 ) THEN ! Look for Yes/No values instead - SELECT CASE (LINE(1:1) ) - CASE ('Y') - CWise = .TRUE. - CASE ('N') - CWise = .FALSE. - CASE DEFAULT - CALL SetErrStat( ErrID_Fatal, ' Error reading rotation direction (CLOCKWISE) from FF summary file.', ErrStat, ErrMsg, RoutineName ) - RETURN - END SELECT + LINE = ADJUSTL ( LINE ) ! Remove leading spaces from input line - ENDIF ! TmpErrStat /= 0 - StrNeeded(1) = .FALSE. + SELECT CASE (LINE(1:1) ) + CASE ('Y') + CWise = .TRUE. + CASE ('N') + CWise = .FALSE. + CASE DEFAULT + CALL SetErrStat( ErrID_Fatal, ' Error reading rotation direction (CLOCKWISE) from FF summary file.', ErrStat, ErrMsg, RoutineName ) + RETURN + END SELECT + CYCLE - ENDIF ! INDEX for "CLOCKWISE" + ENDIF ! TmpErrStat /= 0 + StrNeeded(1) = .FALSE. - ELSEIF ( StrNeeded(2) ) THEN + ENDIF ! INDEX for "CLOCKWISE" + + END IF !------------------------------------------------------------------------------------------- ! #2: Get the hub height, using the strings "HUB HEIGHT" or "ZHUB" @@ -614,7 +620,7 @@ SUBROUTINE Read_Summary_FF ( UnitWind, FileName, CWise, ZCenter, TI, UBar, RefHt RETURN ENDIF StrNeeded(2) = .FALSE. - + ENDIF !INDEX for "HUB HEIGHT" or "ZHUB" ! ELSEIF ( StrNeeded(3) ) THEN diff --git a/modules/inflowwind/src/IfW_C_Binding.f90 b/modules/inflowwind/src/IfW_C_Binding.f90 index 502ba8236d..6df338953e 100644 --- a/modules/inflowwind/src/IfW_C_Binding.f90 +++ b/modules/inflowwind/src/IfW_C_Binding.f90 @@ -32,23 +32,22 @@ MODULE InflowWind_C_BINDING PUBLIC :: IfW_C_End ! Accessible to all routines inside module - TYPE(InflowWind_InputType) :: InputGuess !< An initial guess for the input; the input mesh must be defined, returned by Init - TYPE(InflowWind_InputType) :: InputData !< Created by IFW_CALCOUTPUT_C and used by IFW_END_C + TYPE(InflowWind_InputType) :: InputData !< Inputs to InflowWind TYPE(InflowWind_InitInputType) :: InitInp TYPE(InflowWind_InitOutputType) :: InitOutData !< Initial output data -- Names, units, and version info. TYPE(InflowWind_ParameterType) :: p !< Parameters TYPE(InflowWind_ContinuousStateType) :: ContStates !< Initial continuous states TYPE(InflowWind_DiscreteStateType) :: DiscStates !< Initial discrete states - TYPE(InflowWind_ConstraintStateType) :: ConstrStateGuess !< Initial guess of the constraint states TYPE(InflowWind_ConstraintStateType) :: ConstrStates !< Constraint states at Time TYPE(InflowWind_OtherStateType) :: OtherStates !< Initial other/optimization states TYPE(InflowWind_OutputType) :: y !< Initial output (outputs are not calculated; only the output mesh is initialized) TYPE(InflowWind_MiscVarType) :: m !< Misc variables for optimization (not copied in glue code) - ! This must exactly match the value in the Python interface. If ErrMsgLen changes - ! in the NWTC Library, this should be updated, but the logic - ! exists to correctly handle different lengths of the strings - integer(IntKi), parameter :: ErrMsgLen_C=1025 + ! This must exactly match the value in the Python interface. We are not using the variable 'ErrMsgLen' + ! so that we avoid issues if ErrMsgLen changes in the NWTC Library. If the value of ErrMsgLen does change + ! in the NWTC Library, ErrMsgLen_C (and the equivalent value in the Python interface) can be updated + ! to be equivalent to ErrMsgLen + 1, but the logic exists to correctly handle different lengths of the strings + integer(IntKi), parameter :: ErrMsgLen_C=1025 ! Numerical equivalent of ErrMsgLen + 1 CONTAINS @@ -76,8 +75,8 @@ end subroutine SetErr SUBROUTINE IfW_C_Init(InputFileString_C, InputFileStringLength_C, InputUniformString_C, InputUniformStringLength_C, NumWindPts_C, DT_C, NumChannels_C, OutputChannelNames_C, OutputChannelUnits_C, ErrStat_C, ErrMsg_C) BIND (C, NAME='IfW_C_Init') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: IfW_Init_c -!GCC$ ATTRIBUTES DLLEXPORT :: IfW_Init_c +!DEC$ ATTRIBUTES DLLEXPORT :: IfW_C_Init +!GCC$ ATTRIBUTES DLLEXPORT :: IfW_C_Init #endif TYPE(C_PTR) , INTENT(IN ) :: InputFileString_C INTEGER(C_INT) , INTENT(IN ) :: InputFileStringLength_C @@ -130,7 +129,7 @@ SUBROUTINE IfW_C_Init(InputFileString_C, InputFileStringLength_C, InputUniformSt TimeInterval = REAL(DT_C, DbKi) ! Call the main subroutine InflowWind_Init - only need InitInp and TimeInterval as inputs, the rest are set by InflowWind_Init - CALL InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ConstrStateGuess, OtherStates, y, m, TimeInterval, InitOutData, ErrStat2, ErrMsg2 ) + CALL InflowWind_Init( InitInp, InputData, p, ContStates, DiscStates, ConstrStates, OtherStates, y, m, TimeInterval, InitOutData, ErrStat2, ErrMsg2 ) if (Failed()) return ! Number of channels @@ -150,11 +149,6 @@ SUBROUTINE IfW_C_Init(InputFileString_C, InputFileStringLength_C, InputUniformSt OutputChannelNames_C(k) = C_NULL_CHAR OutputChannelUnits_C(k) = C_NULL_CHAR - ! Clean up variables and set up for IFW_CALCOUTPUT_C - CALL InflowWind_CopyInput(InputGuess, InputData, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) - if (Failed()) return - CALL InflowWind_CopyConstrState(ConstrStateGuess, ConstrStates, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) - if (Failed()) return call Cleanup() call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) @@ -169,8 +163,6 @@ logical function Failed() endif end function Failed subroutine Cleanup() ! NOTE: we are ignoring any error reporting from here - CALL InflowWind_DestroyInput(InputGuess, ErrStat2, ErrMsg2 ) - CALL InflowWind_DestroyConstrState(ConstrStateGuess, ErrStat2, ErrMsg2 ) end subroutine Cleanup END SUBROUTINE IfW_C_Init @@ -181,8 +173,8 @@ END SUBROUTINE IfW_C_Init SUBROUTINE IfW_C_CalcOutput(Time_C,Positions_C,Velocities_C,OutputChannelValues_C,ErrStat_C,ErrMsg_C) BIND (C, NAME='IfW_C_CalcOutput') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: IfW_CalcOutput_c -!GCC$ ATTRIBUTES DLLEXPORT :: IfW_CalcOutput_c +!DEC$ ATTRIBUTES DLLEXPORT :: IfW_C_CalcOutput +!GCC$ ATTRIBUTES DLLEXPORT :: IfW_C_CalcOutput #endif REAL(C_DOUBLE) , INTENT(IN ) :: Time_C REAL(C_FLOAT) , INTENT(IN ) :: Positions_C(3*InitInp%NumWindPoints) @@ -234,8 +226,8 @@ END SUBROUTINE IfW_C_CalcOutput SUBROUTINE IfW_C_End(ErrStat_C,ErrMsg_C) BIND (C, NAME='IfW_C_End') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: IfW_End_c -!GCC$ ATTRIBUTES DLLEXPORT :: IfW_End_c +!DEC$ ATTRIBUTES DLLEXPORT :: IfW_C_End +!GCC$ ATTRIBUTES DLLEXPORT :: IfW_C_End #endif INTEGER(C_INT) , INTENT( OUT) :: ErrStat_C CHARACTER(KIND=C_CHAR) , INTENT( OUT) :: ErrMsg_C(ErrMsgLen_C) diff --git a/modules/map/CMakeLists.txt b/modules/map/CMakeLists.txt index 2bf1de3f4c..2589d5a893 100644 --- a/modules/map/CMakeLists.txt +++ b/modules/map/CMakeLists.txt @@ -19,6 +19,11 @@ if(WIN32 OR CYGWIN OR MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAP_DLL_EXPORTS -DCMINPACK_NO_DLL -DNDEBUG -D_WINDOWS -D_USRDLL") endif() +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT WIN32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +endif() + if (GENERATE_TYPES) generate_f90_types(src/MAP_Fortran_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/MAP_Fortran_Types.f90 -noextrap) generate_f90_types(src/MAP_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/MAP_Types.f90 -ccode) diff --git a/modules/map/src/lineroutines.c b/modules/map/src/lineroutines.c index 7a8ca2098e..30fad7a27e 100644 --- a/modules/map/src/lineroutines.c +++ b/modules/map/src/lineroutines.c @@ -832,6 +832,31 @@ MAP_ERROR_CODE increment_psi_dof_by_delta(MAP_InputType_t* u_type, const Vessel* +/* Compute force at current operating point using a similar interface than fd_*_sequence */ +MAP_ERROR_CODE f_op_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const int size, char* map_msg, MAP_ERROR_CODE* ierr) +{ + MAP_ERROR_CODE success = MAP_SAFE; + Domain* domain = other_type->object; + Vessel* vessel = &domain->vessel; + + MAP_BEGIN_ERROR_LOG; + + /* Solve system */ + if (domain->MAP_SOLVE_TYPE==MONOLITHIC) { + success = line_solve_sequence(domain, p_type, 0.0, map_msg, ierr); + } else { + success = node_solve_sequence(domain, p_type, u_type, z_type, other_type, (float)-999.9, map_msg, ierr); // @todo CHECKERRQ() + }; + success = set_force_plus(y_type->Fx, force->fx, size); CHECKERRQ(MAP_FATAL_61); + success = set_force_plus(y_type->Fy, force->fy, size); CHECKERRQ(MAP_FATAL_61); + success = set_force_plus(y_type->Fz, force->fz, size); CHECKERRQ(MAP_FATAL_61); + success = set_moment_plus(y_type, vessel, force->mx, force->my, force->mz, size); CHECKERRQ(MAP_FATAL_61); + + MAP_END_ERROR_LOG; + MAP_RETURN_STATUS(*ierr); +}; + + MAP_ERROR_CODE fd_x_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_pos, char* map_msg, MAP_ERROR_CODE* ierr) { MAP_ERROR_CODE success = MAP_SAFE; @@ -1106,6 +1131,22 @@ MAP_ERROR_CODE calculate_stiffness(double* K, Fd* force, const double delta, con return MAP_SAFE; }; +MAP_ERROR_CODE calculate_sumforce(double* F, Fd* force, const int size) +{ + int i = 0; + + for (i=0 ; ifx[i]); + F[1] += (force->fy[i]); + F[2] += (force->fz[i]); + F[3] += (force->mx[i]); + F[4] += (force->my[i]); + F[5] += (force->mz[i]); + }; + return MAP_SAFE; +}; + + diff --git a/modules/map/src/lineroutines.h b/modules/map/src/lineroutines.h index e927af29ca..d34e9ae4c8 100644 --- a/modules/map/src/lineroutines.h +++ b/modules/map/src/lineroutines.h @@ -96,6 +96,7 @@ MAP_ERROR_CODE increment_the_dof_by_delta(MAP_InputType_t* u_type, const Vessel* MAP_ERROR_CODE increment_psi_dof_by_delta(MAP_InputType_t* u_type, const Vessel* vessel, const double delta, const int size); +MAP_ERROR_CODE f_op_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, int size, char* map_msg, MAP_ERROR_CODE* ierr); MAP_ERROR_CODE fd_x_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_pos, char* map_msg, MAP_ERROR_CODE* ierr); MAP_ERROR_CODE fd_y_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_pos, char* map_msg, MAP_ERROR_CODE* ierr); MAP_ERROR_CODE fd_z_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_pos, char* map_msg, MAP_ERROR_CODE* ierr); @@ -103,6 +104,7 @@ MAP_ERROR_CODE fd_phi_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterTy MAP_ERROR_CODE fd_the_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_x, const double* original_y, const double* original_z, char* map_msg, MAP_ERROR_CODE* ierr); MAP_ERROR_CODE fd_psi_sequence(MAP_OtherStateType_t* other_type, MAP_ParameterType_t* p_type, MAP_InputType_t* u_type, MAP_OutputType_t* y_type, MAP_ConstraintStateType_t* z_type, Fd* force, const double epsilon, const int size, const double* original_x, const double* original_y, const double* original_z, char* map_msg, MAP_ERROR_CODE* ierr); MAP_ERROR_CODE calculate_stiffness(double* K, Fd* force, const double delta, const int size); +MAP_ERROR_CODE calculate_sumforce (double* F, Fd* force, const int size); /** * sets cable excursions (l and h) and reference frame psi rotation diff --git a/modules/map/src/makefile b/modules/map/src/makefile index c8d824692c..a3aff02ca9 100644 --- a/modules/map/src/makefile +++ b/modules/map/src/makefile @@ -31,6 +31,7 @@ ifeq ($(OS),Windows_NT) CFLAGS = $(BITS) -g -std=c99 -DMAP_DLL_EXPORTS -DCMINPACK_NO_DLL -DNDEBUG -D_WINDOWS -D_USRDLL -D_MINGW LDFLAGS = $(BITS) -g -shared -Wl,--export-all-symbols LIB_FLAGS := + CC_TOOLS = gcc else PLATFORM = $(shell uname -s) DEL_CMD = rm -rf diff --git a/modules/map/src/map.f90 b/modules/map/src/map.f90 index 2559e39d86..fbad83037e 100644 --- a/modules/map/src/map.f90 +++ b/modules/map/src/map.f90 @@ -1403,6 +1403,9 @@ SUBROUTINE MAP_JacobianPInput( t, u, p, x, xd, z, OtherState, y, ErrStat, ErrMsg end if call cleanup() + ! Calling CalcOutput at operating point to ensure that "y" does not have the values of y_m (MAP specific issue) + call map_CalcOutput( t, u, p, x, xd, z, OtherState, y, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later contains subroutine cleanup() call map_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) diff --git a/modules/map/src/mapapi.c b/modules/map/src/mapapi.c index f43a7720b3..22584e85a0 100644 --- a/modules/map/src/mapapi.c +++ b/modules/map/src/mapapi.c @@ -358,7 +358,7 @@ MAP_EXTERNCALL void map_offset_vessel(MAP_OtherStateType_t* other_type, MAP_Inpu /* define transformation matrix */ R[0][0] = cpsi*cthe; R[0][1] = cpsi*sthe*sphi - spsi*cphi; R[0][2] = cpsi*sthe*cphi + spsi*sphi; - R[1][0] = spsi*cthe; R[1][1] = sphi*sthe*sphi + cpsi*cphi; R[1][2] = spsi*sthe*cphi - cpsi*sphi; + R[1][0] = spsi*cthe; R[1][1] = sphi*sthe*spsi + cpsi*cphi; R[1][2] = spsi*sthe*cphi - cpsi*sphi; R[2][0] = -sthe; R[2][1] = cthe*sphi; R[2][2] = cthe*cphi; for (i=0 ; ix_Len; + const int SIX = 6; + int i = 0; + Fd force; + double* F; + + map_reset_universal_error(map_msg, ierr); + + /* Summed force */ + F = malloc(SIX*sizeof(double)); + for (i=0 ; iz[k]; }; + /* Compute (transpose of) stiffness matrix by perturbing component by component */ for (i=0 ; iqty-1) { /* iterating through all strings */ if (parsed->entry[i_parsed]->slen) { /* if the string length is not 0 */ if (next==1) { - if (biseqcstrcaseless(parsed->entry[i_parsed],"FIX")) { + if (biseqcstrcaseless(parsed->entry[i_parsed],"FIX") || biseqcstrcaseless(parsed->entry[i_parsed],"FIXED")) { fix_num++; break; /* break the while-loop because the agenda is reached */ } else if (biseqcstrcaseless(parsed->entry[i_parsed],"CONNECT")) { @@ -1898,7 +1898,7 @@ MAP_ERROR_CODE set_node_list(const MAP_ParameterType_t* p_type, MAP_InputType_t if (next==0) { next++; } else if (next==1) { - if (biseqcstrcaseless(parsed->entry[i_parsed],"FIX")) { + if (biseqcstrcaseless(parsed->entry[i_parsed],"FIX") || biseqcstrcaseless(parsed->entry[i_parsed],"FIXED")) { node_iter->type = FIX; fix_num++; /* VarTypePtr FAST derived array index */ success = associate_vartype_ptr(&node_iter->position_ptr.x, other_type->x, fix_num); @@ -2433,19 +2433,19 @@ MAP_ERROR_CODE set_output_list(Domain* domain, MAP_InitOutputType_t* io_type, ch }; if (line_iter->options.azimuth_flag) { - success = push_variable_to_output_list(y_list, line_num, &line_iter->psi, "psi", "[m]"); + success = push_variable_to_output_list(y_list, line_num, &line_iter->psi, "psi", "[rad]"); io_type->writeOutputHdr_Len++; io_type->writeOutputUnt_Len++; }; if (line_iter->options.altitude_flag) { - success = push_variable_to_output_list(y_list, line_num, &line_iter->alpha, "alpha", "[m]"); + success = push_variable_to_output_list(y_list, line_num, &line_iter->alpha, "alpha", "[rad]"); io_type->writeOutputHdr_Len++; io_type->writeOutputUnt_Len++; }; if (line_iter->options.altitude_anchor_flag) { - success = push_variable_to_output_list(y_list, line_num, &line_iter->alpha_at_anchor, "alpha_a", "[m]"); + success = push_variable_to_output_list(y_list, line_num, &line_iter->alpha_at_anchor, "alpha_a", "[rad]"); io_type->writeOutputHdr_Len++; io_type->writeOutputUnt_Len++; }; @@ -2797,8 +2797,8 @@ MAP_ERROR_CODE print_help_to_screen() printf(" -v_anch, --Vertical force at anchor (does NOT include applied forces) [N]\n"); printf(" -tension_fair, --Line force-magnitude at fairlead (include applied loads) [N]\n"); printf(" -tension_anch, --Line force-magnitude at anchor (include applied loads) [N]\n"); - printf(" -azimuth, --Line lateral offset angle global X axis [deg]\n"); - printf(" -altitude, --Line inclination angle relative to global XY plane at fairlead [deg]\n"); + printf(" -azimuth, --Line lateral offset angle global X axis [rad]\n"); + printf(" -altitude, --Line inclination angle relative to global XY plane at fairlead [rad]\n"); printf(" -lay_length, --Length of line on seabed [m]\n"); printf(" -line_tension, -- \n"); printf(" Model features:\n"); diff --git a/modules/moordyn/CMakeLists.txt b/modules/moordyn/CMakeLists.txt index 4bd406ba23..18f66807b8 100644 --- a/modules/moordyn/CMakeLists.txt +++ b/modules/moordyn/CMakeLists.txt @@ -25,7 +25,7 @@ set(MOORDYN_LIBS_SOURCES ) add_library(moordynlib ${MOORDYN_LIBS_SOURCES}) -target_link_libraries(moordynlib nwtclibs) +target_link_libraries(moordynlib nwtclibs versioninfolib) install(TARGETS moordynlib EXPORT "${CMAKE_PROJECT_NAME}Libraries" @@ -35,7 +35,7 @@ install(TARGETS moordynlib set(MD_DRIVER_SOURCES src/MoorDyn_Driver.f90) add_executable(moordyn_driver ${MD_DRIVER_SOURCES}) -target_link_libraries(moordyn_driver moordynlib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) +target_link_libraries(moordyn_driver moordynlib nwtclibs ${CMAKE_DL_LIBS}) install(TARGETS moordyn_driver RUNTIME DESTINATION bin diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 99ad3b8019..0b501336ea 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -23,6 +23,7 @@ PROGRAM MoorDyn_Driver USE MoorDyn_Types USE MoorDyn USE NWTC_Library + USE VersionInfo IMPLICIT NONE diff --git a/modules/nwtc-library/CMakeLists.txt b/modules/nwtc-library/CMakeLists.txt index 7bf80a9b3c..6883581a0e 100644 --- a/modules/nwtc-library/CMakeLists.txt +++ b/modules/nwtc-library/CMakeLists.txt @@ -125,9 +125,9 @@ add_library(nwtclibs ${NWTCLIBS_SOURCES}) if(BUILD_OPENFAST_SIMULINK_API) find_package(Matlab REQUIRED) - target_link_libraries(nwtclibs versioninfolib ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS} ${Matlab_MEX_LIBRARY}) + target_link_libraries(nwtclibs ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS} ${Matlab_MEX_LIBRARY}) else() - target_link_libraries(nwtclibs versioninfolib ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS}) + target_link_libraries(nwtclibs ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS}) endif() install(TARGETS nwtclibs diff --git a/modules/nwtc-library/test/Compare_LAPACK_MUMPS/Compare_LAPACK_MUMPS.f90 b/modules/nwtc-library/Old_test/Compare_LAPACK_MUMPS/Compare_LAPACK_MUMPS.f90 similarity index 100% rename from modules/nwtc-library/test/Compare_LAPACK_MUMPS/Compare_LAPACK_MUMPS.f90 rename to modules/nwtc-library/Old_test/Compare_LAPACK_MUMPS/Compare_LAPACK_MUMPS.f90 diff --git a/modules/nwtc-library/test/ReadMe.md b/modules/nwtc-library/Old_test/ReadMe.md similarity index 100% rename from modules/nwtc-library/test/ReadMe.md rename to modules/nwtc-library/Old_test/ReadMe.md diff --git a/modules/nwtc-library/test/Test_CheckArgs.f90 b/modules/nwtc-library/Old_test/Test_CheckArgs.f90 similarity index 100% rename from modules/nwtc-library/test/Test_CheckArgs.f90 rename to modules/nwtc-library/Old_test/Test_CheckArgs.f90 diff --git a/modules/nwtc-library/test/Test_ChkRealFmtStr/Test_ChkRealFmtStr.f90 b/modules/nwtc-library/Old_test/Test_ChkRealFmtStr/Test_ChkRealFmtStr.f90 similarity index 100% rename from modules/nwtc-library/test/Test_ChkRealFmtStr/Test_ChkRealFmtStr.f90 rename to modules/nwtc-library/Old_test/Test_ChkRealFmtStr/Test_ChkRealFmtStr.f90 diff --git a/modules/nwtc-library/test/Test_ChkRealFmtStr/makefile b/modules/nwtc-library/Old_test/Test_ChkRealFmtStr/makefile similarity index 100% rename from modules/nwtc-library/test/Test_ChkRealFmtStr/makefile rename to modules/nwtc-library/Old_test/Test_ChkRealFmtStr/makefile diff --git a/modules/nwtc-library/test/Test_FileSize/Test_FileSize.f90 b/modules/nwtc-library/Old_test/Test_FileSize/Test_FileSize.f90 similarity index 100% rename from modules/nwtc-library/test/Test_FileSize/Test_FileSize.f90 rename to modules/nwtc-library/Old_test/Test_FileSize/Test_FileSize.f90 diff --git a/modules/nwtc-library/test/Test_FileSize/makefile b/modules/nwtc-library/Old_test/Test_FileSize/makefile similarity index 100% rename from modules/nwtc-library/test/Test_FileSize/makefile rename to modules/nwtc-library/Old_test/Test_FileSize/makefile diff --git a/modules/nwtc-library/test/Test_MeshMapping/Makefile b/modules/nwtc-library/Old_test/Test_MeshMapping/Makefile similarity index 100% rename from modules/nwtc-library/test/Test_MeshMapping/Makefile rename to modules/nwtc-library/Old_test/Test_MeshMapping/Makefile diff --git a/modules/nwtc-library/test/Test_MeshMapping/Test_MeshMapping.f90 b/modules/nwtc-library/Old_test/Test_MeshMapping/Test_MeshMapping.f90 similarity index 100% rename from modules/nwtc-library/test/Test_MeshMapping/Test_MeshMapping.f90 rename to modules/nwtc-library/Old_test/Test_MeshMapping/Test_MeshMapping.f90 diff --git a/modules/nwtc-library/test/Test_MeshMapping/Test_MeshMapping_Mod.f90 b/modules/nwtc-library/Old_test/Test_MeshMapping/Test_MeshMapping_Mod.f90 similarity index 100% rename from modules/nwtc-library/test/Test_MeshMapping/Test_MeshMapping_Mod.f90 rename to modules/nwtc-library/Old_test/Test_MeshMapping/Test_MeshMapping_Mod.f90 diff --git a/modules/nwtc-library/test/Test_NWTC_Library.f90 b/modules/nwtc-library/Old_test/Test_NWTC_Library.f90 similarity index 100% rename from modules/nwtc-library/test/Test_NWTC_Library.f90 rename to modules/nwtc-library/Old_test/Test_NWTC_Library.f90 diff --git a/modules/nwtc-library/test/Test_OpenCon_GnuWin/Test_OpenCon_GnuWin.f90 b/modules/nwtc-library/Old_test/Test_OpenCon_GnuWin/Test_OpenCon_GnuWin.f90 similarity index 100% rename from modules/nwtc-library/test/Test_OpenCon_GnuWin/Test_OpenCon_GnuWin.f90 rename to modules/nwtc-library/Old_test/Test_OpenCon_GnuWin/Test_OpenCon_GnuWin.f90 diff --git a/modules/nwtc-library/test/Test_OpenCon_GnuWin/makefile b/modules/nwtc-library/Old_test/Test_OpenCon_GnuWin/makefile similarity index 100% rename from modules/nwtc-library/test/Test_OpenCon_GnuWin/makefile rename to modules/nwtc-library/Old_test/Test_OpenCon_GnuWin/makefile diff --git a/modules/nwtc-library/test/Test_ReadComFile/Test_ReadComFile.f90 b/modules/nwtc-library/Old_test/Test_ReadComFile/Test_ReadComFile.f90 similarity index 100% rename from modules/nwtc-library/test/Test_ReadComFile/Test_ReadComFile.f90 rename to modules/nwtc-library/Old_test/Test_ReadComFile/Test_ReadComFile.f90 diff --git a/modules/nwtc-library/test/Test_ReadComFile/makefile b/modules/nwtc-library/Old_test/Test_ReadComFile/makefile similarity index 100% rename from modules/nwtc-library/test/Test_ReadComFile/makefile rename to modules/nwtc-library/Old_test/Test_ReadComFile/makefile diff --git a/modules/nwtc-library/test/Test_ReadFASTbin.f90 b/modules/nwtc-library/Old_test/Test_ReadFASTbin.f90 similarity index 100% rename from modules/nwtc-library/test/Test_ReadFASTbin.f90 rename to modules/nwtc-library/Old_test/Test_ReadFASTbin.f90 diff --git a/modules/nwtc-library/test/Test_RegCubicSpline/Test_RegCubicSpline.f90 b/modules/nwtc-library/Old_test/Test_RegCubicSpline/Test_RegCubicSpline.f90 similarity index 100% rename from modules/nwtc-library/test/Test_RegCubicSpline/Test_RegCubicSpline.f90 rename to modules/nwtc-library/Old_test/Test_RegCubicSpline/Test_RegCubicSpline.f90 diff --git a/modules/nwtc-library/src/ModMesh.f90 b/modules/nwtc-library/src/ModMesh.f90 index 9c386cf531..edfbc27fbb 100644 --- a/modules/nwtc-library/src/ModMesh.f90 +++ b/modules/nwtc-library/src/ModMesh.f90 @@ -3075,20 +3075,21 @@ END SUBROUTINE PackMotionMesh_Names !> This subroutine returns the operating point values of the mesh fields. It assumes all fields marked !! by FieldMask are allocated; Some fields may be allocated by the ModMesh module and not used in !! the linearization procedure, thus I am not using the check if they are allocated to determine if they should be included. - SUBROUTINE PackMotionMesh(M, Ary, indx_first, FieldMask, UseLogMaps) + SUBROUTINE PackMotionMesh(M, Ary, indx_first, FieldMask, UseSmlAngle) TYPE(MeshType) , INTENT(IN ) :: M !< Motion mesh REAL(ReKi) , INTENT(INOUT) :: Ary(:) !< array to pack this mesh into INTEGER(IntKi) , INTENT(INOUT) :: indx_first !< index into Ary; gives location of next array position to fill LOGICAL, OPTIONAL , INTENT(IN ) :: FieldMask(FIELDMASK_SIZE) !< flags to determine if this field is part of the packing - LOGICAL, OPTIONAL , INTENT(IN ) :: UseLogMaps !< flag to determine if the orientation should be packed as a DCM or a log map + LOGICAL, OPTIONAL , INTENT(IN ) :: UseSmlAngle !< flag to determine if the orientation should be packed as a DCM or a log map ! local variables: INTEGER(IntKi) :: i, j, k LOGICAL :: Mask(FIELDMASK_SIZE) !< flags to determine if this field is part of the packing - LOGICAL :: OutputLogMap - REAL(R8Ki) :: logmap(3) !< array to pack logmaps into + LOGICAL :: OutputSmlAngle + !REAL(R8Ki) :: logmap(3) !< array to pack logmaps into + REAL(R8Ki) :: angles(3) !< array to pack logmaps into INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3110,17 +3111,19 @@ SUBROUTINE PackMotionMesh(M, Ary, indx_first, FieldMask, UseLogMaps) end if if (Mask(MASKID_ORIENTATION)) then - if (present(UseLogMaps)) then - OutputLogMap = UseLogMaps + if (present(UseSmlAngle)) then + OutputSmlAngle = UseSmlAngle else - OutputLogMap = .false. + OutputSmlAngle = .false. end if - if (OutputLogMap) then + if (OutputSmlAngle) then do i=1,M%NNodes - call DCM_logMap(M%Orientation(:,:,i), logmap, ErrStat2, ErrMsg2) + !call DCM_logMap(M%Orientation(:,:,i), logmap, ErrStat2, ErrMsg2) + angles = GetSmllRotAngs ( M%Orientation(:,:,i), ErrStat2, ErrMsg2 ) do k=1,3 - Ary(indx_first) = logmap(k) + !Ary(indx_first) = logmap(k) + Ary(indx_first) = angles(k) indx_first = indx_first + 1 end do end do @@ -3176,22 +3179,27 @@ SUBROUTINE PackMotionMesh(M, Ary, indx_first, FieldMask, UseLogMaps) END SUBROUTINE PackMotionMesh !............................................................................................................................... !> This subroutine computes the differences of two meshes and packs that value into appropriate locations in the dY array. - SUBROUTINE PackMotionMesh_dY(M_p, M_m, dY, indx_first, FieldMask) + SUBROUTINE PackMotionMesh_dY(M_p, M_m, dY, indx_first, FieldMask, UseSmlAngle) TYPE(MeshType) , INTENT(IN ) :: M_p !< ED outputs on given mesh at \f$ u + \Delta u \f$ (p=plus) TYPE(MeshType) , INTENT(IN ) :: M_m !< ED outputs on given mesh at \f$ u - \Delta u \f$ (m=minus) REAL(R8Ki) , INTENT(INOUT) :: dY(:) !< column of dYdu \f$ \frac{\partial Y}{\partial u_i} = \frac{y_p - y_m}{2 \, \Delta u}\f$ INTEGER(IntKi) , INTENT(INOUT) :: indx_first !< index into dY array; gives location of next array position to fill LOGICAL, OPTIONAL , INTENT(IN ) :: FieldMask(FIELDMASK_SIZE) !< flags to determine if this field is part of the packing + LOGICAL, OPTIONAL , INTENT(IN ) :: UseSmlAngle !< flag to determine if the orientation should be packed as a DCM or a log map ! local variables: INTEGER(IntKi) :: ErrStat2 ! we're ignoring the errors about small angles CHARACTER(ErrMsgLen) :: ErrMsg2 INTEGER(IntKi) :: i, indx_last - REAL(R8Ki) :: lambda_m(3) - REAL(R8Ki) :: lambda_p(3) + LOGICAL :: OutputSmlAngle + !REAL(R8Ki) :: lambda_m(3) + !REAL(R8Ki) :: lambda_p(3) + REAL(R8Ki) :: angles_m(3) + REAL(R8Ki) :: angles_p(3) REAL(R8Ki) :: smallAngles(3) + REAL(R8Ki) :: orientation(3,3) LOGICAL :: Mask(FIELDMASK_SIZE) !< flags to determine if this field is part of the packing if (present(FieldMask)) then @@ -3210,16 +3218,38 @@ SUBROUTINE PackMotionMesh_dY(M_p, M_m, dY, indx_first, FieldMask) end if if (Mask(MASKID_ORIENTATION)) then - do i=1,M_p%NNodes - call DCM_logMap( M_m%Orientation(:,:,i), lambda_m, ErrStat2, ErrMsg2 ) - call DCM_logMap( M_p%Orientation(:,:,i), lambda_p, ErrStat2, ErrMsg2 ) + if (present(UseSmlAngle)) then + OutputSmlAngle = UseSmlAngle + else + OutputSmlAngle = .false. + end if - smallAngles = lambda_p - lambda_m + if (OutputSmlAngle) then + do i=1,M_p%NNodes + !call DCM_logMap( M_m%Orientation(:,:,i), lambda_m, ErrStat2, ErrMsg2 ) + !call DCM_logMap( M_p%Orientation(:,:,i), lambda_p, ErrStat2, ErrMsg2 ) + angles_m = GetSmllRotAngs ( M_m%Orientation(:,:,i), ErrStat2, ErrMsg2 ) + angles_p = GetSmllRotAngs ( M_p%Orientation(:,:,i), ErrStat2, ErrMsg2 ) - indx_last = indx_first + 2 - dY(indx_first:indx_last) = smallAngles - indx_first = indx_last + 1 - end do + !smallAngles = lambda_p - lambda_m + smallAngles = angles_p - angles_m + + indx_last = indx_first + 2 + dY(indx_first:indx_last) = smallAngles + indx_first = indx_last + 1 + end do + else + do i=1,M_p%NNodes + orientation = transpose(M_m%Orientation(:,:,i)) + orientation = matmul(orientation, M_p%Orientation(:,:,i)) + + smallAngles = GetSmllRotAngs( orientation, ErrStat2, ErrMsg2 ) + + indx_last = indx_first + 2 + dY(indx_first:indx_last) = smallAngles + indx_first = indx_last + 1 + end do + endif end if if (Mask(MASKID_TRANSLATIONVEL)) then diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 47da20580c..7be142eecb 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -23,7 +23,6 @@ MODULE NWTC_IO USE SysSubs USE NWTC_Library_Types ! ProgDesc and other types with copy and other routines for those types USE IEEE_ARITHMETIC - USE VersionInfo IMPLICIT NONE @@ -1496,181 +1495,7 @@ SUBROUTINE AllR16Ary5 ( Ary, AryDim1, AryDim2, AryDim3, AryDim4, AryDim5, Descr RETURN END SUBROUTINE AllR16Ary5 -!======================================================================= -!> This subroutine checks for command-line arguments. - SUBROUTINE CheckArgs ( Arg1, ErrStat, Arg2, Flag, InputArgArray ) - - ! Argument declarations: - CHARACTER(*), INTENT(INOUT) :: Arg1 !< The first non-flag argument; generally, the name of the input file. - INTEGER, INTENT( OUT), OPTIONAL :: ErrStat !< An optional argument for catching errors; if present, program does not abort on error. - CHARACTER(*), INTENT( OUT), OPTIONAL :: Arg2 !< An optional 2nd non-flag argument. - CHARACTER(*), INTENT( OUT), OPTIONAL :: Flag !< An optional flag argument; the first argument starting with a switch character. - CHARACTER(*), INTENT(IN ), DIMENSION(:), OPTIONAL :: InputArgArray !< An optional argument containing the arguments to parse; primarily used for unit testing. - - ! Local declarations: - INTEGER :: I, J ! Iterator variables - CHARACTER(1024) :: Arg, FlagIter - CHARACTER(1024), DIMENSION(:), ALLOCATABLE :: ArgArray, TempArray, Flags - LOGICAL :: FirstArgumentSet, SecondArgumentSet - - FirstArgumentSet = .FALSE. - SecondArgumentSet = .FALSE. - - IF ( PRESENT(Arg2) ) Arg2 = "" - IF ( PRESENT(Flag) ) Flag = "" - - ! Save all arguments in a single argument array; this is primarily used to enable unit testing - IF ( PRESENT(InputArgArray) ) THEN - ALLOCATE( ArgArray( SIZE(InputArgArray) ) ) - ArgArray = InputArgArray - ELSE - ALLOCATE( ArgArray( COMMAND_ARGUMENT_COUNT() ) ) - DO I = 1, SIZE(ArgArray) - CALL GET_COMMAND_LINE_ARG( I, ArgArray(I) ) - END DO - END IF - - ! Early return if no arguments and no default input file given - IF ( SIZE(ArgArray) == 0 .AND. LEN( TRIM(Arg1) ) == 0 ) THEN - CALL INVALID_SYNTAX( 'no command-line arguments given.' ) - CALL CLEANUP() - RETURN - END IF - - ! Split arguments into flags and non-flags - ALLOCATE( Flags(0) ) - DO I = 1, SIZE(ArgArray) - Arg = TRIM(ArgArray(I)) - IF ( IsFlag(Arg) ) THEN - ! This is how we can dynamically resize an array in Fortran... - ! Dont do this where performance matters. - ALLOCATE( TempArray( SIZE(Flags) + 1 ) ) - DO J = 1, SIZE(Flags) - TempArray(J) = Flags(J) - END DO - TempArray(SIZE(Flags) + 1) = TRIM(Arg) - DEALLOCATE(Flags) - CALL MOVE_ALLOC(TempArray, Flags) - ELSE IF ( .NOT. FirstArgumentSet ) THEN - Arg1 = TRIM(Arg) - FirstArgumentSet = .TRUE. - ELSE IF ( .NOT. SecondArgumentSet ) THEN - Arg2 = TRIM(Arg) - SecondArgumentSet = .True. - ELSE - CALL INVALID_SYNTAX( 'too many command-line arguments given.' ) - CALL CLEANUP() - RETURN - END IF - END DO - DO I = 1, SIZE(Flags) - - FlagIter = Flags(I)(2:) ! This results in the flag without the switch character - CALL Conv2UC( FlagIter ) - IF ( PRESENT(Flag) ) Flag = FlagIter - - SELECT CASE ( TRIM(FlagIter) ) - - CASE ('H') - CALL DispCopyrightLicense( ProgName ) - CALL DispCompileRuntimeInfo - CALL NWTC_DisplaySyntax( Arg1, ProgName ) - IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None - CALL CLEANUP() - RETURN - - CASE ('V', 'VERSION') - CALL DispCopyrightLicense( ProgName ) - CALL DispCompileRuntimeInfo - IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None - CALL CLEANUP() - RETURN - - CASE ('RESTART') - IF ( FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN - Arg2 = Arg1 - Arg1 = "" - END IF - IF ( .NOT. FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN - CALL INVALID_SYNTAX( 'the restart capability requires at least one argument: -restart ' ) - CALL CLEANUP() - RETURN - END IF - - CASE ('VTKLIN') - IF ( FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN - Arg2 = Arg1 - Arg1 = "" - END IF - IF ( .NOT. FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN - CALL INVALID_SYNTAX( 'the restart capability for vtk mode shapes requires at least one argument: -vtklin ' ) - CALL CLEANUP() - RETURN - END IF - - CASE DEFAULT - CALL INVALID_SYNTAX( 'unknown command-line argument given: '//TRIM(FlagIter) ) - CALL CLEANUP() - RETURN - - END SELECT - - END DO - - IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None - CALL CLEANUP() - - RETURN - - CONTAINS - SUBROUTINE CLEANUP() - IF ( ALLOCATED(ArgArray) ) DEALLOCATE(ArgArray) - IF ( ALLOCATED(Flags) ) DEALLOCATE(Flags) - IF ( ALLOCATED(TempArray) ) DEALLOCATE(TempArray) - END SUBROUTINE - - SUBROUTINE INVALID_SYNTAX(ErrorMessage) - - CHARACTER(*), INTENT(IN) :: ErrorMessage - - CALL DispCopyrightLicense( ProgName ) - CALL DispCompileRuntimeInfo - CALL NWTC_DisplaySyntax( Arg1, ProgName ) - CALL ProgAbort( ' Invalid syntax: '//TRIM(ErrorMessage), PRESENT(ErrStat) ) - IF ( PRESENT(ErrStat) ) ErrStat = ErrID_Fatal - - END SUBROUTINE - - SUBROUTINE GET_COMMAND_LINE_ARG(ArgIndex, ArgGiven) - - INTEGER, INTENT(IN) :: ArgIndex !< Index location of the argument to get. - CHARACTER(1024), INTENT(OUT) :: ArgGiven !< The gotten command-line argument. - INTEGER :: Error !< Indicates if there was an error getting an argument. - - CALL GET_COMMAND_ARGUMENT( ArgIndex, ArgGiven, STATUS=Error ) - ArgGiven = TRIM(ArgGiven) - IF ( Error /= 0 ) THEN - CALL ProgAbort ( ' Error getting command-line argument #'//TRIM( Int2LStr( ArgIndex ) )//'.', PRESENT(ErrStat) ) - IF ( PRESENT(ErrStat) ) ErrStat = ErrID_Fatal - END IF - - END SUBROUTINE - - FUNCTION IsFlag(ArgString) - - CHARACTER(*), INTENT(IN) :: ArgString - LOGICAL :: IsFlag - - IF ( ArgString(1:1) == SwChar .OR. ArgString(1:1) == '-' ) THEN - IsFlag = .TRUE. - ELSE - IsFlag = .FALSE. - END IF - - END FUNCTION - - END SUBROUTINE CheckArgs !======================================================================= !> This subroutine checks the data to be parsed to make sure it finds !! the expected variable name and an associated value. @@ -2259,65 +2084,6 @@ SUBROUTINE DLLTypeUnPack( OutData, ReKiBuf, DbKiBuf, IntKiBuf, ErrStat, ErrMsg ) END SUBROUTINE DLLTypeUnPack !======================================================================= -!> - SUBROUTINE DispCompileRuntimeInfo() -#ifdef _OPENMP - USE OMP_LIB -#endif -#ifdef HAS_FORTRAN2008_FEATURES - USE iso_fortran_env, ONLY: compiler_version -#endif - CHARACTER(200) :: compiler_version_str - CHARACTER(200) :: name - CHARACTER(200) :: git_commit, architecture, compiled_precision - CHARACTER(200) :: execution_date, execution_time, execution_zone - - name = ProgName - git_commit = QueryGitVersion() - architecture = TRIM(Num2LStr(BITS_IN_ADDR))//' bit' - IF (ReKi == SiKi) THEN - compiled_precision = 'single' - ELSE IF (ReKi == R8Ki) THEN - compiled_precision = 'double' - ELSE - compiled_precision = 'unknown' - END IF - -#if defined(HAS_FORTRAN2008_FEATURES) - compiler_version_str = compiler_version() -#elif defined(__INTEL_COMPILER) - compiler_version_str = 'Intel(R) Fortran Compiler '//num2lstr(__INTEL_COMPILER) -#else - compiler_version_str = OS_Desc -#endif - - CALL WrScr(trim(name)//'-'//trim(git_commit)) - CALL WrScr('Compile Info:') - call wrscr(' - Compiler: '//trim(compiler_version_str)) - CALL WrScr(' - Architecture: '//trim(architecture)) - CALL WrScr(' - Precision: '//trim(compiled_precision)) -#ifdef _OPENMP - !$OMP PARALLEL default(shared) - if (omp_get_thread_num()==0) then - call WrScr(' - OpenMP: Yes, number of threads: '//trim(Num2LStr(omp_get_num_threads()))//'/'//trim(Num2LStr(omp_get_max_threads()))) - endif - !$OMP END PARALLEL -#else - call WrScr(' - OpenMP: No') -#endif - CALL WrScr(' - Date: '//__DATE__) - CALL WrScr(' - Time: '//__TIME__) - ! call wrscr(' - Options: '//trim(compiler_options())) - - CALL DATE_AND_TIME(execution_date, execution_time, execution_zone) - - CALL WrScr('Execution Info:') - CALL WrScr(' - Date: '//TRIM(execution_date(5:6)//'/'//execution_date(7:8)//'/'//execution_date(1:4))) - CALL WrScr(' - Time: '//TRIM(execution_time(1:2)//':'//execution_time(3:4)//':'//execution_time(5:6))//TRIM(execution_zone)) - CALL WrScr('') - - END SUBROUTINE -!======================================================================= !> This routine displays the name of the program, its version, and its release date. !! Use DispNVD (nwtc_io::dispnvd) instead of directly calling a specific routine in the generic interface. SUBROUTINE DispNVD0() @@ -2519,7 +2285,11 @@ FUNCTION GetNVD ( ProgInfo ) ! Store all the version info into a single string: if (len_trim(ProgInfo%Ver) > 0) then - GetNVD = TRIM( ProgInfo%Name )//' ('//Trim( ProgInfo%Ver )//', '//Trim( ProgInfo%Date )//')' + if (len_trim(ProgInfo%Date) > 0) then + GetNVD = TRIM( ProgInfo%Name )//' ('//Trim( ProgInfo%Ver )//', '//Trim( ProgInfo%Date )//')' + else + GetNVD = TRIM( ProgInfo%Name )//' ('//Trim( ProgInfo%Ver )//')' + end if else GetNVD = TRIM( ProgInfo%Name ) end if @@ -7657,6 +7427,8 @@ SUBROUTINE WrBinFAST(FileName, FileID, DescStr, ChanName, ChanUnit, TimeData, Al REAL(SiKi), PARAMETER :: IntMin = -32768.0 ! Smallest integer represented in 2 bytes REAL(SiKi), PARAMETER :: IntRng = IntMax - IntMin ! Max Range of 2 byte integer + REAL(SiKi), PARAMETER :: SqrtEps = SQRT(EPSILON(1.0_SiKi)) ! small number for tolerance + ! Local variables @@ -7862,8 +7634,8 @@ SUBROUTINE WrBinFAST(FileName, FileID, DescStr, ChanName, ChanUnit, TimeData, Al ! Calculate the scaling parameters for each channel !............................................................................................................................... DO IC=1,NumOutChans ! Loop through the output channels - IF ( ColMax(IC) == ColMin(IC) ) THEN - ColScl(IC) = IntRng/SQRT(EPSILON(1.0_SiKi)) + IF ( abs(ColMax(IC) - ColMin(IC)) < SqrtEps ) THEN + ColScl(IC) = IntRng/SqrtEps ELSE ColScl(IC) = IntRng/REAL( ColMax(IC) - ColMin(IC), SiKi ) ENDIF diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 7e4cdaf16f..8154109871 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -4578,29 +4578,60 @@ FUNCTION OuterProductR16(u,v) END FUNCTION OuterProductR16 !======================================================================= -!> This subroutine perturbs an orientation matrix by a small angle, using -!! a logarithmic map. For small angles, the change in angle is equivalent to -!! a change in log map parameters. - SUBROUTINE PerturbOrientationMatrix( Orientation, Perturbation, AngleDim, Perturbations ) +!> This subroutine perturbs an orientation matrix by a small angle. Two methods +!! are used: +!! small angle DCM: perturb small angles extracted from DCM +!! large angle DCM: multiply input DCM with DCM created with small angle +!! perturbations +!! NOTE1: this routine originally used logarithmic mapping for small angle +!! perturbations +!! NOTE2: all warnings from SmllRotTrans are ignored. +!! NOTE3: notice no checks are made to verify correct set of inputs given +!! one of the follwing combinations must be provided (others truly +!! optional): +!! Perturbations +!! Perturbation + AngleDim + SUBROUTINE PerturbOrientationMatrix( Orientation, Perturbation, AngleDim, Perturbations, UseSmlAngle ) REAL(R8Ki), INTENT(INOUT) :: Orientation(3,3) REAL(R8Ki), OPTIONAL, INTENT(IN) :: Perturbation ! angle (radians) of the perturbation INTEGER, OPTIONAL, INTENT(IN) :: AngleDim REAL(R8Ki), OPTIONAL, INTENT(IN) :: Perturbations(3) ! angles (radians) of the perturbations + LOGICAL, OPTIONAL, INTENT(IN) :: UseSmlAngle ! Local variables REAL(R8Ki) :: angles(3) + REAL(R8Ki) :: OrientationTmp(3,3) + LOGICAL :: OutputSmlAngle integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - CALL DCM_LogMap( Orientation, angles, ErrStat2, ErrMsg2 ) - - IF (PRESENT(Perturbations)) THEN - angles = angles + Perturbations - ELSE - angles(AngleDim) = angles(AngleDim) + Perturbation - END IF + if (present(UseSmlAngle)) then + OutputSmlAngle = UseSmlAngle + else + OutputSmlAngle = .false. + end if + + if (OutputSmlAngle) then +! CALL DCM_LogMap( Orientation, angles, ErrStat2, ErrMsg2 ) + angles = GetSmllRotAngs ( Orientation, ErrStat2, ErrMsg2 ) + IF (PRESENT(Perturbations)) THEN + angles = angles + Perturbations + ELSE + angles(AngleDim) = angles(AngleDim) + Perturbation + END IF +! Orientation = DCM_exp( angles ) + call SmllRotTrans( 'linearization perturbation', angles(1), angles(2), angles(3), Orientation, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + else !Only works if AngleDim is specified + IF (PRESENT(Perturbations)) THEN + angles = Perturbations + ELSE + angles = 0.0_R8Ki + angles(AngleDim) = Perturbation + END IF + call SmllRotTrans( 'linearization perturbation', angles(1), angles(2), angles(3), OrientationTmp, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + Orientation = matmul(Orientation, OrientationTmp) + endif - Orientation = DCM_exp( angles ) END SUBROUTINE PerturbOrientationMatrix !======================================================================= diff --git a/modules/openfast-library/CMakeLists.txt b/modules/openfast-library/CMakeLists.txt index c4fd656b78..7f30d9396f 100644 --- a/modules/openfast-library/CMakeLists.txt +++ b/modules/openfast-library/CMakeLists.txt @@ -54,15 +54,17 @@ add_library(openfast_postlib ) target_link_libraries(openfast_postlib openfast_prelib scdataexlib foamfastlib versioninfolib) -add_library(openfastlib src/FAST_Library.f90) +add_library(openfastlib SHARED src/FAST_Library.f90) target_link_libraries(openfastlib openfast_postlib openfast_prelib scdataexlib foamfastlib) +set_property(TARGET openfastlib PROPERTY LINKER_LANGUAGE Fortran) string(TOUPPER ${CMAKE_Fortran_COMPILER_ID} _compiler_id) string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type) -if (${_compiler_id} STREQUAL "GNU" AND ${_build_type} STREQUAL "RELEASE") +if (${_compiler_id} STREQUAL "GNU" AND NOT ${VARIABLE_TRACKING}) # With variable tracking enabled, the compile step frequently aborts on large modules and - # restarts with this option off. Disabling in Release mode avoids this problem when compiling with - # full optimizations, but leaves it enabled for RelWithDebInfo which adds both -O2 and -g flags. + # restarts with this option off. Disabling avoids this problem when compiling with + # full optimizations. However, variable tracking should be enabled when actively debugging + # for better runtime debugging output. # https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html set_source_files_properties( src/FAST_Subs.f90 src/FAST_Types.f90 src/FAST_Library.f90 diff --git a/modules/openfast-library/src/FAST_Library.f90 b/modules/openfast-library/src/FAST_Library.f90 index a70bfe7fe5..f57e97b053 100644 --- a/modules/openfast-library/src/FAST_Library.f90 +++ b/modules/openfast-library/src/FAST_Library.f90 @@ -83,22 +83,23 @@ subroutine FAST_DeallocateTurbines(ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Deal ErrMsg_c = C_NULL_CHAR end subroutine !================================================================================================================================== -subroutine FAST_Sizes(iTurb, TMax, InitInpAry, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, ErrStat_c, ErrMsg_c, ChannelNames_c) BIND (C, NAME='FAST_Sizes') +subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_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 - REAL(C_DOUBLE), INTENT(IN ) :: TMax - REAL(C_DOUBLE), INTENT(IN ) :: InitInpAry(MAXInitINPUTS) CHARACTER(KIND=C_CHAR), INTENT(IN ) :: InputFileName_c(IntfStrLen) INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c INTEGER(C_INT), INTENT( OUT) :: NumOuts_c REAL(C_DOUBLE), INTENT( OUT) :: dt_c + REAL(C_DOUBLE), INTENT( OUT) :: tmax_c INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ChannelNames_c(ChanLen*MAXOUTPUTS+1) + REAL(C_DOUBLE), OPTIONAL, INTENT(IN ) :: TMax + REAL(C_DOUBLE), OPTIONAL, INTENT(IN ) :: InitInpAry(MAXInitINPUTS) ! local CHARACTER(IntfStrLen) :: InputFileName @@ -112,30 +113,45 @@ subroutine FAST_Sizes(iTurb, TMax, InitInpAry, InputFileName_c, AbortErrLev_c, N ! initialize variables: n_t_global = 0 - - ExternInitData%TMax = TMax - ExternInitData%TurbineID = -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 - ExternInitData%SensorType = NINT(InitInpAry(1)) - ! -- MATLAB Integration -- - ! Make sure fast farm integration is false - ExternInitData%FarmIntegration = .false. - - IF ( NINT(InitInpAry(2)) == 1 ) THEN - ExternInitData%LidRadialVel = .true. + + IF (PRESENT(TMax) .AND. .NOT. PRESENT(InitInpAry)) THEN + ErrStat_c = ErrID_Fatal + ErrMsg = "FAST_Sizes: TMax optional argument provided but it is invalid without InitInpAry optional argument. Provide InitInpAry to use TMax." + ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) + RETURN + END IF + + IF (PRESENT(InitInpAry)) THEN + 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%TurbinePos = 0.0_ReKi ! turbine position is at the origin + ExternInitData%NumCtrl2SC = 0 + ExternInitData%NumSC2Ctrl = 0 + ExternInitData%SensorType = NINT(InitInpAry(1)) + ! -- MATLAB Integration -- + ! Make sure fast farm integration is false + ExternInitData%FarmIntegration = .false. + + IF ( NINT(InitInpAry(2)) == 1 ) THEN + ExternInitData%LidRadialVel = .true. + ELSE + ExternInitData%LidRadialVel = .false. + END IF + + CALL FAST_InitializeAll_T( t_initial, iTurb, Turbine(iTurb), ErrStat, ErrMsg, InputFileName, ExternInitData) + ELSE - ExternInitData%LidRadialVel = .false. + + CALL FAST_InitializeAll_T( t_initial, iTurb, Turbine(iTurb), ErrStat, ErrMsg, InputFileName) + END IF - - - - CALL FAST_InitializeAll_T( t_initial, iTurb, Turbine(iTurb), ErrStat, ErrMsg, InputFileName, ExternInitData ) AbortErrLev_c = AbortErrLev NumOuts_c = min(MAXOUTPUTS, SUM( Turbine(iTurb)%y_FAST%numOuts )) dt_c = Turbine(iTurb)%p_FAST%dt + tmax_c = Turbine(iTurb)%p_FAST%TMax ErrStat_c = ErrStat ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR @@ -225,7 +241,7 @@ 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, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_Update') +subroutine FAST_Update(iTurb, 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 @@ -236,6 +252,7 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, Er INTEGER(C_INT), INTENT(IN ) :: NumOutputs_c REAL(C_DOUBLE), INTENT(IN ) :: InputAry(NumInputs_c) REAL(C_DOUBLE), INTENT( OUT) :: OutputAry(NumOutputs_c) + LOGICAL(C_BOOL), INTENT( OUT) :: EndSimulationEarly INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) @@ -245,7 +262,8 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, Er 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) - + EndSimulationEarly = .FALSE. + 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 @@ -284,20 +302,16 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, Er ErrMsg = TRIM(ErrMsg)//NewLine//TRIM(ErrMsg2) end if - ! NOTE: if there is ever more than one turbine, this logic will need to be revisited IF ( Turbine(iTurb)%m_FAST%Lin%FoundSteady) THEN - ErrStat = ErrID_Fatal + 1 ! it's not really "fatal", but we do want to end prematurely; FAST_SFunc.c will look to see that it's larger than AbortErrLev - ErrMsg = TRIM(ErrMsg)//NewLine//"Ending because steady-state trim solution was successfully found." + EndSimulationEarly = .TRUE. END IF - ! set the outputs for external code here... - ! return y_FAST%ChannelNames - ErrStat_c = ErrStat ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) END IF - + + ! set the outputs for external code here CALL FillOutputAry_T(Turbine(iTurb), Outputs) OutputAry(1) = Turbine(iTurb)%m_FAST%t_global OutputAry(2:NumOutputs_c) = Outputs @@ -308,6 +322,42 @@ subroutine FAST_Update(iTurb, NumInputs_c, NumOutputs_c, InputAry, OutputAry, Er 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') + IMPLICIT NONE +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_HubPosition +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_HubPosition +#endif + INTEGER(C_INT), INTENT(IN ) :: iTurb + 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) + + ErrStat_c = ErrID_None + ErrMsg = C_NULL_CHAR + + if (iTurb > size(Turbine) ) then + ErrStat_c = ErrID_Fatal + ErrMsg = "iTurb is greater than the number of turbines in the simulation."//C_NULL_CHAR + ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) + return + end if + + if (.NOT. Turbine(iTurb)%ED%y%HubPtMotion%Committed) then + ErrStat_c = ErrID_Fatal + ErrMsg = "HubPtMotion mesh has not been committed."//C_NULL_CHAR + ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) + return + end if + + AbsPosition_c = REAL(Turbine(iTurb)%ED%y%HubPtMotion%Position(:,1), C_FLOAT) + REAL(Turbine(iTurb)%ED%y%HubPtMotion%TranslationDisp(:,1), C_FLOAT) + Orientation_c = reshape( Turbine(iTurb)%ED%y%HubPtMotion%Orientation(1:3,1:3,1), (/9/) ) + RotationalVel_c = Turbine(iTurb)%ED%y%HubPtMotion%RotationVel(:,1) + +end subroutine FAST_HubPosition +!================================================================================================================================== !> NOTE: If this interface is changed, update the table in the ServoDyn_IO.f90::WrSumInfo4Simulink routine !! Ideally we would write this summary info from here, but that isn't currently done. So as a workaround so the user has some !! vague idea what went wrong with their simulation, we have ServoDyn include the arrangement set here in the SrvD.sum file. diff --git a/modules/openfast-library/src/FAST_Library.h b/modules/openfast-library/src/FAST_Library.h index 69fbec8b83..139ab6fc58 100644 --- a/modules/openfast-library/src/FAST_Library.h +++ b/modules/openfast-library/src/FAST_Library.h @@ -4,6 +4,7 @@ // routines in FAST_Library_$(PlatformName).dll #include "OpenFOAM_Types.h" #include "SCDataEx_Types.h" +#include "stdio.h" #ifdef __cplusplus #define EXTERNAL_ROUTINE extern "C" @@ -22,10 +23,16 @@ EXTERNAL_ROUTINE void FAST_OpFM_Init(int * iTurb, double *TMax, const char *Inpu EXTERNAL_ROUTINE void FAST_OpFM_Solution0(int * iTurb, int *ErrStat, char *ErrMsg); EXTERNAL_ROUTINE void FAST_OpFM_Step(int * iTurb, int *ErrStat, char *ErrMsg); +EXTERNAL_ROUTINE void FAST_HubPosition(int * iTurb, float * absolute_position, float * rotation_veocity, double * orientation_dcm, int *ErrStat, char *ErrMsg); + EXTERNAL_ROUTINE void FAST_Restart(int * iTurb, const char *CheckpointRootName, int *AbortErrLev, int * NumOuts, double * dt, int * n_t_global, int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_Sizes(int * iTurb, double *TMax, double *InitInputAry, const char *InputFileName, int *AbortErrLev, int * NumOuts, double * dt, int *ErrStat, char *ErrMsg, char *ChannelNames); +#ifdef __cplusplus +EXTERNAL_ROUTINE void FAST_Sizes(int * iTurb, const char *InputFileName, int *AbortErrLev, int * NumOuts, double * dt, double * tmax, int *ErrStat, char *ErrMsg, char *ChannelNames, double *TMax = NULL, double *InitInputAry = NULL); +#else +EXTERNAL_ROUTINE void FAST_Sizes(int * iTurb, const char *InputFileName, int *AbortErrLev, int * NumOuts, double * dt, double * tmax, int *ErrStat, char *ErrMsg, char *ChannelNames, double *TMax, double *InitInputAry); +#endif EXTERNAL_ROUTINE void FAST_Start(int * iTurb, int *NumInputs_c, int *NumOutputs_c, double *InputAry, double *OutputAry, int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_Update(int * iTurb, int *NumInputs_c, int *NumOutputs_c, double *InputAry, double *OutputAry, int *ErrStat, char *ErrMsg); +EXTERNAL_ROUTINE void FAST_Update(int * iTurb, int *NumInputs_c, int *NumOutputs_c, double *InputAry, double *OutputAry, bool *EndSimulationEarly, int *ErrStat, char *ErrMsg); EXTERNAL_ROUTINE void FAST_End(int * iTurb, bool * stopThisProgram); EXTERNAL_ROUTINE void FAST_CreateCheckpoint(int * iTurb, const char *CheckpointRootName, int *ErrStat, char *ErrMsg); @@ -51,6 +58,16 @@ EXTERNAL_ROUTINE void FAST_CreateCheckpoint(int * iTurb, const char *CheckpointR #define MAXInitINPUTS 53 #define NumFixedInputs 2 + 2 + MAXIMUM_BLADES + 1 + MAXIMUM_AFCTRL + MAXIMUM_CABLE_DELTAL + MAXIMUM_CABLE_DELTALDOT - +/* Fixed inputs list: + 1 Generator Torque (N-m) + 2 Electrical Power (W) + 3 Yaw pos (rad) + 4 Yaw rate (rad/s) + 5-7 Blade 1-3 pitch angle (rad) + 8 High speed shaft brake fraction (-) + 9-11 Blade 1-3 Airfoil control (-) + 12-31 Cable control channel 1-20 DeltaL (m) + 32-51 Cable control channel 1-20 DeltaLDot (m/s) +*/ #endif diff --git a/modules/openfast-library/src/FAST_Lin.f90 b/modules/openfast-library/src/FAST_Lin.f90 index b26bacf7fa..63b06f2344 100644 --- a/modules/openfast-library/src/FAST_Lin.f90 +++ b/modules/openfast-library/src/FAST_Lin.f90 @@ -809,13 +809,24 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, if ( p_FAST%CompServo == Module_SrvD ) then ! get the jacobians call SrvD_JacobianPInput( t_global, SrvD%Input(1), SrvD%p, SrvD%x(STATE_CURR), SrvD%xd(STATE_CURR), SrvD%z(STATE_CURR), & - SrvD%OtherSt(STATE_CURR), SrvD%y, SrvD%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%D ) + SrvD%OtherSt(STATE_CURR), SrvD%y, SrvD%m, ErrStat2, ErrMsg2, & + dXdu=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%B, & + dYdu=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%D ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call SrvD_JacobianPContState( t_global, SrvD%Input(1), SrvD%p, SrvD%x(STATE_CURR), SrvD%xd(STATE_CURR), SrvD%z(STATE_CURR), & + SrvD%OtherSt(STATE_CURR), SrvD%y, SrvD%m, ErrStat2, ErrMsg2, & + dYdx=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%C, & + dXdx=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%A ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! get the operating point call SrvD_GetOP( t_global, SrvD%Input(1), SrvD%p, SrvD%x(STATE_CURR), SrvD%xd(STATE_CURR), SrvD%z(STATE_CURR), & - SrvD%OtherSt(STATE_CURR), SrvD%y, SrvD%m, ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_u, & - y_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_y ) + SrvD%OtherSt(STATE_CURR), SrvD%y, SrvD%m, ErrStat2, ErrMsg2, & + u_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_u, & + dx_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_dx, & + x_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_x, & + y_op=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%op_y ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then call cleanup() @@ -835,9 +846,12 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, ! Jacobians if (p_FAST%LinOutJac) then - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', & - UseRow=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_y, UseCol=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_u ) + ! Jacobians + call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx') + call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_u) + call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_y) + call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_y, & + UseCol=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_u) end if ! finish writing the file @@ -1598,7 +1612,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, !! 0 & 0 & 0 & 0 & \frac{\partial U_\Lambda^{AD}}{\partial u^{AD}} \\ !! \end{bmatrix} \f$ !..................................... -! LIN-TODO: Add doc strings for new modules: HD & MAP & SD +! LIN-TODO: Add doc strings for new modules: SrvD & HD & MAP & SD if (.not. allocated(dUdu)) then call AllocAry(dUdu, y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), 'dUdu', ErrStat2, ErrMsg2) @@ -1635,16 +1649,25 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, call Linear_IfW_InputSolve_du_AD( p_FAST, y_FAST, AD%Input(1), dUdu ) end if ! we're using the InflowWind module + !............ + ! \f$ \frac{\partial U_\Lambda^{SrvD}}{\partial u^{SrvD}} \end{bmatrix} = \f$ (dUdu block row 2=SrvD) + !............ + if (p_FAST%CompServo == MODULE_SrvD) then + call Linear_SrvD_InputSolve_du( p_FAST, y_FAST, SrvD%p, SrvD%Input(1), ED%y, BD, SD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + !............ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{BD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{AD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{HD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{SD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{MAP}} \end{bmatrix} = \f$ (dUdu block row 3=ED) + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{SrvD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{BD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{AD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{HD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{SD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{MAP}} \end{bmatrix} = \f$ (dUdu block row 3=ED) !............ ! we need to do this for CompElast=ED and CompElast=BD - call Linear_ED_InputSolve_du( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, SD, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call Linear_ED_InputSolve_du( p_FAST, y_FAST, SrvD, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, SD, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !............ @@ -1652,7 +1675,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial u^{AD}} \end{bmatrix} = \f$ (dUdu block row 4=BD) !............ IF (p_FAST%CompElast == Module_BD) THEN - call Linear_BD_InputSolve_du( p_FAST, y_FAST, ED%y, AD%y, AD%Input(1), BD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call Linear_BD_InputSolve_du( p_FAST, y_FAST, SrvD, ED%y, AD%y, AD%Input(1), BD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) END IF @@ -1680,13 +1703,13 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, ! \f$ \frac{\partial U_\Lambda^{SD}}{\partial u^{MAP}} \end{bmatrix} = \f$ (dUdu block row 7=SD) !............ IF (p_FAST%CompSub == MODULE_SD) THEN - call Linear_SD_InputSolve_du( p_FAST, y_FAST, SD%Input(1), SD%y, ED%y, HD, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call Linear_SD_InputSolve_du( p_FAST, y_FAST, SrvD, SD%Input(1), SD%y, ED%y, HD, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ELSE IF (p_FAST%CompSub == Module_ExtPtfm) THEN CALL WrScr('>>> FAST_LIN: Linear_ExtPtfm_InputSolve_du, TODO') ENDIF - ! LIN-TODO: Update the doc lines below to include HD, SD, and MAP + ! LIN-TODO: Update the doc lines below to include SrvD, HD, SD, and MAP !..................................... ! dUdy !> \f$ \frac{\partial U_\Lambda}{\partial y} = @@ -1720,21 +1743,22 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, ! \f$ \frac{\partial U_\Lambda^{SrvD}}{\partial y^{ED}} \end{bmatrix} = \f$ (dUdy block row 2=SrvD) !............ if (p_FAST%CompServo == MODULE_SrvD) then ! need to do this regardless of CompElast - call Linear_SrvD_InputSolve_dy( p_FAST, y_FAST, dUdy ) + call Linear_SrvD_InputSolve_dy( p_FAST, y_FAST, SrvD%p, SrvD%Input(1), ED%y, BD, SD%y, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if !............ ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{SrvD}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{ED}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{BD}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{AD}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{HD}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{SD}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{MAP}} \end{bmatrix} = \f$ (dUdy block row 3=ED) + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{ED}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{BD}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{AD}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{HD}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{SD}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial y^{MAP}} \end{bmatrix} = \f$ (dUdy block row 3=ED) !............ - call Linear_ED_InputSolve_dy( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, SD, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, SD, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) !............ @@ -1743,7 +1767,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial y^{AD}} \end{bmatrix} = \f$ (dUdy block row 4=BD) !............ if (p_FAST%CompElast == MODULE_BD) then - call Linear_BD_InputSolve_dy( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call Linear_BD_InputSolve_dy( p_FAST, y_FAST, SrvD, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if @@ -1764,15 +1788,6 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, end if - !............ - ! \f$ \frac{\partial U_\Lambda^{HD}}{\partial y^{ED}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{HD}}{\partial y^{SD}} \end{bmatrix} = \f$ (dUdy block row 6=HD) - !............ - if (p_FAST%CompHydro == MODULE_HD) then - call Linear_HD_InputSolve_dy( p_FAST, y_FAST, HD%Input(1), ED%y, SD%y, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - end if - !............ ! \f$ \frac{\partial U_\Lambda^{SD}}{\partial y^{ED}} \end{bmatrix} = \f$ ! \f$ \frac{\partial U_\Lambda^{SD}}{\partial y^{HD}} \end{bmatrix} = \f$ @@ -1786,7 +1801,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, !LIN-TODO: Add doc strings and look at above doc string IF (p_FAST%CompSub == Module_SD) THEN - call Linear_SD_InputSolve_dy( p_FAST, y_FAST, SD%Input(1), SD%y, ED%y, HD, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call Linear_SD_InputSolve_dy( p_FAST, y_FAST, SrvD, SD%Input(1), SD%y, ED%y, HD, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ELSE IF (p_FAST%CompSub == Module_ExtPtfm) THEN write(*,*)'>>> FAST_LIN: Linear_ExtPtfm_InputSolve_dy, TODO' @@ -1801,9 +1816,9 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if - - END SUBROUTINE Glue_Jacobians + + !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{IfW}/du^{AD} block of dUdu. (i.e., how do changes in the AD inputs affect IfW inputs?) SUBROUTINE Linear_IfW_InputSolve_du_AD( p_FAST, y_FAST, u_AD, dUdu ) @@ -1862,14 +1877,16 @@ SUBROUTINE Linear_IfW_InputSolve_du_AD( p_FAST, y_FAST, u_AD, dUdu ) END DO END IF - END SUBROUTINE Linear_IfW_InputSolve_du_AD + + !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{ED}/du^{BD} and dU^{ED}/du^{AD} blocks (ED row) of dUdu. (i.e., how do changes in the AD and BD inputs affect the ED inputs?) -SUBROUTINE Linear_ED_InputSolve_du( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, HD, SD, MAPp, MeshMapData, dUdu, ErrStat, ErrMsg ) +SUBROUTINE Linear_ED_InputSolve_du( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD, BD, HD, SD, MAPp, MeshMapData, dUdu, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs @@ -1884,7 +1901,9 @@ SUBROUTINE Linear_ED_InputSolve_du( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message ! local variables + INTEGER(IntKi) :: j ! Loops through StC instances INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: SrvD_Start ! starting index of dUdu (column) where SrvD StC load is INTEGER(IntKi) :: BD_Start ! starting index of dUdu (column) where BD root motion inputs are located INTEGER(IntKi) :: AD_Start_Bl ! starting index of dUdu (column) where AD blade motion inputs are located INTEGER(IntKi) :: ED_Start_mt ! starting index of dUdu (row) where ED blade/tower or hub moment inputs are located @@ -1902,6 +1921,93 @@ SUBROUTINE Linear_ED_InputSolve_du( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ErrStat = ErrID_None ErrMsg = "" + !.......... + ! dU^{ED}/du^{SrvD} + !.......... + if (p_FAST%CompServo == MODULE_SrvD) then + ED_Start_mt = y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%LinStartIndx(LIN_INPUT_COL) + !-------------------- + ! Blade (BD or ED) + if ( p_FAST%CompElast == Module_ED ) then + if ( allocated(SrvD%y%BStCLoadMesh) ) then + do j=1,size(SrvD%y%BStCLoadMesh,2) + do K = 1,SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) + if (SrvD%y%BStCLoadMesh(K,j)%Committed) then + CALL Linearize_Point_to_Point( SrvD%y%BStCLoadMesh(k,j), u_ED%BladePtLoads(k), MeshMapData%BStC_P_2_ED_P_B(k,j), ErrStat2, ErrMsg2, SrvD%Input(1)%BStCMotionMesh(k,j), y_ED%BladeLn2Mesh(k) ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ED_Start_mt = ED_Start_mt + u_ED%BladePtLoads(k)%NNodes*3 ! 3 forces at each node (we're going to start at the moments since the M_us matrix is for moments...) + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_BStC_u(1,k,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%BStC_P_2_ED_P_B(k,j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%BStC_P_2_ED_P_B(k,j)%dM%m_us, ED_Start_mt, SrvD_Start ) + end if + ! get starting index of next blade + ED_Start_mt = ED_Start_mt + u_ED%BladePtLoads(k)%NNodes* 3 + endif + enddo + enddo + endif + endif + !-------------------- + ! Nacelle (ED only) + if ( allocated(SrvD%y%NStCLoadMesh) ) then + do j = 1,size(SrvD%y%NStCLoadMesh) + if (SrvD%y%NStCLoadMesh(j)%Committed) then + call Linearize_Point_to_Point( SrvD%y%NStCLoadMesh(j), u_ED%NacelleLoads, MeshMapData%NStC_P_2_ED_P_N(j), ErrStat2, ErrMsg2, SrvD%Input(1)%NStCMotionMesh(j), y_ED%NacelleMotion ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ED_Start_mt = Indx_u_ED_Nacelle_Start(u_ED, y_FAST) & + + u_ED%NacelleLoads%NNodes * 3 ! 3 forces at the nacelle (so we start at the moments) + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_NStC_u(1,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%NStC_P_2_ED_P_N(j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%NStC_P_2_ED_P_N(j)%dM%m_us, ED_Start_mt, SrvD_Start ) + end if + endif + enddo + endif + !-------------------- + ! Tower (ED only) + if ( allocated(SrvD%y%TStCLoadMesh) ) then + do j = 1,size(SrvD%y%TStCLoadMesh) + if (SrvD%y%TStCLoadMesh(j)%Committed) then + call Linearize_Point_to_Point( SrvD%y%TStCLoadMesh(j), u_ED%TowerPtLoads, MeshMapData%TStC_P_2_ED_P_T(j), ErrStat2, ErrMsg2, SrvD%Input(1)%TStCMotionMesh(j), y_ED%TowerLn2Mesh ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ED_Start_mt = Indx_u_ED_Tower_Start(u_ED, y_FAST) & + + u_ED%TowerPtLoads%NNodes * 3 ! 3 forces at the nacelle (so we start at the moments) + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_TStC_u(1,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%TStC_P_2_ED_P_T(j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%TStC_P_2_ED_P_T(j)%dM%m_us, ED_Start_mt, SrvD_Start ) + endif + endif + enddo + endif + !-------------------- + ! Substructure (SD or ED) + if (p_FAST%CompSub /= MODULE_SD) then + if ( allocated(SrvD%y%SStCLoadMesh) ) then + do j=1,size(SrvD%y%SStCLoadMesh) + if (SrvD%y%SStCLoadMesh(j)%Committed) then + call Linearize_Point_to_Point( SrvD%y%SStCLoadMesh(j), u_ED%PlatformPtMesh, MeshMapData%SStC_P_P_2_ED_P(j), ErrStat2, ErrMsg2, SrvD%Input(1)%SStCMotionMesh(j), y_ED%PlatformPtMesh ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ED_Start_mt = Indx_u_ED_Platform_Start(u_ED, y_FAST) & + + u_ED%PlatformPtMesh%NNodes * 3 ! 3 forces at the nacelle (so we start at the moments) + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_SStC_u(1,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%SStC_P_P_2_ED_P(j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%SStC_P_P_2_ED_P(j)%dM%m_us, ED_Start_mt, SrvD_Start ) + endif + endif + enddo + endif + endif + endif + + !.......... ! dU^{ED}/du^{AD} !.......... @@ -2063,12 +2169,14 @@ SUBROUTINE Linear_ED_InputSolve_du( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, end if END SUBROUTINE Linear_ED_InputSolve_du + !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine forms the dU^{SD}/du^{HD} and dU^{SD}/du^{SD} and dU^{SD}/du^{MAP} blocks (SD row) of dUdu. (i.e., how do changes in the HD and SD inputs affect the SD inputs?) -SUBROUTINE Linear_SD_InputSolve_du( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, MeshMapData, dUdu, ErrStat, ErrMsg ) +!> This routine forms the dU^{SD}/du^{SrvD}, dU^{SD}/du^{HD}, dU^{SD}/du^{SD}, and dU^{SD}/du^{MAP} blocks (SD row) of dUdu. (i.e., how do changes in SrvD, HD, SD, and MAP inputs affect the SD inputs?) +SUBROUTINE Linear_SD_InputSolve_du( p_FAST, y_FAST, SrvD, u_SD, y_SD, y_ED, HD, MAPp, MeshMapData, dUdu, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(SD_InputType), INTENT(INOUT) :: u_SD !< SD Inputs at t TYPE(SD_OutputType), INTENT(IN ) :: y_SD !< SubDyn outputs (need translation displacement on meshes for loads mapping) TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs @@ -2080,6 +2188,7 @@ SUBROUTINE Linear_SD_InputSolve_du( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message ! local variables + INTEGER(IntKi) :: j, SrvD_Start INTEGER(IntKi) :: HD_Start INTEGER(IntKi) :: MAP_Start INTEGER(IntKi) :: SD_Start, SD_Start_td, SD_Start_tr @@ -2096,6 +2205,32 @@ SUBROUTINE Linear_SD_InputSolve_du( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, IF ( p_FAST%CompSub == Module_SD ) THEN ! see routine U_ED_SD_HD_BD_Orca_Residual() in SolveOption1 + + !.......... + ! dU^{SD}/du^{SrvD} + !.......... + if (p_FAST%CompServo == MODULE_SrvD) then + !-------------------- + ! Substructure (SD or ED) + if ( allocated(SrvD%y%SStCLoadMesh) ) then + SD_Start = Indx_u_SD_LMesh_Start(u_SD, y_FAST) & + + u_SD%LMesh%NNodes * 3 ! 3 forces at each node (we're going to start at the moments) + do j=1,size(SrvD%y%SStCLoadMesh) + if (SrvD%y%SStCLoadMesh(j)%Committed) then + call Linearize_Point_to_Point( SrvD%y%SStCLoadMesh(j), u_SD%LMesh, MeshMapData%SStC_P_P_2_SD_P(j), ErrStat2, ErrMsg2, SrvD%Input(1)%SStCMotionMesh(j), y_SD%Y3Mesh ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_SStC_u(1,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%SStC_P_P_2_SD_P(j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%SStC_P_P_2_SD_P(j)%dM%m_us, SD_Start, SrvD_Start ) + endif + endif + enddo + endif + endif + + !.......... ! dU^{SD}/du^{SD} !.......... @@ -2195,12 +2330,14 @@ SUBROUTINE Linear_SD_InputSolve_du( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, END IF END SUBROUTINE Linear_SD_InputSolve_du + !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine forms the dU^{SD}/du^{HD} and dU^{SD}/du^{SD} blocks (SD row) of dUdu. (i.e., how do changes in the HD and SD inputs affect the SD inputs?) -SUBROUTINE Linear_SD_InputSolve_dy( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, MeshMapData, dUdy, ErrStat, ErrMsg ) +!> This routine forms the dU^{SD}/dy^{SrvD}, dU^{SD}/dy^{HD} and dU^{SD}/dy^{SD} blocks (SD row) of dUdu. (i.e., how do changes in SrvD, HD, and SD inputs affect the SD inputs?) +SUBROUTINE Linear_SD_InputSolve_dy( p_FAST, y_FAST, SrvD, u_SD, y_SD, y_ED, HD, MAPp, MeshMapData, dUdy, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(SD_InputType), INTENT(INOUT) :: u_SD !< SD Inputs at t TYPE(SD_OutputType), INTENT(IN ) :: y_SD !< SubDyn outputs (need translation displacement on meshes for loads mapping) TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs @@ -2212,7 +2349,8 @@ SUBROUTINE Linear_SD_InputSolve_dy( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message ! local variables - INTEGER(IntKi) :: SD_Start, SD_Out_Start, HD_Out_Start, ED_Out_Start, MAP_Out_Start + INTEGER(IntKi) :: j, SrvD_Out_Start, SD_Start, SD_Out_Start, HD_Start, HD_Out_Start, ED_Out_Start, MAP_Out_Start + INTEGER(IntKi) :: MAP_Start ! INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation ! CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None @@ -2225,6 +2363,23 @@ SUBROUTINE Linear_SD_InputSolve_dy( p_FAST, y_FAST, u_SD, y_SD, y_ED, HD, MAPp, ErrMsg = "" if ( p_FAST%CompSub /= Module_SD ) return + !.......... + ! dU^{SD}/dy^{SrvD} + !.......... + if (p_FAST%CompServo == MODULE_SrvD) then + !-------------------- + ! Substructure (SD or ED) + if ( allocated(SrvD%y%SStCLoadMesh) ) then + SD_Start = Indx_u_SD_LMesh_Start(u_SD, y_FAST) ! start of u_SD%LMesh%Force field + do j=1,size(SrvD%y%SStCLoadMesh) + if (SrvD%y%SStCLoadMesh(j)%Committed) then + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_SStC_y(1,j) + call Assemble_dUdy_Loads(SrvD%y%SStCLoadMesh(j), u_SD%LMesh, MeshMapData%SStC_P_P_2_SD_P(j), SD_Start, SrvD_Out_Start, dUdy) + endif + enddo + endif + endif + !.......... ! dU^{SD}/dy^{ED} !.......... @@ -2297,10 +2452,11 @@ END SUBROUTINE Linear_SD_InputSolve_dy !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{BD}/du^{BD} and dU^{BD}/du^{AD} blocks (BD row) of dUdu. (i.e., how do changes in the AD and BD inputs !! affect the BD inputs?) This should be called only when p_FAST%CompElast == Module_BD. -SUBROUTINE Linear_BD_InputSolve_du( p_FAST, y_FAST, y_ED, y_AD, u_AD, BD, MeshMapData, dUdu, ErrStat, ErrMsg ) +SUBROUTINE Linear_BD_InputSolve_du( p_FAST, y_FAST, SrvD, y_ED, y_AD, u_AD, BD, MeshMapData, dUdu, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load linerization) @@ -2312,7 +2468,9 @@ SUBROUTINE Linear_BD_InputSolve_du( p_FAST, y_FAST, y_ED, y_AD, u_AD, BD, MeshMa CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message ! local variables + INTEGER(IntKi) :: j ! Loops through StC instances INTEGER(IntKi) :: k ! Loops through blades + INTEGER(IntKi) :: SrvD_Start ! starting index of dUdu (row) where BD inputs are located INTEGER(IntKi) :: BD_Start ! starting index of dUdu (row) where BD inputs are located INTEGER(IntKi) :: AD_Start ! starting index of dUdu (column) where AD inputs are located INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation @@ -2326,6 +2484,34 @@ SUBROUTINE Linear_BD_InputSolve_du( p_FAST, y_FAST, y_ED, y_AD, u_AD, BD, MeshMa ErrStat = ErrID_None ErrMsg = "" + !.......... + ! dU^{BD}/du^{SrvD} + !.......... + if (p_FAST%CompServo == MODULE_SrvD) then + !-------------------- + ! Blade (BD or ED) + if ( allocated(SrvD%y%BStCLoadMesh) ) then + do j=1,size(SrvD%y%BStCLoadMesh,2) + do K = 1,p_FAST%nBeams ! Loop through all blades + if (SrvD%y%BStCLoadMesh(K,j)%Committed) then + CALL Linearize_Point_to_Line2( SrvD%y%BStCLoadMesh(k,j), BD%Input(1,k)%DistrLoad, MeshMapData%BStC_P_2_BD_P_B(k,j), ErrStat2, ErrMsg2, SrvD%Input(1)%BStCMotionMesh(k,j), BD%y(k)%BldMotion ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) & + + BD%Input(1,k)%RootMotion%NNodes *18 & ! displacement, rotation, & acceleration fields for each node + + BD%Input(1,k)%PointLoad%NNodes * 6 & ! force + moment fields for each node + + BD%Input(1,k)%DistrLoad%NNodes * 3 ! force field for each node (start with moment field) + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_BStC_u(1,k,j) + ! SrvD is source in the mapping, so we want M_{uSm} (moments) + if (allocated(MeshMapData%BStC_P_2_BD_P_B(k,j)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%BStC_P_2_BD_P_B(k,j)%dM%m_us, BD_Start, SrvD_Start ) + end if + endif + enddo + enddo + endif + endif + !.......... ! dU^{BD}/du^{AD} !.......... @@ -2499,56 +2685,327 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, end if END DO - - - END SUBROUTINE Linear_AD_InputSolve_du -!---------------------------------------------------------------------------------------------------------------------------------- -!> This routine forms the dU^{SrvD}/dy^{ED} block of dUdy. (i.e., how do changes in the ED outputs affect the SrvD inputs?) -SUBROUTINE Linear_SrvD_InputSolve_dy( p_FAST, y_FAST, dUdy ) -!.................................................................................................................................. - TYPE(FAST_ParameterType), INTENT(IN) :: p_FAST !< Glue-code simulation parameters - TYPE(FAST_OutputFileType), INTENT(IN) :: y_FAST !< Output variables for the glue code - REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< Jacobian matrix of which we are computing the dU^{SrvD}/dy^{ED} block - - integer(intKi) :: ED_Start_Yaw !< starting index of dUdy (column) where ED Yaw/YawRate/HSS_Spd outputs are located (just before WriteOutput) - integer(intKi) :: thisModule + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{SrvD}/du^{SrvD} block (SrvD row) of dUdu. +!! (i.e., how do changes in the SrvD inputs affect the SrvD inputs?) +SUBROUTINE Linear_SrvD_InputSolve_du( p_FAST, y_FAST, p_SrvD, u_SrvD, y_ED, BD, SD, MeshMapData, dUdu, ErrStat, ErrMsg ) + type(FAST_ParameterType), intent(in ) :: p_FAST !< Glue-code simulation parameters + type(FAST_OutputFileType), intent(in ) :: y_FAST !< Glue-code output parameters (for linearization) + type(SrvD_ParameterType), intent(in ) :: p_SrvD !< SrvD parameters + type(SrvD_InputType), intent(inout) :: u_SrvD !< SrvD Inputs at t + type(ED_OutputType), intent(in ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) + type(BeamDyn_Data), intent(in ) :: BD !< BD data at t + type(SubDyn_Data), intent(in ) :: SD !< SD data at t + type(FAST_ModuleMapType), intent(inout) :: MeshMapData !< Data for mapping between modules + real(R8Ki), intent(inout) :: dUdu(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + integer(IntKi), intent( out) :: ErrStat !< Error status + character(*), intent( out) :: ErrMsg !< Error message + ! local variables + integer(IntKi) :: i,j,k ! Generic counters + INTEGER(IntKi) :: SrvD_Start ! starting index of dUdu (column) where the StC motion inputs are located + integer(IntKi) :: ErrStat2 ! temporary Error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'Linear_SrvD_InputSolve_du' - INTEGER(IntKi) :: i ! loop counter + ! Initialize error status + ErrStat = ErrID_None + ErrMsg = "" + + !-------------------- + ! dU^{SrvD}/du^{SrvD} + !-------------------- + ! Blade StrucCtrl + if ( p_FAST%CompElast == Module_ED ) then + if ( ALLOCATED(u_SrvD%BStCMotionMesh) ) then + do j=1,size(u_SrvD%BStCMotionMesh,2) + do K = 1,size(y_ED%BladeLn2Mesh) + if (u_SrvD%BStCMotionMesh(K,j)%Committed) then + CALL Linearize_Line2_to_Point( y_ED%BladeLn2Mesh(K), u_SrvD%BStCMotionMesh(K,j), MeshMapData%ED_L_2_BStC_P_B(K,j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%ED_L_2_BStC_P_B(K,j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_L_2_BStC_P_B(K,j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + + ! translational acceleration: + if (allocated(MeshMapData%ED_L_2_BStC_P_B(K,j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_L_2_BStC_P_B(K,j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + enddo + endif + elseif ( p_FAST%CompElast == Module_BD ) then + if ( ALLOCATED(u_SrvD%BStCMotionMesh) ) then + do j=1,size(u_SrvD%BStCMotionMesh,2) + do K = 1,p_FAST%nBeams + if (u_SrvD%BStCMotionMesh(K,j)%Committed) then + CALL Linearize_Line2_to_Point( BD%y(k)%BldMotion, u_SrvD%BStCMotionMesh(K,j), MeshMapData%BD_L_2_BStC_P_B(K,j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%BD_L_2_BStC_P_B(K,j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%BD_L_2_BStC_P_B(K,j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + + ! translational acceleration: + if (allocated(MeshMapData%BD_L_2_BStC_P_B(K,j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%BD_L_2_BStC_P_B(K,j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + enddo + endif + endif + !-------------------- + ! Nacelle (ED only) + if ( ALLOCATED(u_SrvD%NStCMotionMesh) ) then + do j = 1,size(u_SrvD%NStCMotionMesh) + if (u_SrvD%NStCMotionMesh(j)%Committed) then + call Linearize_Point_to_Point( y_ED%NacelleMotion, u_SrvD%NStCMotionMesh(j), MeshMapData%ED_P_2_NStC_P_N(j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%ED_P_2_NStC_P_N(j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_NStC_u(1,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_P_2_NStC_P_N(j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + + ! translational acceleration: + if (allocated(MeshMapData%ED_P_2_NStC_P_N(j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_NStC_u(1,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_P_2_NStC_P_N(j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + endif + !-------------------- + ! Tower + if ( ALLOCATED(u_SrvD%TStCMotionMesh) ) then + do j = 1,size(u_SrvD%TStCMotionMesh) + if (u_SrvD%TStCMotionMesh(j)%Committed) then + call Linearize_Line2_to_Point( y_ED%TowerLn2Mesh, u_SrvD%TStCMotionMesh(j), MeshMapData%ED_L_2_TStC_P_T(j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%ED_L_2_TStC_P_T(j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_TStC_u(1,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_L_2_TStC_P_T(j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + + ! translational acceleration: + if (allocated(MeshMapData%ED_L_2_TStC_P_T(j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_TStC_u(1,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_L_2_TStC_P_T(j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + endif + !-------------------- + ! Substructure (SD or ED) + if (p_FAST%CompSub /= MODULE_SD) then + if ( ALLOCATED(u_SrvD%SStCMotionMesh) ) then + do j=1,size(u_SrvD%SStCMotionMesh) + if (u_SrvD%SStCMotionMesh(j)%Committed) then + CALL Linearize_Point_to_Point( y_ED%PlatformPtMesh, u_SrvD%SStCMotionMesh(j), MeshMapData%ED_P_2_SStC_P_P(j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%ED_P_2_SStC_P_P(j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_P_2_SStC_P_P(j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if - CHARACTER(*), PARAMETER :: RoutineName = 'Linear_SrvD_InputSolve_dy' + ! translational acceleration: + if (allocated(MeshMapData%ED_P_2_SStC_P_P(j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%ED_P_2_SStC_P_P(j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + endif + else + if ( ALLOCATED(u_SrvD%SStCMotionMesh) ) then + do j=1,size(u_SrvD%SStCMotionMesh) + IF (u_SrvD%SStCMotionMesh(j)%Committed) then + CALL Linearize_Point_to_Point( SD%y%y3Mesh, u_SrvD%SStCMotionMesh(j), MeshMapData%SDy3_P_2_SStC_P_P(j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! SrvD is destination in the mapping, so we want M_{tv_uD} and M_{ta_uD} + ! translational velocity: + if (allocated(MeshMapData%SDy3_P_2_SStC_P_P(j)%dM%tv_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j) + 6) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%SDy3_P_2_SStC_P_P(j)%dM%tv_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if - thisModule = Module_ED - ED_Start_Yaw = Indx_y_Yaw_Start(y_FAST, ThisModule) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) + ! translational acceleration: + if (allocated(MeshMapData%SDy3_P_2_SStC_P_P(j)%dM%ta_uD )) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j) + 12) ! skip translational displacement and orientation fields + call SetBlockMatrix( dUdu, MeshMapData%SDy3_P_2_SStC_P_P(j)%dM%ta_uD, SrvD_Start, y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) ) + end if + endif + enddo + endif + endif +END SUBROUTINE Linear_SrvD_InputSolve_du + + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{SrvD}/dy^{ED}, dU^{SrvD}/dy^{BD}, dU^{SrvD}/dy^{SD} block of dUdy. +!! (i.e., how do changes in the ED, SD, BD outputs affect the SrvD inputs?) +!! NOTE: Linearze_Point_to_Point routines done in Linear_SrvD_InputSolve_du +SUBROUTINE Linear_SrvD_InputSolve_dy( p_FAST, y_FAST, p_SrvD, u_SrvD, y_ED, BD, y_SD, MeshMapData, dUdy, ErrStat, ErrMsg ) +!.................................................................................................................................. + type(FAST_ParameterType), intent(in ) :: p_FAST !< Glue-code simulation parameters + type(FAST_OutputFileType), intent(in ) :: y_FAST !< Output variables for the glue code + type(SrvD_ParameterType), intent(in ) :: p_SrvD !< SrvD parameters (holds indices for jacobian entries for each StC) + type(SrvD_InputType), intent(inout) :: u_SrvD !< SrvD Inputs at t + type(ED_OutputType), intent(in ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) + type(BeamDyn_Data), intent(in ) :: BD !< BeamDyn data + type(SD_OutputType), intent(in ) :: y_SD !< SubDyn outputs (need translation displacement on meshes for loads mapping) + + type(FAST_ModuleMapType), intent(inout) :: MeshMapData !< Data for mapping between modules + real(R8Ki), intent(inout) :: dUdy(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + integer(IntKi), intent( out) :: ErrStat !< Error status + character(*), intent( out) :: ErrMsg !< Error message + + integer(IntKi) :: i,j,k ! loop counters + integer(intKi) :: ED_Start_Yaw !< starting index of dUdy (column) where ED Yaw/YawRate/HSS_Spd outputs are located (just before WriteOutput) + integer(IntKi) :: SrvD_Start, ED_Out_Start, BD_Out_Start, SD_Out_Start + character(*), parameter :: RoutineName = 'Linear_SrvD_InputSolve_dy' - do i=1,size(SrvD_Indx_Y_BlPitchCom) + ! Initialize error status + ErrStat = ErrID_None + ErrMsg = "" + + !-------------------- + ! dU^{SrvD}/dy^{ED} + !-------------------- + ED_Start_Yaw = Indx_y_Yaw_Start(y_FAST, Module_ED) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) + do i=1,size(SrvD_Indx_Y_BlPitchCom) ! first 3 columns dUdy(y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) + SrvD_Indx_Y_BlPitchCom(i) - 1, ED_Start_Yaw + i - 1) = -1.0_ReKi end do - - !IF (u_SrvD%NStC%Mesh%Committed) THEN - ! - ! CALL Linearize_Point_to_Point( y_ED%NacelleMotion, u_SrvD%NStC%Mesh, MeshMapData%ED_P_2_NStC_P_N, ErrStat2, ErrMsg2 ) - ! call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! - !END IF - ! - !IF (u_SrvD%TSC%Mesh%Committed) THEN - ! - ! CALL Linearize_Line2_to_Point( y_ED%TowerLn2Mesh, u_SrvD%TStC%Mesh, MeshMapData%ED_L_2_TStC_P_T, ErrStat2, ErrMsg2 ) - ! call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! - !END IF - + + !---------------------------------------- + ! Structural controls + !---------------------------------------- + ! Blade + if ( p_FAST%CompElast == Module_ED ) then + !-------------------- + ! dU^{SrvD}/dy^{ED} + !-------------------- + if ( ALLOCATED(u_SrvD%BStCMotionMesh) ) then + do j=1,size(u_SrvD%BStCMotionMesh,2) + do K = 1,size(y_ED%BladeLn2Mesh) + if (u_SrvD%BStCMotionMesh(K,j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j)) + ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( y_ED%BladeLn2Mesh(K), u_SrvD%BStCMotionMesh(K,j), MeshMapData%ED_L_2_BStC_P_B(K,j), SrvD_Start, ED_Out_Start, dUdy, .false.) + endif + enddo + enddo + endif + elseif ( p_FAST%CompElast == Module_BD ) then + !-------------------- + ! dU^{SrvD}/dy^{BD} + !-------------------- + if ( ALLOCATED(u_SrvD%BStCMotionMesh) ) then + do j=1,size(u_SrvD%BStCMotionMesh,2) + do K = 1,p_FAST%nBeams + if (u_SrvD%BStCMotionMesh(K,j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_BStC_u(1,k,j)) + BD_Out_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( BD%y(k)%BldMotion, u_SrvD%BStCMotionMesh(K,j), MeshMapData%BD_L_2_BStC_P_B(K,j), SrvD_Start, BD_Out_Start, dUdy, .false.) + endif + enddo + enddo + endif + endif + + !-------------------- + ! Nacelle -- dU^{SrvD}/dy^{ED} + !-------------------- + if ( ALLOCATED(u_SrvD%NStCMotionMesh) ) then + do j = 1,size(u_SrvD%NStCMotionMesh) + if (u_SrvD%NStCMotionMesh(j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_NStC_u(1,j)) + ED_Out_Start = Indx_y_ED_Nacelle_Start(y_ED, y_FAST) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( y_ED%NacelleMotion, u_SrvD%NStCMotionMesh(j), MeshMapData%ED_P_2_NStC_P_N(j), SrvD_Start, ED_Out_Start, dUdy, .false.) + endif + enddo + endif + + !-------------------- + ! Tower -- dU^{SrvD}/dy^{ED} + !-------------------- + if ( ALLOCATED(u_SrvD%TStCMotionMesh) ) then + do j = 1,size(u_SrvD%TStCMotionMesh) + if (u_SrvD%TStCMotionMesh(j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_TStC_u(1,j)) + ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( y_ED%TowerLn2Mesh, u_SrvD%TStCMotionMesh(j), MeshMapData%ED_L_2_TStC_P_T(j), SrvD_Start, ED_Out_Start, dUdy, .false.) + endif + enddo + endif + + !-------------------- + ! Substructure (SD or ED) + !-------------------- + if (p_FAST%CompSub /= MODULE_SD) then + !-------------------- + ! dU^{SrvD}/dy^{ED} + !-------------------- + if ( ALLOCATED(u_SrvD%SStCMotionMesh) ) then + do j=1,size(u_SrvD%SStCMotionMesh) + if (u_SrvD%SStCMotionMesh(j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j)) + ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( y_ED%PlatformPtMesh, u_SrvD%SStCMotionMesh(j), MeshMapData%ED_P_2_SStC_P_P(j), SrvD_Start, ED_Out_Start, dUdy, .false.) + endif + enddo + endif + else + !-------------------- + ! dU^{SrvD}/dy^{SD} + !-------------------- + if ( ALLOCATED(u_SrvD%SStCMotionMesh) ) then + do j=1,size(u_SrvD%SStCMotionMesh) + if (u_SrvD%SStCMotionMesh(j)%Committed) then + SrvD_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + (p_SrvD%Jac_Idx_SStC_u(1,j)) + SD_Out_Start = Indx_y_SD_Y3Mesh_Start(y_SD, y_FAST) ! start of %TranslationDisp field + call Assemble_dUdy_Motions( y_SD%y3Mesh, u_SrvD%SStCMotionMesh(j), MeshMapData%SDy3_P_2_SStC_P_P(j), SrvD_Start, SD_Out_Start, dUdy, .false.) + endif + enddo + endif + endif END SUBROUTINE Linear_SrvD_InputSolve_dy + + + !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{ED}/dy^{SrvD}, dU^{ED}/dy^{ED}, dU^{ED}/dy^{BD}, dU^{ED}/dy^{AD}, dU^{ED}/dy^{HD}, and dU^{ED}/dy^{MAP} !! blocks of dUdy. (i.e., how do changes in the SrvD, ED, BD, AD, HD, and MAP outputs effect the ED inputs?) -SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, HD, SD, MAPp, MeshMapData, dUdy, ErrStat, ErrMsg ) +SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD, BD, HD, SD, MAPp, MeshMapData, dUdy, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs @@ -2565,7 +3022,9 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ! local variables INTEGER(IntKi) :: i ! rows/columns + INTEGER(IntKi) :: j ! Loops through StC instance INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: SrvD_Out_Start ! starting index of dUdy (column) where the StC motion inputs are located INTEGER(IntKi) :: AD_Out_Start ! starting index of dUdy (column) where particular AD fields are located INTEGER(IntKi) :: BD_Out_Start ! starting index of dUdy (column) where particular BD fields are located INTEGER(IntKi) :: ED_Start ! starting index of dUdy (row) where ED input fields are located @@ -2580,8 +3039,11 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ErrStat = ErrID_None ErrMsg = "" - - ! ED inputs from ServoDyn outputs + + !.......... + ! dU^{ED}/dy^{SrvD} + ! ED inputs from ServoDyn outputs + !.......... IF ( p_FAST%CompServo == Module_SrvD ) THEN ! BlPitchCom, YawMom, GenTrq @@ -2589,17 +3051,76 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, do i=1,size(u_ED%BlPitchCom)+2 ! BlPitchCom, YawMom, GenTrq (NOT collective pitch) dUdy(ED_Start + i - 1, y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) + i - 1) = -1.0_ReKi !SrvD_Indx_Y_BlPitchCom end do - - !IF (y_SrvD%NStC%Mesh%Committed) THEN - ! CALL Linearize_Point_to_Point( y_SrvD%NStC%Mesh, u_ED%NacelleLoads, MeshMapData%NStC_P_2_ED_P_N, ErrStat2, ErrMsg2, u_SrvD%NStC%Mesh, y_ED%NacelleMotion ) - ! CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat, ErrMsg,RoutineName//':u_ED%NacelleLoads' ) - !END IF - ! - !IF (y_SrvD%TStC%Mesh%Committed) THEN - ! CALL Linearize_Point_to_Point( y_SrvD%TStC%Mesh, u_ED%TowerPtLoads, MeshMapData%TStC_P_2_ED_P_T, ErrStat2, ErrMsg2, u_SrvD%TStC%Mesh, y_ED%TowerLn2Mesh ) - ! CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat, ErrMsg,RoutineName//':u_ED%TowerPtLoads' ) - !END IF - + !-------------------- + ! Blade (BD or ED) + if ( p_FAST%CompElast == Module_ED ) then + if ( allocated(SrvD%y%BStCLoadMesh) ) then + do j=1,size(SrvD%y%BStCLoadMesh,2) + do K = 1,SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) + if (SrvD%y%BStCLoadMesh(K,j)%Committed) then + ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) ! start of u_ED%BladePtLoads(k)%Force field + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_BStC_y(1,k,j) + call Assemble_dUdy_Loads(SrvD%y%BStCLoadMesh(k,j), u_ED%BladePtLoads(k), MeshMapData%BStC_P_2_ED_P_B(k,j), ED_Start, SrvD_Out_Start, dUdy) + + ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): + ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) + u_ED%BladePtLoads(k)%NNodes*3 ! start of u_ED%BladePtLoads(k)%Moment field (skip the ED forces) + ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of y_ED%BladeLn2Mesh(1)%TranslationDisp field + call SumBlockMatrix( dUdy, MeshMapData%BStC_P_2_ED_P_B(k,j)%dM%m_uD, ED_Start, ED_Out_Start ) + endif + enddo + enddo + endif + endif + !-------------------- + ! Nacelle (ED only) + if ( allocated(SrvD%y%NStCLoadMesh) ) then + do j = 1,size(SrvD%y%NStCLoadMesh) + if (SrvD%y%NStCLoadMesh(j)%Committed) then + ED_Start = Indx_u_ED_Nacelle_Start(u_ED, y_FAST) + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_NStC_y(1,j) + call Assemble_dUdy_Loads(SrvD%y%NStCLoadMesh(j), u_ED%NacelleLoads, MeshMapData%NStC_P_2_ED_P_N(j), ED_Start, SrvD_Out_Start, dUdy) + + ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): + ED_Start = Indx_u_ED_Nacelle_Start(u_ED, y_FAST) + u_ED%NacelleLoads%NNodes*3 ! start of u_ED%NacelleLoads%Moment field (skip the ED forces) + ED_Out_Start = Indx_y_ED_Nacelle_Start(y_ED, y_FAST) ! start of y_ED%NacelleMotion%TranslationDisp field + call SumBlockMatrix( dUdy, MeshMapData%NStC_P_2_ED_P_N(j)%dM%m_uD, ED_Start, ED_Out_Start ) + endif + enddo + endif + !-------------------- + ! Tower (ED only) + if ( allocated(SrvD%y%TStCLoadMesh) ) then + do j = 1,size(SrvD%y%TStCLoadMesh) + if (SrvD%y%TStCLoadMesh(j)%Committed) then + ED_Start = Indx_u_ED_Tower_Start(u_ED, y_FAST) + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_TStC_y(1,j) + call Assemble_dUdy_Loads(SrvD%y%TStCLoadMesh(j), u_ED%TowerPtLoads, MeshMapData%TStC_P_2_ED_P_T(j), ED_Start, SrvD_Out_Start, dUdy) + + ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): + ED_Start = Indx_u_ED_Tower_Start(u_ED, y_FAST) + u_ED%TowerPtLoads%NNodes*3 ! start of u_ED%TowerPtLoads%Moment field [skip the ED forces to get to the moments] + ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of y_ED%TowerLn2Mesh%TranslationDisp field + call SumBlockMatrix( dUdy, MeshMapData%TStC_P_2_ED_P_T(j)%dM%m_uD, ED_Start, ED_Out_Start ) + endif + enddo + endif + !-------------------- + ! Substructure (SD or ED) + if (p_FAST%CompSub /= MODULE_SD) then + if ( allocated(SrvD%y%SStCLoadMesh) ) then + do j=1,size(SrvD%y%SStCLoadMesh) + if (SrvD%y%SStCLoadMesh(j)%Committed) then + ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_SStC_y(1,j) + call Assemble_dUdy_Loads(SrvD%y%SStCLoadMesh(j), u_ED%PlatformPtMesh, MeshMapData%SStC_P_P_2_ED_P(j), ED_Start, SrvD_Out_Start, dUdy) + + ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): + ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) + u_ED%PlatformPtMesh%NNodes*3 ! start of u_ED%PlatformPtMesh%Moment field (skip the ED forces) + ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field + call SumBlockMatrix( dUdy, MeshMapData%HD_M_P_2_ED_P%dM%m_uD, ED_Start, ED_Out_Start ) + endif + enddo + endif + endif END IF ! parts of dU^{ED}/dy^{AD} and dU^{ED}/dy^{ED}: @@ -2622,7 +3143,7 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) + u_ED%BladePtLoads(k)%NNodes*3 ! start of u_ED%BladePtLoads(k)%Moment field (skip the ED forces) ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of y_ED%BladeLn2Mesh(1)%TranslationDisp field - call SetBlockMatrix( dUdy, MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD, ED_Start, ED_Out_Start ) + call SumBlockMatrix( dUdy, MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD, ED_Start, ED_Out_Start ) AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%BladeLoad(k+1)%Force field [skip 2 fields to forces on next blade] END DO @@ -2642,7 +3163,7 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): ED_Start = ED_Start + u_ED%TowerPtLoads%NNodes*3 ! start of u_ED%TowerPtLoads%Moment field [skip the ED forces to get to the moments] ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of y_ED%TowerLn2Mesh%TranslationDisp field - call SetBlockMatrix( dUdy, MeshMapData%AD_L_2_ED_P_T%dM%m_uD, ED_Start, ED_Out_Start ) + call SumBlockMatrix( dUdy, MeshMapData%AD_L_2_ED_P_T%dM%m_uD, ED_Start, ED_Out_Start ) END IF ! tower @@ -2746,10 +3267,11 @@ END SUBROUTINE Linear_ED_InputSolve_dy !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{BD}/dy^{ED}, dU^{BD}/dy^{BD}, and dU^{BD}/dy^{AD} blocks of dUdy. (i.e., how do !! changes in the ED, BD, and AD outputs effect the BD inputs?) -SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, MeshMapData, dUdy, ErrStat, ErrMsg ) +SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD, BD, MeshMapData, dUdy, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + type(ServoDyn_Data), intent(in ) :: SrvD !< SrvD parameters TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs @@ -2762,7 +3284,9 @@ SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message ! local variables + INTEGER(IntKi) :: j ! Loops through StC instance INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: SrvD_Out_Start ! starting index of dUdy (column) where particular SrvD fields are located INTEGER(IntKi) :: AD_Out_Start ! starting index of dUdy (column) where particular AD fields are located INTEGER(IntKi) :: BD_Start ! starting index of dUdy (column) where particular BD fields are located INTEGER(IntKi) :: BD_Out_Start ! starting index of dUdy (column) where BD output fields are located @@ -2778,6 +3302,29 @@ SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, BD, ErrStat = ErrID_None ErrMsg = "" + !.......... + ! dU^{ED}/du^{SrvD} + !.......... + if (p_FAST%CompServo == MODULE_SrvD) then + !-------------------- + ! Blade (BD or ED) + if ( allocated(SrvD%y%BStCLoadMesh) ) then + do j=1,size(SrvD%y%BStCLoadMesh,2) + do K = 1,p_FAST%nBeams ! Loop through all blades + if (SrvD%y%BStCLoadMesh(K,j)%Committed) then + ! Start of DistrLoad nodes + BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) & + + BD%Input(1,k)%RootMotion%NNodes *18 & ! displacement, rotation, & acceleration fields for each node + + BD%Input(1,k)%PointLoad%NNodes * 6 ! force + moment fields for each node + SrvD_Out_Start = y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - 1 + SrvD%p%Jac_Idx_BStC_y(1,k,j) + call Assemble_dUdy_Loads(SrvD%y%BStCLoadMesh(k,j), BD%Input(1,k)%DistrLoad, MeshMapData%BStC_P_2_BD_P_B(k,j), BD_Start, SrvD_Out_Start, dUdy) + endif + enddo + enddo + endif + endif + + ! parts of dU^{BD}/dy^{AD} and dU^{BD}/dy^{BD}: ! BeamDyn inputs on blade from AeroDyn and BeamDyn @@ -3539,7 +4086,7 @@ SUBROUTINE Glue_StateMatrices( p_FAST, y_FAST, dUdu, dUdy, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - !LIN-TODO: Update doc string comments below for HD, MAP, SD + !LIN-TODO: Update doc string comments below for SrvD, HD, MAP, SD !..................................... ! allocate the glue-code state matrices; after this call they will contain the state matrices from the @@ -4148,6 +4695,18 @@ FUNCTION Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, BladeNum) RESULT(ED_Out_Start) end do END FUNCTION Indx_y_ED_BladeRoot_Start !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine returns the starting index for the y_ED%NacelleMotion mesh in the FAST linearization outputs. +FUNCTION Indx_y_ED_Nacelle_Start(y_ED, y_FAST) RESULT(ED_Out_Start) + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ED outputs at t + INTEGER :: k !< blade number loop + + INTEGER :: ED_Out_Start !< starting index of this blade mesh in ElastoDyn outputs + + ED_Out_Start = Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, size(y_ED%BladeRootMotion)) ! start of last blade root + ED_Out_Start = ED_Out_Start + y_ED%BladeRootMotion(size(y_ED%BladeRootMotion))%NNodes*18 ! N blade roots, 6 fields with 3 components per blade. +END FUNCTION Indx_y_ED_Nacelle_Start +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine returns the starting index for y_ED%Yaw in the FAST linearization outputs. FUNCTION Indx_y_Yaw_Start(y_FAST, ThisModule) RESULT(ED_Out_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) @@ -4320,7 +4879,8 @@ FUNCTION Indx_y_SD_Y1Mesh_Start(y_SD, y_FAST) RESULT(SD_Out_Start) INTEGER :: SD_Out_Start !< starting index of this mesh in ElastoDyn outputs SD_Out_Start = y_FAST%Lin%Modules(MODULE_SD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) -END FUNCTION Indx_y_SD_Y1Mesh_Start!---------------------------------------------------------------------------------------------------------------------------------- +END FUNCTION Indx_y_SD_Y1Mesh_Start +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine returns the starting index for the y_SD%Y2Mesh mesh in the FAST linearization outputs. FUNCTION Indx_y_SD_Y2Mesh_Start(y_SD, y_FAST) RESULT(SD_Out_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) @@ -5360,6 +5920,25 @@ SUBROUTINE FAST_CalcSteady( n_t_global, t_global, p_FAST, y_FAST, m_FAST, ED, BD m_FAST%Lin%AzimIndx = 1 m_FAST%Lin%CopyOP_CtrlCode = MESH_UPDATECOPY end if + ! Forcing linearization if time is close to tmax (with sufficient margin) + if (.not.m_FAST%Lin%FoundSteady) then + if (ED%p%RotSpeed>0) then + ! If simulation is at least 10 revolutions, and error in rotor speed less than 0.1% + if ((p_FAST%TMax>10*(TwoPi_D)/ED%p%RotSpeed) .and. ( t_global >= p_FAST%TMax - 2._DbKi*(TwoPi_D)/ED%p%RotSpeed)) then + if (abs(ED%y%RotSpeed-ED%p%RotSpeed)/ED%p%RotSpeed<0.001) then + call WrScr('') + call WrScr('[WARNING] Steady state not found before end of simulation. Forcing linearization.') + m_FAST%Lin%ForceLin = .True. + endif + endif + else + if (t_global >= p_FAST%TMax - 1.5_DbKi*p_FAST%DT) then + call WrScr('') + call WrScr('[WARNING] Steady state not found before end of simulation. Forcing linearization.') + m_FAST%Lin%ForceLin = .True. + endif + endif + endif end if end if @@ -5826,7 +6405,7 @@ SUBROUTINE FAST_DiffInterpOutputs( psi_target, p_FAST, y_FAST, m_FAST, ED, BD, S CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName ) call ED_GetOP( t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & - ED%y_interp, ED%m, ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_y, NeedLogMap=.true.) + ED%y_interp, ED%m, ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_y, NeedPackedOrient=.true.) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! BeamDyn @@ -5838,7 +6417,7 @@ SUBROUTINE FAST_DiffInterpOutputs( psi_target, p_FAST, y_FAST, m_FAST, ED, BD, S CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName ) call BD_GetOP( t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & - BD%y_interp(k), BD%m(k), ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_y, NeedLogMap=.true.) + BD%y_interp(k), BD%m(k), ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_y, NeedPackedOrient=.true.) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) END DO ! k=p_FAST%nBeams @@ -5899,7 +6478,7 @@ SUBROUTINE FAST_DiffInterpOutputs( psi_target, p_FAST, y_FAST, m_FAST, ED, BD, S CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName ) call SD_GetOP( t_global, SD%Input(1), SD%p, SD%x(STATE_CURR), SD%xd(STATE_CURR), SD%z(STATE_CURR), SD%OtherSt(STATE_CURR), & - SD%y_interp, SD%m, ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_SD)%Instance(1)%op_y) + SD%y_interp, SD%m, ErrStat2, ErrMsg2, y_op=y_FAST%Lin%Modules(Module_SD)%Instance(1)%op_y, NeedPackedOrient=.true.) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ELSE IF ( p_FAST%CompSub == Module_ExtPtfm ) THEN END IF ! SubDyn/ExtPtfm_MCKF diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 401c4f3026..14961cb9b5 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -1020,6 +1020,10 @@ SUBROUTINE SrvD_InputSolve( p_FAST, m_FAST, u_SrvD, y_ED, y_IfW, y_OpFM, y_BD, y u_SrvD%RotPwr = y_ED%RotPwr + u_SrvD%LSShftFxa = y_ED%LSShftFxa + u_SrvD%LSShftFys = y_ED%LSShftFys + u_SrvD%LSShftFzs = y_ED%LSShftFzs + ! ! ServoDyn inputs from AeroDyn !IF ( p_FAST%CompAero == Module_AD ) THEN !ELSE diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 5d284fb4a5..dd09c68c31 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -24,6 +24,7 @@ MODULE FAST_Subs USE FAST_Solver USE FAST_Linear USE SC_DataEx + USE VersionInfo IMPLICIT NONE @@ -1318,9 +1319,12 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, else if (allocated(Init%OutData_SrvD%LinNames_y)) call move_alloc(Init%OutData_SrvD%LinNames_y,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%Names_y ) if (allocated(Init%OutData_SrvD%LinNames_u)) call move_alloc(Init%OutData_SrvD%LinNames_u,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%Names_u ) + if (allocated(Init%OutData_SrvD%LinNames_x)) call move_alloc(Init%OutData_SrvD%LinNames_x,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%Names_x ) if (allocated(Init%OutData_SrvD%RotFrame_y)) call move_alloc(Init%OutData_SrvD%RotFrame_y,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%RotFrame_y ) if (allocated(Init%OutData_SrvD%RotFrame_u)) call move_alloc(Init%OutData_SrvD%RotFrame_u,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%RotFrame_u ) + if (allocated(Init%OutData_SrvD%RotFrame_x)) call move_alloc(Init%OutData_SrvD%RotFrame_x,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%RotFrame_x ) if (allocated(Init%OutData_SrvD%IsLoad_u )) call move_alloc(Init%OutData_SrvD%IsLoad_u ,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%IsLoad_u ) + if (allocated(Init%OutData_SrvD%DerivOrder_x)) call move_alloc(Init%OutData_SrvD%DerivOrder_x,y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%DerivOrder_x) if (allocated(Init%OutData_SrvD%WriteOutputHdr)) y_FAST%Lin%Modules(MODULE_SrvD)%Instance(1)%NumOutputs = size(Init%OutData_SrvD%WriteOutputHdr) end if @@ -1569,48 +1573,6 @@ END SUBROUTINE SetSrvDCableControls END SUBROUTINE FAST_InitializeAll -!---------------------------------------------------------------------------------------------------------------------------------- -!> This function returns a string describing the glue code and some of the compilation options we're using. -FUNCTION GetVersion(ThisProgVer) - - ! Passed Variables: - - TYPE(ProgDesc), INTENT( IN ) :: ThisProgVer !< program name/date/version description - CHARACTER(1024) :: GetVersion !< String containing a description of the compiled precision. - - CHARACTER(200) :: git_commit - - GetVersion = TRIM(GetNVD(ThisProgVer))//', compiled' - - IF ( Cmpl4SFun ) THEN ! FAST has been compiled as an S-Function for Simulink - GetVersion = TRIM(GetVersion)//' as a DLL S-Function for Simulink' - ELSEIF ( Cmpl4LV ) THEN ! FAST has been compiled as a DLL for Labview - GetVersion = TRIM(GetVersion)//' as a DLL for LabVIEW' - ENDIF - - GetVersion = TRIM(GetVersion)//' as a '//TRIM(Num2LStr(BITS_IN_ADDR))//'-bit application using' - - ! determine precision - - IF ( ReKi == SiKi ) THEN ! Single precision - GetVersion = TRIM(GetVersion)//' single' - ELSEIF ( ReKi == R8Ki ) THEN ! Double precision - GetVersion = TRIM(GetVersion)// ' double' - ELSE ! Unknown precision - GetVersion = TRIM(GetVersion)//' unknown' - ENDIF - - -! GetVersion = TRIM(GetVersion)//' precision with '//OS_Desc - GetVersion = TRIM(GetVersion)//' precision' - - ! add git info - git_commit = QueryGitVersion() - GetVersion = TRIM(GetVersion)//' at commit '//git_commit - - RETURN -END FUNCTION GetVersion - !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine is called at the start (or restart) of a FAST program (or FAST.Farm). It initializes the NWTC subroutine library, !! displays the copyright notice, and displays some version information (including addressing scheme and precision). @@ -1621,10 +1583,9 @@ SUBROUTINE FAST_ProgStart(ThisProgVer) ! sets the pi constants, open console for output, etc... CALL NWTC_Init( ProgNameIN=ThisProgVer%Name, EchoLibVer=.FALSE. ) - ! Display the copyright notice + ! Display the copyright notice and compile info: CALL DispCopyrightLicense( ThisProgVer%Name ) - - CALL DispCompileRuntimeInfo + CALL DispCompileRuntimeInfo( ThisProgVer%Name ) END SUBROUTINE FAST_ProgStart !---------------------------------------------------------------------------------------------------------------------------------- @@ -2067,7 +2028,7 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) !...................................................... ! Set the description lines to be printed in the output file !...................................................... - y_FAST%FileDescLines(1) = 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//TRIM(GetVersion(FAST_Ver)) + y_FAST%FileDescLines(1) = 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//TRIM(GetVersion(FAST_Ver, Cmpl4SFun, Cmpl4LV)) y_FAST%FileDescLines(2) = 'linked with ' //' '//TRIM(GetNVD(NWTC_Ver )) ! we'll get the rest of the linked modules in the section below y_FAST%FileDescLines(3) = 'Description from the FAST input file: '//TRIM(p_FAST%FTitle) diff --git a/modules/openfast-library/tests/test_openfast_library.py b/modules/openfast-library/tests/test_openfast_library.py new file mode 100644 index 0000000000..d166dab6c8 --- /dev/null +++ b/modules/openfast-library/tests/test_openfast_library.py @@ -0,0 +1,47 @@ + +import sys +import argparse +import numpy as np +from pathlib import Path +interface_path = Path(__file__).parent.parent.parent.parent / "glue-codes" / "python" +sys.path.insert(0, str(interface_path)) +import openfast_library + +def test_hub_position(library_path, input_file): + openfastlib = openfast_library.FastLibAPI(library_path, input_file) + openfastlib.fast_init() + absolute_position, rotational_velocity, orientation_dcm = openfastlib.get_hub_position() + + # Initial hub position is at -5, 0, 90.55 + np.testing.assert_allclose( + absolute_position, + np.array([-5.0, 0.0, 90.55]), + rtol=1e-5, + atol=1e-8, + verbose=True + ) + + # This case is initially still + # Velocities should be 0 and the DCM should be identity + np.testing.assert_array_equal( rotational_velocity, np.zeros(3) ) + np.testing.assert_array_equal( np.reshape( orientation_dcm[:], (3,3) ), np.eye(3) ) + + +if __name__=="__main__": + + parser = argparse.ArgumentParser(description="Executes Python-based tests for OpenFAST Library.") + parser.add_argument("input_file", metavar="Input-File", type=str, nargs=1, help="Path to an input file.") + + args = parser.parse_args() + input_file = args.input_file[0] + + library_path = Path(__file__).parent.parent.parent.parent / "build" / "modules" / "openfast-library" / "libopenfastlib" + if sys.platform == "linux" or sys.platform == "linux2": + library_path = library_path.with_suffix(".so") + elif sys.platform == "darwin": + library_path = library_path.with_suffix(".dylib") + elif sys.platform == "win32": + # TODO + pass + + test_hub_position(library_path, input_file) diff --git a/modules/servodyn/CMakeLists.txt b/modules/servodyn/CMakeLists.txt index 342392810e..0f74f81919 100644 --- a/modules/servodyn/CMakeLists.txt +++ b/modules/servodyn/CMakeLists.txt @@ -36,7 +36,7 @@ add_library(servodynlib ${SrvD_SOURCES}) target_link_libraries(servodynlib nwtclibs) add_executable(servodyn_driver src/ServoDyn_Driver.f90) -target_link_libraries(servodyn_driver servodynlib nwtclibs ${CMAKE_DL_LIBS}) +target_link_libraries(servodyn_driver servodynlib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) # The Structural Control driver is currently not functional, so commenting this temporarily # add_executable(strucctrl_driver src/StrucCtrl_Driver.f90) diff --git a/modules/servodyn/src/BladedInterface.f90 b/modules/servodyn/src/BladedInterface.f90 index 72d0bfb9a9..d9b7df4f9b 100644 --- a/modules/servodyn/src/BladedInterface.f90 +++ b/modules/servodyn/src/BladedInterface.f90 @@ -603,6 +603,9 @@ subroutine WrLegacyChannelInfoToSummaryFile(u,p,dll_data,UnSum,ErrStat,ErrMsg) call WrSumInfoSend(95, 'Reserved (SrvD customization: set to SrvD AirDens parameter)') call WrSumInfoSend(96, 'Reserved (SrvD customization: set to SrvD AvgWindSpeed parameter)') call WrSumInfoSend(109, 'Shaft torque (=hub Mx for clockwise rotor) (Nm) [SrvD input]') + call WrSumInfoSend(110, 'Thrust - Rotating low-speed shaft force x (GL co-ords) (N) [SrvD input]') + call WrSumInfoSend(111, 'Nonrotating low-speed shaft force y (GL co-ords) (N) [SrvD input]') + call WrSumInfoSend(112, 'Nonrotating low-speed shaft force z (GL co-ords) (N) [SrvD input]') call WrSumInfoSend(117, 'Controller state [always set to 0]') if (dll_data%DLL_NumTrq>0) call WrSumInfoSend(R-1, 'Start of generator speed torque lookup table') if (dll_data%DLL_NumTrq>0) call WrSumInfoSend(R-1+dll_data%DLL_NumTrq,'End of generator speed torque lookup table') @@ -1047,6 +1050,9 @@ SUBROUTINE Fill_avrSWAP( t, u, p, ErrMsgSz, dll_data ) ! Records 107-108 are outputs [see Retrieve_avrSWAP()] dll_data%avrSWAP(109) = u%LSSTipMxa ! or u%LSShftMxs !> * Record 109: Shaft torque (=hub Mx for clockwise rotor) (Nm) [SrvD input] + dll_data%avrSWAP(110) = u%LSShftFxa !> * Record 110: Thrust - Rotating low-speed shaft force x (GL co-ords) (N) [SrvD input] + dll_data%avrSWAP(111) = u%LSShftFys !> * Record 111: Nonrotating low-speed shaft force y (GL co-ords) (N) [SrvD input] + dll_data%avrSWAP(112) = u%LSShftFzs !> * Record 112: Nonrotating low-speed shaft force z (GL co-ords) (N) [SrvD input] dll_data%avrSWAP(117) = 0 !> * Record 117: Controller state [always set to 0] !> * Records \f$R\f$ through \f$R + 2*DLL\_NumTrq - 1\f$: torque-speed look-up table elements. diff --git a/modules/servodyn/src/ServoDyn.f90 b/modules/servodyn/src/ServoDyn.f90 index 3253bea851..fd544611c6 100644 --- a/modules/servodyn/src/ServoDyn.f90 +++ b/modules/servodyn/src/ServoDyn.f90 @@ -48,16 +48,10 @@ MODULE ServoDyn LOGICAL, PARAMETER, PUBLIC :: Cmpl4LV = .FALSE. ! Is the module being compiled for Labview? #endif + ! indices into linearization arrays - INTEGER, PARAMETER :: Indx_u_Yaw = 1 - INTEGER, PARAMETER :: Indx_u_YawRate = 2 - INTEGER, PARAMETER :: Indx_u_HSS_Spd = 3 - INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_BlPitchCom(3) = (/1,2,3/) - INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_YawMom = 4 - INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_GenTrq = 5 - INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_ElecPwr = 6 - INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_WrOutput = 6 ! last non-writeoutput variable + INTEGER, PARAMETER, PUBLIC :: SrvD_Indx_Y_BlPitchCom(3) = (/1,2,3/) ! sometime remove this and calculate by p%NumBl (requires mods to FAST_Lin that I'm too lazy to deal with right now -- ADP) ! Parameters for type of control @@ -528,54 +522,9 @@ SUBROUTINE SrvD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO p%RotSpeedRef = InitInp%RotSpeedRef if (InitInp%Linearize) then - - ! If the module does allow linearization, return the appropriate Jacobian row/column names here: - ! Allocate and set these variables: InitOut%LinNames_y, InitOut%LinNames_x, InitOut%LinNames_xd, InitOut%LinNames_z, InitOut%LinNames_u - - CALL AllocAry( InitOut%RotFrame_y, SrvD_Indx_Y_WrOutput+p%NumOuts, 'RotFrame_y', ErrStat2, ErrMsg2 ) - if (Failed()) return; - - CALL AllocAry( InitOut%LinNames_y, SrvD_Indx_Y_WrOutput+p%NumOuts, 'LinNames_y', ErrStat2, ErrMsg2 ) - if (Failed()) return; - - do i=1,size(SrvD_Indx_Y_BlPitchCom) ! NOTE: potentially limit to NumBl - InitOut%LinNames_y(SrvD_Indx_Y_BlPitchCom(i)) = 'BlPitchCom('//trim(num2lstr(i))//'), rad' - InitOut%RotFrame_y(SrvD_Indx_Y_BlPitchCom(i)) = .true. - end do - InitOut%LinNames_y(SrvD_Indx_Y_YawMom) = 'YawMom, Nm' - InitOut%RotFrame_y(SrvD_Indx_Y_YawMom) = .false. - - InitOut%LinNames_y(SrvD_Indx_Y_GenTrq) = 'GenTrq, Nm' - InitOut%RotFrame_y(SrvD_Indx_Y_GenTrq) = .false. - - InitOut%LinNames_y(SrvD_Indx_Y_ElecPwr) = 'ElecPwr, W' - InitOut%RotFrame_y(SrvD_Indx_Y_ElecPwr) = .false. - - do i=1,p%NumOuts - InitOut%LinNames_y(i+SrvD_Indx_Y_WrOutput) = trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units - InitOut%RotFrame_y(i+SrvD_Indx_Y_WrOutput) = ANY( p%OutParam(i)%Indx == BlPitchC ) ! the only WriteOutput values in the rotating frame are BlPitch commands - end do - - - CALL AllocAry( InitOut%RotFrame_u, 3, 'RotFrame_u', ErrStat2, ErrMsg2 ) - if (Failed()) return; - - CALL AllocAry( InitOut%IsLoad_u, 3, 'IsLoad_u', ErrStat2, ErrMsg2 ) - if (Failed()) return; - - CALL AllocAry( InitOut%LinNames_u, 3, 'LinNames_u', ErrStat2, ErrMsg2 ) - if (Failed()) return; - - InitOut%LinNames_u(Indx_u_Yaw ) = 'Yaw, rad' - InitOut%LinNames_u(Indx_u_YawRate) = 'YawRate, rad/s' - InitOut%LinNames_u(Indx_u_HSS_Spd) = 'HSS_Spd, rad/s' - InitOut%RotFrame_u = .false. ! none of these are in the rotating frame - InitOut%IsLoad_u = .false. ! none of these linearization inputs are loads - + call SrvD_Init_Jacobian(InitInp, p, u, y, InitOut, ErrStat2, ErrMsg2); if(Failed()) return; else - p%TrimCase = TrimCase_none - end if @@ -644,7 +593,518 @@ subroutine Cleanup() ! Ignore any errors here CALL StC_DestroyCtrlChanInitInfoType(StC_CtrlChanInitInfo, ErrStat2, ErrMsg2 ) end subroutine Cleanup END SUBROUTINE SrvD_Init + !---------------------------------------------------------------------------------------------------------------------------------- +!> Initialize everything needed for linearization +subroutine SrvD_Init_Jacobian( InitInp, p, u, y, InitOut, ErrStat, ErrMsg ) + type(SrvD_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine + type(SrvD_ParameterType), intent(inout) :: p !< Parameters + type(SrvD_InputType), intent(in ) :: u !< An initial guess for the input; input mesh must be defined + type(SrvD_OutputType), intent(in ) :: y !< outputs + type(SrvD_InitOutputType), intent(inout) :: InitOut !< Output for initialization routine + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables: + character(*), parameter :: RoutineName = 'SrvD_Init_Jacobian' + integer(IntKi) :: ErrStat2 ! temporary Error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + real(ReKi) :: dx + real(R8Ki) :: du_t, du_r + + ErrStat = ErrID_None + ErrMsg = "" + + ! --- System dimension + ! rough estimate based on tower length + dx = 0.2_ReKi*Pi/180.0_ReKi * max(TwoNorm(InitInp%NacRefPos - InitInp%TwrBaseRefPos), 1.0_ReKi) + ! for translation inputs + du_t = 0.2_R8Ki*Pi_R8/180.0_R8Ki * max(real(TwoNorm(InitInp%NacRefPos - InitInp%TwrBaseRefPos),R8Ki), 1.0_R8Ki) + ! for rotation inputs + du_r = 0.2_R8Ki * Pi_R8 / 180.0_R8Ki + + ! initialize jacobian indices + call SrvD_Init_Jacobian_y(); if (ErrStat >= AbortErrLev) return; + call SrvD_Init_Jacobian_x(dx); if (ErrStat >= AbortErrLev) return; + call SrvD_Init_Jacobian_u(du_t,du_r); if (ErrStat >= AbortErrLev) return; + + ! To figure out what is going on, use this to print stuff to screen + !call CheckInfo() + +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + !> This routine initializes the Jacobian parameters and + !! initialization outputs for the linearized outputs. + subroutine SrvD_Init_Jacobian_y() + integer(IntKi) :: i, j, index_next + ! determine how many outputs there are in the Jacobian + p%Jac_ny = 0 + + ! outputs always passed + p%Jac_ny = p%Jac_ny & + + size(y%BlPitchCom) & ! y%BlPitchCom(:) + + 1 & ! y%YawMom + + 1 & ! y%GenTrq + + 1 ! y%ElecPwr + + ! StC related outputs + p%Jac_ny = p%Jac_ny & + + p%NumBStC * 6 * p%NumBl & ! 3 Force, 3 Moment at each BStC instance on each blade + + p%NumNStC * 6 & ! 3 Force, 3 Moment at each NStC instance + + p%NumTStC * 6 & ! 3 Force, 3 Moment at each TStC instance + + p%NumSStC * 6 ! 3 Force, 3 Moment at each SStC instance + + ! User requested outputs + p%Jac_ny = p%Jac_ny & + + p%NumOuts ! user requested outputs + + !-------------------------------- + ! linearization output names + !-------------------------------- + call AllocAry(InitOut%LinNames_y, p%Jac_ny, 'LinNames_y', ErrStat2, ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%RotFrame_y, p%Jac_ny, 'RotFrame_y', ErrStat2, ErrMsg2); if (Failed()) return; + InitOut%RotFrame_y = .false. ! Meshes are in global, not rotating frame + index_next = 1 ! Index counter initialize + + ! y%BlPitchCom -- NOTE: assumed order of these outputs + do i=1,size(y%BlPitchCom) + InitOut%LinNames_y(index_next) = 'BlPitchCom('//trim(num2lstr(i))//'), rad' + InitOut%RotFrame_y(index_next) = .true. + index_next = index_next + 1 + end do + + ! y%YawMom -- not in rotating frame + InitOut%LinNames_y(index_next) = 'YawMom, Nm'; index_next = index_next + 1 + + ! y%GenPwr -- not in rotating frame + InitOut%LinNames_y(index_next) = 'GenTrq, Nm'; index_next = index_next + 1 + + ! y%ElecPwr -- not in rotating frame + InitOut%LinNames_y(index_next) = 'ElecPwr, W'; index_next = index_next + 1 + + !-------------------------------- + ! StC related outputs + !-------------------------------- + CALL AllocAry(p%Jac_Idx_BStC_y, 2, p%NumBl, p%NumBStC, 'Jac_Idx_BStC_y', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_BStC_y = 0_IntKi + CALL AllocAry(p%Jac_Idx_NStC_y, 2, p%NumNStC, 'Jac_Idx_NStC_y', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_NStC_y = 0_IntKi + CALL AllocAry(p%Jac_Idx_TStC_y, 2, p%NumTStC, 'Jac_Idx_TStC_y', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_TStC_y = 0_IntKi + CALL AllocAry(p%Jac_Idx_SStC_y, 2, p%NumSStC, 'Jac_Idx_SStC_y', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_SStC_y = 0_IntKi + ! Blade + if (p%NumBStC > 0) then + do j=1,p%NumBStC + do i=1,p%NumBl + p%Jac_Idx_BStC_y(1,i,j) = index_next ! Start index of BStC in y + call PackLoadMesh_Names( y%BStCLoadMesh(i,j), 'Blade '//trim(num2lstr(i))//' StC '//trim(num2lstr(j)), InitOut%LinNames_y, index_next ) + p%Jac_Idx_BStC_y(2,i,j) = index_next-1 ! End index of BStC in y + enddo + enddo + endif + ! Nacelle + if (p%NumNStC > 0) then + do j=1,p%NumNStC + p%Jac_Idx_NStC_y(1,j) = index_next ! Start index of NStC in y + call PackLoadMesh_Names( y%NStCLoadMesh(j), 'Nacelle StC '//trim(num2lstr(j)), InitOut%LinNames_y, index_next ) + p%Jac_Idx_NStC_y(2,j) = index_next-1 ! End index of NStC in y + enddo + endif + ! Tower + if (p%NumTStC > 0) then + do j=1,p%NumTStC + p%Jac_Idx_TStC_y(1,j) = index_next ! Start index of TStC in y + call PackLoadMesh_Names( y%TStCLoadMesh(j), 'Tower StC '//trim(num2lstr(j)), InitOut%LinNames_y, index_next ) + p%Jac_Idx_TStC_y(2,j) = index_next-1 ! End index of TStC in y + enddo + endif + ! Sub-tructure + if (p%NumSStC > 0) then + do j=1,p%NumSStC + p%Jac_Idx_SStC_y(1,j) = index_next ! Start index of SStC in y + call PackLoadMesh_Names( y%SStCLoadMesh(j), 'Substructure StC '//trim(num2lstr(j)), InitOut%LinNames_y, index_next ) + p%Jac_Idx_SStC_y(2,j) = index_next-1 ! End index of SStC in y + enddo + endif + + !-------------------------------- + ! y%OutParam -- User requested outputs + ! Some outputs are in rotating frame + !-------------------------------- + do i=1,p%NumOuts + InitOut%LinNames_y(index_next) = trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units + if (ANY( p%OutParam(i)%Indx == BlPitchC )) InitOut%RotFrame_y(index_next) = .true. ! WriteOutput BlPitch commands + ! Blade StC local output channels + if (ANY( p%OutParam(i)%Indx == BStC_XQ )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC X displacements + if (ANY( p%OutParam(i)%Indx == BStC_XQD )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC X displacement velocities + if (ANY( p%OutParam(i)%Indx == BStC_YQ )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC Y displacements + if (ANY( p%OutParam(i)%Indx == BStC_YQD )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC Y displacement velocities + if (ANY( p%OutParam(i)%Indx == BStC_ZQ )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC Z displacements + if (ANY( p%OutParam(i)%Indx == BStC_ZQD )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC Z displacement velocities + if (ANY( p%OutParam(i)%Indx == BStC_Fxl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + if (ANY( p%OutParam(i)%Indx == BStC_Fyl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + if (ANY( p%OutParam(i)%Indx == BStC_Fzl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + if (ANY( p%OutParam(i)%Indx == BStC_Mxl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + if (ANY( p%OutParam(i)%Indx == BStC_Myl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + if (ANY( p%OutParam(i)%Indx == BStC_Mzl )) InitOut%RotFrame_y(index_next) = .true. ! Blade StC local forces and moments + index_next = index_next + 1 + end do + end subroutine SrvD_Init_Jacobian_y + + !> This routine initializes the Jacobian parameters and initialization outputs for the linearized continuous states. + subroutine SrvD_Init_Jacobian_x(dx) + real(ReKi), intent(in ) :: dx ! default perturbation size + integer(IntKi) :: i, j, k, index_next + p%Jac_nx = 0 ! no states other than StC states + ! StC related states + p%Jac_nx = p%Jac_nx & + + p%NumBStC * 2 * 3 * p%NumBl & ! 3 displacement state, 3 displacement state derivatives at each BStC instance on each blade + + p%NumNStC * 2 * 3 & ! 3 displacement state, 3 displacement state derivatives at each NStC instance + + p%NumTStC * 2 * 3 & ! 3 displacement state, 3 displacement state derivatives at each TStC instance + + p%NumSStC * 2 * 3 ! 3 displacement state, 3 displacement state derivatives at each SStC instance + + ! allocate space for the row/column names and for perturbation sizes + CALL AllocAry(InitOut%LinNames_x , p%Jac_nx, 'LinNames_x' , ErrStat2, ErrMsg2); if (Failed()) return; + CALL AllocAry(InitOut%RotFrame_x , p%Jac_nx, 'RotFrame_x' , ErrStat2, ErrMsg2); if (Failed()) return; + CALL AllocAry(InitOut%DerivOrder_x, p%Jac_nx, 'DerivOrder_x', ErrStat2, ErrMsg2); if (Failed()) return; + ! --- Jac_x_indx: matrix to store index to help us figure out what the ith value of the x vector really means + ! column 1 indicates module's mesh and field perturbation index (index to p%dx) + ! column 2 indicates the first index (x-y-z component) (unused) + ! column 3 is the StC motion mesh (Instance index) + ! column 4 is the StC motion mesh (blade index BStC mesh, ignored on others) + call allocAry( p%Jac_x_indx, p%Jac_nx, 4, 'p%Jac_x_indx', ErrStat2, ErrMsg2); if (Failed()) return; + p%Jac_x_indx = 0_IntKi + ! perturbation sizes + CALL AllocAry(p%dx, 24, 'x perturbation', ErrStat2, ErrMsg2); if (Failed()) return; + p%dx(1:24) = dx ! all state perturbations are the same for disp and velocity + + ! Initialize RotFrame and DerivOrder + InitOut%RotFrame_x = .false. + InitOut%DerivOrder_x = 2 + !-------------------------------- + ! linearization state names + !-------------------------------- + CALL AllocAry(p%Jac_Idx_BStC_x, 2, p%NumBl, p%NumBStC, 'Jac_Idx_BStC_x', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_BStC_x = 0_IntKi + CALL AllocAry(p%Jac_Idx_NStC_x, 2, p%NumNStC, 'Jac_Idx_NStC_x', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_NStC_x = 0_IntKi + CALL AllocAry(p%Jac_Idx_TStC_x, 2, p%NumTStC, 'Jac_Idx_TStC_x', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_TStC_x = 0_IntKi + CALL AllocAry(p%Jac_Idx_SStC_x, 2, p%NumSStC, 'Jac_Idx_SStC_x', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_SStC_x = 0_IntKi + index_next = 0 ! Index counter initialize + ! Blade StC -- displacement state + if (p%NumBStC > 0) then + do j=1,p%NumBStC + do k=1,p%NumBl + p%Jac_Idx_BStC_x(1,k,j) = index_next+1 ! Start index of BStC in x + p%Jac_x_indx(index_next+1:index_next+6,1) = (/ 1, 2, 3, 4, 5, 6/) ! StC type and field index + p%Jac_x_indx(index_next+1:index_next+6,2) = (/ 1, 2, 3, 1, 2, 3/) ! component (x,y,z) + p%Jac_x_indx(index_next+1:index_next+6,3) = j ! Instance + p%Jac_x_indx(index_next+1:index_next+6,4) = k ! blade + InitOut%LinNames_x(index_next+1) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state X m'; ! x x%BStC(j)%StC_x(1,k) + InitOut%LinNames_x(index_next+2) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state Y m'; ! y x%BStC(j)%StC_x(3,k) + InitOut%LinNames_x(index_next+3) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state Z m'; ! z x%BStC(j)%StC_x(5,k) + InitOut%LinNames_x(index_next+4) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state dX/dt m/s'; ! x-dot x%BStC(j)%StC_x(2,k) + InitOut%LinNames_x(index_next+5) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state dY/dt m/s'; ! y-dot x%BStC(j)%StC_x(4,k) + InitOut%LinNames_x(index_next+6) = 'Blade '//trim(num2lstr(k))//' StC '//trim(num2lstr(j))//' local displacement state dZ/dt m/s'; ! z-dot x%BStC(j)%StC_x(6,k) + InitOut%RotFrame_x(index_next+1:index_next+6) = .true. + index_next = index_next + 6 + p%Jac_Idx_BStC_x(2,k,j) = index_next ! End index of BStC in x + enddo + enddo + endif + ! Nacelle StC -- displacement state + if (p%NumNStC > 0) then + do j=1,p%NumNStC + p%Jac_Idx_NStC_x(1,j) = index_next+1 ! Start index of NStC in x + p%Jac_x_indx(index_next+1:index_next+6,1) = (/ 7, 8, 9,10,11,12/) ! StC type and field index + p%Jac_x_indx(index_next+1:index_next+6,2) = (/ 1, 2, 3, 1, 2, 3/) ! component (x,y,z) + p%Jac_x_indx(index_next+1:index_next+6,3) = j ! Instance + InitOut%LinNames_x(index_next+1) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state X m'; ! x x%NStC(j)%StC_x(1,1) + InitOut%LinNames_x(index_next+2) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state Y m'; ! y x%NStC(j)%StC_x(3,1) + InitOut%LinNames_x(index_next+3) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state Z m'; ! z x%NStC(j)%StC_x(5,1) + InitOut%LinNames_x(index_next+4) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state dX/dt m/s'; ! x-dot x%NStC(j)%StC_x(2,1) + InitOut%LinNames_x(index_next+5) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state dY/dt m/s'; ! y-dot x%NStC(j)%StC_x(4,1) + InitOut%LinNames_x(index_next+6) = 'Nacelle StC '//trim(num2lstr(j))//' local displacement state dZ/dt m/s'; ! z-dot x%NStC(j)%StC_x(6,1) + index_next = index_next + 6 + p%Jac_Idx_NStC_x(2,j) = index_next ! End index of NStC in x + enddo + endif + ! Tower StC -- displacement state + if (p%NumTStC > 0) then + do j=1,p%NumTStC + p%Jac_Idx_TStC_x(1,j) = index_next+1 ! Start index of TStC in x + p%Jac_x_indx(index_next+1:index_next+6,1) = (/13,14,15,16,17,18/) ! StC type and field index + p%Jac_x_indx(index_next+1:index_next+6,2) = (/ 1, 2, 3, 1, 2, 3/) ! component (x,y,z) + p%Jac_x_indx(index_next+1:index_next+6,3) = j ! Instance + InitOut%LinNames_x(index_next+1) = 'Tower StC '//trim(num2lstr(j))//' local displacement state X m'; ! x x%TStC(j)%StC_x(1,1) + InitOut%LinNames_x(index_next+2) = 'Tower StC '//trim(num2lstr(j))//' local displacement state Y m'; ! y x%TStC(j)%StC_x(3,1) + InitOut%LinNames_x(index_next+3) = 'Tower StC '//trim(num2lstr(j))//' local displacement state Z m'; ! z x%TStC(j)%StC_x(5,1) + InitOut%LinNames_x(index_next+4) = 'Tower StC '//trim(num2lstr(j))//' local displacement state dX/dt m/s'; ! x-dot x%TStC(j)%StC_x(2,1) + InitOut%LinNames_x(index_next+5) = 'Tower StC '//trim(num2lstr(j))//' local displacement state dY/dt m/s'; ! y-dot x%TStC(j)%StC_x(4,1) + InitOut%LinNames_x(index_next+6) = 'Tower StC '//trim(num2lstr(j))//' local displacement state dZ/dt m/s'; ! z-dot x%TStC(j)%StC_x(6,1) + index_next = index_next + 6 + p%Jac_Idx_TStC_x(2,j) = index_next ! End index of TStC in x + enddo + endif + ! Substructure StC -- displacement state + if (p%NumSStC > 0) then + do j=1,p%NumSStC + p%Jac_Idx_SStC_x(1,j) = index_next+1 ! Start index of SStC in x + p%Jac_x_indx(index_next+1:index_next+6,1) = (/19,20,21,22,23,24/) ! StC type and field index + p%Jac_x_indx(index_next+1:index_next+6,2) = (/ 1, 2, 3, 1, 2, 3/) ! component (x,y,z) + p%Jac_x_indx(index_next+1:index_next+6,3) = j ! Instance + InitOut%LinNames_x(index_next+1) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state X m'; ! x x%SStC(j)%StC_x(1,1) + InitOut%LinNames_x(index_next+2) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state Y m'; ! y x%SStC(j)%StC_x(3,1) + InitOut%LinNames_x(index_next+3) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state Z m'; ! z x%SStC(j)%StC_x(5,1) + InitOut%LinNames_x(index_next+4) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state dX/dt m/s'; ! x-dot x%SStC(j)%StC_x(2,1) + InitOut%LinNames_x(index_next+5) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state dY/dt m/s'; ! y-dot x%SStC(j)%StC_x(4,1) + InitOut%LinNames_x(index_next+6) = 'Substructure StC '//trim(num2lstr(j))//' local displacement state dZ/dt m/s'; ! z-dot x%SStC(j)%StC_x(6,1) + index_next = index_next + 6 + p%Jac_Idx_SStC_x(2,j) = index_next ! End index of SStC in x + enddo + endif + end subroutine SrvD_Init_Jacobian_x + + !> This routine initializes the Jacobian parameters and initialization outputs for the linearized inputs + subroutine SrvD_Init_Jacobian_u(du_t,du_r) + real(R8Ki), intent(in ) :: du_t ! default perturbation size for input translations + real(R8Ki), intent(in ) :: du_r ! default perturbation size for input rotations + integer(IntKi) :: i, j, k, index_next + integer(IntKi) :: i_meshField ! Counter for mesh fields + ! Standard inputs + p%Jac_nu = 3 ! Yaw, YawRate, HSS_Spd + ! StC related inputs + p%Jac_nu = p%Jac_nu & + + p%NumBStC * 18 * p%NumBl & ! 3 Translation Displacements + 3 orientations + 6 velocities + 6 accelerations at each BStC instance on each blade + + p%NumNStC * 18 & ! 3 Translation Displacements + 3 orientations + 6 velocities + 6 accelerations at each NStC instance + + p%NumTStC * 18 & ! 3 Translation Displacements + 3 orientations + 6 velocities + 6 accelerations at each TStC instance + + p%NumSStC * 18 ! 3 Translation Displacements + 3 orientations + 6 velocities + 6 accelerations at each SStC instance + + ! allocate space for the row/column names and for perturbation sizes + ! --- Info of linearized inputs (Names, RotFrame, IsLoad) + call AllocAry(InitOut%LinNames_u, p%Jac_nu, 'LinNames_u', ErrStat2, ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%RotFrame_u, p%Jac_nu, 'RotFrame_u', ErrStat2, ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%IsLoad_u, p%Jac_nu, 'IsLoad_u' , ErrStat2, ErrMsg2); if (Failed()) return; + ! --- Jac_u_indx: matrix to store index to help us figure out what the ith value of the u vector really means + ! column 1 indicates module's mesh and field perturbation index (index to p%du) + ! column 2 indicates the first index (x-y-z component) of the field + ! column 3 is the StC motion mesh (Instance index) + ! column 4 is the StC motion mesh (blade index BStC mesh, ignored on others) + call allocAry( p%Jac_u_indx, p%Jac_nu, 4, 'p%Jac_u_indx', ErrStat2, ErrMsg2); if (Failed()) return; + p%Jac_u_indx = 0 + ! perturbation sizes + CALL AllocAry(p%du, 24, 'u perturbation', ErrStat2, ErrMsg2); if (Failed()) return; + p%du( 1) = du_t ! Blade u%*Mesh%TranslationDisp = 1; + p%du( 2) = du_r ! Blade u%*Mesh%Orientation = 2; + p%du( 3) = du_t ! Blade u%*Mesh%TranslationVel = 3; + p%du( 4) = du_r ! Blade u%*Mesh%RotationVel = 4; + p%du( 5) = du_t ! Blade u%*Mesh%TranslationAcc = 5; + p%du( 6) = du_r ! Blade u%*Mesh%RotationAcc = 6; + p%du( 7:12) = p%du( 1:6) ! Nacelle + p%du(13:18) = p%du( 1:6) ! Tower + p%du(19:24) = p%du( 1:6) ! Substructure + + ! Initialize RotFrame_u and IsLoad_u + InitOut%RotFrame_u = .false. ! every StC input is on a mesh, which stores values in the global (not rotating) frame + InitOut%IsLoad_u = .false. ! No loads present + + !-------------------------------- + ! linearization input names + !-------------------------------- + index_next = 1 + ! u%Yaw -- not in rotating frame + InitOut%LinNames_u(index_next) = 'Yaw, rad'; index_next = index_next + 1 + + ! u%YawRate -- not in rotating frame + InitOut%LinNames_u(index_next) = 'YawRate, rad/s'; index_next = index_next + 1 + + ! u%HSS_Spd -- not in rotating frame + InitOut%LinNames_u(index_next) = 'HSS_Spd, rad/s'; index_next = index_next + 1 + + !-------------------------------- + ! StC related inputs + !-------------------------------- + CALL AllocAry(p%Jac_Idx_BStC_u, 2, p%NumBl, p%NumBStC, 'Jac_Idx_BStC_u', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_BStC_u = 0_IntKi + CALL AllocAry(p%Jac_Idx_NStC_u, 2, p%NumNStC, 'Jac_Idx_NStC_u', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_NStC_u = 0_IntKi + CALL AllocAry(p%Jac_Idx_TStC_u, 2, p%NumTStC, 'Jac_Idx_TStC_u', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_TStC_u = 0_IntKi + CALL AllocAry(p%Jac_Idx_SStC_u, 2, p%NumSStC, 'Jac_Idx_SStC_u', ErrStat2, ErrMsg2); if (Failed()) return; p%Jac_Idx_SStC_u = 0_IntKi + ! Blade + if (p%NumBStC > 0) then + do j=1,p%NumBStC + do i=1,p%NumBl + p%Jac_Idx_BStC_u(1,i,j) = index_next ! Start index of BStC in u + call PackMotionMesh_Names( u%BStCMotionMesh(i,j), 'Blade '//trim(num2lstr(i))//' StC '//trim(num2lstr(j)), InitOut%LinNames_u, index_next ) + p%Jac_Idx_BStC_u(2,i,j) = index_next-1 ! End index of BStC in u + enddo + enddo + endif + ! Nacelle + if (p%NumNStC > 0) then + do j=1,p%NumNStC + p%Jac_Idx_NStC_u(1,j) = index_next ! Start index of NStC in u + call PackMotionMesh_Names( u%NStCMotionMesh(j), 'Nacelle StC '//trim(num2lstr(j)), InitOut%LinNames_u, index_next ) + p%Jac_Idx_NStC_u(2,j) = index_next-1 ! End index of NStC in u + enddo + endif + ! Tower + if (p%NumTStC > 0) then + do j=1,p%NumTStC + p%Jac_Idx_TStC_u(1,j) = index_next ! Start index of TStC in u + call PackMotionMesh_Names( u%TStCMotionMesh(j), 'Tower StC '//trim(num2lstr(j)), InitOut%LinNames_u, index_next ) + p%Jac_Idx_TStC_u(2,j) = index_next-1 ! End index of TStC in u + enddo + endif + ! Sub-structure + if (p%NumSStC > 0) then + do j=1,p%NumSStC + p%Jac_Idx_SStC_u(1,j) = index_next ! Start index of SStC in u + call PackMotionMesh_Names( u%SStCMotionMesh(j), 'Substructure StC '//trim(num2lstr(j)), InitOut%LinNames_u, index_next ) + p%Jac_Idx_SStC_u(2,j) = index_next-1 ! End index of SStC in u + enddo + endif + + !-------------------------------- + ! linearization perturbation size + !-------------------------------- + index_next = 1 + !! u%Yaw -- not in rotating frame NOTE: this is calculated exactly, so not necessary to track + !! u%YawRate -- not in rotating frame NOTE: this is calculated exactly, so not necessary to track + !! u%HSS_Spd -- not in rotating frame NOTE: this is calculated exactly, so not necessary to track + + ! Blade StC instances + do j=1,p%NumBStC + do i=1,p%NumBl + index_next = p%Jac_Idx_BStC_u(1,i,j) + do i_meshField = 1,6 + do k=1,3 + p%Jac_u_indx(index_next,1) = i_meshField ! (TransDisp,Orient,TransVel,RotVel,TransAcc,RotAcc) + p%Jac_u_indx(index_next,2) = k ! component (x,y,z) + p%Jac_u_indx(index_next,3) = j ! Instance + p%Jac_u_indx(index_next,4) = i ! blade + index_next = index_next + 1 + enddo + enddo + enddo + enddo + ! Nacelle StC instances + do j=1,p%NumNStC + index_next = p%Jac_Idx_NStC_u(1,j) + do i_meshField = 7,12 + do k=1,3 + p%Jac_u_indx(index_next,1) = i_meshField ! (TransDisp,Orient,TransVel,RotVel,TransAcc,RotAcc) + p%Jac_u_indx(index_next,2) = k ! component (x,y,z) + p%Jac_u_indx(index_next,3) = j ! Instance + p%Jac_u_indx(index_next,4) = 1 ! Ignored + index_next = index_next + 1 + enddo + enddo + enddo + ! Tower StC instances + do j=1,p%NumTStC + index_next = p%Jac_Idx_TStC_u(1,j) + do i_meshField = 13,18 + do k=1,3 + p%Jac_u_indx(index_next,1) = i_meshField ! (TransDisp,Orient,TransVel,RotVel,TransAcc,RotAcc) + p%Jac_u_indx(index_next,2) = k ! component (x,y,z) + p%Jac_u_indx(index_next,3) = j ! Instance + p%Jac_u_indx(index_next,4) = 1 ! Ignored + index_next = index_next + 1 + enddo + enddo + enddo + ! Substructure StC instances + do j=1,p%NumSStC + index_next = p%Jac_Idx_SStC_u(1,j) + do i_meshField = 19,24 + do k=1,3 + p%Jac_u_indx(index_next,1) = i_meshField ! (TransDisp,Orient,TransVel,RotVel,TransAcc,RotAcc) + p%Jac_u_indx(index_next,2) = k ! component (x,y,z) + p%Jac_u_indx(index_next,3) = j ! Instance + p%Jac_u_indx(index_next,4) = 1 ! Ignored + index_next = index_next + 1 + enddo + enddo + enddo + end subroutine SrvD_Init_Jacobian_u + + subroutine CheckInfo() + character(1) :: Flag,FlagLoad + integer(IntKi) :: i,j,k + ! print out some info + if (allocated(InitOut%LinNames_y)) then + call WrScr('LinNames_y') + do j=1,p%NumBStC + do k=1,p%NumBl + call WrScr(' BStC '//trim(Num2LStr(j))//' blade '//trim(Num2LStr(k))//' range: '//trim(Num2LStr(p%Jac_Idx_BStC_y(1,k,j)))//' '//trim(Num2LStr(p%Jac_Idx_BStC_y(2,k,j)))) + enddo + enddo + do j=1,p%NumNStC + call WrScr(' NStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_NStC_y(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_NStC_y(2,j)))) + enddo + do j=1,p%NumTStC + call WrScr(' TStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_TStC_y(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_TStC_y(2,j)))) + enddo + do j=1,p%NumSStC + call WrScr(' SStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_SStC_y(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_SStC_y(2,j)))) + enddo + do i=1,size(InitOut%LinNames_y) + Flag='F' + if (InitOut%RotFrame_y(i)) Flag='T' + call WrFileNR(CU,' '//Num2LStr(i)//Flag//' '//InitOut%LinNames_y(i)//NewLine) + enddo + endif + if (allocated(InitOut%LinNames_x)) then + call WrScr('LinNames_x') + do j=1,p%NumBStC + do k=1,p%NumBl + call WrScr(' BStC '//trim(Num2LStr(j))//' blade '//trim(Num2LStr(k))//' range: '//trim(Num2LStr(p%Jac_Idx_BStC_x(1,k,j)))//' '//trim(Num2LStr(p%Jac_Idx_BStC_x(2,k,j)))) + enddo + enddo + do j=1,p%NumNStC + call WrScr(' NStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_NStC_x(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_NStC_x(2,j)))) + enddo + do j=1,p%NumTStC + call WrScr(' TStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_TStC_x(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_TStC_x(2,j)))) + enddo + do j=1,p%NumSStC + call WrScr(' SStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_SStC_x(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_SStC_x(2,j)))) + enddo + do i=1,size(InitOut%LinNames_x) + Flag='F' + if (InitOut%RotFrame_x(i)) Flag='T' + call WrFileNR(CU,' '//Num2LStr(i)//Flag//' '//trim(Num2LStr(InitOut%DerivOrder_x(i)))//' '//InitOut%LinNames_x(i)//NewLine) + enddo + endif + if (allocated(InitOut%LinNames_u)) then + call WrScr('Perturb Size u') + do i=1,size(p%du) + call WrFileNR(CU,' '//trim(Num2LStr(i))//' '//trim(Num2LStr(p%du(i)))//NewLine) + enddo + call WrScr('LinNames_u') + do j=1,p%NumBStC + do k=1,p%NumBl + call WrScr(' BStC '//trim(Num2LStr(j))//' blade '//trim(Num2LStr(k))//' range: '//trim(Num2LStr(p%Jac_Idx_BStC_u(1,k,j)))//' '//trim(Num2LStr(p%Jac_Idx_BStC_u(2,k,j)))) + enddo + enddo + do j=1,p%NumNStC + call WrScr(' NStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_NStC_u(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_NStC_u(2,j)))) + enddo + do j=1,p%NumTStC + call WrScr(' TStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_TStC_u(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_TStC_u(2,j)))) + enddo + do j=1,p%NumSStC + call WrScr(' SStC '//trim(Num2LStr(j))//' range: '//trim(Num2LStr(p%Jac_Idx_SStC_u(1,j)))//' '//trim(Num2LStr(p%Jac_Idx_SStC_u(2,j)))) + enddo + do i=1,size(InitOut%LinNames_u) + Flag='F' + FlagLoad='F' + if (InitOut%RotFrame_u(i)) Flag='T' + if (InitOut%IsLoad_u(i)) FlagLoad='T' + call WrFileNR(CU,' '//Num2LStr(i)//Flag//' '//FlagLoad//' ('// & + trim(Num2LStr(p%Jac_u_indx(i,1)))//','//trim(Num2LStr(p%Jac_u_indx(i,2)))//','//trim(Num2LStr(p%Jac_u_indx(i,3)))// & + ') '//InitOut%LinNames_u(i)//NewLine) + enddo + endif + end subroutine CheckInfo +end subroutine SrvD_Init_Jacobian !---------------------------------------------------------------------------------------------------------------------------------- !> This routine sets the data structures for the structural control (StC) module -- Nacelle Instances @@ -870,7 +1330,7 @@ subroutine StC_Tower_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)') ' Tower StC instance: ',j - write(UnSum, '(10x,A)') 'Input file: '//trim(InputFileData%NStCfiles(j)) + write(UnSum, '(10x,A)') 'Input file: '//trim(InputFileData%TStCfiles(j)) write(UnSum, '(10x,A36)') 'Initial location (global/inertial): ' write(UnSum, '(20x,3(2x,ES10.3e2))') u(1,j)%Mesh(1)%Position(1:3,1) write(UnSum, '(10x,A61)') 'Initial location relative to tower base (tower coordinates): ' @@ -1918,30 +2378,35 @@ SUBROUTINE SrvD_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrS ErrStat = ErrID_None ErrMsg = "" + call SrvD_CopyContState( x, dxdt, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; ! Compute the first time derivatives of the continuous states here: - dxdt%DummyContState = 0.0_ReKi + if (.not. allocated(dxdt%BStC) .and. p%NumBStC > 0_IntKi) allocate(dxdt%BStC(p%NumBStC)) + if (.not. allocated(dxdt%NStC) .and. p%NumNStC > 0_IntKi) allocate(dxdt%NStC(p%NumNStC)) + if (.not. allocated(dxdt%TStC) .and. p%NumTStC > 0_IntKi) allocate(dxdt%TStC(p%NumTStC)) + if (.not. allocated(dxdt%SStC) .and. p%NumSStC > 0_IntKi) allocate(dxdt%SStC(p%NumSStC)) ! StrucCtrl do j=1,p%NumBStC ! Blade - CALL StC_CalcContStateDeriv( t, m%u_BStC(1,j), p%BStC(j), x%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), m%BStC(j), dxdt%BStC(j), ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL StC_CalcContStateDeriv( t, m%u_BStC(1,j), p%BStC(j), x%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), m%BStC(j), dxdt%BStC(j), ErrStat2, ErrMsg2 ); if (Failed()) return; enddo do j=1,p%NumNStC ! Nacelle - CALL StC_CalcContStateDeriv( t, m%u_NStC(1,j), p%NStC(j), x%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), m%NStC(j), dxdt%NStC(j), ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL StC_CalcContStateDeriv( t, m%u_NStC(1,j), p%NStC(j), x%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), m%NStC(j), dxdt%NStC(j), ErrStat2, ErrMsg2 ); if (Failed()) return; enddo do j=1,p%NumTStC ! Tower - CALL StC_CalcContStateDeriv( t, m%u_TStC(1,j), p%TStC(j), x%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), m%TStC(j), dxdt%TStC(j), ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL StC_CalcContStateDeriv( t, m%u_TStC(1,j), p%TStC(j), x%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), m%TStC(j), dxdt%TStC(j), ErrStat2, ErrMsg2 ); if (Failed()) return; enddo do j=1,p%NumSStC ! Platform - CALL StC_CalcContStateDeriv( t, m%u_SStC(1,j), p%SStC(j), x%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), m%SStC(j), dxdt%SStC(j), ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL StC_CalcContStateDeriv( t, m%u_SStC(1,j), p%SStC(j), x%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), m%SStC(j), dxdt%SStC(j), ErrStat2, ErrMsg2 ); if (Failed()) return; enddo - +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + END SUBROUTINE SrvD_CalcContStateDeriv !---------------------------------------------------------------------------------------------------------------------------------- !> Tight coupling routine for updating discrete states. @@ -2066,55 +2531,236 @@ SUBROUTINE SrvD_CalcConstrStateResidual( t, u, p, x, xd, z, OtherState, m, z_res END SUBROUTINE SrvD_CalcConstrStateResidual -!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -! ###### The following four routines are Jacobian routines for linearization capabilities ####### !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions -!! with respect to the inputs (u). The partial derivative dY/du is returned. +!! with respect to the inputs (u). The partial derivatives dY/du and dX/du are returned. SUBROUTINE SrvD_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(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) - TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters - TYPE(SrvD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point - TYPE(SrvD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point - TYPE(SrvD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at operating point - TYPE(SrvD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at operating point - TYPE(SrvD_OutputType), INTENT(IN ) :: y !< Output (change to inout if a mesh copy is required); - !! Output fields are not used by this routine, but type is - !! available here so that mesh parameter information (i.e., - !! connectivity) does not have to be recalculated for dYdu. - TYPE(SrvD_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(:,:) !< Partial derivatives of output functions - !! (Y) with respect to the inputs (u) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dXdu(:,:) !< Partial derivatives of continuous state - !! functions (X) with respect to inputs (u) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dXddu(:,:) !< Partial derivatives of discrete state - !! functions (Xd) with respect to inputs (u) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dZdu(:,:) !< Partial derivatives of constraint state - !! functions (Z) with respect to inputs (u) [intent in to avoid deallocation] + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(inout) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_OutputType), intent(inout) :: y !< Output (change to inout if a mesh copy is required); + !! Output fields are not used by this routine, but type is + !! available here so that mesh parameter information (i.e., + !! connectivity) does not have to be recalculated for dYdu. + type(SrvD_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(:,:) !< Partial derivatives of output functions + !! (Y) with respect to the inputs (u) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dXdu(:,:) !< Partial derivatives of continuous state + !! functions (X) with respect to inputs (u) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dXddu(:,:) !< Partial derivatives of discrete state + !! functions (Xd) with respect to inputs (u) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dZdu(:,:) !< Partial derivatives of constraint state + !! functions (Z) with respect to inputs (u) [intent in to avoid deallocation] ! local variables - REAL(R8Ki) :: AllOuts(3,1:MaxOutPts) ! All the the available output channels - REAL(R8Ki) :: GenTrq_du, ElecPwr_du ! derivatives of generator torque and electrical power w.r.t. u%HSS_SPD - INTEGER(IntKi) :: I ! Generic loop index - INTEGER(IntKi) :: ErrStat2 ! Error status of the operation - CHARACTER(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_JacobianPInput' - + integer(IntKi) :: ErrStat2 ! Error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'SrvD_JacobianPInput' ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' + ! Calculate the partial derivative of the output functions (Y) with respect to the inputs (u) here: + IF ( PRESENT( dYdu ) ) THEN + call Jac_dYdu( t, u, p, x, xd, z, OtherState, y, m, ErrStat2, ErrMsg2, dYdu ) + if (Failed()) return + END IF + + IF ( PRESENT( dXdu ) ) THEN + call Jac_dXdu( t, u, p, x, xd, z, OtherState, m, ErrStat2, ErrMsg2, dXdu ) + if (Failed()) return + END IF + + IF ( PRESENT( dXddu ) ) THEN + if (allocated(dXddu)) deallocate(dXddu) + END IF + + IF ( PRESENT( dZdu ) ) THEN + if (allocated(dZdu)) deallocate(dZdu) + END IF + +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed +END SUBROUTINE SrvD_JacobianPInput + +!> Calculate the jacobian dYdu +subroutine Jac_dYdu( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdu ) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(inout) :: u !< Inputs at operating point (out for copy only) + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_OutputType), intent(inout) :: y !< Output (need to make copies) + type(SrvD_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, intent(inout) :: dYdu(:,:) !< Partial derivatives of output functions + + integer(IntKi) :: n ! Generic loop index + type(SrvD_InputType) :: u_perturb ! copy of inputs to perturb + type(SrvD_OutputType) :: y_p ! outputs positive perturbed + type(SrvD_OutputType) :: y_m ! outputs negative perturbed + real(R8Ki) :: delta_p ! delta+ change in input or state + real(R8Ki) :: delta_m ! delta- change in input or state + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Jac_dYdu' + + ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = '' + ! Allocate the dYdu array + if (.not. allocated(dYdu)) then + call allocAry(dYdu, p%Jac_ny, p%Jac_nu, 'dYdu', ErrStat2, ErrMsg2) + if (Failed()) return + elseif ( (size(dYdu,1) /= p%Jac_ny) .or. (size(dYdu,2) /= p%Jac_nu) ) then + deallocate(dYdu) + call allocAry(dYdu, p%Jac_ny, p%Jac_nu, 'dYdu', ErrStat2, ErrMsg2) + if (Failed()) return + end if + dYdu = 0.0_R8Ki + + !------------------------------------------------------------- + ! Calculate first three rows for Yaw, YawRate, HSS_Spd inputs + ! This is an analytical calculation. + ! First 3 columns in dY/du + !------------------------------------------------------------- + call dYdu_YawGen(); if (ErrStat > AbortErrLev) return; + + !------------------------------------------------------------- + ! Perturb each StC instance individually and place in appropriate location in dYdu + ! Each StC is basically an isolated piece that doesn't interact with any other StC or with anything else in SrvD, + ! so we take advantage of that here for computational expediency. + !------------------------------------------------------------- + ! make a copy of the inputs to perturb if an StC exists + if ( (p%NumBStC + p%NumNStC + p%NumTStC + p%NumSStC) > 0 ) then + call SrvD_CopyInput( u, u_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + endif + !------------------- + ! Blade StC + if (p%NumBStC > 0) then + do n=p%Jac_Idx_BStC_u(1,1,1),p%Jac_Idx_BStC_u(2,p%NumBl,p%NumBStC) ! input range for BStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dYdu( n, +1, u_perturb, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dYdu( n, -1, u_perturb, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,n) ) + enddo + endif + !------------------- + ! Nacelle StC + if (p%NumNStC > 0) then + do n=p%Jac_Idx_NStC_u(1,1),p%Jac_Idx_NStC_u(2,p%NumNStC) ! input range for NStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dYdu( n, +1, u_perturb, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dYdu( n, -1, u_perturb, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,n) ) + enddo + endif + !------------------- + ! Tower StC + if (p%NumTStC > 0) then + do n=p%Jac_Idx_TStC_u(1,1),p%Jac_Idx_TStC_u(2,p%NumTStC) ! input range for TStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dYdu( n, +1, u_perturb, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dYdu( n, -1, u_perturb, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,n) ) + enddo + endif + !------------------- + ! Substructure StC + if (p%NumSStC > 0) then + do n=p%Jac_Idx_SStC_u(1,1),p%Jac_Idx_SStC_u(2,p%NumSStC) ! input range for SStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dYdu( n, +1, u_perturb, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dYdu( n, -1, u_perturb, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,n) ) + enddo + endif + call Cleanup() - ! Calculate the partial derivative of the output functions (Y) with respect to the inputs (u) here: +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call Cleanup + end function Failed - IF ( PRESENT( dYdu ) ) THEN + subroutine Cleanup() + ! Ignore any errors from the destroy (these weren't created if no StCs) + call SrvD_DestroyInput( u_perturb, ErrStat2, ErrMsg2 ) + call SrvD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) + call SrvD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) + end subroutine Cleanup + + !> Subroutine for the yaw and generator portions of the dYdu matrix (first three rows of dYdu) + !! This is part of dYdu uses analytical results + subroutine dYdu_YawGen() + integer(IntKi) :: i ! Generic indices + real(R8Ki) :: GenTrq_du, ElecPwr_du ! derivatives of generator torque and electrical power w.r.t. u%HSS_SPD + integer,parameter :: Indx_u_Yaw = 1 + integer,parameter :: Indx_u_YawRate = 2 + integer,parameter :: Indx_u_HSS_Spd = 3 + integer :: SrvD_Indx_Y_YawMom + integer :: SrvD_Indx_Y_GenTrq + integer :: SrvD_Indx_Y_ElecPwr + integer :: SrvD_Indx_Y_WrOutput + real(R8Ki) :: AllOuts(3,MaxOutPts) ! Extra precision here since analytical + + SrvD_Indx_Y_YawMom = size(SrvD_Indx_Y_BlPitchCom) + 1 ! sometime change this to p%NumBl + SrvD_Indx_Y_GenTrq = SrvD_Indx_Y_YawMom + 1 + SrvD_Indx_Y_ElecPwr = SrvD_Indx_Y_GenTrq + 1 + SrvD_Indx_Y_WrOutput = p%Jac_ny - p%NumOuts ! Index to location before user requested outputs !> \f{equation}{ \frac{\partial Y}{\partial u} = \begin{bmatrix} !! \frac{\partial Y_{BlPitchCom_1}}{\partial u_{Yaw}} & \frac{\partial Y_{BlPitchCom_1}}{\partial u_{YawRate}} & \frac{\partial Y_{BlPitchCom_1}}{\partial u_{HSS\_Spd}} \\ @@ -2134,153 +2780,1343 @@ SUBROUTINE SrvD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, Er !! \frac{\partial Y_{WriteOutput_i}}{\partial u_{Yaw}} & \frac{\partial Y_{WriteOutput_i}}{\partial u_{YawRate}} & \frac{\partial Y_{WriteOutput_i}}{\partial u_{HSS\_Spd}} \end{bmatrix} !!\f} - - ! Note this is similiar to SrvD_CalcOutput - - if (.not. allocated(dYdu)) then - call allocAry(dYdu, SrvD_Indx_Y_WrOutput+p%NumOuts, 3, 'dYdu', ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - end if - dYdu = 0.0_R8Ki - - ! ! Torque control: !> Compute !> \f$ \frac{\partial Y_{GenTrq}}{\partial u_{HSS\_Spd}} \f$ and !> \f$ \frac{\partial Y_{ElecPwr}}{\partial u_{HSS\_Spd}} \f$ in servodyn::torque_jacobianpinput. - call Torque_JacobianPInput( t, u, p, x, xd, z, OtherState, m, GenTrq_du, ElecPwr_du, ErrStat, ErrMsg ) ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) RETURN - dYdu(SrvD_Indx_Y_GenTrq, Indx_u_HSS_Spd) = GenTrq_du - dYdu(SrvD_Indx_Y_ElecPwr,Indx_u_HSS_Spd) = ElecPwr_du - + call Torque_JacobianPInput( t, u, p, x, xd, z, OtherState, m, GenTrq_du, ElecPwr_du, ErrStat2, ErrMsg2 ) + if (Failed()) return + dYdu(SrvD_Indx_Y_GenTrq, Indx_u_HSS_Spd) = GenTrq_du + dYdu(SrvD_Indx_Y_ElecPwr,Indx_u_HSS_Spd) = ElecPwr_du ! Pitch control: !> \f$ \frac{\partial Y_{BlPitchCom_k}}{\partial u} = 0 \f$ ! Yaw control: !> \f$ \frac{\partial Y_{YawMom}}{\partial u_{Yaw}} = -p\%YawSpr \f$ - dYdu(SrvD_Indx_Y_YawMom,Indx_u_Yaw) = -p%YawSpr ! from Yaw_CalcOutput + dYdu(SrvD_Indx_Y_YawMom,Indx_u_Yaw) = -p%YawSpr ! from Yaw_CalcOutput !> \f$ \frac{\partial Y_{YawMom}}{\partial u_{YawRate}} = -p\%YawDamp \f$ - dYdu(SrvD_Indx_Y_YawMom,Indx_u_YawRate) = -p%YawDamp ! from Yaw_CalcOutput - + dYdu(SrvD_Indx_Y_YawMom,Indx_u_YawRate) = -p%YawDamp ! from Yaw_CalcOutput - !......................................................................................................................... - ! Calculate all of the available output channels (because they repeat for the derivative) here: - !......................................................................................................................... + !............................................................................... + ! Calculate the output channels that will be affected by u%{Yaw,YawRate,HSS_Spd} + ! These terms are analytically calculated + !............................................................................... AllOuts = 0.0_R8Ki ! all variables not specified below are zeros (either constant or disabled): + AllOuts(1:3, GenTq) = 0.001_R8Ki*dYdu(SrvD_Indx_Y_GenTrq,1:3) + AllOuts(1:3, GenPwr) = 0.001_R8Ki*dYdu(SrvD_Indx_Y_ElecPwr,1:3) + AllOuts(1:3, YawMomCom) = -0.001_R8Ki*dYdu(SrvD_Indx_Y_YawMom,1:3) + + !............................................................................... + ! Place the selected output channels into the WriteOutput(:) portion of the + ! jacobian with the proper sign: + !............................................................................... + do I = 1,p%NumOuts ! Loop through all selected output channels + if (p%OutParam(I)%Indx > 0_IntKi) then + dYdu(I+SrvD_Indx_Y_WrOutput,1:3) = p%OutParam(I)%SignM * AllOuts( 1:3, p%OutParam(I)%Indx ) + else + dYdu(I+SrvD_Indx_Y_WrOutput,1:3) = 0.0_R8Ki + endif + enddo ! I - All selected output channels + end subroutine dYdu_YawGen + + !> Calculated dYdu for BStC instance + subroutine Jac_BStC_dYdu( n, sgn, u_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j,k ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_u_indx(n,4) ! this blade + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_BStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%BStCMotionMesh(k,j), u_StC%Mesh(k), m%SrvD_MeshMap%u_BStC_Mot2_BStC(k,j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! Set StC control channels + !call SetStCInput_CtrlChans(u_BStC) + ! call Calc + call StC_CopyOutput(m%y_BStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, u_StC, p%BStC(j), x%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), y_StC, m%BStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(k), y_perturb%BStCLoadMesh(k,j), m%SrvD_MeshMap%BStC_Frc2_y_BStC(k,j), ErrStat3, ErrMsg3, u_perturb%BStCMotionMesh(k,j), u_perturb%BStCMotionMesh(k,j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_BStC_Outs_Instance( j, p%NumBl, x%BStC(j), m%BStC(j), y_StC, AllOuts) + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_BStC_dYdu + + !> Calculated dYdu for NStC instance + subroutine Jac_NStC_dYdu( n, sgn, u_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j,k ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_NStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%NStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_NStC_Mot2_NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! Set StC control channels + !call SetStCInput_CtrlChans(u_NStC) + ! call Calc + call StC_CopyOutput(m%y_NStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3) + CALL StC_CalcOutput( t, u_StC, p%NStC(j), x%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), y_StC, m%NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%NStCLoadMesh(j), m%SrvD_MeshMap%NStC_Frc2_y_NStC(j), ErrStat3, ErrMsg3, u_perturb%NStCMotionMesh(j), u_perturb%NStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_NStC_Outs_Instance( j, x%NStC(j), m%NStC(j), y_StC, AllOuts) + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo ! I - All selected output channels +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_NStC_dYdu + + !> Calculated dYdu for TStC instance + subroutine Jac_TStC_dYdu( n, sgn, u_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j,k ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_TStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%TStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_TStC_Mot2_TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! Set StC control channels + !call SetStCInput_CtrlChans(u_TStC) + ! call Calc + call StC_CopyOutput(m%y_TStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, u_StC, p%TStC(j), x%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), y_StC, m%TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%TStCLoadMesh(j), m%SrvD_MeshMap%TStC_Frc2_y_TStC(j), ErrStat3, ErrMsg3, u_perturb%TStCMotionMesh(j), u_perturb%TStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_TStC_Outs_Instance( j, x%TStC(j), m%TStC(j), y_StC, AllOuts) + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo ! I - All selected output channels +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_TStC_dYdu + + !> Calculated dYdu for SStC instance + subroutine Jac_SStC_dYdu( n, sgn, u_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j,k ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_SStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%SStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_SStC_Mot2_SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! Set StC control channels + !call SetStCInput_CtrlChans(u_SStC) + ! call Calc + call StC_CopyOutput(m%y_SStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, u_StC, p%SStC(j), x%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), y_StC, m%SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%SStCLoadMesh(j), m%SrvD_MeshMap%SStC_Frc2_y_SStC(j), ErrStat3, ErrMsg3, u_perturb%SStCMotionMesh(j), u_perturb%SStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_SStC_Outs_Instance( j, x%SStC(j), m%SStC(j), y_StC, AllOuts) + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo ! I - All selected output channels +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_SStC_dYdu +end subroutine Jac_dYdu + +!> Calculate the jacobian dXdu +!! The only states exist with the StC instances +subroutine Jac_dXdu(t, u, p, x, xd, z, OtherState, m, ErrStat, ErrMsg, dXdu) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(inout) :: u !< Inputs at operating point (out for copy only) + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_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, intent(inout) :: dXdu(:,:) !< Partial derivatives of output functions + + integer(IntKi) :: n ! Generic loop index + type(SrvD_InputType) :: u_perturb ! copy of inputs to perturb + type(SrvD_ContinuousStateType) :: dx_p ! states positive perturbed + type(SrvD_ContinuousStateType) :: dx_m ! states negative perturbed + real(R8Ki) :: delta_p ! delta+ change in input or state + real(R8Ki) :: delta_m ! delta- change in input or state + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Jac_dXdu' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' - AllOuts(:, GenTq) = 0.001_R8Ki*dYdu(SrvD_Indx_Y_GenTrq,:) - AllOuts(:, GenPwr) = 0.001_R8Ki*dYdu(SrvD_Indx_Y_ElecPwr,:) - AllOuts(:, YawMomCom) = -0.001_R8Ki*dYdu(SrvD_Indx_Y_YawMom,:) + ! Allocate the dXdu array regardless what states may or may not exist (glue code needs this) + if (.not. allocated(dXdu)) then + call allocAry(dXdu, p%Jac_nx, p%Jac_nu, 'dXdu', ErrStat2, ErrMsg2) + if (Failed()) return + elseif ( (size(dXdu,1) /= p%Jac_nx) .or. (size(dXdu,2) /= p%Jac_nu) ) then + deallocate(dXdu) + call allocAry(dXdu, p%Jac_nx, p%Jac_nu, 'dXdu', ErrStat2, ErrMsg2) + if (Failed()) return + endif + dXdu = 0.0_R8Ki + + !------------------------------------------------------------- + ! Perturb each StC instance individually and place in appropriate location in dXdu + ! Each StC is basically an isolated piece that doesn't interact with any other StC or with anything else in SrvD, + ! so we take advantage of that here for computational expediency. + !------------------------------------------------------------- + ! make a copy of the inputs to perturb if an StC exists + if ( (p%NumBStC + p%NumNStC + p%NumTStC + p%NumSStC) > 0 ) then + call SrvD_CopyInput( u, u_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + else + return ! nothing further to do here + endif + !------------------- + ! Blade StC + if (p%NumBStC > 0) then + do n=p%Jac_Idx_BStC_u(1,1,1),p%Jac_Idx_BStC_u(2,p%NumBl,p%NumBStC) ! input range for BStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dXdu( n, +1, u_perturb, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dXdu( n, -1, u_perturb, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdu(:,n) ) + enddo + endif + !------------------- + ! Nacelle StC + if (p%NumNStC > 0) then + do n=p%Jac_Idx_NStC_u(1,1),p%Jac_Idx_NStC_u(2,p%NumNStC) ! input range for NStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dXdu( n, +1, u_perturb, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dXdu( n, -1, u_perturb, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdu(:,n) ) + enddo + endif + !------------------- + ! Tower StC + if (p%NumTStC > 0) then + do n=p%Jac_Idx_TStC_u(1,1),p%Jac_Idx_TStC_u(2,p%NumTStC) ! input range for TStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dXdu( n, +1, u_perturb, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dXdu( n, -1, u_perturb, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdu(:,n) ) + enddo + endif + !------------------- + ! Substructure StC + if (p%NumSStC > 0) then + do n=p%Jac_Idx_SStC_u(1,1),p%Jac_Idx_SStC_u(2,p%NumSStC) ! input range for SStC + + ! perturb positive + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dXdu( n, +1, u_perturb, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dXdu( n, -1, u_perturb, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdu(:,n) ) + enddo + endif + call Cleanup() - !............................................................................................................................... - ! Place the selected output channels into the WriteOutput(:) portion of the jacobian with the proper sign: - !............................................................................................................................... +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call Cleanup + end function Failed - DO I = 1,p%NumOuts ! Loop through all selected output channels - dYdu(I+SrvD_Indx_Y_WrOutput,:) = p%OutParam(I)%SignM * AllOuts( :, p%OutParam(I)%Indx ) - ENDDO ! I - All selected output channels + subroutine Cleanup() + ! Ignore any errors from the destroy (these weren't created if no StCs) + call SrvD_DestroyInput( u_perturb, ErrStat2, ErrMsg2 ) + call SrvD_DestroyContState( dx_p, ErrStat2, ErrMsg2 ) + call SrvD_DestroyContState( dx_m, ErrStat2, ErrMsg2 ) + end subroutine Cleanup - END IF + !> Calculated dXdu for BStC instance + subroutine Jac_BStC_dXdu( n, sgn, u_perturb, delta, x_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j,k ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_u_indx(n,4) ! this blade + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_BStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%BStCMotionMesh(k,j), u_StC%Mesh(k), m%SrvD_MeshMap%u_BStC_Mot2_BStC(k,j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! calculate change in ContState + call StC_CalcContStateDeriv( t, u_StC, p%BStC(j), x%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), m%BStC(j), x_perturb%BStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! cleanup + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_BStC_dXdu + + !> Calculated dXdu for NStC instance + subroutine Jac_NStC_dXdu( n, sgn, u_perturb, delta, x_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_NStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%NStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_NStC_Mot2_NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! calculate change in ContState + call StC_CalcContStateDeriv( t, u_StC, p%NStC(j), x%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), m%NStC(j), x_perturb%NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! cleanup + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_NStC_dXdu + + !> Calculated dXdu for TStC instance + subroutine Jac_TStC_dXdu( n, sgn, u_perturb, delta, x_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_TStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%TStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_TStC_Mot2_TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! calculate change in ContState + call StC_CalcContStateDeriv( t, u_StC, p%TStC(j), x%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), m%TStC(j), x_perturb%TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! cleanup + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_TStC_dXdu + + !> Calculated dXdu for SStC instance + subroutine Jac_SStC_dXdu( n, sgn, u_perturb, delta, x_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_InputType), intent(inout) :: u_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j ! Generic indices + type(StC_InputType) :: u_StC ! copy of the StC inputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_u_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_u_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_u( p, n, sgn, u_perturb, delta ) + ! Transfer motion mesh to this particular instance + call StC_CopyInput( m%u_SStC(1,j), u_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + call Transfer_Point_to_Point( u_perturb%SStCMotionMesh(j), u_StC%Mesh(1), m%SrvD_MeshMap%u_SStC_Mot2_SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! calculate change in ContState + call StC_CalcContStateDeriv( t, u_StC, p%SStC(j), x%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), m%SStC(j), x_perturb%SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + ! cleanup + call StC_DestroyInput( u_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_SStC_dXdu +end subroutine Jac_dXdu - IF ( PRESENT( dXdu ) ) THEN - if (allocated(dXdu)) deallocate(dXdu) - END IF - IF ( PRESENT( dXddu ) ) THEN - if (allocated(dXddu)) deallocate(dXddu) - END IF +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine perturbs the single mesh point associated with the nth element of the u array +!! WARNING: this routine must exactly match Init_Jacobian::SrvD_Init_Jacobian_u +subroutine SrvD_Perturb_u( p, n, perturb_sign, u, du ) + type(SrvD_ParameterType), intent(in ) :: p !< parameters + integer(IntKi), intent(in ) :: n !< number of array element to use + integer(IntKi), intent(in ) :: perturb_sign !< +1 or -1 (value to multiply perturbation by; positive or negative difference) + type(SrvD_InputType), intent(inout) :: u !< perturbed SrvD inputs + real(R8Ki), intent( out) :: du !< amount that specific input was perturbed + ! local variables + integer :: fieldIndx + integer :: instance, blade ! for StC mesh motions + fieldIndx = p%Jac_u_indx(n,2) + instance = p%Jac_u_indx(n,3) + blade = p%Jac_u_indx(n,4) + du = p%du( p%Jac_u_indx(n,1) ) + ! determine which mesh we're trying to perturb and perturb the input: + select case( p%Jac_u_indx(n,1) ) + !------------------------------- + ! 1:6 --> u%BStCMotionMesh(:,:)% + case ( 1) ! TranslationDisp = 1; + u%BStCMotionMesh(blade,instance)%TranslationDisp(fieldIndx,1) = u%BStCMotionMesh(blade,instance)%TranslationDisp(fieldIndx,1) + du * perturb_sign + case ( 2) ! Orientation = 2; + CALL PerturbOrientationMatrix( u%BStCMotionMesh(blade,instance)%Orientation(:,:,1), du * perturb_sign, fieldIndx ) + case ( 3) ! TranslationVel = 3; + u%BStCMotionMesh(blade,instance)%TranslationVel( fieldIndx,1) = u%BStCMotionMesh(blade,instance)%TranslationVel( fieldIndx,1) + du * perturb_sign + case ( 4) ! RotationVel = 4; + u%BStCMotionMesh(blade,instance)%RotationVel( fieldIndx,1) = u%BStCMotionMesh(blade,instance)%RotationVel( fieldIndx,1) + du * perturb_sign + case ( 5) ! TranslationAcc = 5; + u%BStCMotionMesh(blade,instance)%TranslationAcc( fieldIndx,1) = u%BStCMotionMesh(blade,instance)%TranslationAcc( fieldIndx,1) + du * perturb_sign + case ( 6) ! RotationAcc = 6; + u%BStCMotionMesh(blade,instance)%RotationAcc( fieldIndx,1) = u%BStCMotionMesh(blade,instance)%RotationAcc( fieldIndx,1) + du * perturb_sign + !------------------------------- + ! 7:12 --> u%NStCMotionMesh(:)% + case ( 7) ! TranslationDisp = 1; + u%NStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) = u%NStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) + du * perturb_sign + case ( 8) ! Orientation = 2; + CALL PerturbOrientationMatrix( u%NStCMotionMesh(instance)%Orientation(:,:,1), du * perturb_sign, fieldIndx ) + case ( 9) ! TranslationVel = 3; + u%NStCMotionMesh(instance)%TranslationVel( fieldIndx,1) = u%NStCMotionMesh(instance)%TranslationVel( fieldIndx,1) + du * perturb_sign + case (10) ! RotationVel = 4; + u%NStCMotionMesh(instance)%RotationVel( fieldIndx,1) = u%NStCMotionMesh(instance)%RotationVel( fieldIndx,1) + du * perturb_sign + case (11) ! TranslationAcc = 5; + u%NStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) = u%NStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) + du * perturb_sign + case (12) ! RotationAcc = 6; + u%NStCMotionMesh(instance)%RotationAcc( fieldIndx,1) = u%NStCMotionMesh(instance)%RotationAcc( fieldIndx,1) + du * perturb_sign + !------------------------------- + ! 13:18 --> u%TStCMotionMesh(:)% + case (13) ! TranslationDisp = 1; + u%TStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) = u%TStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) + du * perturb_sign + case (14) ! Orientation = 2; + CALL PerturbOrientationMatrix( u%TStCMotionMesh(instance)%Orientation(:,:,1), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) + case (15) ! TranslationVel = 3; + u%TStCMotionMesh(instance)%TranslationVel( fieldIndx,1) = u%TStCMotionMesh(instance)%TranslationVel( fieldIndx,1) + du * perturb_sign + case (16) ! RotationVel = 4; + u%TStCMotionMesh(instance)%RotationVel( fieldIndx,1) = u%TStCMotionMesh(instance)%RotationVel( fieldIndx,1) + du * perturb_sign + case (17) ! TranslationAcc = 5; + u%TStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) = u%TStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) + du * perturb_sign + case (18) ! RotationAcc = 6; + u%TStCMotionMesh(instance)%RotationAcc( fieldIndx,1) = u%TStCMotionMesh(instance)%RotationAcc( fieldIndx,1) + du * perturb_sign + !------------------------------- + ! 19:24 --> u%SStCMotionMesh(:)% + case (19) ! TranslationDisp = 1; + u%SStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) = u%SStCMotionMesh(instance)%TranslationDisp(fieldIndx,1) + du * perturb_sign + case (20) ! Orientation = 2; + CALL PerturbOrientationMatrix( u%SStCMotionMesh(instance)%Orientation(:,:,1), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) + case (21) ! TranslationVel = 3; + u%SStCMotionMesh(instance)%TranslationVel( fieldIndx,1) = u%SStCMotionMesh(instance)%TranslationVel( fieldIndx,1) + du * perturb_sign + case (22) ! RotationVel = 4; + u%SStCMotionMesh(instance)%RotationVel( fieldIndx,1) = u%SStCMotionMesh(instance)%RotationVel( fieldIndx,1) + du * perturb_sign + case (23) ! TranslationAcc = 5; + u%SStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) = u%SStCMotionMesh(instance)%TranslationAcc( fieldIndx,1) + du * perturb_sign + case (24) ! RotationAcc = 6; + u%SStCMotionMesh(instance)%RotationAcc( fieldIndx,1) = u%SStCMotionMesh(instance)%RotationAcc( fieldIndx,1) + du * perturb_sign + end select +end subroutine SrvD_Perturb_u - IF ( PRESENT( dZdu ) ) THEN - if (allocated(dZdu)) deallocate(dZdu) - END IF +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine perturbs the single mesh point associated with the nth element of the u array +!! WARNING: this routine must exactly match Init_Jacobian::SrvD_Init_Jacobian_x +subroutine SrvD_Perturb_x( p, n, perturb_sign, x, dx ) + type(SrvD_ParameterType), intent(in ) :: p !< parameters + integer(IntKi), intent(in ) :: n !< number of array element to use + integer(IntKi), intent(in ) :: perturb_sign !< +1 or -1 (value to multiply perturbation by; positive or negative difference) + type(SrvD_ContinuousStateType), intent(inout) :: x !< perturbed SrvD ContStates + real(R8Ki), intent( out) :: dx !< amount that specific input was perturbed + ! local variables + integer :: component + integer :: instance, blade ! for StC mesh motions + component = p%Jac_x_indx(n,2) ! component (x,y,z) -- unused + instance = p%Jac_x_indx(n,3) + blade = p%Jac_x_indx(n,4) + dx = p%dx( p%Jac_x_indx(n,1) ) + ! determine which mesh we're trying to perturb and perturb the input: + select case( p%Jac_x_indx(n,1) ) ! StC+field index + !------------------------------- + ! 1:6 --> x%BStC(instance)%StC_x + case ( 1) ! x + x%BStC(instance)%StC_x(1,blade) = x%BStC(instance)%StC_x(1,blade) + dx * perturb_sign + case ( 2) ! y + x%BStC(instance)%StC_x(3,blade) = x%BStC(instance)%StC_x(3,blade) + dx * perturb_sign + case ( 3) ! z + x%BStC(instance)%StC_x(5,blade) = x%BStC(instance)%StC_x(5,blade) + dx * perturb_sign + case ( 4) ! x-dot + x%BStC(instance)%StC_x(2,blade) = x%BStC(instance)%StC_x(2,blade) + dx * perturb_sign + case ( 5) ! y-dot + x%BStC(instance)%StC_x(4,blade) = x%BStC(instance)%StC_x(4,blade) + dx * perturb_sign + case ( 6) ! z-dot + x%BStC(instance)%StC_x(6,blade) = x%BStC(instance)%StC_x(6,blade) + dx * perturb_sign + !------------------------------- + ! 7:12 --> x%NStC(instance)%StC_x + case ( 7) ! x + x%NStC(instance)%StC_x(1,1) = x%NStC(instance)%StC_x(1,1) + dx * perturb_sign + case ( 8) ! y + x%NStC(instance)%StC_x(3,1) = x%NStC(instance)%StC_x(3,1) + dx * perturb_sign + case ( 9) ! z + x%NStC(instance)%StC_x(5,1) = x%NStC(instance)%StC_x(5,1) + dx * perturb_sign + case (10) ! x-dot + x%NStC(instance)%StC_x(2,1) = x%NStC(instance)%StC_x(2,1) + dx * perturb_sign + case (11) ! y-dot + x%NStC(instance)%StC_x(4,1) = x%NStC(instance)%StC_x(4,1) + dx * perturb_sign + case (12) ! z-dot + x%NStC(instance)%StC_x(6,1) = x%NStC(instance)%StC_x(6,1) + dx * perturb_sign + !------------------------------- + ! 13:18 --> x%TStC(instance)%StC_x + case (13) ! x + x%TStC(instance)%StC_x(1,1) = x%TStC(instance)%StC_x(1,1) + dx * perturb_sign + case (14) ! y + x%TStC(instance)%StC_x(3,1) = x%TStC(instance)%StC_x(3,1) + dx * perturb_sign + case (15) ! z + x%TStC(instance)%StC_x(5,1) = x%TStC(instance)%StC_x(5,1) + dx * perturb_sign + case (16) ! x-dot + x%TStC(instance)%StC_x(2,1) = x%TStC(instance)%StC_x(2,1) + dx * perturb_sign + case (17) ! y-dot + x%TStC(instance)%StC_x(4,1) = x%TStC(instance)%StC_x(4,1) + dx * perturb_sign + case (18) ! z-dot + x%TStC(instance)%StC_x(6,1) = x%TStC(instance)%StC_x(6,1) + dx * perturb_sign + !------------------------------- + ! 19:24 --> x%SStC(instance)%StC_x + case (19) ! x + x%SStC(instance)%StC_x(1,1) = x%SStC(instance)%StC_x(1,1) + dx * perturb_sign + case (20) ! y + x%SStC(instance)%StC_x(3,1) = x%SStC(instance)%StC_x(3,1) + dx * perturb_sign + case (21) ! z + x%SStC(instance)%StC_x(5,1) = x%SStC(instance)%StC_x(5,1) + dx * perturb_sign + case (22) ! x-dot + x%SStC(instance)%StC_x(2,1) = x%SStC(instance)%StC_x(2,1) + dx * perturb_sign + case (23) ! y-dot + x%SStC(instance)%StC_x(4,1) = x%SStC(instance)%StC_x(4,1) + dx * perturb_sign + case (24) ! z-dot + x%SStC(instance)%StC_x(6,1) = x%SStC(instance)%StC_x(6,1) + dx * perturb_sign + end select +end subroutine SrvD_Perturb_x + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine uses values of two output types to compute an array of differences. +!! Do not change this packing without making sure subroutine servodyn::SrvD_Init_Jacobian_y is consistant with this routine! +SUBROUTINE Compute_dY(p, y_p, y_m, delta_p, delta_m, dY) + type(SrvD_ParameterType), intent(in ) :: p !< parameters + type(SrvD_OutputType), intent(in ) :: y_p !< SrvD outputs at \f$ u + \Delta u \f$ or \f$ x + \Delta x \f$ (p=plus) + type(SrvD_OutputType), intent(in ) :: y_m !< SrvD outputs at \f$ u - \Delta u \f$ or \f$ x - \Delta x \f$ (m=minus) + real(R8Ki), intent(in ) :: delta_p !< difference in inputs or states \f$ delta = \Delta u \f$ or \f$ delta = \Delta x \f$ + real(R8Ki), intent(in ) :: delta_m !< difference in inputs or states \f$ delta = \Delta u \f$ or \f$ delta = \Delta x \f$ + real(R8Ki), intent(inout) :: dY(:) !< column of dYdu or dYdx: \f$ \frac{\partial Y}{\partial u_i} = \frac{y_p - y_m}{2 \, \Delta u}\f$ or \f$ \frac{\partial Y}{\partial x_i} = \frac{y_p - y_m}{2 \, \Delta x}\f$ + + ! local variables: + integer(IntKi) :: i,j,k ! generic counters + integer(IntKi) :: indx_first ! index indicating next value of dY to be filled + integer(IntKi) :: SrvD_Indx_Y_WrOutput + + ! StC related outputs + if (p%NumBStC > 0) then + do j=1,p%NumBStC + do i=1,p%NumBl + indx_first = p%Jac_Idx_BStC_y(1,i,j) + call PackLoadMesh_dY( y_p%BStCLoadMesh(i,j), y_m%BStCLoadMesh(i,j), dY, indx_first ) + enddo + enddo + endif + if (p%NumNStC > 0) then + do j=1,p%NumNStC + indx_first = p%Jac_Idx_NStC_y(1,j) + call PackLoadMesh_dY( y_p%NStCLoadMesh(j), y_m%NStCLoadMesh(j), dY, indx_first ) + enddo + endif + if (p%NumTStC > 0) then + do j=1,p%NumTStC + indx_first = p%Jac_Idx_TStC_y(1,j) + call PackLoadMesh_dY( y_p%TStCLoadMesh(j), y_m%TStCLoadMesh(j), dY, indx_first ) + enddo + endif + if (p%NumSStC > 0) then + do j=1,p%NumSStC + indx_first = p%Jac_Idx_SStC_y(1,j) + call PackLoadMesh_dY( y_p%SStCLoadMesh(j), y_m%SStCLoadMesh(j), dY, indx_first ) + enddo + endif + + ! outputs + SrvD_Indx_Y_WrOutput = p%Jac_ny - p%NumOuts ! Index to location before user requested outputs + do k=1,p%NumOuts + dY(SrvD_Indx_Y_WrOutput+k) = real( y_p%WriteOutput(k) - y_m%WriteOutput(k), R8Ki ) + end do + + dY = dY / (delta_p + delta_m) +END SUBROUTINE Compute_dY + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine uses values of two output types to compute an array of differences. +!! Do not change this packing without making sure subroutine servodyn::SrvD_Init_Jacobian_x is consistant with this routine! +subroutine Compute_dX( p, x_p, x_m, delta_p, delta_m, dX ) + type(SrvD_ParameterType), intent(in ) :: p !< parameters + type(SrvD_ContinuousStateType), intent(in ) :: x_p !< SrvD continuous states at \f$ u + \Delta u \f$ or \f$ x + \Delta x \f$ (p=plus) + type(SrvD_ContinuousStateType), intent(in ) :: x_m !< SrvD continuous states at \f$ u - \Delta u \f$ or \f$ x - \Delta x \f$ (m=minus) + real(R8Ki), intent(in ) :: delta_p !< difference in inputs or states \f$ delta = \Delta u \f$ or \f$ delta = \Delta x \f$ + real(R8Ki), intent(in ) :: delta_m !< difference in inputs or states \f$ delta = \Delta u \f$ or \f$ delta = \Delta x \f$ + real(R8Ki), intent(inout) :: dX(:) !< column of dXdu or dXdx: \f$ \frac{\partial X}{\partial u_i} = \frac{x_p - x_m}{2 \, \Delta u}\f$ or \f$ \frac{\partial X}{\partial x_i} = \frac{x_p - x_m}{2 \, \Delta x}\f$ + + ! local variables: + integer(IntKi) :: i,j,k ! generic counters + integer(IntKi) :: indx_prev ! index indicating index in dX before this one to be filled + + ! StC related outputs + if (p%NumBStC > 0) then + do j=1,p%NumBStC + do k=1,p%NumBl + indx_prev = p%Jac_Idx_BStC_x(1,k,j)-1 + dX(indx_prev+1) = x_p%BStC(j)%StC_x(1,k) - x_m%BStC(j)%StC_x(1,k) ! x x%BStC(j)%StC_x(1,k) + dX(indx_prev+2) = x_p%BStC(j)%StC_x(3,k) - x_m%BStC(j)%StC_x(3,k) ! y x%BStC(j)%StC_x(3,k) + dX(indx_prev+3) = x_p%BStC(j)%StC_x(5,k) - x_m%BStC(j)%StC_x(5,k) ! z x%BStC(j)%StC_x(5,k) + dX(indx_prev+4) = x_p%BStC(j)%StC_x(2,k) - x_m%BStC(j)%StC_x(2,k) ! x-dot x%BStC(j)%StC_x(2,k) + dX(indx_prev+5) = x_p%BStC(j)%StC_x(4,k) - x_m%BStC(j)%StC_x(4,k) ! y-dot x%BStC(j)%StC_x(4,k) + dX(indx_prev+6) = x_p%BStC(j)%StC_x(6,k) - x_m%BStC(j)%StC_x(6,k) ! z-dot x%BStC(j)%StC_x(6,k) + indx_prev = indx_prev + 6 + enddo + enddo + endif + if (p%NumNStC > 0) then + do j=1,p%NumNStC + indx_prev = p%Jac_Idx_NStC_x(1,j)-1 + dX(indx_prev+1) = x_p%NStC(j)%StC_x(1,1) - x_m%NStC(j)%StC_x(1,1) ! x x%NStC(j)%StC_x(1,1) + dX(indx_prev+2) = x_p%NStC(j)%StC_x(3,1) - x_m%NStC(j)%StC_x(3,1) ! y x%NStC(j)%StC_x(3,1) + dX(indx_prev+3) = x_p%NStC(j)%StC_x(5,1) - x_m%NStC(j)%StC_x(5,1) ! z x%NStC(j)%StC_x(5,1) + dX(indx_prev+4) = x_p%NStC(j)%StC_x(2,1) - x_m%NStC(j)%StC_x(2,1) ! x-dot x%NStC(j)%StC_x(2,1) + dX(indx_prev+5) = x_p%NStC(j)%StC_x(4,1) - x_m%NStC(j)%StC_x(4,1) ! y-dot x%NStC(j)%StC_x(4,1) + dX(indx_prev+6) = x_p%NStC(j)%StC_x(6,1) - x_m%NStC(j)%StC_x(6,1) ! z-dot x%NStC(j)%StC_x(6,1) + indx_prev = indx_prev + 6 + enddo + endif + if (p%NumTStC > 0) then + do j=1,p%NumTStC + indx_prev = p%Jac_Idx_TStC_x(1,j)-1 + dX(indx_prev+1) = x_p%TStC(j)%StC_x(1,1) - x_m%TStC(j)%StC_x(1,1) ! x x%TStC(j)%StC_x(1,1) + dX(indx_prev+2) = x_p%TStC(j)%StC_x(3,1) - x_m%TStC(j)%StC_x(3,1) ! y x%TStC(j)%StC_x(3,1) + dX(indx_prev+3) = x_p%TStC(j)%StC_x(5,1) - x_m%TStC(j)%StC_x(5,1) ! z x%TStC(j)%StC_x(5,1) + dX(indx_prev+4) = x_p%TStC(j)%StC_x(2,1) - x_m%TStC(j)%StC_x(2,1) ! x-dot x%TStC(j)%StC_x(2,1) + dX(indx_prev+5) = x_p%TStC(j)%StC_x(4,1) - x_m%TStC(j)%StC_x(4,1) ! y-dot x%TStC(j)%StC_x(4,1) + dX(indx_prev+6) = x_p%TStC(j)%StC_x(6,1) - x_m%TStC(j)%StC_x(6,1) ! z-dot x%TStC(j)%StC_x(6,1) + indx_prev = indx_prev + 6 + enddo + endif + if (p%NumSStC > 0) then + do j=1,p%NumSStC + indx_prev = p%Jac_Idx_SStC_x(1,j)-1 + dX(indx_prev+1) = x_p%SStC(j)%StC_x(1,1) - x_m%SStC(j)%StC_x(1,1) ! x x%SStC(j)%StC_x(1,1) + dX(indx_prev+2) = x_p%SStC(j)%StC_x(3,1) - x_m%SStC(j)%StC_x(3,1) ! y x%SStC(j)%StC_x(3,1) + dX(indx_prev+3) = x_p%SStC(j)%StC_x(5,1) - x_m%SStC(j)%StC_x(5,1) ! z x%SStC(j)%StC_x(5,1) + dX(indx_prev+4) = x_p%SStC(j)%StC_x(2,1) - x_m%SStC(j)%StC_x(2,1) ! x-dot x%SStC(j)%StC_x(2,1) + dX(indx_prev+5) = x_p%SStC(j)%StC_x(4,1) - x_m%SStC(j)%StC_x(4,1) ! y-dot x%SStC(j)%StC_x(4,1) + dX(indx_prev+6) = x_p%SStC(j)%StC_x(6,1) - x_m%SStC(j)%StC_x(6,1) ! z-dot x%SStC(j)%StC_x(6,1) + indx_prev = indx_prev + 6 + enddo + endif + + dX = dX / (delta_p + delta_m) +end subroutine Compute_dX -END SUBROUTINE SrvD_JacobianPInput !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions !! with respect to the continuous states (x). The partial derivatives dY/dx, dX/dx, dXd/dx, and DZ/dx are returned. !! Note SrvD does not have continuous states, so these are not set. SUBROUTINE SrvD_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(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) - TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters - TYPE(SrvD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point - TYPE(SrvD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point - TYPE(SrvD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at operating point - TYPE(SrvD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at operating point - TYPE(SrvD_OutputType), INTENT(IN ) :: y !< Output (change to inout if a mesh copy is required); - !! Output fields are not used by this routine, but type is - !! available here so that mesh parameter information (i.e., - !! connectivity) does not have to be recalculated for dYdx. - TYPE(SrvD_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(:,:) !< Partial derivatives of output functions - !! (Y) with respect to the continuous - !! states (x) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dXdx(:,:) !< Partial derivatives of continuous state - !! functions (X) with respect to - !! the continuous states (x) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dXddx(:,:) !< Partial derivatives of discrete state - !! functions (Xd) with respect to - !! the continuous states (x) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dZdx(:,:) !< Partial derivatives of constraint state - !! functions (Z) with respect to - !! the continuous states (x) [intent in to avoid deallocation] - + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(in ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_OutputType), intent(inout) :: y !< Output (change to inout if a mesh copy is required); + !! Output fields are not used by this routine, but type is + !! available here so that mesh parameter information (i.e., + !! connectivity) does not have to be recalculated for dYdx. + type(SrvD_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(:,:) !< Partial derivatives of output functions + !! (Y) with respect to the continuous + !! states (x) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dXdx(:,:) !< Partial derivatives of continuous state + !! functions (X) with respect to + !! the continuous states (x) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dXddx(:,:) !< Partial derivatives of discrete state + !! functions (Xd) with respect to + !! the continuous states (x) [intent in to avoid deallocation] + real(R8Ki), allocatable, optional, intent(inout) :: dZdx(:,:) !< Partial derivatives of constraint state + !! functions (Z) with respect to + !! the continuous states (x) [intent in to avoid deallocation] + ! local variables + integer(IntKi) :: ErrStat2 ! Error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'SrvD_JacobianPContState' ! Initialize ErrStat - ErrStat = ErrID_None ErrMsg = '' - - + ! Calculate the partial derivative of the output functions (Y) with respect to the inputs (u) here: IF ( PRESENT( dYdx ) ) THEN - - ! Calculate the partial derivative of the output functions (Y) with respect to the continuous states (x) here: - - ! allocate and set dYdx - + call Jac_dYdx( t, u, p, x, xd, z, OtherState, y, m, ErrStat2, ErrMsg2, dYdx ) + if (Failed()) return END IF IF ( PRESENT( dXdx ) ) THEN + call Jac_dXdx( t, u, p, x, xd, z, OtherState, m, ErrStat2, ErrMsg2, dXdx ) + if (Failed()) return + END IF - ! Calculate the partial derivative of the continuous state functions (X) with respect to the continuous states (x) here: - - ! allocate and set dXdx + IF ( PRESENT( dXddx ) ) THEN + if (allocated(dXddx)) deallocate(dXddx) + END IF + IF ( PRESENT( dZdx ) ) THEN + if (allocated(dZdx)) deallocate(dZdx) END IF - IF ( PRESENT( dXddx ) ) THEN +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed +END SUBROUTINE SrvD_JacobianPContState - ! Calculate the partial derivative of the discrete state functions (Xd) with respect to the continuous states (x) here: +!> Calculate the jacobian dYdx +subroutine Jac_dYdx( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdx ) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(in ) :: u !< Inputs at operating point + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_OutputType), intent(inout) :: y !< Output (need to make copies) + type(SrvD_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, intent(inout) :: dYdx(:,:) !< Partial derivatives of output functions + + integer(IntKi) :: n ! Generic loop index -- index to x for perturb + type(SrvD_OutputType) :: y_p ! outputs positive perturbed + type(SrvD_OutputType) :: y_m ! outputs negative perturbed + type(SrvD_ContinuousStateType) :: x_temp ! copy of inputs to perturb + real(R8Ki) :: delta_p ! delta+ change in input or state + real(R8Ki) :: delta_m ! delta- change in input or state + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Jac_dYdx' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' - ! allocate and set dXddx + ! Allocate the dYdx array regardless what states may or may not exist (glue code needs this) + if (.not. allocated(dYdx)) then + call allocAry(dYdx, p%Jac_ny, p%Jac_nx, 'dYdx', ErrStat2, ErrMsg2) + if (Failed()) return + elseif ( (size(dYdx,1) /= p%Jac_ny) .or. (size(dYdx,2) /= p%Jac_nx) ) then + deallocate(dYdx) + call allocAry(dYdx, p%Jac_ny, p%Jac_nx, 'dYdx', ErrStat2, ErrMsg2) + if (Failed()) return + endif + dYdx = 0.0_R8Ki + + !------------------------------------------------------------- + ! Perturb each StC instance individually and place in appropriate location in dYdx + ! Each StC is basically an isolated piece that doesn't interact with any other StC or with anything else in SrvD, + ! so we take advantage of that here for computational expediency. + !------------------------------------------------------------- + ! make a copy of the inputs to perturb if an StC exists + if ( (p%NumBStC + p%NumNStC + p%NumTStC + p%NumSStC) > 0 ) then + call SrvD_CopyContState( x, x_temp, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + else + return ! Nothing further to do here + endif + !------------------- + ! Blade StC + if (p%NumBStC > 0) then + do n=p%Jac_Idx_BStC_x(1,1,1),p%Jac_Idx_BStC_x(2,p%NumBl,p%NumBStC) ! state range for BStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dYdx( n, +1, x_temp, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dYdx( n, -1, x_temp, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdx(:,n) ) + enddo + endif + !------------------- + ! Nacelle StC + if (p%NumNStC > 0) then + do n=p%Jac_Idx_NStC_x(1,1),p%Jac_Idx_NStC_x(2,p%NumNStC) ! state range for NStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dYdx( n, +1, x_temp, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dYdx( n, -1, x_temp, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdx(:,n) ) + enddo + endif + !------------------- + ! Tower StC + if (p%NumTStC > 0) then + do n=p%Jac_Idx_TStC_x(1,1),p%Jac_Idx_TStC_x(2,p%NumTStC) ! state range for TStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dYdx( n, +1, x_temp, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dYdx( n, -1, x_temp, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdx(:,n) ) + enddo + endif + !------------------- + ! Substructure StC + if (p%NumSStC > 0) then + do n=p%Jac_Idx_SStC_x(1,1),p%Jac_Idx_SStC_x(2,p%NumSStC) ! state range for SStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dYdx( n, +1, x_temp, delta_p, y_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyOutput( y, y_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dYdx( n, -1, x_temp, delta_m, y_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdx(:,n) ) + enddo + endif + call Cleanup() - END IF +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call Cleanup + end function Failed - IF ( PRESENT( dZdx ) ) THEN + subroutine Cleanup() + ! Ignore any errors from the destroy (these weren't created if no StCs) + call SrvD_DestroyContState( x_temp, ErrStat2, ErrMsg2 ) + call SrvD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) + call SrvD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) + end subroutine Cleanup + !> Calculated dYdx for BStC instance + subroutine Jac_BStC_dYdx( n, sgn, x_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j,k ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_x_indx(n,4) ! this blade + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! call Calc + call StC_CopyOutput(m%y_BStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, m%u_BStC(1,j), p%BStC(j), x%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), y_StC, m%BStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(k), y_perturb%BStCLoadMesh(k,j), m%SrvD_MeshMap%BStC_Frc2_y_BStC(k,j), ErrStat3, ErrMsg3, u%BStCMotionMesh(k,j), u%BStCMotionMesh(k,j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_BStC_Outs_Instance(j, p%NumBl, x_perturb%BStC(j), m%BStC(j), y_StC, AllOuts) + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_BStC_dYdx + + !> Calculated dYdx for NStC instance + subroutine Jac_NStC_dYdx( n, sgn, x_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! call Calc + call StC_CopyOutput(m%y_NStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, m%u_NStC(1,j), p%NStC(j), x%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), y_StC, m%NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%NStCLoadMesh(j), m%SrvD_MeshMap%NStC_Frc2_y_NStC(j), ErrStat3, ErrMsg3, u%NStCMotionMesh(j), u%NStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_NStC_Outs_Instance(j, x_perturb%NStC(j), m%NStC(j), y_StC, AllOuts) + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_NStC_dYdx + + !> Calculated dYdx for TStC instance + subroutine Jac_TStC_dYdx( n, sgn, x_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! call Calc + call StC_CopyOutput(m%y_TStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, m%u_TStC(1,j), p%TStC(j), x%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), y_StC, m%TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%TStCLoadMesh(j), m%SrvD_MeshMap%TStC_Frc2_y_TStC(j), ErrStat3, ErrMsg3, u%TStCMotionMesh(j), u%TStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_TStC_Outs_Instance(j, x_perturb%TStC(j), m%TStC(j), y_StC, AllOuts) + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_TStC_dYdx + + !> Calculated dYdx for SStC instance + subroutine Jac_SStC_dYdx( n, sgn, x_perturb, delta, y_perturb, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of inputs to perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + type(SrvD_OutputType), intent(inout) :: y_perturb ! outputs perturbed + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: i,j ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + real(ReKi) :: AllOuts(0:MaxOutPts) ! All the the available output channels - perturbed (ReKi since WriteOutput is ReKi) + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! call Calc + call StC_CopyOutput(m%y_SStC( j), y_StC, MESH_NEWCOPY, ErrStat3, ErrMsg3); if (ErrStat3 > AbortErrLev) return + CALL StC_CalcOutput( t, m%u_SStC(1,j), p%SStC(j), x%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), y_StC, m%SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + CALL Transfer_Point_to_Point( y_StC%Mesh(1), y_perturb%SStCLoadMesh(j), m%SrvD_MeshMap%SStC_Frc2_y_SStC(j), ErrStat3, ErrMsg3, u%SStCMotionMesh(j), u%SStCMotionMesh(j) ); if (ErrStat3 > AbortErrLev) return + ! collect relevant outputs + AllOuts = 0.0_ReKi + call Set_SStC_Outs_Instance(j, x_perturb%SStC(j), m%SStC(j), y_StC, AllOuts) + call StC_DestroyOutput( y_StC, ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + !------------------- + ! Store outputs + do I = 1,p%NumOuts ! Loop through all selected output channels + y_perturb%WriteOutput(I) = p%OutParam(I)%SignM * AllOuts( p%OutParam(I)%Indx ) + enddo +! do I = 1,p%NumOuts_DLL ! Loop through all DLL logging channels +! y_perturb%WriteOutput(I+p%NumOuts) = m%dll_data%LogChannels( I ) +! enddo + end subroutine Jac_SStC_dYdx +end subroutine Jac_dYdx + +!> Calculate the jacobian dXdx +!! The only states exist with the StC instances +subroutine Jac_dXdx(t, u, p, x, xd, z, OtherState, m, ErrStat, ErrMsg, dXdx) + real(DbKi), intent(in ) :: t !< Time in seconds at operating point + type(SrvD_InputType), intent(in ) :: u !< Inputs at operating point + type(SrvD_ParameterType), intent(in ) :: p !< Parameters + type(SrvD_ContinuousStateType), intent(in ) :: x !< Continuous states at operating point + type(SrvD_DiscreteStateType), intent(in ) :: xd !< Discrete states at operating point + type(SrvD_ConstraintStateType), intent(in ) :: z !< Constraint states at operating point + type(SrvD_OtherStateType), intent(in ) :: OtherState !< Other states at operating point + type(SrvD_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, intent(inout) :: dXdx(:,:) !< Partial derivatives of output functions + + integer(IntKi) :: n ! Generic loop index + type(SrvD_ContinuousStateType) :: dx_p ! states positive perturbed + type(SrvD_ContinuousStateType) :: dx_m ! states negative perturbed + type(SrvD_ContinuousStateType) :: x_temp ! copy of states to perturb + real(R8Ki) :: delta_p ! delta+ change in input or state + real(R8Ki) :: delta_m ! delta- change in input or state + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Jac_dXdx' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = '' - ! Calculate the partial derivative of the constraint state functions (Z) with respect to the continuous states (x) here: + ! Allocate the dXdx array regardless what states may or may not exist (glue code needs this) + if (.not. allocated(dXdx)) then + call allocAry(dXdx, p%Jac_nx, p%Jac_nx, 'dXdx', ErrStat2, ErrMsg2) + if (Failed()) return + elseif ( (size(dXdx,1) /= p%Jac_nx) .or. (size(dXdx,2) /= p%Jac_nx) ) then + deallocate(dXdx) + call allocAry(dXdx, p%Jac_nx, p%Jac_nx, 'dXdx', ErrStat2, ErrMsg2) + if (Failed()) return + endif + dXdx = 0.0_R8Ki + + !------------------------------------------------------------- + ! Perturb each StC instance individually and place in appropriate location in dYdx + ! Each StC is basically an isolated piece that doesn't interact with any other StC or with anything else in SrvD, + ! so we take advantage of that here for computational expediency. + !------------------------------------------------------------- + ! make a copy of the inputs to perturb if an StC exists + if ( (p%NumBStC + p%NumNStC + p%NumTStC + p%NumSStC) > 0 ) then + call SrvD_CopyContState( x, x_temp, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + else + return ! Nothing futher to do here + endif + !------------------- + ! Blade StC + if (p%NumBStC > 0) then + do n=p%Jac_Idx_BStC_x(1,1,1),p%Jac_Idx_BStC_x(2,p%NumBl,p%NumBStC) ! state range for BStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dXdx( n, +1, x_temp, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_BStC_dXdx( n, -1, x_temp, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdx(:,n) ) + enddo + endif + !------------------- + ! Nacelle StC + if (p%NumNStC > 0) then + do n=p%Jac_Idx_NStC_x(1,1),p%Jac_Idx_NStC_x(2,p%NumNStC) ! state range for NStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dXdx( n, +1, x_temp, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_NStC_dXdx( n, -1, x_temp, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdx(:,n) ) + enddo + endif + !------------------- + ! Tower StC + if (p%NumTStC > 0) then + do n=p%Jac_Idx_TStC_x(1,1),p%Jac_Idx_TStC_x(2,p%NumTStC) ! state range for TStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dXdx( n, +1, x_temp, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_TStC_dXdx( n, -1, x_temp, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdx(:,n) ) + enddo + endif + !------------------- + ! Substructure StC + if (p%NumSStC > 0) then + do n=p%Jac_Idx_SStC_x(1,1),p%Jac_Idx_SStC_x(2,p%NumSStC) ! state range for SStC + ! perturb positive + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_p, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dXdx( n, +1, x_temp, delta_p, dx_p, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! perturb negative + call SrvD_CopyContState( x, x_temp, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call SrvD_CopyContState( x, dx_m, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + call Jac_SStC_dXdx( n, -1, x_temp, delta_m, dx_m, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Central difference + call Compute_dX( p, dx_p, dx_m, delta_p, delta_m, dXdx(:,n) ) + enddo + endif + call Cleanup() - ! allocate and set dZdx +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) call Cleanup + end function Failed - END IF + subroutine Cleanup() + ! Ignore any errors from the destroy (these weren't created if no StCs) + call SrvD_DestroyContState( x_temp, ErrStat2, ErrMsg2 ) + call SrvD_DestroyContState( dx_p, ErrStat2, ErrMsg2 ) + call SrvD_DestroyContState( dx_m, ErrStat2, ErrMsg2 ) + end subroutine Cleanup + !> Calculated dYdx for BStC instance + subroutine Jac_BStC_dXdx( n, sgn, x_perturb, delta, x_perturb_out, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of states before perturb + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb_out ! copy of states after perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j,k ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_x_indx(n,4) ! this blade + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! calculate change in ContState + call StC_CalcContStateDeriv( t, m%u_BStC(1,j), p%BStC(j), x_perturb%BStC(j), xd%BStC(j), z%BStC(j), OtherState%BStC(j), m%BStC(j), x_perturb_out%BStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_BStC_dXdx + + !> Calculated dYdx for NStC instance + subroutine Jac_NStC_dXdx( n, sgn, x_perturb, delta, x_perturb_out, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of states before perturb + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb_out ! copy of states after perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j,k ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_x_indx(n,4) ! this blade + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! calculate change in ContState + call StC_CalcContStateDeriv( t, m%u_NStC(1,j), p%NStC(j), x_perturb%NStC(j), xd%NStC(j), z%NStC(j), OtherState%NStC(j), m%NStC(j), x_perturb_out%NStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_NStC_dXdx + + !> Calculated dYdx for TStC instance + subroutine Jac_TStC_dXdx( n, sgn, x_perturb, delta, x_perturb_out, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of states before perturb + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb_out ! copy of states after perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j,k ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_x_indx(n,4) ! this blade + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! calculate change in ContState + call StC_CalcContStateDeriv( t, m%u_TStC(1,j), p%TStC(j), x_perturb%TStC(j), xd%TStC(j), z%TStC(j), OtherState%TStC(j), m%TStC(j), x_perturb_out%TStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_TStC_dXdx + + !> Calculated dYdx for SStC instance + subroutine Jac_SStC_dXdx( n, sgn, x_perturb, delta, x_perturb_out, ErrStat3, ErrMsg3) + integer(IntKi), intent(in ) :: n ! which input to perturb + integer(IntKi), intent(in ) :: sgn ! sign of perturbation + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb ! copy of states before perturb + type(SrvD_ContinuousStateType), intent(inout) :: x_perturb_out ! copy of states after perturb + real(R8Ki), intent( out) :: delta ! delta+/- change in input or state + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: j,k ! Generic indices + type(StC_OutputType) :: y_StC ! copy of the StC outputs for StC_CalcOutput call + ! Since this is acting on only a single blade within a single StC instance, we can look up exactly which one + ! from the Jac_x_indx array. This allows us to simplify the number of calls dramatically + k = p%Jac_x_indx(n,4) ! this blade + j = p%Jac_x_indx(n,3) ! this instance + !------------------- + ! get u_op +/- delta u + call SrvD_Perturb_x( p, n, sgn, x_perturb, delta ) + ! calculate change in ContState + call StC_CalcContStateDeriv( t, m%u_SStC(1,j), p%SStC(j), x_perturb%SStC(j), xd%SStC(j), z%SStC(j), OtherState%SStC(j), m%SStC(j), x_perturb_out%SStC(j), ErrStat3, ErrMsg3 ); if (ErrStat3 > AbortErrLev) return + end subroutine Jac_SStC_dXdx + +end subroutine Jac_dXdx -END SUBROUTINE SrvD_JacobianPContState !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions !! with respect to the discrete states (xd). The partial derivatives dY/dxd, dX/dxd, dXd/dxd, and DZ/dxd are returned. !! Note SrvD does not have discrete states, so these are not set. SUBROUTINE SrvD_JacobianPDiscState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdxd, dXdxd, dXddxd, dZdxd ) -!.................................................................................................................................. - REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters @@ -2308,54 +4144,31 @@ SUBROUTINE SrvD_JacobianPDiscState( t, u, p, x, xd, z, OtherState, y, m, ErrStat !! functions (Z) with respect to the !! discrete states (xd) [intent in to avoid deallocation] - ! Initialize ErrStat - ErrStat = ErrID_None ErrMsg = '' - IF ( PRESENT( dYdxd ) ) THEN - - ! Calculate the partial derivative of the output functions (Y) with respect to the discrete states (xd) here: - - ! allocate and set dYdxd - + if (allocated(dYdxd)) deallocate(dYdxd) END IF IF ( PRESENT( dXdxd ) ) THEN - - ! Calculate the partial derivative of the continuous state functions (X) with respect to the discrete states (xd) here: - - ! allocate and set dXdxd - + if (allocated(dXdxd)) deallocate(dXdxd) END IF IF ( PRESENT( dXddxd ) ) THEN - - ! Calculate the partial derivative of the discrete state functions (Xd) with respect to the discrete states (xd) here: - - ! allocate and set dXddxd - + if (allocated(dXddxd)) deallocate(dXddxd) END IF IF ( PRESENT( dZdxd ) ) THEN - - ! Calculate the partial derivative of the constraint state functions (Z) with respect to the discrete states (xd) here: - - ! allocate and set dZdxd - + if (allocated(dZdxd)) deallocate(dZdxd) END IF - - END SUBROUTINE SrvD_JacobianPDiscState !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions !! with respect to the constraint states (z). The partial derivatives dY/dz, dX/dz, dXd/dz, and DZ/dz are returned. !! Note SrvD does not have constraint states, so these are not set. SUBROUTINE SrvD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdz, dXdz, dXddz, dZdz ) -!.................................................................................................................................. - REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters @@ -2383,137 +4196,274 @@ SUBROUTINE SrvD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrSt !! state functions (Z) with respect to !! the constraint states (z) [intent in to avoid deallocation] - ! Initialize ErrStat - ErrStat = ErrID_None ErrMsg = '' IF ( PRESENT( dYdz ) ) THEN - - ! Calculate the partial derivative of the output functions (Y) with respect to the constraint states (z) here: - - ! allocate and set dYdz - + if (allocated(dYdz)) deallocate(dYdz) END IF IF ( PRESENT( dXdz ) ) THEN - - ! Calculate the partial derivative of the continuous state functions (X) with respect to the constraint states (z) here: - - ! allocate and set dXdz - + if (allocated(dXdz)) deallocate(dXdz) END IF IF ( PRESENT( dXddz ) ) THEN - - ! Calculate the partial derivative of the discrete state functions (Xd) with respect to the constraint states (z) here: - - ! allocate and set dXddz - + if (allocated(dXddz)) deallocate(dXddz) END IF IF ( PRESENT( dZdz ) ) THEN - - ! Calculate the partial derivative of the constraint state functions (Z) with respect to the constraint states (z) here: - - ! allocate and set dZdz - + if (allocated(dZdz)) deallocate(dZdz) END IF - - END SUBROUTINE SrvD_JacobianPConstrState !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !> Routine to pack the data structures representing the operating points into arrays for linearization. SUBROUTINE SrvD_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(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) - TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters - TYPE(SrvD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point - TYPE(SrvD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point - TYPE(SrvD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at operating point - TYPE(SrvD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at operating point - TYPE(SrvD_OutputType), INTENT(IN ) :: y !< Output at operating point - TYPE(SrvD_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 - INTEGER(IntKi) :: ErrStat2 ! Error status of the operation (occurs after initial error) - CHARACTER(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat2 /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_GetOP' - + REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point + TYPE(SrvD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(SrvD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point + TYPE(SrvD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point + TYPE(SrvD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at operating point + TYPE(SrvD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at operating point + TYPE(SrvD_OutputType), INTENT(IN ) :: y !< Output at operating point + TYPE(SrvD_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) :: ErrStat2 ! Error status of the operation (occurs after initial error) + CHARACTER(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat2 /= ErrID_None + CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_GetOP' ! Initialize ErrStat - ErrStat = ErrID_None ErrMsg = '' !.......................................... IF ( PRESENT( u_op ) ) THEN + call Get_u_op() + if (ErrStat >= AbortErrLev) return + END IF + !.......................................... + IF ( PRESENT( y_op ) ) THEN + call Get_y_op() + if (ErrStat >= AbortErrLev) return + END IF + !.......................................... + IF ( PRESENT( x_op ) ) THEN + call Get_x_op() + if (ErrStat >= AbortErrLev) return + END IF + !.......................................... + IF ( PRESENT( dx_op ) ) THEN + call Get_dx_op() + if (ErrStat >= AbortErrLev) return + END IF + !.......................................... + IF ( PRESENT( xd_op ) ) THEN + END IF + !.......................................... + IF ( PRESENT( z_op ) ) THEN + END IF +CONTAINS + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + + !> Get the operating point inputs and pack + subroutine Get_u_op() + integer(IntKi) :: nu,i,j,index_next if (.not. allocated(u_op)) then - CALL AllocAry( u_op, 3, 'u_op', ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) RETURN + ! our operating point includes DCM (orientation) matrices, not just small angles like the perturbation matrices do + nu = p%Jac_nu & + + p%NumBStC * 6 * p%NumBl & ! Jac_nu has 3 for Orientation, but we need 9 at each BStC instance on each blade + + p%NumNStC * 6 & ! Jac_nu has 3 for Orientation, but we need 9 at each NStC instance + + p%NumTStC * 6 & ! Jac_nu has 3 for Orientation, but we need 9 at each TStC instance + + p%NumSStC * 6 ! Jac_nu has 3 for Orientation, but we need 9 at each SStC instance + CALL AllocAry( u_op, nu, 'u_op', ErrStat2, ErrMsg2 ) + if (Failed()) return; end if + index_next=1 + ! Fixed inputs + u_op(index_next) = u%Yaw; index_next = index_next + 1 + u_op(index_next) = u%YawRate; index_next = index_next + 1 + u_op(index_next) = u%HSS_Spd; index_next = index_next + 1 - u_op(Indx_u_Yaw ) = u%Yaw - u_op(Indx_u_YawRate) = u%YawRate - u_op(Indx_u_HSS_Spd) = u%HSS_Spd - - END IF + ! StC related inputs + do j=1,p%NumBStC ! Blade + do i=1,p%NumBl + call PackMotionMesh( u%BStCMotionMesh(i,j), u_op, index_next ) + enddo + enddo + do j=1,p%NumNStC ! Nacelle + call PackMotionMesh( u%NStCMotionMesh(j), u_op, index_next ) + enddo + do j=1,p%NumTStC ! Tower + call PackMotionMesh( u%TStCMotionMesh(j), u_op, index_next ) + enddo + do j=1,p%NumSStC ! Sub-structure + call PackMotionMesh( u%SStCMotionMesh(j), u_op, index_next ) + enddo + end subroutine Get_u_op - !.......................................... - IF ( PRESENT( y_op ) ) THEN + !> Get the operating point outputs and pack + subroutine Get_y_op() + integer(IntKi) :: i,j,index_next if (.not. allocated(y_op)) then - CALL AllocAry( y_op, SrvD_Indx_Y_WrOutput+p%NumOuts, 'y_op', ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) RETURN + CALL AllocAry( y_op, p%Jac_ny, 'y_op', ErrStat2, ErrMsg2 ) + if (Failed()) return; end if - - - do i=1,size(SrvD_Indx_Y_BlPitchCom) ! Note: Potentially limit to NumBl - if (i<=p%NumBl) then - y_op(SrvD_Indx_Y_BlPitchCom(i)) = y%BlPitchCom(i) - else - y_op(SrvD_Indx_Y_BlPitchCom(i)) = 0.0_ReKI - endif - end do - y_op(SrvD_Indx_Y_YawMom) = y%YawMom - y_op(SrvD_Indx_Y_GenTrq) = y%GenTrq - y_op(SrvD_Indx_Y_ElecPwr) = y%ElecPwr - do i=1,p%NumOuts - y_op(i+SrvD_Indx_Y_WrOutput) = y%WriteOutput(i) - end do - - END IF - IF ( PRESENT( x_op ) ) THEN + index_next=1 + do i=1,size(y%BlPitchCom) + y_op(index_next) = y%BlPitchCom(i) + index_next = index_next + 1 + end do - END IF + y_op(index_next) = y%YawMom; index_next = index_next + 1 + y_op(index_next) = y%GenTrq; index_next = index_next + 1 + y_op(index_next) = y%ElecPwr; index_next = index_next + 1 - IF ( PRESENT( dx_op ) ) THEN + ! StC related outputs + do j=1,p%NumBStC ! Blade + do i=1,p%NumBl + call PackLoadMesh( y%BStCLoadMesh(i,j), y_op, index_next ) + enddo + enddo + do j=1,p%NumNStC ! Nacelle + call PackLoadMesh( y%NStCLoadMesh(j), y_op, index_next ) + enddo + do j=1,p%NumTStC ! Tower + call PackLoadMesh( y%TStCLoadMesh(j), y_op, index_next ) + enddo + do j=1,p%NumSStC ! Sub-structure + call PackLoadMesh( y%SStCLoadMesh(j), y_op, index_next ) + enddo - END IF + ! y%outputs + do i=1,p%NumOuts + y_op(index_next) = y%WriteOutput(i) + index_next = index_next + 1 + end do + end subroutine Get_y_op - IF ( PRESENT( xd_op ) ) THEN + !> Get the operating point continuous states and pack + subroutine Get_x_op() + integer(IntKi) :: i,j,k,idx - END IF + if (.not. allocated(x_op)) then + CALL AllocAry( x_op, p%Jac_nx, 'x_op', ErrStat2, ErrMsg2 ) + if (Failed()) return; + end if + idx = 0 + do j=1,p%NumBStC ! Blade StC -- displacement and velocity state + do k=1,p%NumBl + x_op(idx+1) = x%BStC(j)%StC_x(1,k) ! x --> x%BStC(j)%StC_x(1,k) + x_op(idx+2) = x%BStC(j)%StC_x(3,k) ! y --> x%BStC(j)%StC_x(3,k) + x_op(idx+3) = x%BStC(j)%StC_x(5,k) ! z --> x%BStC(j)%StC_x(5,k) + x_op(idx+4) = x%BStC(j)%StC_x(2,k) ! dx/dt --> x%BStC(j)%StC_x(2,k) + x_op(idx+5) = x%BStC(j)%StC_x(4,k) ! dy/dt --> x%BStC(j)%StC_x(4,k) + x_op(idx+6) = x%BStC(j)%StC_x(6,k) ! dz/dt --> x%BStC(j)%StC_x(6,k) + idx = idx + 6 + enddo + enddo + do j=1,p%NumNStC ! Nacelle StC -- displacement and velocity state + x_op(idx+1) = x%NStC(j)%StC_x(1,1) ! x --> x%NStC(j)%StC_x(1,1) + x_op(idx+2) = x%NStC(j)%StC_x(3,1) ! y --> x%NStC(j)%StC_x(3,1) + x_op(idx+3) = x%NStC(j)%StC_x(5,1) ! z --> x%NStC(j)%StC_x(5,1) + x_op(idx+4) = x%NStC(j)%StC_x(2,1) ! dx/dt --> x%NStC(j)%StC_x(2,1) + x_op(idx+5) = x%NStC(j)%StC_x(4,1) ! dy/dt --> x%NStC(j)%StC_x(4,1) + x_op(idx+6) = x%NStC(j)%StC_x(6,1) ! dz/dt --> x%NStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + do j=1,p%NumTStC ! Tower StC -- displacement and velocity state + x_op(idx+1) = x%TStC(j)%StC_x(1,1) ! x --> x%TStC(j)%StC_x(1,1) + x_op(idx+2) = x%TStC(j)%StC_x(3,1) ! y --> x%TStC(j)%StC_x(3,1) + x_op(idx+3) = x%TStC(j)%StC_x(5,1) ! z --> x%TStC(j)%StC_x(5,1) + x_op(idx+4) = x%TStC(j)%StC_x(2,1) ! dx/dt --> x%TStC(j)%StC_x(2,1) + x_op(idx+5) = x%TStC(j)%StC_x(4,1) ! dy/dt --> x%TStC(j)%StC_x(4,1) + x_op(idx+6) = x%TStC(j)%StC_x(6,1) ! dz/dt --> x%TStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + do j=1,p%NumSStC ! Substructure StC -- displacement and velocity state + x_op(idx+1) = x%SStC(j)%StC_x(1,1) ! x --> x%SStC(j)%StC_x(1,1) + x_op(idx+2) = x%SStC(j)%StC_x(3,1) ! y --> x%SStC(j)%StC_x(3,1) + x_op(idx+3) = x%SStC(j)%StC_x(5,1) ! z --> x%SStC(j)%StC_x(5,1) + x_op(idx+4) = x%SStC(j)%StC_x(2,1) ! dx/dt --> x%SStC(j)%StC_x(2,1) + x_op(idx+5) = x%SStC(j)%StC_x(4,1) ! dy/dt --> x%SStC(j)%StC_x(4,1) + x_op(idx+6) = x%SStC(j)%StC_x(6,1) ! dz/dt --> x%SStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + end subroutine Get_x_op - IF ( PRESENT( z_op ) ) THEN + !> Get the operating point continuous states derivatives and pack + !! rather than copy the logic in CalcContStateDeriv for the StCs, we'll just + !! call it directly + subroutine Get_dx_op() + integer(IntKi) :: i,j,k,idx + type(SrvD_ContinuousStateType) :: dx !< derivative of continuous states at operating point - END IF + if (.not. allocated(dx_op)) then + CALL AllocAry( dx_op, p%Jac_nx, 'dx_op', ErrStat2, ErrMsg2 ) + if (Failed()) return; + end if + call SrvD_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dx, ErrStat2, ErrMsg2 ) + if (Failed()) then + call SrvD_DestroyContState( dx, ErrStat2, ErrMsg2) + return + end if + idx = 0 + do j=1,p%NumBStC ! Blade StC -- displacement and velocity state + do k=1,p%NumBl + dx_op(idx+1) = dx%BStC(j)%StC_x(1,k) ! x --> dx%BStC(j)%StC_x(1,k) + dx_op(idx+2) = dx%BStC(j)%StC_x(3,k) ! y --> dx%BStC(j)%StC_x(3,k) + dx_op(idx+3) = dx%BStC(j)%StC_x(5,k) ! z --> dx%BStC(j)%StC_x(5,k) + dx_op(idx+4) = dx%BStC(j)%StC_x(2,k) ! dx/dt --> dx%BStC(j)%StC_x(2,k) + dx_op(idx+5) = dx%BStC(j)%StC_x(4,k) ! dy/dt --> dx%BStC(j)%StC_x(4,k) + dx_op(idx+6) = dx%BStC(j)%StC_x(6,k) ! dz/dt --> dx%BStC(j)%StC_x(6,k) + idx = idx + 6 + enddo + enddo + do j=1,p%NumNStC ! Nacelle StC -- displacement and velocity state + dx_op(idx+1) = dx%NStC(j)%StC_x(1,1) ! x --> dx%NStC(j)%StC_x(1,1) + dx_op(idx+2) = dx%NStC(j)%StC_x(3,1) ! y --> dx%NStC(j)%StC_x(3,1) + dx_op(idx+3) = dx%NStC(j)%StC_x(5,1) ! z --> dx%NStC(j)%StC_x(5,1) + dx_op(idx+4) = dx%NStC(j)%StC_x(2,1) ! dx/dt --> dx%NStC(j)%StC_x(2,1) + dx_op(idx+5) = dx%NStC(j)%StC_x(4,1) ! dy/dt --> dx%NStC(j)%StC_x(4,1) + dx_op(idx+6) = dx%NStC(j)%StC_x(6,1) ! dz/dt --> dx%NStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + do j=1,p%NumTStC ! Tower StC -- displacement and velocity state + dx_op(idx+1) = dx%TStC(j)%StC_x(1,1) ! x --> dx%TStC(j)%StC_x(1,1) + dx_op(idx+2) = dx%TStC(j)%StC_x(3,1) ! y --> dx%TStC(j)%StC_x(3,1) + dx_op(idx+3) = dx%TStC(j)%StC_x(5,1) ! z --> dx%TStC(j)%StC_x(5,1) + dx_op(idx+4) = dx%TStC(j)%StC_x(2,1) ! dx/dt --> dx%TStC(j)%StC_x(2,1) + dx_op(idx+5) = dx%TStC(j)%StC_x(4,1) ! dy/dt --> dx%TStC(j)%StC_x(4,1) + dx_op(idx+6) = dx%TStC(j)%StC_x(6,1) ! dz/dt --> dx%TStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + do j=1,p%NumSStC ! Substructure StC -- displacement and velocity state + dx_op(idx+1) = dx%SStC(j)%StC_x(1,1) ! x --> dx%SStC(j)%StC_x(1,1) + dx_op(idx+2) = dx%SStC(j)%StC_x(3,1) ! y --> dx%SStC(j)%StC_x(3,1) + dx_op(idx+3) = dx%SStC(j)%StC_x(5,1) ! z --> dx%SStC(j)%StC_x(5,1) + dx_op(idx+4) = dx%SStC(j)%StC_x(2,1) ! dx/dt --> dx%SStC(j)%StC_x(2,1) + dx_op(idx+5) = dx%SStC(j)%StC_x(4,1) ! dy/dt --> dx%SStC(j)%StC_x(4,1) + dx_op(idx+6) = dx%SStC(j)%StC_x(6,1) ! dz/dt --> dx%SStC(j)%StC_x(6,1) + idx = idx + 6 + enddo + ! clean up + call SrvD_DestroyContState( dx, ErrStat2, ErrMsg2) + end subroutine Get_dx_op END SUBROUTINE SrvD_GetOP !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -2570,10 +4520,7 @@ SUBROUTINE ValidatePrimaryData( InitInp, InputFileData, ErrStat, ErrMsg ) call SetErrStat(ErrID_Fatal,"HSSBrMode must be 0 for linearization.",ErrStat,ErrMsg,RoutineName) if (InputFileData%YCMode /= ControlMode_NONE) & call SetErrStat(ErrID_Fatal,"YCMode must be 0 for linearization.",ErrStat,ErrMsg,RoutineName) - - if ((InputFileData%NumNStC + InputFileData%NumTStC + InputFileData%NumBStC + InputFileData%NumSStC) > 0_IntKi) & - call SetErrStat(ErrID_Fatal,"StrucCtrl module is not currently allowed in linearization. NumNStC, NumTStC, NumBStC, and NumSStC must all be ZERO.",ErrStat,ErrMsg,RoutineName) - + if (InitInp%TrimCase /= TrimCase_none) then if (InitInp%TrimCase /= TrimCase_yaw .and. InitInp%TrimCase /= TrimCase_torque .and. InitInp%TrimCase /= TrimCase_pitch) then call SetErrStat(ErrID_Fatal,"Invalid value entered for TrimCase.",ErrStat,ErrMsg,RoutineName) @@ -4482,6 +6429,10 @@ subroutine StC_SetDLLinputs(p,m,MeasDisp,MeasVel,ErrStat,ErrMsg,InitResize) ErrStat = ErrID_None ErrMsg = "" + ! Since we do averaging of these signal + if (allocated(MeasDisp)) MeasDisp = 0.0_SiKi + if (allocated(MeasVel)) MeasVel = 0.0_SiKi + ! Only proceed if we have have StC controls with the extended swap and legacy interface if ((p%NumStC_Control <= 0) .or. (.not. p%EXavrSWAP)) return if (.not. allocated(MeasDisp) .or. .not. allocated(MeasVel)) then @@ -4579,6 +6530,7 @@ end subroutine Cleanup subroutine GetMeas(iNum,CChan,y) ! Assemble info about who requested which channel integer(IntKi), intent(in) :: iNum ! instance number integer(IntKi), allocatable,intent(in) :: CChan(:) ! Channel request set from that StC instance + type(StC_OutputType), intent(in) :: y ! outputs from the StC instance do j=1,size(CChan) if (CChan(j) > 0) then diff --git a/modules/servodyn/src/ServoDyn_Driver.f90 b/modules/servodyn/src/ServoDyn_Driver.f90 index 6bc6d0ef47..4de06f0ee0 100644 --- a/modules/servodyn/src/ServoDyn_Driver.f90 +++ b/modules/servodyn/src/ServoDyn_Driver.f90 @@ -23,6 +23,7 @@ PROGRAM SrvD_Driver USE NWTC_Library USE ServoDyn USE ServoDyn_Types + USE VersionInfo IMPLICIT NONE diff --git a/modules/servodyn/src/ServoDyn_IO.f90 b/modules/servodyn/src/ServoDyn_IO.f90 index e01b085c6b..805b2be99e 100644 --- a/modules/servodyn/src/ServoDyn_IO.f90 +++ b/modules/servodyn/src/ServoDyn_IO.f90 @@ -809,129 +809,178 @@ subroutine Set_NStC_Outs( p_SrvD, x, m, y, AllOuts ) ! Nacelle type(StC_MiscVarType), allocatable,intent(in ) :: m(:) !< Misc (optimization) variables type(StC_OutputType), allocatable,intent(in ) :: y(:) !< Outputs computed at Time real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels - integer :: i,j - j=1 + integer :: i if (allocated(x) .and. allocated(m) .and. allocated(y)) then do i=1,min(p_SrvD%NumNStC,MaxStC) ! in case we have more Nacelle StCs than the outputs are set for - AllOuts(NStC_XQ( i)) = x(i)%StC_x(1,1) ! x - AllOuts(NStC_XQD(i)) = x(i)%StC_x(2,1) ! x-dot - AllOuts(NStC_YQ( i)) = x(i)%StC_x(3,1) ! y - AllOuts(NStC_YQD(i)) = x(i)%StC_x(4,1) ! y-dot - AllOuts(NStC_ZQ( i)) = x(i)%StC_x(5,1) ! z - AllOuts(NStC_ZQD(i)) = x(i)%StC_x(6,1) ! z-dot - AllOuts(NStC_Fxi(i)) = 0.001*y(i)%Mesh(j)%Force(1,1) ! only one mesh per NStC instance - AllOuts(NStC_Fyi(i)) = 0.001*y(i)%Mesh(j)%Force(2,1) ! only one mesh per NStC instance - AllOuts(NStC_Fzi(i)) = 0.001*y(i)%Mesh(j)%Force(3,1) ! only one mesh per NStC instance - AllOuts(NStC_Mxi(i)) = 0.001*y(i)%Mesh(j)%Moment(1,1) ! only one mesh per NStC instance - AllOuts(NStC_Myi(i)) = 0.001*y(i)%Mesh(j)%Moment(2,1) ! only one mesh per NStC instance - AllOuts(NStC_Mzi(i)) = 0.001*y(i)%Mesh(j)%Moment(3,1) ! only one mesh per NStC instance - AllOuts(NStC_Fxl(i)) = 0.001*m(i)%F_P(1,j) - AllOuts(NStC_Fyl(i)) = 0.001*m(i)%F_P(2,j) - AllOuts(NStC_Fzl(i)) = 0.001*m(i)%F_P(3,j) - AllOuts(NStC_Mxl(i)) = 0.001*m(i)%M_P(1,j) - AllOuts(NStC_Myl(i)) = 0.001*m(i)%M_P(2,j) - AllOuts(NStC_Mzl(i)) = 0.001*m(i)%M_P(3,j) + call Set_NStC_Outs_Instance( i, x(i), m(i), y(i), AllOuts ) enddo endif end subroutine Set_NStC_Outs !--------------------------- +subroutine Set_NStC_Outs_Instance( i, x, m, y, AllOuts ) ! Nacelle single StC instance + integer(IntKi), intent(in ) :: i ! This instance + type(StC_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(StC_MiscVarType), intent(in ) :: m !< Misc (optimization) variables + type(StC_OutputType), intent(in ) :: y !< Outputs computed at Time + real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels + integer :: j + j=1 + if (i < MaxStC) then + AllOuts(NStC_XQ( i)) = x%StC_x(1,1) ! x + AllOuts(NStC_XQD(i)) = x%StC_x(2,1) ! x-dot + AllOuts(NStC_YQ( i)) = x%StC_x(3,1) ! y + AllOuts(NStC_YQD(i)) = x%StC_x(4,1) ! y-dot + AllOuts(NStC_ZQ( i)) = x%StC_x(5,1) ! z + AllOuts(NStC_ZQD(i)) = x%StC_x(6,1) ! z-dot + AllOuts(NStC_Fxi(i)) = 0.001*y%Mesh(j)%Force(1,1) ! only one mesh per NStC instance + AllOuts(NStC_Fyi(i)) = 0.001*y%Mesh(j)%Force(2,1) ! only one mesh per NStC instance + AllOuts(NStC_Fzi(i)) = 0.001*y%Mesh(j)%Force(3,1) ! only one mesh per NStC instance + AllOuts(NStC_Mxi(i)) = 0.001*y%Mesh(j)%Moment(1,1) ! only one mesh per NStC instance + AllOuts(NStC_Myi(i)) = 0.001*y%Mesh(j)%Moment(2,1) ! only one mesh per NStC instance + AllOuts(NStC_Mzi(i)) = 0.001*y%Mesh(j)%Moment(3,1) ! only one mesh per NStC instance + AllOuts(NStC_Fxl(i)) = 0.001*m%F_P(1,j) + AllOuts(NStC_Fyl(i)) = 0.001*m%F_P(2,j) + AllOuts(NStC_Fzl(i)) = 0.001*m%F_P(3,j) + AllOuts(NStC_Mxl(i)) = 0.001*m%M_P(1,j) + AllOuts(NStC_Myl(i)) = 0.001*m%M_P(2,j) + AllOuts(NStC_Mzl(i)) = 0.001*m%M_P(3,j) + endif +end subroutine Set_NStC_Outs_Instance +!--------------------------- subroutine Set_TStC_Outs( p_SrvD, x, m, y, AllOuts ) ! Tower type(SrvD_ParameterType), intent(in ) :: p_SrvD !< Parameters type(StC_ContinuousStateType), allocatable,intent(in ) :: x(:) !< Continuous states at t type(StC_MiscVarType), allocatable,intent(in ) :: m(:) !< Misc (optimization) variables type(StC_OutputType), allocatable,intent(in ) :: y(:) !< Outputs computed at Time real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels - integer :: i,j - j=1 + integer :: i if (allocated(x) .and. allocated(m) .and. allocated(y)) then do i=1,min(p_SrvD%NumTStC,MaxStC) ! in case we have more Nacelle StCs than the outputs are set for - AllOuts(TStC_XQ( i)) = x(i)%StC_x(1,1) ! x - AllOuts(TStC_XQD(i)) = x(i)%StC_x(2,1) ! x-dot - AllOuts(TStC_YQ( i)) = x(i)%StC_x(3,1) ! y - AllOuts(TStC_YQD(i)) = x(i)%StC_x(4,1) ! y-dot - AllOuts(TStC_ZQ( i)) = x(i)%StC_x(5,1) ! z - AllOuts(TStC_ZQD(i)) = x(i)%StC_x(6,1) ! z-dot - AllOuts(TStC_Fxi(i)) = 0.001*y(i)%Mesh(j)%Force(1,1) ! only one mesh per TStC instance - AllOuts(TStC_Fyi(i)) = 0.001*y(i)%Mesh(j)%Force(2,1) ! only one mesh per TStC instance - AllOuts(TStC_Fzi(i)) = 0.001*y(i)%Mesh(j)%Force(3,1) ! only one mesh per TStC instance - AllOuts(TStC_Mxi(i)) = 0.001*y(i)%Mesh(j)%Moment(1,1) ! only one mesh per TStC instance - AllOuts(TStC_Myi(i)) = 0.001*y(i)%Mesh(j)%Moment(2,1) ! only one mesh per TStC instance - AllOuts(TStC_Mzi(i)) = 0.001*y(i)%Mesh(j)%Moment(3,1) ! only one mesh per TStC instance - AllOuts(TStC_Fxl(i)) = 0.001*m(i)%F_P(1,j) - AllOuts(TStC_Fyl(i)) = 0.001*m(i)%F_P(2,j) - AllOuts(TStC_Fzl(i)) = 0.001*m(i)%F_P(3,j) - AllOuts(TStC_Mxl(i)) = 0.001*m(i)%M_P(1,j) - AllOuts(TStC_Myl(i)) = 0.001*m(i)%M_P(2,j) - AllOuts(TStC_Mzl(i)) = 0.001*m(i)%M_P(3,j) + call Set_TStC_Outs_Instance( i, x(i), m(i), y(i), AllOuts ) enddo endif end subroutine Set_TStC_Outs !--------------------------- +subroutine Set_TStC_Outs_Instance( i, x, m, y, AllOuts ) ! Tower single StC instance + integer(IntKi), intent(in ) :: i ! This instance + type(StC_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(StC_MiscVarType), intent(in ) :: m !< Misc (optimization) variables + type(StC_OutputType), intent(in ) :: y !< Outputs computed at Time + real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels + integer :: j + j=1 + if (i < MaxStC) then + AllOuts(TStC_XQ( i)) = x%StC_x(1,1) ! x + AllOuts(TStC_XQD(i)) = x%StC_x(2,1) ! x-dot + AllOuts(TStC_YQ( i)) = x%StC_x(3,1) ! y + AllOuts(TStC_YQD(i)) = x%StC_x(4,1) ! y-dot + AllOuts(TStC_ZQ( i)) = x%StC_x(5,1) ! z + AllOuts(TStC_ZQD(i)) = x%StC_x(6,1) ! z-dot + AllOuts(TStC_Fxi(i)) = 0.001*y%Mesh(j)%Force(1,1) ! only one mesh per TStC instance + AllOuts(TStC_Fyi(i)) = 0.001*y%Mesh(j)%Force(2,1) ! only one mesh per TStC instance + AllOuts(TStC_Fzi(i)) = 0.001*y%Mesh(j)%Force(3,1) ! only one mesh per TStC instance + AllOuts(TStC_Mxi(i)) = 0.001*y%Mesh(j)%Moment(1,1) ! only one mesh per TStC instance + AllOuts(TStC_Myi(i)) = 0.001*y%Mesh(j)%Moment(2,1) ! only one mesh per TStC instance + AllOuts(TStC_Mzi(i)) = 0.001*y%Mesh(j)%Moment(3,1) ! only one mesh per TStC instance + AllOuts(TStC_Fxl(i)) = 0.001*m%F_P(1,j) + AllOuts(TStC_Fyl(i)) = 0.001*m%F_P(2,j) + AllOuts(TStC_Fzl(i)) = 0.001*m%F_P(3,j) + AllOuts(TStC_Mxl(i)) = 0.001*m%M_P(1,j) + AllOuts(TStC_Myl(i)) = 0.001*m%M_P(2,j) + AllOuts(TStC_Mzl(i)) = 0.001*m%M_P(3,j) + endif +end subroutine Set_TStC_Outs_Instance +!--------------------------- subroutine Set_BStC_Outs( p_SrvD, x, m, y, AllOuts ) ! Blades type(SrvD_ParameterType), intent(in ) :: p_SrvD !< Parameters type(StC_ContinuousStateType), allocatable,intent(in ) :: x(:) !< Continuous states at t type(StC_MiscVarType), allocatable,intent(in ) :: m(:) !< Misc (optimization) variables type(StC_OutputType), allocatable,intent(in ) :: y(:) !< Outputs computed at Time real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels - integer :: i,j + integer :: i if (allocated(x) .and. allocated(m) .and. allocated(y)) then - do j=1,min(p_SrvD%NumBl,MaxBlOuts) - do i=1,min(p_SrvD%NumBStC,MaxStC) ! in case we have more Nacelle StCs than the outputs are set for - AllOuts(BStC_XQ( i,j)) = x(i)%StC_x(1,j) ! x - AllOuts(BStC_XQD(i,j)) = x(i)%StC_x(2,j) ! x-dot - AllOuts(BStC_YQ( i,j)) = x(i)%StC_x(3,j) ! y - AllOuts(BStC_YQD(i,j)) = x(i)%StC_x(4,j) ! y-dot - AllOuts(BStC_ZQ( i,j)) = x(i)%StC_x(5,j) ! z - AllOuts(BStC_ZQD(i,j)) = x(i)%StC_x(6,j) ! z-dot - AllOuts(BStC_Fxi(i,j)) = 0.001*y(i)%Mesh(j)%Force(1,1) ! only one mesh per BStC instance - AllOuts(BStC_Fyi(i,j)) = 0.001*y(i)%Mesh(j)%Force(2,1) ! only one mesh per BStC instance - AllOuts(BStC_Fzi(i,j)) = 0.001*y(i)%Mesh(j)%Force(3,1) ! only one mesh per BStC instance - AllOuts(BStC_Mxi(i,j)) = 0.001*y(i)%Mesh(j)%Moment(1,1) ! only one mesh per BStC instance - AllOuts(BStC_Myi(i,j)) = 0.001*y(i)%Mesh(j)%Moment(2,1) ! only one mesh per BStC instance - AllOuts(BStC_Mzi(i,j)) = 0.001*y(i)%Mesh(j)%Moment(3,1) ! only one mesh per BStC instance - AllOuts(BStC_Fxl(i,j)) = 0.001*m(i)%F_P(1,j) - AllOuts(BStC_Fyl(i,j)) = 0.001*m(i)%F_P(2,j) - AllOuts(BStC_Fzl(i,j)) = 0.001*m(i)%F_P(3,j) - AllOuts(BStC_Mxl(i,j)) = 0.001*m(i)%M_P(1,j) - AllOuts(BStC_Myl(i,j)) = 0.001*m(i)%M_P(2,j) - AllOuts(BStC_Mzl(i,j)) = 0.001*m(i)%M_P(3,j) - enddo + do i=1,min(p_SrvD%NumBStC,MaxStC) ! in case we have more Blade StCs than the outputs are set for + call Set_BStC_Outs_Instance( i, p_SrvD%numBl, x(i), m(i), y(i), AllOuts ) enddo endif end subroutine Set_BStC_Outs !--------------------------- +subroutine Set_BStC_Outs_Instance( i, numBl, x, m, y, AllOuts ) ! Single StC on all blades + integer(IntKi), intent(in ) :: i ! This instance + integer(IntKi), intent(in ) :: numBl ! number of blades + type(StC_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(StC_MiscVarType), intent(in ) :: m !< Misc (optimization) variables + type(StC_OutputType), intent(in ) :: y !< Outputs computed at Time + real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels + integer :: j + if (i < MaxStC) then + do j=1,min(NumBl,MaxBlOuts) + AllOuts(BStC_XQ( i,j)) = x%StC_x(1,j) ! x + AllOuts(BStC_XQD(i,j)) = x%StC_x(2,j) ! x-dot + AllOuts(BStC_YQ( i,j)) = x%StC_x(3,j) ! y + AllOuts(BStC_YQD(i,j)) = x%StC_x(4,j) ! y-dot + AllOuts(BStC_ZQ( i,j)) = x%StC_x(5,j) ! z + AllOuts(BStC_ZQD(i,j)) = x%StC_x(6,j) ! z-dot + AllOuts(BStC_Fxi(i,j)) = 0.001*y%Mesh(j)%Force(1,1) ! only one mesh per BStC instance + AllOuts(BStC_Fyi(i,j)) = 0.001*y%Mesh(j)%Force(2,1) ! only one mesh per BStC instance + AllOuts(BStC_Fzi(i,j)) = 0.001*y%Mesh(j)%Force(3,1) ! only one mesh per BStC instance + AllOuts(BStC_Mxi(i,j)) = 0.001*y%Mesh(j)%Moment(1,1) ! only one mesh per BStC instance + AllOuts(BStC_Myi(i,j)) = 0.001*y%Mesh(j)%Moment(2,1) ! only one mesh per BStC instance + AllOuts(BStC_Mzi(i,j)) = 0.001*y%Mesh(j)%Moment(3,1) ! only one mesh per BStC instance + AllOuts(BStC_Fxl(i,j)) = 0.001*m%F_P(1,j) + AllOuts(BStC_Fyl(i,j)) = 0.001*m%F_P(2,j) + AllOuts(BStC_Fzl(i,j)) = 0.001*m%F_P(3,j) + AllOuts(BStC_Mxl(i,j)) = 0.001*m%M_P(1,j) + AllOuts(BStC_Myl(i,j)) = 0.001*m%M_P(2,j) + AllOuts(BStC_Mzl(i,j)) = 0.001*m%M_P(3,j) + enddo + endif +end subroutine Set_BStC_Outs_Instance +!--------------------------- subroutine Set_SStC_Outs( p_SrvD, x, m, y, AllOuts ) ! Platform type(SrvD_ParameterType), intent(in ) :: p_SrvD !< Parameters type(StC_ContinuousStateType), allocatable,intent(in ) :: x(:) !< Continuous states at t type(StC_MiscVarType), allocatable,intent(in ) :: m(:) !< Misc (optimization) variables type(StC_OutputType), allocatable,intent(in ) :: y(:) !< Outputs computed at Time real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels - integer :: i,j - j=1 + integer :: i if (allocated(x) .and. allocated(m) .and. allocated(y)) then do i=1,min(p_SrvD%NumSStC,MaxStC) ! in case we have more Nacelle StCs than the outputs are set for - AllOuts(SStC_XQ( i)) = x(i)%StC_x(1,1) ! x - AllOuts(SStC_XQD(i)) = x(i)%StC_x(2,1) ! x-dot - AllOuts(SStC_YQ( i)) = x(i)%StC_x(3,1) ! y - AllOuts(SStC_YQD(i)) = x(i)%StC_x(4,1) ! y-dot - AllOuts(SStC_ZQ( i)) = x(i)%StC_x(5,1) ! z - AllOuts(SStC_ZQD(i)) = x(i)%StC_x(6,1) ! z-dot - AllOuts(SStC_Fxi(i)) = 0.001*y(i)%Mesh(j)%Force(1,1) ! only one mesh per SStC instance - AllOuts(SStC_Fyi(i)) = 0.001*y(i)%Mesh(j)%Force(2,1) ! only one mesh per SStC instance - AllOuts(SStC_Fzi(i)) = 0.001*y(i)%Mesh(j)%Force(3,1) ! only one mesh per SStC instance - AllOuts(SStC_Mxi(i)) = 0.001*y(i)%Mesh(j)%Moment(1,1) ! only one mesh per SStC instance - AllOuts(SStC_Myi(i)) = 0.001*y(i)%Mesh(j)%Moment(2,1) ! only one mesh per SStC instance - AllOuts(SStC_Mzi(i)) = 0.001*y(i)%Mesh(j)%Moment(3,1) ! only one mesh per SStC instance - AllOuts(SStC_Fxl(i)) = 0.001*m(i)%F_P(1,j) - AllOuts(SStC_Fyl(i)) = 0.001*m(i)%F_P(2,j) - AllOuts(SStC_Fzl(i)) = 0.001*m(i)%F_P(3,j) - AllOuts(SStC_Mxl(i)) = 0.001*m(i)%M_P(1,j) - AllOuts(SStC_Myl(i)) = 0.001*m(i)%M_P(2,j) - AllOuts(SStC_Mzl(i)) = 0.001*m(i)%M_P(3,j) + call Set_SStC_Outs_Instance( i, x(i), m(i), y(i), AllOuts ) enddo endif end subroutine Set_SStC_Outs !--------------------------- +subroutine Set_SStC_Outs_Instance( i, x, m, y, AllOuts ) ! Platform + integer(IntKi), intent(in ) :: i ! This instance + type(StC_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(StC_MiscVarType), intent(in ) :: m !< Misc (optimization) variables + type(StC_OutputType), intent(in ) :: y !< Outputs computed at Time + real(ReKi), intent(inout) :: AllOuts(0:MaxOutPts) ! All the the available output channels + integer :: j + j=1 + if (i < MaxStC) then + AllOuts(SStC_XQ( i)) = x%StC_x(1,1) ! x + AllOuts(SStC_XQD(i)) = x%StC_x(2,1) ! x-dot + AllOuts(SStC_YQ( i)) = x%StC_x(3,1) ! y + AllOuts(SStC_YQD(i)) = x%StC_x(4,1) ! y-dot + AllOuts(SStC_ZQ( i)) = x%StC_x(5,1) ! z + AllOuts(SStC_ZQD(i)) = x%StC_x(6,1) ! z-dot + AllOuts(SStC_Fxi(i)) = 0.001*y%Mesh(j)%Force(1,1) ! only one mesh per SStC instance + AllOuts(SStC_Fyi(i)) = 0.001*y%Mesh(j)%Force(2,1) ! only one mesh per SStC instance + AllOuts(SStC_Fzi(i)) = 0.001*y%Mesh(j)%Force(3,1) ! only one mesh per SStC instance + AllOuts(SStC_Mxi(i)) = 0.001*y%Mesh(j)%Moment(1,1) ! only one mesh per SStC instance + AllOuts(SStC_Myi(i)) = 0.001*y%Mesh(j)%Moment(2,1) ! only one mesh per SStC instance + AllOuts(SStC_Mzi(i)) = 0.001*y%Mesh(j)%Moment(3,1) ! only one mesh per SStC instance + AllOuts(SStC_Fxl(i)) = 0.001*m%F_P(1,j) + AllOuts(SStC_Fyl(i)) = 0.001*m%F_P(2,j) + AllOuts(SStC_Fzl(i)) = 0.001*m%F_P(3,j) + AllOuts(SStC_Mxl(i)) = 0.001*m%M_P(1,j) + AllOuts(SStC_Myl(i)) = 0.001*m%M_P(2,j) + AllOuts(SStC_Mzl(i)) = 0.001*m%M_P(3,j) + endif +end subroutine Set_SStC_Outs_Instance +!--------------------------- !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine parses the input file and stores all the data in the SrvD_InputFile structure. @@ -2319,7 +2368,7 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) IF ( Indx > 0 ) THEN ! we found the channel name IF ( InvalidOutput( ParamIndxAry(Indx) ) ) THEN ! but, it isn't valid for these settings - p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) + p%OutParam(I)%Indx = ParamIndxAry(Indx) ! don't reset the index -- causes issues in linearization p%OutParam(I)%Units = "INVALID" p%OutParam(I)%SignM = 0 ELSE diff --git a/modules/servodyn/src/ServoDyn_Registry.txt b/modules/servodyn/src/ServoDyn_Registry.txt index 7b145279fc..7cc14b7d4c 100644 --- a/modules/servodyn/src/ServoDyn_Registry.txt +++ b/modules/servodyn/src/ServoDyn_Registry.txt @@ -59,16 +59,20 @@ typedef ^ InitInputType ReKi fromSC {:} - - "Initial turbine specific inputs to # 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 IntKi CouplingScheme - - - "Switch that indicates if a particular coupling scheme is required" - -typedef ^ InitOutputType Logical UseHSSBrake - - - "flag to determine if high-speed shaft brake is potentially used (true=yes)" - -typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_y {:} - - "Names of the outputs used in linearization" - -typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_u {:} - - "Names of the inputs used in linearization" - -typedef ^ InitOutputType LOGICAL RotFrame_y {:} - - "Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame" - -typedef ^ InitOutputType LOGICAL RotFrame_u {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - -typedef ^ InitOutputType LOGICAL IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - +typedef ^ InitOutputType 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 IntKi CouplingScheme - - - "Switch that indicates if a particular coupling scheme is required" - +typedef ^ InitOutputType Logical UseHSSBrake - - - "flag to determine if high-speed shaft brake is potentially used (true=yes)" - +# Linearization +typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_y {:} - - "Names of the outputs used in linearization" - +typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_x {:} - - "Names of the states used in linearization" - +typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_u {:} - - "Names of the inputs used in linearization" - +typedef ^ InitOutputType LOGICAL RotFrame_y {:} - - "Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame" - +typedef ^ InitOutputType LOGICAL RotFrame_x {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - +typedef ^ InitOutputType LOGICAL RotFrame_u {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - +typedef ^ InitOutputType LOGICAL IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - +typedef ^ InitOutputType IntKi DerivOrder_x {:} - - "Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization" - # ..... Input file data ........................................................................................................... # This is data defined in the Input File for this module (or could otherwise be passed in) @@ -148,7 +152,7 @@ typedef ^ SrvD_InputFile IntKi DLL_NumTrq - - - "Record 26: No. of points in tor typedef ^ SrvD_InputFile ReKi GenSpd_TLU {:} - - "Records R:2:R+2*DLL_NumTrq-2: Generator speed values in look-up table [used only with DLL Interface]" rad/s typedef ^ SrvD_InputFile ReKi GenTrq_TLU {:} - - "Records R+1:2:R+2*DLL_NumTrq-1: Generator torque values in look-up table [used only with DLL Interface]" Nm typedef ^ SrvD_InputFile LOGICAL UseLegacyInterface - - - "Flag that determines if the legacy Bladed interface is (legacy=DISCON with avrSWAP instead of CONTROLLER)" - - +# StC input files/instances typedef ^ SrvD_InputFile IntKi NumBStC - - - "Number of blade structural controllers (integer)" - typedef ^ SrvD_InputFile CHARACTER(1024) BStCfiles {:} - - "Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0]" - typedef ^ SrvD_InputFile IntKi NumNStC - - - "Number of nacelle structural controllers (integer)" - @@ -157,14 +161,14 @@ typedef ^ SrvD_InputFile IntKi NumTStC - - - "Number of tower structural control typedef ^ SrvD_InputFile CHARACTER(1024) TStCfiles {:} - - "Name of the files for tower structural controllers (quoted strings) [unused when NumTStC==0]" - typedef ^ SrvD_InputFile IntKi NumSStC - - - "Number of substructure structural controllers (integer)" - typedef ^ SrvD_InputFile CHARACTER(1024) SStCfiles {:} - - "Name of the files for subtructure structural controllers (quoted strings) [unused when NumSStC==0]" - - +# Airfoil control typedef ^ SrvD_InputFile IntKi AfCmode - - - "Airfoil control mode {0: none, 1: sine wave cycle, 4: user-defined from Simulink/Labview, 5: user-defined from Bladed-style DLL}" - typedef ^ SrvD_InputFile ReKi AfC_Mean - - - "Mean level for cosine cycling or steady value [used only with AfCmode==1]" - typedef ^ SrvD_InputFile ReKi AfC_Amp - - - "Amplitude for for cosine cycling of flap signal (-) [used only with AfCmode==1]" - typedef ^ SrvD_InputFile ReKi AfC_Phase - - - "Phase relative to the blade azimuth (0 is vertical) for for cosine cycling of flap signal (deg) [used only with AfCmode==1]" deg - +# cable control typedef ^ SrvD_InputFile IntKi CCmode - - - "Cable control control mode {0: none, 4: user-defined from Simulink/Labview, 5: user-defined from Bladed-style DLL}" - - +# extended avrSWAP (this is currently hard coded to true in the input parsing -- left this in case we run into issues and need to make it an input file option typedef ^ SrvD_InputFile Logical EXavrSWAP - - - "Use extendend AVR swap" - # ..... Data for using Bladed DLLs ....................................................................................................... @@ -219,6 +223,9 @@ typedef ^ BladedDLLType ReKi RotPwr - - - "Rotor power (this is equivalent to th typedef ^ BladedDLLType ReKi LSSTipMxa - - - "Rotating low-speed shaft bending moment at the shaft tip (teeter pin for 2-blader, apex of rotation for 3-blader)" N-m typedef ^ BladedDLLType ReKi RootMyc 3 - - "Out-of-plane moment (i.e., the moment caused by out-of-plane forces) at the blade root for each of the blades (max 3)" N-m typedef ^ BladedDLLType ReKi RootMxc 3 - - "In-plane moment (i.e., the moment caused by in-plane forces) at the blade root" N-m +typedef ^ BladedDLLType ReKi LSShftFxa - - - "Rotating low-speed shaft force x" N +typedef ^ BladedDLLType ReKi LSShftFys - - - "Nonrotating low-speed shaft force y" N +typedef ^ BladedDLLType ReKi LSShftFzs - - - "Nonrotating low-speed shaft force z" N ## these are PARAMETERS sent to the DLL (THEIR VALUES SHOULD NOT CHANGE DURING SIMULATION): typedef ^ BladedDLLType DbKi DLL_DT - - - "interval for calling DLL (integer multiple number of DT)" s typedef ^ BladedDLLType CHARACTER(1024) DLL_InFile - - - "Name of input file used in DLL" - @@ -442,6 +449,28 @@ typedef ^ ParameterType IntKi NumCableControl - - - "Number of cable control cha typedef ^ ParameterType IntKi NumStC_Control - - - "Number of cable StC channels requested" - typedef ^ ParameterType IntKi StCMeasNumPerChan {:} - - "Number of cable StC channel to average on each control channel sent to DLL" - typedef ^ ParameterType LOGICAL UseSC - - - "Supercontroller on/off flag" - +# parameters for linearization +typedef ^ ParameterType Integer Jac_u_indx {:}{:} - - "matrix to help fill/pack the u vector in computing the jacobian" - +typedef ^ ParameterType Integer Jac_x_indx {:}{:} - - "matrix to help fill/pack the x vector in computing the jacobian" - +typedef ^ ParameterType R8Ki du {:} - - "vector that determines size of perturbation for u (inputs)" +typedef ^ ParameterType ReKi dx {:} - - "vector that determines size of perturbation for x (continuous states)" +typedef ^ ParameterType Integer Jac_nu - - - "number of inputs in jacobian matrix" - +typedef ^ ParameterType Integer Jac_ny - - - "number of outputs in jacobian matrix" - +typedef ^ ParameterType Integer Jac_nx - - - "the number of continuous states in jacobian matrix" - +typedef ^ ParameterType Integer Jac_Idx_BStC_u {:}{:}{:} - - "the start and end indices of blade StC u jacobian [ start/end, blade, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_NStC_u {:}{:} - - "the start and end indices of nacelle StC u jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_TStC_u {:}{:} - - "the start and end indices of tower StC u jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_SStC_u {:}{:} - - "the start and end indices of substructure StC u jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_BStC_x {:}{:}{:} - - "the start and end indices of blade StC x jacobian [ start/end, blade, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_NStC_x {:}{:} - - "the start and end indices of nacelle StC x jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_TStC_x {:}{:} - - "the start and end indices of tower StC x jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_SStC_x {:}{:} - - "the start and end indices of substructure StC x jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_BStC_y {:}{:}{:} - - "the start and end indices of blade StC y jacobian [ start/end, blade, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_NStC_y {:}{:} - - "the start and end indices of nacelle StC y jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_TStC_y {:}{:} - - "the start and end indices of tower StC y jacobian [ start/end, instance ]" - +typedef ^ ParameterType Integer Jac_Idx_SStC_y {:}{:} - - "the start and end indices of substructure StC y jacobian [ start/end, instance ]" - + + # ..... Inputs .................................................................................................................... # Define inputs that are not on this mesh here: @@ -481,6 +510,9 @@ typedef ^ InputType ReKi NcIMURAzs - - - "Nacelle inertial measurement unit angu typedef ^ InputType ReKi RotPwr - - - "Rotor power (this is equivalent to the low-speed shaft power)" W typedef ^ InputType ReKi HorWindV - - - "Horizontal hub-height wind velocity magnitude" m/s typedef ^ InputType ReKi YawAngle - - 2pi "Estimate of yaw (nacelle + platform)" radians +typedef ^ InputType ReKi LSShftFxa - - - "Rotating low-speed shaft force x" N +typedef ^ InputType ReKi LSShftFys - - - "Nonrotating low-speed shaft force y" N +typedef ^ InputType ReKi LSShftFzs - - - "Nonrotating low-speed shaft force z" N typedef ^ InputType SiKi fromSC {:} - - "A swap array: used to pass turbine specific input data to the DLL controller from the supercontroller" - typedef ^ InputType SiKi fromSCglob {:} - - "A swap array: used to pass global input data to the DLL controller from the supercontroller" - typedef ^ InputType SiKi Lidar {:} - - "A swap array: used to pass input data to the DLL controller from the Lidar" - diff --git a/modules/servodyn/src/ServoDyn_Types.f90 b/modules/servodyn/src/ServoDyn_Types.f90 index ba93e4640d..801601b2e3 100644 --- a/modules/servodyn/src/ServoDyn_Types.f90 +++ b/modules/servodyn/src/ServoDyn_Types.f90 @@ -84,10 +84,13 @@ MODULE ServoDyn_Types INTEGER(IntKi) :: CouplingScheme !< Switch that indicates if a particular coupling scheme is required [-] LOGICAL :: UseHSSBrake !< flag to determine if high-speed shaft brake is potentially used (true=yes) [-] CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_y !< Names of the outputs used in linearization [-] + CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_x !< Names of the 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 inputs 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 SrvD_InitOutputType ! ======================= ! ========= SrvD_InputFile ======= @@ -233,6 +236,9 @@ MODULE ServoDyn_Types REAL(ReKi) :: LSSTipMxa !< Rotating low-speed shaft bending moment at the shaft tip (teeter pin for 2-blader, apex of rotation for 3-blader) [N-m] REAL(ReKi) , DIMENSION(1:3) :: RootMyc !< Out-of-plane moment (i.e., the moment caused by out-of-plane forces) at the blade root for each of the blades (max 3) [N-m] REAL(ReKi) , DIMENSION(1:3) :: RootMxc !< In-plane moment (i.e., the moment caused by in-plane forces) at the blade root [N-m] + REAL(ReKi) :: LSShftFxa !< Rotating low-speed shaft force x [N] + REAL(ReKi) :: LSShftFys !< Nonrotating low-speed shaft force y [N] + REAL(ReKi) :: LSShftFzs !< Nonrotating low-speed shaft force z [N] REAL(DbKi) :: DLL_DT !< interval for calling DLL (integer multiple number of DT) [s] CHARACTER(1024) :: DLL_InFile !< Name of input file used in DLL [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] @@ -451,6 +457,25 @@ MODULE ServoDyn_Types INTEGER(IntKi) :: NumStC_Control !< Number of cable StC channels requested [-] INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: StCMeasNumPerChan !< Number of cable StC channel to average on each control channel sent to DLL [-] LOGICAL :: UseSC !< Supercontroller on/off flag [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_u_indx !< matrix to help fill/pack the u vector in computing the jacobian [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_x_indx !< matrix to help fill/pack the x vector in computing the jacobian [-] + REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: du !< vector that determines size of perturbation for u (inputs) [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: dx !< vector that determines size of perturbation for x (continuous states) [-] + INTEGER(IntKi) :: Jac_nu !< number of inputs in jacobian matrix [-] + INTEGER(IntKi) :: Jac_ny !< number of outputs in jacobian matrix [-] + INTEGER(IntKi) :: Jac_nx !< the number of continuous states in jacobian matrix [-] + INTEGER(IntKi) , DIMENSION(:,:,:), ALLOCATABLE :: Jac_Idx_BStC_u !< the start and end indices of blade StC u jacobian [ start/end, blade, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_NStC_u !< the start and end indices of nacelle StC u jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_TStC_u !< the start and end indices of tower StC u jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_SStC_u !< the start and end indices of substructure StC u jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:,:), ALLOCATABLE :: Jac_Idx_BStC_x !< the start and end indices of blade StC x jacobian [ start/end, blade, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_NStC_x !< the start and end indices of nacelle StC x jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_TStC_x !< the start and end indices of tower StC x jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_SStC_x !< the start and end indices of substructure StC x jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:,:), ALLOCATABLE :: Jac_Idx_BStC_y !< the start and end indices of blade StC y jacobian [ start/end, blade, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_NStC_y !< the start and end indices of nacelle StC y jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_TStC_y !< the start and end indices of tower StC y jacobian [ start/end, instance ] [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_Idx_SStC_y !< the start and end indices of substructure StC y jacobian [ start/end, instance ] [-] END TYPE SrvD_ParameterType ! ======================= ! ========= SrvD_InputType ======= @@ -491,6 +516,9 @@ MODULE ServoDyn_Types REAL(ReKi) :: RotPwr !< Rotor power (this is equivalent to the low-speed shaft power) [W] REAL(ReKi) :: HorWindV !< Horizontal hub-height wind velocity magnitude [m/s] REAL(ReKi) :: YawAngle !< Estimate of yaw (nacelle + platform) [radians] + REAL(ReKi) :: LSShftFxa !< Rotating low-speed shaft force x [N] + REAL(ReKi) :: LSShftFys !< Nonrotating low-speed shaft force y [N] + REAL(ReKi) :: LSShftFzs !< Nonrotating low-speed shaft force z [N] REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: fromSC !< A swap array: used to pass turbine specific input data to the DLL controller from the supercontroller [-] REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: fromSCglob !< A swap array: used to pass global input data to the DLL controller from the supercontroller [-] REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: Lidar !< A swap array: used to pass input data to the DLL controller from the Lidar [-] @@ -1589,6 +1617,18 @@ SUBROUTINE SrvD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, END IF DstInitOutputData%LinNames_y = SrcInitOutputData%LinNames_y ENDIF +IF (ALLOCATED(SrcInitOutputData%LinNames_x)) THEN + i1_l = LBOUND(SrcInitOutputData%LinNames_x,1) + i1_u = UBOUND(SrcInitOutputData%LinNames_x,1) + IF (.NOT. ALLOCATED(DstInitOutputData%LinNames_x)) THEN + ALLOCATE(DstInitOutputData%LinNames_x(i1_l:i1_u),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 +ENDIF IF (ALLOCATED(SrcInitOutputData%LinNames_u)) THEN i1_l = LBOUND(SrcInitOutputData%LinNames_u,1) i1_u = UBOUND(SrcInitOutputData%LinNames_u,1) @@ -1613,6 +1653,18 @@ SUBROUTINE SrvD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, END IF DstInitOutputData%RotFrame_y = SrcInitOutputData%RotFrame_y ENDIF +IF (ALLOCATED(SrcInitOutputData%RotFrame_x)) THEN + i1_l = LBOUND(SrcInitOutputData%RotFrame_x,1) + i1_u = UBOUND(SrcInitOutputData%RotFrame_x,1) + IF (.NOT. ALLOCATED(DstInitOutputData%RotFrame_x)) THEN + ALLOCATE(DstInitOutputData%RotFrame_x(i1_l:i1_u),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 +ENDIF IF (ALLOCATED(SrcInitOutputData%RotFrame_u)) THEN i1_l = LBOUND(SrcInitOutputData%RotFrame_u,1) i1_u = UBOUND(SrcInitOutputData%RotFrame_u,1) @@ -1636,6 +1688,18 @@ SUBROUTINE SrvD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, END IF END IF DstInitOutputData%IsLoad_u = SrcInitOutputData%IsLoad_u +ENDIF +IF (ALLOCATED(SrcInitOutputData%DerivOrder_x)) THEN + i1_l = LBOUND(SrcInitOutputData%DerivOrder_x,1) + i1_u = UBOUND(SrcInitOutputData%DerivOrder_x,1) + IF (.NOT. ALLOCATED(DstInitOutputData%DerivOrder_x)) THEN + ALLOCATE(DstInitOutputData%DerivOrder_x(i1_l:i1_u),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 ENDIF END SUBROUTINE SrvD_CopyInitOutput @@ -1658,17 +1722,26 @@ SUBROUTINE SrvD_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) IF (ALLOCATED(InitOutputData%LinNames_y)) THEN DEALLOCATE(InitOutputData%LinNames_y) ENDIF +IF (ALLOCATED(InitOutputData%LinNames_x)) THEN + DEALLOCATE(InitOutputData%LinNames_x) +ENDIF IF (ALLOCATED(InitOutputData%LinNames_u)) THEN DEALLOCATE(InitOutputData%LinNames_u) ENDIF IF (ALLOCATED(InitOutputData%RotFrame_y)) THEN DEALLOCATE(InitOutputData%RotFrame_y) ENDIF +IF (ALLOCATED(InitOutputData%RotFrame_x)) THEN + DEALLOCATE(InitOutputData%RotFrame_x) +ENDIF IF (ALLOCATED(InitOutputData%RotFrame_u)) THEN DEALLOCATE(InitOutputData%RotFrame_u) ENDIF IF (ALLOCATED(InitOutputData%IsLoad_u)) THEN DEALLOCATE(InitOutputData%IsLoad_u) +ENDIF +IF (ALLOCATED(InitOutputData%DerivOrder_x)) THEN + DEALLOCATE(InitOutputData%DerivOrder_x) ENDIF END SUBROUTINE SrvD_DestroyInitOutput @@ -1742,6 +1815,11 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + 2*1 ! LinNames_y upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%LinNames_y)*LEN(InData%LinNames_y) ! LinNames_y END IF + Int_BufSz = Int_BufSz + 1 ! LinNames_x allocated yes/no + IF ( ALLOCATED(InData%LinNames_x) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! LinNames_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%LinNames_x)*LEN(InData%LinNames_x) ! LinNames_x + END IF Int_BufSz = Int_BufSz + 1 ! LinNames_u allocated yes/no IF ( ALLOCATED(InData%LinNames_u) ) THEN Int_BufSz = Int_BufSz + 2*1 ! LinNames_u upper/lower bounds for each dimension @@ -1752,6 +1830,11 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + 2*1 ! RotFrame_y upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%RotFrame_y) ! RotFrame_y END IF + Int_BufSz = Int_BufSz + 1 ! RotFrame_x allocated yes/no + IF ( ALLOCATED(InData%RotFrame_x) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! RotFrame_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%RotFrame_x) ! RotFrame_x + END IF Int_BufSz = Int_BufSz + 1 ! RotFrame_u allocated yes/no IF ( ALLOCATED(InData%RotFrame_u) ) THEN Int_BufSz = Int_BufSz + 2*1 ! RotFrame_u upper/lower bounds for each dimension @@ -1762,6 +1845,11 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + 2*1 ! IsLoad_u upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%IsLoad_u) ! IsLoad_u END IF + Int_BufSz = Int_BufSz + 1 ! DerivOrder_x allocated yes/no + IF ( ALLOCATED(InData%DerivOrder_x) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! DerivOrder_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%DerivOrder_x) ! DerivOrder_x + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1872,6 +1960,23 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err END DO ! I END DO END IF + IF ( .NOT. ALLOCATED(InData%LinNames_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%LinNames_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%LinNames_x,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%LinNames_x,1), UBOUND(InData%LinNames_x,1) + DO I = 1, LEN(InData%LinNames_x) + IntKiBuf(Int_Xferred) = ICHAR(InData%LinNames_x(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF IF ( .NOT. ALLOCATED(InData%LinNames_u) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -1904,6 +2009,21 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_Xferred = Int_Xferred + 1 END DO END IF + IF ( .NOT. ALLOCATED(InData%RotFrame_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%RotFrame_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RotFrame_x,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%RotFrame_x,1), UBOUND(InData%RotFrame_x,1) + IntKiBuf(Int_Xferred) = TRANSFER(InData%RotFrame_x(i1), IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END DO + END IF IF ( .NOT. ALLOCATED(InData%RotFrame_u) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -1934,6 +2054,21 @@ SUBROUTINE SrvD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_Xferred = Int_Xferred + 1 END DO END IF + IF ( .NOT. ALLOCATED(InData%DerivOrder_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%DerivOrder_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%DerivOrder_x,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%DerivOrder_x,1), UBOUND(InData%DerivOrder_x,1) + IntKiBuf(Int_Xferred) = InData%DerivOrder_x(i1) + Int_Xferred = Int_Xferred + 1 + END DO + END IF END SUBROUTINE SrvD_PackInitOutput SUBROUTINE SrvD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -2067,6 +2202,26 @@ SUBROUTINE SrvD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, END DO ! I END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! LinNames_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%LinNames_x)) DEALLOCATE(OutData%LinNames_x) + ALLOCATE(OutData%LinNames_x(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%LinNames_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%LinNames_x,1), UBOUND(OutData%LinNames_x,1) + DO I = 1, LEN(OutData%LinNames_x) + OutData%LinNames_x(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! LinNames_u not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -2105,6 +2260,24 @@ SUBROUTINE SrvD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Xferred = Int_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RotFrame_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%RotFrame_x)) DEALLOCATE(OutData%RotFrame_x) + ALLOCATE(OutData%RotFrame_x(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RotFrame_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%RotFrame_x,1), UBOUND(OutData%RotFrame_x,1) + OutData%RotFrame_x(i1) = TRANSFER(IntKiBuf(Int_Xferred), OutData%RotFrame_x(i1)) + Int_Xferred = Int_Xferred + 1 + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RotFrame_u not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -2141,6 +2314,24 @@ SUBROUTINE SrvD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Xferred = Int_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! DerivOrder_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%DerivOrder_x)) DEALLOCATE(OutData%DerivOrder_x) + ALLOCATE(OutData%DerivOrder_x(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%DerivOrder_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%DerivOrder_x,1), UBOUND(OutData%DerivOrder_x,1) + OutData%DerivOrder_x(i1) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END IF END SUBROUTINE SrvD_UnPackInitOutput SUBROUTINE SrvD_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) @@ -3294,6 +3485,9 @@ SUBROUTINE SrvD_CopyBladedDLLType( SrcBladedDLLTypeData, DstBladedDLLTypeData, C DstBladedDLLTypeData%LSSTipMxa = SrcBladedDLLTypeData%LSSTipMxa DstBladedDLLTypeData%RootMyc = SrcBladedDLLTypeData%RootMyc DstBladedDLLTypeData%RootMxc = SrcBladedDLLTypeData%RootMxc + DstBladedDLLTypeData%LSShftFxa = SrcBladedDLLTypeData%LSShftFxa + DstBladedDLLTypeData%LSShftFys = SrcBladedDLLTypeData%LSShftFys + DstBladedDLLTypeData%LSShftFzs = SrcBladedDLLTypeData%LSShftFzs DstBladedDLLTypeData%DLL_DT = SrcBladedDLLTypeData%DLL_DT DstBladedDLLTypeData%DLL_InFile = SrcBladedDLLTypeData%DLL_InFile DstBladedDLLTypeData%RootName = SrcBladedDLLTypeData%RootName @@ -3726,6 +3920,9 @@ SUBROUTINE SrvD_PackBladedDLLType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_BufSz = Re_BufSz + 1 ! LSSTipMxa Re_BufSz = Re_BufSz + SIZE(InData%RootMyc) ! RootMyc Re_BufSz = Re_BufSz + SIZE(InData%RootMxc) ! RootMxc + Re_BufSz = Re_BufSz + 1 ! LSShftFxa + Re_BufSz = Re_BufSz + 1 ! LSShftFys + Re_BufSz = Re_BufSz + 1 ! LSShftFzs Db_BufSz = Db_BufSz + 1 ! DLL_DT Int_BufSz = Int_BufSz + 1*LEN(InData%DLL_InFile) ! DLL_InFile Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName @@ -4055,6 +4252,12 @@ SUBROUTINE SrvD_PackBladedDLLType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ReKiBuf(Re_Xferred) = InData%RootMxc(i1) Re_Xferred = Re_Xferred + 1 END DO + ReKiBuf(Re_Xferred) = InData%LSShftFxa + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFys + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFzs + Re_Xferred = Re_Xferred + 1 DbKiBuf(Db_Xferred) = InData%DLL_DT Db_Xferred = Db_Xferred + 1 DO I = 1, LEN(InData%DLL_InFile) @@ -4657,6 +4860,12 @@ SUBROUTINE SrvD_UnPackBladedDLLType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta OutData%RootMxc(i1) = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 END DO + OutData%LSShftFxa = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFys = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFzs = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 OutData%DLL_DT = DbKiBuf(Db_Xferred) Db_Xferred = Db_Xferred + 1 DO I = 1, LEN(OutData%DLL_InFile) @@ -11627,6 +11836,8 @@ SUBROUTINE SrvD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ! Local INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_CopyParam' @@ -11873,6 +12084,235 @@ SUBROUTINE SrvD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg DstParamData%StCMeasNumPerChan = SrcParamData%StCMeasNumPerChan ENDIF DstParamData%UseSC = SrcParamData%UseSC +IF (ALLOCATED(SrcParamData%Jac_u_indx)) THEN + i1_l = LBOUND(SrcParamData%Jac_u_indx,1) + i1_u = UBOUND(SrcParamData%Jac_u_indx,1) + i2_l = LBOUND(SrcParamData%Jac_u_indx,2) + i2_u = UBOUND(SrcParamData%Jac_u_indx,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_u_indx)) THEN + ALLOCATE(DstParamData%Jac_u_indx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_u_indx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_u_indx = SrcParamData%Jac_u_indx +ENDIF +IF (ALLOCATED(SrcParamData%Jac_x_indx)) THEN + i1_l = LBOUND(SrcParamData%Jac_x_indx,1) + i1_u = UBOUND(SrcParamData%Jac_x_indx,1) + i2_l = LBOUND(SrcParamData%Jac_x_indx,2) + i2_u = UBOUND(SrcParamData%Jac_x_indx,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_x_indx)) THEN + ALLOCATE(DstParamData%Jac_x_indx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_x_indx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_x_indx = SrcParamData%Jac_x_indx +ENDIF +IF (ALLOCATED(SrcParamData%du)) THEN + i1_l = LBOUND(SrcParamData%du,1) + i1_u = UBOUND(SrcParamData%du,1) + IF (.NOT. ALLOCATED(DstParamData%du)) THEN + ALLOCATE(DstParamData%du(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%du.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%du = SrcParamData%du +ENDIF +IF (ALLOCATED(SrcParamData%dx)) THEN + i1_l = LBOUND(SrcParamData%dx,1) + i1_u = UBOUND(SrcParamData%dx,1) + IF (.NOT. ALLOCATED(DstParamData%dx)) THEN + ALLOCATE(DstParamData%dx(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%dx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%dx = SrcParamData%dx +ENDIF + DstParamData%Jac_nu = SrcParamData%Jac_nu + DstParamData%Jac_ny = SrcParamData%Jac_ny + DstParamData%Jac_nx = SrcParamData%Jac_nx +IF (ALLOCATED(SrcParamData%Jac_Idx_BStC_u)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_BStC_u,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_BStC_u,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_BStC_u,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_BStC_u,2) + i3_l = LBOUND(SrcParamData%Jac_Idx_BStC_u,3) + i3_u = UBOUND(SrcParamData%Jac_Idx_BStC_u,3) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_BStC_u)) THEN + ALLOCATE(DstParamData%Jac_Idx_BStC_u(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_BStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_BStC_u = SrcParamData%Jac_Idx_BStC_u +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_NStC_u)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_NStC_u,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_NStC_u,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_NStC_u,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_NStC_u,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_NStC_u)) THEN + ALLOCATE(DstParamData%Jac_Idx_NStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_NStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_NStC_u = SrcParamData%Jac_Idx_NStC_u +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_TStC_u)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_TStC_u,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_TStC_u,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_TStC_u,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_TStC_u,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_TStC_u)) THEN + ALLOCATE(DstParamData%Jac_Idx_TStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_TStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_TStC_u = SrcParamData%Jac_Idx_TStC_u +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_SStC_u)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_SStC_u,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_SStC_u,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_SStC_u,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_SStC_u,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_SStC_u)) THEN + ALLOCATE(DstParamData%Jac_Idx_SStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_SStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_SStC_u = SrcParamData%Jac_Idx_SStC_u +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_BStC_x)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_BStC_x,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_BStC_x,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_BStC_x,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_BStC_x,2) + i3_l = LBOUND(SrcParamData%Jac_Idx_BStC_x,3) + i3_u = UBOUND(SrcParamData%Jac_Idx_BStC_x,3) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_BStC_x)) THEN + ALLOCATE(DstParamData%Jac_Idx_BStC_x(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_BStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_BStC_x = SrcParamData%Jac_Idx_BStC_x +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_NStC_x)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_NStC_x,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_NStC_x,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_NStC_x,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_NStC_x,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_NStC_x)) THEN + ALLOCATE(DstParamData%Jac_Idx_NStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_NStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_NStC_x = SrcParamData%Jac_Idx_NStC_x +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_TStC_x)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_TStC_x,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_TStC_x,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_TStC_x,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_TStC_x,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_TStC_x)) THEN + ALLOCATE(DstParamData%Jac_Idx_TStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_TStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_TStC_x = SrcParamData%Jac_Idx_TStC_x +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_SStC_x)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_SStC_x,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_SStC_x,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_SStC_x,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_SStC_x,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_SStC_x)) THEN + ALLOCATE(DstParamData%Jac_Idx_SStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_SStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_SStC_x = SrcParamData%Jac_Idx_SStC_x +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_BStC_y)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_BStC_y,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_BStC_y,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_BStC_y,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_BStC_y,2) + i3_l = LBOUND(SrcParamData%Jac_Idx_BStC_y,3) + i3_u = UBOUND(SrcParamData%Jac_Idx_BStC_y,3) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_BStC_y)) THEN + ALLOCATE(DstParamData%Jac_Idx_BStC_y(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_BStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_BStC_y = SrcParamData%Jac_Idx_BStC_y +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_NStC_y)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_NStC_y,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_NStC_y,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_NStC_y,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_NStC_y,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_NStC_y)) THEN + ALLOCATE(DstParamData%Jac_Idx_NStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_NStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_NStC_y = SrcParamData%Jac_Idx_NStC_y +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_TStC_y)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_TStC_y,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_TStC_y,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_TStC_y,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_TStC_y,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_TStC_y)) THEN + ALLOCATE(DstParamData%Jac_Idx_TStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_TStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_TStC_y = SrcParamData%Jac_Idx_TStC_y +ENDIF +IF (ALLOCATED(SrcParamData%Jac_Idx_SStC_y)) THEN + i1_l = LBOUND(SrcParamData%Jac_Idx_SStC_y,1) + i1_u = UBOUND(SrcParamData%Jac_Idx_SStC_y,1) + i2_l = LBOUND(SrcParamData%Jac_Idx_SStC_y,2) + i2_u = UBOUND(SrcParamData%Jac_Idx_SStC_y,2) + IF (.NOT. ALLOCATED(DstParamData%Jac_Idx_SStC_y)) THEN + ALLOCATE(DstParamData%Jac_Idx_SStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Jac_Idx_SStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Jac_Idx_SStC_y = SrcParamData%Jac_Idx_SStC_y +ENDIF END SUBROUTINE SrvD_CopyParam SUBROUTINE SrvD_DestroyParam( ParamData, ErrStat, ErrMsg ) @@ -11932,6 +12372,54 @@ SUBROUTINE SrvD_DestroyParam( ParamData, ErrStat, ErrMsg ) ENDIF IF (ALLOCATED(ParamData%StCMeasNumPerChan)) THEN DEALLOCATE(ParamData%StCMeasNumPerChan) +ENDIF +IF (ALLOCATED(ParamData%Jac_u_indx)) THEN + DEALLOCATE(ParamData%Jac_u_indx) +ENDIF +IF (ALLOCATED(ParamData%Jac_x_indx)) THEN + DEALLOCATE(ParamData%Jac_x_indx) +ENDIF +IF (ALLOCATED(ParamData%du)) THEN + DEALLOCATE(ParamData%du) +ENDIF +IF (ALLOCATED(ParamData%dx)) THEN + DEALLOCATE(ParamData%dx) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_BStC_u)) THEN + DEALLOCATE(ParamData%Jac_Idx_BStC_u) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_NStC_u)) THEN + DEALLOCATE(ParamData%Jac_Idx_NStC_u) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_TStC_u)) THEN + DEALLOCATE(ParamData%Jac_Idx_TStC_u) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_SStC_u)) THEN + DEALLOCATE(ParamData%Jac_Idx_SStC_u) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_BStC_x)) THEN + DEALLOCATE(ParamData%Jac_Idx_BStC_x) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_NStC_x)) THEN + DEALLOCATE(ParamData%Jac_Idx_NStC_x) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_TStC_x)) THEN + DEALLOCATE(ParamData%Jac_Idx_TStC_x) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_SStC_x)) THEN + DEALLOCATE(ParamData%Jac_Idx_SStC_x) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_BStC_y)) THEN + DEALLOCATE(ParamData%Jac_Idx_BStC_y) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_NStC_y)) THEN + DEALLOCATE(ParamData%Jac_Idx_NStC_y) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_TStC_y)) THEN + DEALLOCATE(ParamData%Jac_Idx_TStC_y) +ENDIF +IF (ALLOCATED(ParamData%Jac_Idx_SStC_y)) THEN + DEALLOCATE(ParamData%Jac_Idx_SStC_y) ENDIF END SUBROUTINE SrvD_DestroyParam @@ -12220,6 +12708,89 @@ SUBROUTINE SrvD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + SIZE(InData%StCMeasNumPerChan) ! StCMeasNumPerChan END IF Int_BufSz = Int_BufSz + 1 ! UseSC + Int_BufSz = Int_BufSz + 1 ! Jac_u_indx allocated yes/no + IF ( ALLOCATED(InData%Jac_u_indx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_u_indx upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_u_indx) ! Jac_u_indx + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_x_indx allocated yes/no + IF ( ALLOCATED(InData%Jac_x_indx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_x_indx upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_x_indx) ! Jac_x_indx + END IF + Int_BufSz = Int_BufSz + 1 ! du allocated yes/no + IF ( ALLOCATED(InData%du) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! du upper/lower bounds for each dimension + Db_BufSz = Db_BufSz + SIZE(InData%du) ! du + END IF + Int_BufSz = Int_BufSz + 1 ! dx allocated yes/no + IF ( ALLOCATED(InData%dx) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! dx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%dx) ! dx + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_nu + Int_BufSz = Int_BufSz + 1 ! Jac_ny + Int_BufSz = Int_BufSz + 1 ! Jac_nx + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_BStC_u allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_BStC_u) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Jac_Idx_BStC_u upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_BStC_u) ! Jac_Idx_BStC_u + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_NStC_u allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_NStC_u) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_NStC_u upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_NStC_u) ! Jac_Idx_NStC_u + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_TStC_u allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_TStC_u) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_TStC_u upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_TStC_u) ! Jac_Idx_TStC_u + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_SStC_u allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_SStC_u) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_SStC_u upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_SStC_u) ! Jac_Idx_SStC_u + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_BStC_x allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_BStC_x) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Jac_Idx_BStC_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_BStC_x) ! Jac_Idx_BStC_x + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_NStC_x allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_NStC_x) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_NStC_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_NStC_x) ! Jac_Idx_NStC_x + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_TStC_x allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_TStC_x) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_TStC_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_TStC_x) ! Jac_Idx_TStC_x + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_SStC_x allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_SStC_x) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_SStC_x upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_SStC_x) ! Jac_Idx_SStC_x + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_BStC_y allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_BStC_y) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Jac_Idx_BStC_y upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_BStC_y) ! Jac_Idx_BStC_y + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_NStC_y allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_NStC_y) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_NStC_y upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_NStC_y) ! Jac_Idx_NStC_y + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_TStC_y allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_TStC_y) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_TStC_y upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_TStC_y) ! Jac_Idx_TStC_y + END IF + Int_BufSz = Int_BufSz + 1 ! Jac_Idx_SStC_y allocated yes/no + IF ( ALLOCATED(InData%Jac_Idx_SStC_y) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Jac_Idx_SStC_y upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%Jac_Idx_SStC_y) ! Jac_Idx_SStC_y + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -12748,62 +13319,395 @@ SUBROUTINE SrvD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, END IF IntKiBuf(Int_Xferred) = TRANSFER(InData%UseSC, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - END SUBROUTINE SrvD_PackParam + IF ( .NOT. ALLOCATED(InData%Jac_u_indx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_u_indx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_u_indx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_u_indx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_u_indx,2) + Int_Xferred = Int_Xferred + 2 - SUBROUTINE SrvD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) - REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(SrvD_ParameterType), INTENT(INOUT) :: OutData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - ! Local variables - INTEGER(IntKi) :: Buf_size - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_UnPackParam' - ! buffers to store meshes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - OutData%DT = DbKiBuf(Db_Xferred) - Db_Xferred = Db_Xferred + 1 - OutData%HSSBrDT = DbKiBuf(Db_Xferred) - Db_Xferred = Db_Xferred + 1 - OutData%HSSBrTqF = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SIG_POSl = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SIG_POTq = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SIG_SlPc = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SIG_Slop = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SIG_SySp = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_A0 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_C0 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_C1 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_C2 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_K2 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%TEC_MR = ReKiBuf(Re_Xferred) + DO i2 = LBOUND(InData%Jac_u_indx,2), UBOUND(InData%Jac_u_indx,2) + DO i1 = LBOUND(InData%Jac_u_indx,1), UBOUND(InData%Jac_u_indx,1) + IntKiBuf(Int_Xferred) = InData%Jac_u_indx(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_x_indx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_x_indx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_x_indx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_x_indx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_x_indx,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_x_indx,2), UBOUND(InData%Jac_x_indx,2) + DO i1 = LBOUND(InData%Jac_x_indx,1), UBOUND(InData%Jac_x_indx,1) + IntKiBuf(Int_Xferred) = InData%Jac_x_indx(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%du) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%du,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%du,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%du,1), UBOUND(InData%du,1) + DbKiBuf(Db_Xferred) = InData%du(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%dx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dx,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%dx,1), UBOUND(InData%dx,1) + ReKiBuf(Re_Xferred) = InData%dx(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IntKiBuf(Int_Xferred) = InData%Jac_nu + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%Jac_ny + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%Jac_nx + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%Jac_Idx_BStC_u) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_u,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_u,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_u,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_u,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_u,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_u,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Jac_Idx_BStC_u,3), UBOUND(InData%Jac_Idx_BStC_u,3) + DO i2 = LBOUND(InData%Jac_Idx_BStC_u,2), UBOUND(InData%Jac_Idx_BStC_u,2) + DO i1 = LBOUND(InData%Jac_Idx_BStC_u,1), UBOUND(InData%Jac_Idx_BStC_u,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_BStC_u(i1,i2,i3) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_NStC_u) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_u,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_u,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_u,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_u,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_NStC_u,2), UBOUND(InData%Jac_Idx_NStC_u,2) + DO i1 = LBOUND(InData%Jac_Idx_NStC_u,1), UBOUND(InData%Jac_Idx_NStC_u,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_NStC_u(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_TStC_u) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_u,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_u,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_u,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_u,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_TStC_u,2), UBOUND(InData%Jac_Idx_TStC_u,2) + DO i1 = LBOUND(InData%Jac_Idx_TStC_u,1), UBOUND(InData%Jac_Idx_TStC_u,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_TStC_u(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_SStC_u) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_u,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_u,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_u,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_u,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_SStC_u,2), UBOUND(InData%Jac_Idx_SStC_u,2) + DO i1 = LBOUND(InData%Jac_Idx_SStC_u,1), UBOUND(InData%Jac_Idx_SStC_u,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_SStC_u(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_BStC_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_x,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_x,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_x,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_x,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_x,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Jac_Idx_BStC_x,3), UBOUND(InData%Jac_Idx_BStC_x,3) + DO i2 = LBOUND(InData%Jac_Idx_BStC_x,2), UBOUND(InData%Jac_Idx_BStC_x,2) + DO i1 = LBOUND(InData%Jac_Idx_BStC_x,1), UBOUND(InData%Jac_Idx_BStC_x,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_BStC_x(i1,i2,i3) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_NStC_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_x,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_x,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_x,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_NStC_x,2), UBOUND(InData%Jac_Idx_NStC_x,2) + DO i1 = LBOUND(InData%Jac_Idx_NStC_x,1), UBOUND(InData%Jac_Idx_NStC_x,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_NStC_x(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_TStC_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_x,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_x,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_x,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_TStC_x,2), UBOUND(InData%Jac_Idx_TStC_x,2) + DO i1 = LBOUND(InData%Jac_Idx_TStC_x,1), UBOUND(InData%Jac_Idx_TStC_x,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_TStC_x(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_SStC_x) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_x,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_x,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_x,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_x,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_SStC_x,2), UBOUND(InData%Jac_Idx_SStC_x,2) + DO i1 = LBOUND(InData%Jac_Idx_SStC_x,1), UBOUND(InData%Jac_Idx_SStC_x,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_SStC_x(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_BStC_y) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_y,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_y,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_y,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_y,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_BStC_y,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_BStC_y,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Jac_Idx_BStC_y,3), UBOUND(InData%Jac_Idx_BStC_y,3) + DO i2 = LBOUND(InData%Jac_Idx_BStC_y,2), UBOUND(InData%Jac_Idx_BStC_y,2) + DO i1 = LBOUND(InData%Jac_Idx_BStC_y,1), UBOUND(InData%Jac_Idx_BStC_y,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_BStC_y(i1,i2,i3) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_NStC_y) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_y,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_y,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_NStC_y,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_NStC_y,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_NStC_y,2), UBOUND(InData%Jac_Idx_NStC_y,2) + DO i1 = LBOUND(InData%Jac_Idx_NStC_y,1), UBOUND(InData%Jac_Idx_NStC_y,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_NStC_y(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_TStC_y) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_y,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_y,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_TStC_y,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_TStC_y,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_TStC_y,2), UBOUND(InData%Jac_Idx_TStC_y,2) + DO i1 = LBOUND(InData%Jac_Idx_TStC_y,1), UBOUND(InData%Jac_Idx_TStC_y,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_TStC_y(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Jac_Idx_SStC_y) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_y,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_y,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Jac_Idx_SStC_y,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Jac_Idx_SStC_y,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Jac_Idx_SStC_y,2), UBOUND(InData%Jac_Idx_SStC_y,2) + DO i1 = LBOUND(InData%Jac_Idx_SStC_y,1), UBOUND(InData%Jac_Idx_SStC_y,1) + IntKiBuf(Int_Xferred) = InData%Jac_Idx_SStC_y(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE SrvD_PackParam + + SUBROUTINE SrvD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SrvD_ParameterType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SrvD_UnPackParam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DT = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%HSSBrDT = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%HSSBrTqF = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SIG_POSl = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SIG_POTq = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SIG_SlPc = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SIG_Slop = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SIG_SySp = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_A0 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_C0 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_C1 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_C2 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_K2 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TEC_MR = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%TEC_Re1 = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 @@ -13383,6 +14287,385 @@ SUBROUTINE SrvD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs END IF OutData%UseSC = TRANSFER(IntKiBuf(Int_Xferred), OutData%UseSC) Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_u_indx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_u_indx)) DEALLOCATE(OutData%Jac_u_indx) + ALLOCATE(OutData%Jac_u_indx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_u_indx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_u_indx,2), UBOUND(OutData%Jac_u_indx,2) + DO i1 = LBOUND(OutData%Jac_u_indx,1), UBOUND(OutData%Jac_u_indx,1) + OutData%Jac_u_indx(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_x_indx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_x_indx)) DEALLOCATE(OutData%Jac_x_indx) + ALLOCATE(OutData%Jac_x_indx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_x_indx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_x_indx,2), UBOUND(OutData%Jac_x_indx,2) + DO i1 = LBOUND(OutData%Jac_x_indx,1), UBOUND(OutData%Jac_x_indx,1) + OutData%Jac_x_indx(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! du not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%du)) DEALLOCATE(OutData%du) + ALLOCATE(OutData%du(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%du.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%du,1), UBOUND(OutData%du,1) + OutData%du(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! dx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%dx)) DEALLOCATE(OutData%dx) + ALLOCATE(OutData%dx(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%dx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%dx,1), UBOUND(OutData%dx,1) + OutData%dx(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + OutData%Jac_nu = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%Jac_ny = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%Jac_nx = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_BStC_u not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_BStC_u)) DEALLOCATE(OutData%Jac_Idx_BStC_u) + ALLOCATE(OutData%Jac_Idx_BStC_u(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_BStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Jac_Idx_BStC_u,3), UBOUND(OutData%Jac_Idx_BStC_u,3) + DO i2 = LBOUND(OutData%Jac_Idx_BStC_u,2), UBOUND(OutData%Jac_Idx_BStC_u,2) + DO i1 = LBOUND(OutData%Jac_Idx_BStC_u,1), UBOUND(OutData%Jac_Idx_BStC_u,1) + OutData%Jac_Idx_BStC_u(i1,i2,i3) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_NStC_u not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_NStC_u)) DEALLOCATE(OutData%Jac_Idx_NStC_u) + ALLOCATE(OutData%Jac_Idx_NStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_NStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_NStC_u,2), UBOUND(OutData%Jac_Idx_NStC_u,2) + DO i1 = LBOUND(OutData%Jac_Idx_NStC_u,1), UBOUND(OutData%Jac_Idx_NStC_u,1) + OutData%Jac_Idx_NStC_u(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_TStC_u not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_TStC_u)) DEALLOCATE(OutData%Jac_Idx_TStC_u) + ALLOCATE(OutData%Jac_Idx_TStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_TStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_TStC_u,2), UBOUND(OutData%Jac_Idx_TStC_u,2) + DO i1 = LBOUND(OutData%Jac_Idx_TStC_u,1), UBOUND(OutData%Jac_Idx_TStC_u,1) + OutData%Jac_Idx_TStC_u(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_SStC_u not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_SStC_u)) DEALLOCATE(OutData%Jac_Idx_SStC_u) + ALLOCATE(OutData%Jac_Idx_SStC_u(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_SStC_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_SStC_u,2), UBOUND(OutData%Jac_Idx_SStC_u,2) + DO i1 = LBOUND(OutData%Jac_Idx_SStC_u,1), UBOUND(OutData%Jac_Idx_SStC_u,1) + OutData%Jac_Idx_SStC_u(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_BStC_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_BStC_x)) DEALLOCATE(OutData%Jac_Idx_BStC_x) + ALLOCATE(OutData%Jac_Idx_BStC_x(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_BStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Jac_Idx_BStC_x,3), UBOUND(OutData%Jac_Idx_BStC_x,3) + DO i2 = LBOUND(OutData%Jac_Idx_BStC_x,2), UBOUND(OutData%Jac_Idx_BStC_x,2) + DO i1 = LBOUND(OutData%Jac_Idx_BStC_x,1), UBOUND(OutData%Jac_Idx_BStC_x,1) + OutData%Jac_Idx_BStC_x(i1,i2,i3) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_NStC_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_NStC_x)) DEALLOCATE(OutData%Jac_Idx_NStC_x) + ALLOCATE(OutData%Jac_Idx_NStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_NStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_NStC_x,2), UBOUND(OutData%Jac_Idx_NStC_x,2) + DO i1 = LBOUND(OutData%Jac_Idx_NStC_x,1), UBOUND(OutData%Jac_Idx_NStC_x,1) + OutData%Jac_Idx_NStC_x(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_TStC_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_TStC_x)) DEALLOCATE(OutData%Jac_Idx_TStC_x) + ALLOCATE(OutData%Jac_Idx_TStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_TStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_TStC_x,2), UBOUND(OutData%Jac_Idx_TStC_x,2) + DO i1 = LBOUND(OutData%Jac_Idx_TStC_x,1), UBOUND(OutData%Jac_Idx_TStC_x,1) + OutData%Jac_Idx_TStC_x(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_SStC_x not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_SStC_x)) DEALLOCATE(OutData%Jac_Idx_SStC_x) + ALLOCATE(OutData%Jac_Idx_SStC_x(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_SStC_x.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_SStC_x,2), UBOUND(OutData%Jac_Idx_SStC_x,2) + DO i1 = LBOUND(OutData%Jac_Idx_SStC_x,1), UBOUND(OutData%Jac_Idx_SStC_x,1) + OutData%Jac_Idx_SStC_x(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_BStC_y not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_BStC_y)) DEALLOCATE(OutData%Jac_Idx_BStC_y) + ALLOCATE(OutData%Jac_Idx_BStC_y(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_BStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Jac_Idx_BStC_y,3), UBOUND(OutData%Jac_Idx_BStC_y,3) + DO i2 = LBOUND(OutData%Jac_Idx_BStC_y,2), UBOUND(OutData%Jac_Idx_BStC_y,2) + DO i1 = LBOUND(OutData%Jac_Idx_BStC_y,1), UBOUND(OutData%Jac_Idx_BStC_y,1) + OutData%Jac_Idx_BStC_y(i1,i2,i3) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_NStC_y not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_NStC_y)) DEALLOCATE(OutData%Jac_Idx_NStC_y) + ALLOCATE(OutData%Jac_Idx_NStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_NStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_NStC_y,2), UBOUND(OutData%Jac_Idx_NStC_y,2) + DO i1 = LBOUND(OutData%Jac_Idx_NStC_y,1), UBOUND(OutData%Jac_Idx_NStC_y,1) + OutData%Jac_Idx_NStC_y(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_TStC_y not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_TStC_y)) DEALLOCATE(OutData%Jac_Idx_TStC_y) + ALLOCATE(OutData%Jac_Idx_TStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_TStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_TStC_y,2), UBOUND(OutData%Jac_Idx_TStC_y,2) + DO i1 = LBOUND(OutData%Jac_Idx_TStC_y,1), UBOUND(OutData%Jac_Idx_TStC_y,1) + OutData%Jac_Idx_TStC_y(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Jac_Idx_SStC_y not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Jac_Idx_SStC_y)) DEALLOCATE(OutData%Jac_Idx_SStC_y) + ALLOCATE(OutData%Jac_Idx_SStC_y(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Jac_Idx_SStC_y.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Jac_Idx_SStC_y,2), UBOUND(OutData%Jac_Idx_SStC_y,2) + DO i1 = LBOUND(OutData%Jac_Idx_SStC_y,1), UBOUND(OutData%Jac_Idx_SStC_y,1) + OutData%Jac_Idx_SStC_y(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE SrvD_UnPackParam SUBROUTINE SrvD_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) @@ -13492,6 +14775,9 @@ SUBROUTINE SrvD_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg DstInputData%RotPwr = SrcInputData%RotPwr DstInputData%HorWindV = SrcInputData%HorWindV DstInputData%YawAngle = SrcInputData%YawAngle + DstInputData%LSShftFxa = SrcInputData%LSShftFxa + DstInputData%LSShftFys = SrcInputData%LSShftFys + DstInputData%LSShftFzs = SrcInputData%LSShftFzs IF (ALLOCATED(SrcInputData%fromSC)) THEN i1_l = LBOUND(SrcInputData%fromSC,1) i1_u = UBOUND(SrcInputData%fromSC,1) @@ -13754,6 +15040,9 @@ SUBROUTINE SrvD_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = Re_BufSz + 1 ! RotPwr Re_BufSz = Re_BufSz + 1 ! HorWindV Re_BufSz = Re_BufSz + 1 ! YawAngle + Re_BufSz = Re_BufSz + 1 ! LSShftFxa + Re_BufSz = Re_BufSz + 1 ! LSShftFys + Re_BufSz = Re_BufSz + 1 ! LSShftFzs Int_BufSz = Int_BufSz + 1 ! fromSC allocated yes/no IF ( ALLOCATED(InData%fromSC) ) THEN Int_BufSz = Int_BufSz + 2*1 ! fromSC upper/lower bounds for each dimension @@ -14049,6 +15338,12 @@ SUBROUTINE SrvD_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%YawAngle Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFxa + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFys + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%LSShftFzs + Re_Xferred = Re_Xferred + 1 IF ( .NOT. ALLOCATED(InData%fromSC) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -14481,6 +15776,12 @@ SUBROUTINE SrvD_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Re_Xferred = Re_Xferred + 1 OutData%YawAngle = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%LSShftFxa = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFys = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%LSShftFzs = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! fromSC not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -16150,6 +17451,12 @@ SUBROUTINE SrvD_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg b = -(u1%HorWindV - u2%HorWindV) u_out%HorWindV = u1%HorWindV + b * ScaleFactor CALL Angles_ExtrapInterp( u1%YawAngle, u2%YawAngle, tin, u_out%YawAngle, tin_out ) + b = -(u1%LSShftFxa - u2%LSShftFxa) + u_out%LSShftFxa = u1%LSShftFxa + b * ScaleFactor + b = -(u1%LSShftFys - u2%LSShftFys) + u_out%LSShftFys = u1%LSShftFys + b * ScaleFactor + b = -(u1%LSShftFzs - u2%LSShftFzs) + u_out%LSShftFzs = u1%LSShftFzs + b * ScaleFactor IF (ALLOCATED(u_out%fromSC) .AND. ALLOCATED(u1%fromSC)) THEN DO i1 = LBOUND(u_out%fromSC,1),UBOUND(u_out%fromSC,1) b = -(u1%fromSC(i1) - u2%fromSC(i1)) @@ -16373,6 +17680,15 @@ SUBROUTINE SrvD_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er c = ( (t(2)-t(3))*u1%HorWindV + t(3)*u2%HorWindV - t(2)*u3%HorWindV ) * scaleFactor u_out%HorWindV = u1%HorWindV + b + c * t_out CALL Angles_ExtrapInterp( u1%YawAngle, u2%YawAngle, u3%YawAngle, tin, u_out%YawAngle, tin_out ) + b = (t(3)**2*(u1%LSShftFxa - u2%LSShftFxa) + t(2)**2*(-u1%LSShftFxa + u3%LSShftFxa))* scaleFactor + c = ( (t(2)-t(3))*u1%LSShftFxa + t(3)*u2%LSShftFxa - t(2)*u3%LSShftFxa ) * scaleFactor + u_out%LSShftFxa = u1%LSShftFxa + b + c * t_out + b = (t(3)**2*(u1%LSShftFys - u2%LSShftFys) + t(2)**2*(-u1%LSShftFys + u3%LSShftFys))* scaleFactor + c = ( (t(2)-t(3))*u1%LSShftFys + t(3)*u2%LSShftFys - t(2)*u3%LSShftFys ) * scaleFactor + u_out%LSShftFys = u1%LSShftFys + b + c * t_out + b = (t(3)**2*(u1%LSShftFzs - u2%LSShftFzs) + t(2)**2*(-u1%LSShftFzs + u3%LSShftFzs))* scaleFactor + c = ( (t(2)-t(3))*u1%LSShftFzs + t(3)*u2%LSShftFzs - t(2)*u3%LSShftFzs ) * scaleFactor + u_out%LSShftFzs = u1%LSShftFzs + b + c * t_out IF (ALLOCATED(u_out%fromSC) .AND. ALLOCATED(u1%fromSC)) THEN DO i1 = LBOUND(u_out%fromSC,1),UBOUND(u_out%fromSC,1) b = (t(3)**2*(u1%fromSC(i1) - u2%fromSC(i1)) + t(2)**2*(-u1%fromSC(i1) + u3%fromSC(i1)))* scaleFactor diff --git a/modules/servodyn/src/StrucCtrl.f90 b/modules/servodyn/src/StrucCtrl.f90 index c769c61652..04598a739e 100644 --- a/modules/servodyn/src/StrucCtrl.f90 +++ b/modules/servodyn/src/StrucCtrl.f90 @@ -197,7 +197,11 @@ SUBROUTINE StC_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOu x%StC_x(2,i_pt) = 0 x%StC_x(3,i_pt) = InputFileData%StC_Y_DSP x%StC_x(4,i_pt) = 0 - x%StC_x(5,i_pt) = InputFileData%StC_Z_DSP + if ((p%StC_DOF_MODE == DOFMode_Indept) .and. p%StC_Z_DOF) then ! Should be zero for omni and TLCD + x%StC_x(5,i_pt) = InputFileData%StC_Z_DSP + else + x%StC_x(5,i_pt) = 0.0_ReKi + endif x%StC_x(6,i_pt) = 0 enddo @@ -508,9 +512,7 @@ SUBROUTINE StC_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, !INTEGER :: nTime ! number of inputs - IF ( p%StC_DOF_MODE /= DOFMode_Prescribed ) THEN - CALL StC_RK4( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) - ENDIF + CALL StC_RK4( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) END SUBROUTINE StC_UpdateStates !---------------------------------------------------------------------------------------------------------------------------------- @@ -565,6 +567,19 @@ SUBROUTINE StC_RK4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ErrStat = ErrID_None ErrMsg = "" + ! if prescribed forces, there are no states to advance, so return + if ( p%StC_DOF_MODE == DOFMode_Prescribed ) then + do i_pt=1,p%NumMeshPts + x%StC_x(1,i_pt) = 0 + x%StC_x(2,i_pt) = 0 + x%StC_x(3,i_pt) = 0 + x%StC_x(4,i_pt) = 0 + x%StC_x(5,i_pt) = 0 + x%StC_x(6,i_pt) = 0 + enddo + return + endif + CALL StC_CopyContState( x, k1, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) CALL CheckError(ErrStat2,ErrMsg2) CALL StC_CopyContState( x, k2, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) @@ -1047,7 +1062,7 @@ SUBROUTINE StC_CalcContStateDeriv( Time, u, p, x, xd, z, OtherState, m, dxdt, Er enddo ! NOTE: m%F_stop and m%F_table are calculated earlier - IF (p%StC_DOF_MODE == ControlMode_None) THEN + IF ((p%StC_DOF_MODE == ControlMode_None) .or. (p%StC_DOF_MODE == DOFMode_Prescribed)) THEN do i_pt=1,p%NumMeshPts ! Aggregate acceleration terms m%Acc(1:3,i_pt) = 0.0_ReKi @@ -1086,7 +1101,7 @@ SUBROUTINE StC_CalcContStateDeriv( Time, u, p, x, xd, z, OtherState, m, dxdt, Er ! Compute the first time derivatives, dxdt%StC_x(1) and dxdt%StC_x(3), of the continuous states,: ! Compute elements 1 and 3 of dxdt%StC_x so that we can compute m%C_ctrl,m%C_Brake, and m%F_fr in StC_GroundHookDamp if necessary - IF (p%StC_DOF_MODE == ControlMode_None) THEN + IF ((p%StC_DOF_MODE == ControlMode_None) .or. (p%StC_DOF_MODE == DOFMode_Prescribed)) THEN dxdt%StC_x = 0.0_ReKi ! Whole array @@ -1122,6 +1137,12 @@ SUBROUTINE StC_CalcContStateDeriv( Time, u, p, x, xd, z, OtherState, m, dxdt, Er enddo END IF + if ( .not. (p%StC_DOF_MODE == DOFMode_Indept .AND. p%StC_Z_DOF)) then ! z not used in any other configuration + do i_pt=1,p%NumMeshPts + dxdt%StC_x(5,i_pt) = 0.0_ReKi + enddo + endif + ENDIF @@ -1235,6 +1256,17 @@ SUBROUTINE StC_CalcContStateDeriv( Time, u, p, x, xd, z, OtherState, m, dxdt, Er dxdt%StC_x(6,i_pt) = 0.0_ReKi ! Z is off enddo + ELSE IF ( p%StC_DOF_MODE == DOFMode_Prescribed ) THEN + ! if prescribed forces, there are no states to advance, so return + do i_pt=1,p%NumMeshPts + dxdt%StC_x(1,i_pt) = 0 + dxdt%StC_x(2,i_pt) = 0 + dxdt%StC_x(3,i_pt) = 0 + dxdt%StC_x(4,i_pt) = 0 + dxdt%StC_x(5,i_pt) = 0 + dxdt%StC_x(6,i_pt) = 0 + enddo + return END IF call CleanUp() @@ -1654,14 +1686,14 @@ SUBROUTINE SpringForceExtrapInterp(x, p, F_table,ErrStat,ErrMsg) Nrows = SIZE(p%F_TBL,1) ALLOCATE(TmpRAry(Nrows),STAT=ErrStat2) + IF (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal,'Error allocating temp array.',ErrStat,ErrMsg,'SpringForceExtrapInterp') + RETURN + END IF do i_pt=1,p%NumMeshPts IF (p%StC_DOF_MODE == DOFMode_Indept .OR. p%StC_DOF_MODE == DOFMode_Omni) THEN - IF (ErrStat2 /= 0) then - call SetErrStat(ErrID_Fatal,'Error allocating temp array.',ErrStat,ErrMsg,'SpringForceExtrapInterp') - RETURN - END IF IF (p%StC_DOF_MODE == DOFMode_Indept) THEN DO I = 1,3 @@ -1669,6 +1701,7 @@ SUBROUTINE SpringForceExtrapInterp(x, p, F_table,ErrStat,ErrMsg) END DO ELSE !IF (p%StC_DOF_MODE == DOFMode_Omni) THEN ! Only X and Y Disp = SQRT(x%StC_x(1,i_pt)**2+x%StC_x(3,i_pt)**2) ! constant assignment to vector + Disp(3) = 0.0_ReKi END IF @@ -2238,7 +2271,11 @@ SUBROUTINE StC_SetParameters( InputFileData, InitInp, p, Interval, ErrStat, ErrM p%StC_X_DOF = InputFileData%StC_X_DOF p%StC_Y_DOF = InputFileData%StC_Y_DOF - p%StC_Z_DOF = InputFileData%StC_Z_DOF + if (p%StC_DOF_MODE == DOFMode_Indept) then + p%StC_Z_DOF = InputFileData%StC_Z_DOF + else + p%StC_Z_DOF = .false. + endif ! StC X parameters p%M_X = InputFileData%StC_X_M diff --git a/modules/servodyn/src/StrucCtrl_Registry.txt b/modules/servodyn/src/StrucCtrl_Registry.txt index 3883ed88a7..9a791558b3 100644 --- a/modules/servodyn/src/StrucCtrl_Registry.txt +++ b/modules/servodyn/src/StrucCtrl_Registry.txt @@ -113,7 +113,6 @@ typedef ^ InitOutputType ReKi RelPosition {:}{:} - - "StC position relativ # ..... States .................................................................................................................... # Define continuous (differentiable) states here: typedef ^ ContinuousStateType ReKi StC_x {:}{:} - - "Continuous States -- StrucCtrl x" - -#typedef ^ ContinuousStateType ReKi StC_xdot {:}{:} - - "Continuous States -- StrucCtrl xdot" - # Define discrete (nondifferentiable) states here: typedef ^ DiscreteStateType ReKi DummyDiscState - - - "Remove this variable if you have discrete states" - # Define constraint states here: diff --git a/modules/subdyn/src/SubDyn.f90 b/modules/subdyn/src/SubDyn.f90 index d4b759cf86..248e3e7478 100644 --- a/modules/subdyn/src/SubDyn.f90 +++ b/modules/subdyn/src/SubDyn.f90 @@ -2187,7 +2187,7 @@ SUBROUTINE SD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat END SUBROUTINE SD_JacobianPConstrState !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ !> Routine to pack the data structures representing the operating points into arrays for linearization. -SUBROUTINE SD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op ) +SUBROUTINE SD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedPackedOrient ) REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(SD_InputType), INTENT(INOUT) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) TYPE(SD_ParameterType), INTENT(IN ) :: p !< Parameters @@ -2205,8 +2205,11 @@ SUBROUTINE SD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, 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 + LOGICAL, OPTIONAL, INTENT(IN ) :: NeedPackedOrient !< whether a y_op values should contain 3-value representation instead of full orientation matrices + ! Local INTEGER(IntKi) :: idx, i + LOGICAL :: ReturnPackedOrientation INTEGER(IntKi) :: nu INTEGER(IntKi) :: ny INTEGER(IntKi) :: ErrStat2 @@ -2229,14 +2232,24 @@ SUBROUTINE SD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, FieldMask(MASKID_RotationVel) = .true. FieldMask(MASKID_TranslationAcc) = .true. FieldMask(MASKID_RotationAcc) = .true. - call PackMotionMesh(u%TPMesh, u_op, idx, FieldMask=FieldMask) + call PackMotionMesh(u%TPMesh, u_op, idx, FieldMask=FieldMask, UseSmlAngle=.true.) call PackLoadMesh(u%LMesh, u_op, idx) END IF + IF ( PRESENT( y_op ) ) THEN ny = p%Jac_ny + y%Y2Mesh%NNodes * 6 + y%Y3Mesh%NNodes * 6 ! Jac_ny has 3 orientation angles, but the OP needs the full 9 elements of the DCM (thus 6 more per node) if (.not. allocated(y_op)) then call AllocAry(y_op, ny, 'y_op', ErrStat2, ErrMsg2); if(Failed()) return end if + + if (present(NeedPackedOrient)) then + ReturnPackedOrientation = NeedPackedOrient + else + ReturnPackedOrientation = .false. + end if + + if (ReturnPackedOrientation) y_op = 0.0_ReKi ! initialize in case we are returning packed orientations and don't fill the entire array + idx = 1 call PackLoadMesh(y%Y1Mesh, y_op, idx) FieldMask = .false. @@ -2246,13 +2259,14 @@ SUBROUTINE SD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, FieldMask(MASKID_RotationVel) = .true. FieldMask(MASKID_TranslationAcc) = .true. FieldMask(MASKID_RotationAcc) = .true. - call PackMotionMesh(y%Y2Mesh, y_op, idx, FieldMask=FieldMask) - call PackMotionMesh(y%Y3Mesh, y_op, idx, FieldMask=FieldMask) + call PackMotionMesh(y%Y2Mesh, y_op, idx, FieldMask=FieldMask, UseSmlAngle=ReturnPackedOrientation) + call PackMotionMesh(y%Y3Mesh, y_op, idx, FieldMask=FieldMask, UseSmlAngle=ReturnPackedOrientation) idx = idx - 1 do i=1,p%NumOuts y_op(i+idx) = y%WriteOutput(i) end do END IF + IF ( PRESENT( x_op ) ) THEN if (.not. allocated(x_op)) then call AllocAry(x_op, p%Jac_nx*2,'x_op',ErrStat2,ErrMsg2); if (Failed()) return diff --git a/modules/subdyn/src/SubDyn_Output.f90 b/modules/subdyn/src/SubDyn_Output.f90 index 61ff660054..b731e628fe 100644 --- a/modules/subdyn/src/SubDyn_Output.f90 +++ b/modules/subdyn/src/SubDyn_Output.f90 @@ -978,7 +978,7 @@ SUBROUTINE SD_Perturb_u( p, n, perturb_sign, u, du ) CASE ( 1) !Module/Mesh/Field: u%TPMesh%TranslationDisp = 1; u%TPMesh%TranslationDisp( fieldIndx,node) = u%TPMesh%TranslationDisp( fieldIndx,node) + du * perturb_sign CASE ( 2) !Module/Mesh/Field: u%TPMesh%Orientation = 2; - CALL PerturbOrientationMatrix( u%TPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx ) + CALL PerturbOrientationMatrix( u%TPMesh%Orientation(:,:,node), du * perturb_sign, fieldIndx, UseSmlAngle=.true. ) CASE ( 3) !Module/Mesh/Field: u%TPMesh%TranslationVel = 3; u%TPMesh%TranslationVel( fieldIndx,node) = u%TPMesh%TranslationVel( fieldIndx,node) + du * perturb_sign CASE ( 4) !Module/Mesh/Field: u%TPMesh%RotationVel = 4; @@ -1007,8 +1007,8 @@ SUBROUTINE SD_Compute_dY(p, y_p, y_m, delta, dY) INTEGER(IntKi) :: indx_first ! index indicating next value of dY to be filled indx_first = 1 call PackLoadMesh_dY( y_p%Y1Mesh, y_m%Y1Mesh, dY, indx_first) - call PackMotionMesh_dY(y_p%Y2Mesh, y_m%Y2Mesh, dY, indx_first) ! all 6 motion fields - call PackMotionMesh_dY(y_p%Y3Mesh, y_m%Y3Mesh, dY, indx_first) ! all 6 motion fields + call PackMotionMesh_dY(y_p%Y2Mesh, y_m%Y2Mesh, dY, indx_first, UseSmlAngle=.true.) ! all 6 motion fields + call PackMotionMesh_dY(y_p%Y3Mesh, y_m%Y3Mesh, dY, indx_first, UseSmlAngle=.true.) ! all 6 motion fields do i=1,p%NumOuts dY(i+indx_first-1) = y_p%WriteOutput(i) - y_m%WriteOutput(i) end do diff --git a/modules/turbsim/src/BlankModVKM.f90 b/modules/turbsim/src/BlankModVKM.f90 index 67639b856a..8ef9bbda13 100644 --- a/modules/turbsim/src/BlankModVKM.f90 +++ b/modules/turbsim/src/BlankModVKM.f90 @@ -17,7 +17,7 @@ SUBROUTINE Mod_vKrm ( Ht, Ucmp, Spec ) REAL(ReKi), INTENT(IN) :: Ht ! height REAL(ReKi), INTENT(IN) :: UCmp ! wind speed REAL(ReKi), INTENT( OUT) :: Spec (:,:) - + Spec = 0.0_ReKi RETURN diff --git a/modules/turbsim/src/TS_FileIO.f90 b/modules/turbsim/src/TS_FileIO.f90 index d13fd8d0d3..1264f591bf 100644 --- a/modules/turbsim/src/TS_FileIO.f90 +++ b/modules/turbsim/src/TS_FileIO.f90 @@ -242,6 +242,10 @@ SUBROUTINE ReadInputFile(InFile, p, OtherSt_RandNum, ErrStat, ErrMsg) CALL ReadVar( UI, InFile, p%WrFile(FileExt_TWR), "WrADTWR", "Output tower data? [RootName.twr]",ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! ---------- Read the flag for writing the HAWC FF files. --------------------------------------- + CALL ReadVar( UI, InFile, p%WrFile(FileExt_HAWC), "WrHAWCFF", "Output HAWC FF files? [RootName-u.bin, -v.bin, -w.bin, .hawc]",ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! ---------- Read the flag for writing the formatted FF files. --------------------------------------- CALL ReadVar( UI, InFile, p%WrFile(FileExt_UVW), "WrFMTFF", "Output formatted FF files? [RootName.u, .v, .w]",ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -250,10 +254,6 @@ SUBROUTINE ReadInputFile(InFile, p, OtherSt_RandNum, ErrStat, ErrMsg) CALL ReadVar( UI, InFile, p%WrFile(FileExt_CTS), "WrACT", "Output coherent time series files? [RootName.cts]",ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - ! ---------- Read the flag for turbine rotation. ----------------------------------------------------------- - CALL ReadVar( UI, InFile, p%grid%Clockwise, "Clockwise", "Clockwise rotation when looking downwind?",ErrStat2, ErrMsg2, UnEc) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - ! ---------- Read the flag for determining IEC scaling ----------------------------------------------------- CALL ReadVar( UI, InFile, p%IEC%ScaleIEC, "ScaleIEC", "Scale IEC turbulence models to specified standard deviation?",& ErrStat2, ErrMsg2, UnEc) @@ -302,7 +302,7 @@ SUBROUTINE ReadInputFile(InFile, p, OtherSt_RandNum, ErrStat, ErrMsg) ! Check if usable time is "ALL" (for periodic files) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> READ( Line, *, IOSTAT=ErrStat2) p%grid%UsableTime - + IF ( ErrStat2 /= 0 ) THEN ! Line didn't contain a number CALL Conv2UC( Line ) IF ( TRIM(Line) == 'ALL' ) THEN @@ -316,6 +316,9 @@ SUBROUTINE ReadInputFile(InFile, p, OtherSt_RandNum, ErrStat, ErrMsg) END IF ELSE p%grid%Periodic = .FALSE. + + CALL CheckRealVar( p%grid%UsableTime, 'UsableTime', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) END IF ! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< end check for UsableTime = "ALL" (periodic) @@ -1180,6 +1183,8 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) INTEGER :: U_in ! Input unit. INTEGER(IntKi) :: ErrStat2 ! Error level (local) CHARACTER(MaxMsgLen) :: ErrMsg2 ! Message describing error (local) + character(*), parameter :: RoutineName = 'GetUSRProfiles' + CHARACTER(200) :: TempWarn ! CHARACTER(200) :: LINE @@ -1201,9 +1206,9 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) U_in = -1 CALL GetNewUnit( U_in, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) CALL OpenFInpFile( U_in, FileName, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CLOSE(U_in) @@ -1212,40 +1217,40 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) DO I=1,3 CALL ReadCom( U_in, FileName, "Header line "//trim(num2lstr(I))//" for user-defined profiles", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) END DO ! ---------- Read the size of the arrays -------------------------------------------- CALL ReadVar( U_in, FileName, p_met%NumUSRz, "NumUSRz", "Number of heights in the user-defined profiles", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF ( p_met%NumUSRz < 1 ) THEN - CALL SetErrStat( ErrID_Fatal, 'The number of heights specified in the user-defined profiles must be at least 1.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'The number of heights specified in the user-defined profiles must be at least 1.', ErrStat, ErrMsg, RoutineName) ENDIF DO I=1,3 ! ---------- Read the scaling for the standard deviations -------------------------------------------- CALL ReadVar( U_in, FileName, p_met%USR_StdScale(I), "USR_StdScale", "Scaling value for user-defined standard deviation profile", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF ( p_met%USR_StdScale(I) <= 0. ) THEN - CALL SetErrStat( ErrID_Fatal, 'The scaling value for the user-defined standard deviation profile must be positive.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'The scaling value for the user-defined standard deviation profile must be positive.', ErrStat, ErrMsg, RoutineName) ENDIF ENDDO ! Allocate the data arrays - CALL AllocAry(p_met%USR_Z, p_met%NumUSRz, 'USR_Z (user-defined height)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') - CALL AllocAry(p_met%USR_U, p_met%NumUSRz, 'USR_U (user-defined wind speed)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') - CALL AllocAry(p_met%USR_WindDir, p_met%NumUSRz, 'USR_WindDir (user-defined wind direction)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL AllocAry(p_met%USR_Z, p_met%NumUSRz, 'USR_Z (user-defined height)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(p_met%USR_U, p_met%NumUSRz, 'USR_U (user-defined wind speed)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(p_met%USR_WindDir, p_met%NumUSRz, 'USR_WindDir (user-defined wind direction)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF ( p_met%TurbModel_ID == SpecModel_USRVKM ) THEN ReadSigL = .TRUE. - CALL AllocAry(p_met%USR_Sigma, p_met%NumUSRz, 'USR_Sigma (user-defined sigma)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') - CALL AllocAry(p_met%USR_L, p_met%NumUSRz, 'USR_L (user-defined length scale)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL AllocAry(p_met%USR_Sigma, p_met%NumUSRz, 'USR_Sigma (user-defined sigma)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(p_met%USR_L, p_met%NumUSRz, 'USR_L (user-defined length scale)', ErrStat2, ErrMsg2); CALL SetErrStat(ErrSTat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ELSE ReadSigL = .FALSE. @@ -1259,7 +1264,7 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) ! ---------- Skip 4 lines -------------------------------------------- DO I=1,4 CALL ReadCom( U_in, FileName, "Headers for user-defined variables", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ENDDO @@ -1272,18 +1277,35 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) ENDIF IF ( ErrStat2 /= 0 ) THEN - CALL SetErrStat( ErrID_Fatal, 'Could not read entire user-defined variable list on line '//Int2LStr(I)//'.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'Could not read entire user-defined variable list on line '//Int2LStr(I)//'.', ErrStat, ErrMsg, RoutineName) CLOSE(U_in) RETURN ENDIF + TempWarn = 'Error reading user-defined variable list on line '//Int2LStr(I) + CALL CheckRealVar( p_met%USR_Z(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL CheckRealVar( p_met%USR_U(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL CheckRealVar( p_met%USR_WindDir(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF ( ReadSigL ) THEN IF ( p_met%USR_Sigma(I) <= REAL( 0., ReKi ) ) THEN - CALL SetErrStat( ErrID_Fatal, 'The standard deviation must be a positive number.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'The standard deviation must be a positive number.', ErrStat, ErrMsg, RoutineName) ELSEIF ( p_met%USR_L(I) <= REAL( 0., ReKi ) ) THEN - CALL SetErrStat( ErrID_Fatal, 'The length scale must be a positive number.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'The length scale must be a positive number.', ErrStat, ErrMsg, RoutineName) ENDIF + + CALL CheckRealVar( p_met%USR_Sigma(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL CheckRealVar( p_met%USR_L(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ENDIF + if (ErrStat >= AbortErrLev) then + CLOSE(U_in) + RETURN ENDIF + IF ( p_met%USR_WindDir(I) > 360. ) THEN J = INT ( p_met%USR_WindDir(I) / 360. ) @@ -1304,7 +1326,7 @@ SUBROUTINE GetUSRProfiles(FileName, p_met, UnEc, ErrStat, ErrMsg) Indx = J+1 EXIT ELSEIF ( p_met%USR_Z(I) == p_met%USR_Z(J) ) THEN - CALL SetErrStat( ErrID_Fatal, 'User-defined values must contain unique heights.', ErrStat, ErrMsg, 'GetUSRProfiles') + CALL SetErrStat( ErrID_Fatal, 'User-defined values must contain unique heights.', ErrStat, ErrMsg, RoutineName) CLOSE(U_in) RETURN ENDIF @@ -1371,6 +1393,8 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) INTEGER(IntKi) :: ErrStat2 ! Error level (local) CHARACTER(MaxMsgLen) :: ErrMsg2 ! Message describing error (local) + CHARACTER(*), PARAMETER :: RoutineName = 'GetUSRSpec' + CHARACTER(200) :: TempWarn ErrStat = ErrID_None ErrMSg = "" @@ -1378,10 +1402,10 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) ! --------- Open the file --------------- CALL GetNewUnit( USpec, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2 , ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2 , ErrStat, ErrMsg, RoutineName) CALL OpenFInpFile( USpec, FileName, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2 , ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2 , ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() RETURN @@ -1394,13 +1418,13 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) ! --------- Read the comment lines at the beginning of the file --------------- DO I=1,3 CALL ReadCom( USpec, FileName, "user-spectra header line #"//TRIM(Num2LStr(I)), ErrStat2, ErrMsg2, UnEc) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ENDDO ! ---------- Read the size of the arrays -------------------------------------------- CALL ReadVar( USpec, FileName, p%usr%nFreq, "nFreq", "Number of frequencies in the user-defined spectra", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() RETURN @@ -1410,12 +1434,12 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) DO I=1,3 ! ---------- Read the scaling for the arrays -------------------------------------------- CALL ReadVar( USpec, FileName, SpecScale(I), "SpecScale", "Scaling value for user-defined standard deviation profile", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ENDDO - IF ( p%usr%nFreq < 3 ) CALL SetErrStat(ErrID_Fatal, 'The number of frequencies specified in the user-defined spectra must be at least 3.' , ErrStat, ErrMsg, 'GetUSRSpec') - IF ( ANY(SpecScale <= 0.) ) CALL SetErrStat(ErrID_Fatal, 'The scaling value for the user-defined spectra must be positive.' , ErrStat, ErrMsg, 'GetUSRSpec') + IF ( p%usr%nFreq < 3 ) CALL SetErrStat(ErrID_Fatal, 'The number of frequencies specified in the user-defined spectra must be at least 3.' , ErrStat, ErrMsg, RoutineName) + IF ( ANY(SpecScale <= 0.) ) CALL SetErrStat(ErrID_Fatal, 'The scaling value for the user-defined spectra must be positive.' , ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() @@ -1423,9 +1447,9 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) ENDIF ! Allocate the data arrays - CALL AllocAry( p%usr%f, p%usr%nFreq, 'f (user-defined frequencies)' ,ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'GetUSRSpec') - CALL AllocAry( p%usr%S, p%usr%nFreq,1,3,'S (user-defined spectra)' ,ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'GetUSRSpec') - CALL AllocAry( p%usr%pointzi, iPoint , 'pointzi (user-defined spectra',ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'GetUSRSpec') + CALL AllocAry( p%usr%f, p%usr%nFreq, 'f (user-defined frequencies)' ,ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL AllocAry( p%usr%S, p%usr%nFreq,1,3,'S (user-defined spectra)' ,ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL AllocAry( p%usr%pointzi, iPoint , 'pointzi (user-defined spectra',ErrStat2,ErrMsg2); CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() @@ -1437,32 +1461,47 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) ! ---------- Skip 4 lines -------------------------------------------- DO I=1,4 CALL ReadCom( USpec, FileName, "Headers for user-defined variables", ErrStat2, ErrMsg2, UnEc ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ENDDO ! ---------- Read the data lines -------------------------------------- DO I=1,p%usr%nFreq - + TempWarn = 'Error reading user-defined spectra line '//Int2LStr(I) + READ( USpec, *, IOSTAT=ErrStat2 ) p%usr%f(I), p%usr%S(I,iPoint,1), p%usr%S(I,iPoint,2), p%usr%S(I,iPoint,3) IF ( ErrStat2 /= 0 ) THEN - CALL SetErrStat(ErrID_Fatal, 'Could not read entire user-defined spectra on line '//Int2LStr(I)//'.' , ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrID_Fatal, 'Could not read entire user-defined spectra on line '//Int2LStr(I)//'.' , ErrStat, ErrMsg, RoutineName) CALL Cleanup() RETURN ENDIF IF ( ANY( p%usr%S(I,iPoint,:) <= 0._ReKi ) ) THEN - CALL SetErrStat(ErrID_Fatal, 'The spectra must contain positive numbers.' , ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrID_Fatal, 'The spectra must contain positive numbers.' , ErrStat, ErrMsg, RoutineName) CALL Cleanup() RETURN ! ELSEIF ( p%usr%f(I) <= 0.0_ReKi ) THEN -! CALL SetErrStat(ErrID_Fatal, 'The frequencies must be positive numbers.' , ErrStat, ErrMsg, 'GetUSRSpec') +! CALL SetErrStat(ErrID_Fatal, 'The frequencies must be positive numbers.' , ErrStat, ErrMsg, RoutineName) ! CALL Cleanup() ! RETURN ENDIF + call CheckRealVar( p%usr%f(I), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call CheckRealVar( p%usr%S(I,iPoint,1), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call CheckRealVar( p%usr%S(I,iPoint,2), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call CheckRealVar( p%usr%S(I,iPoint,3), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) then + CALL Cleanup() + RETURN + end if + + ! Scale by the factors earlier in the input file p%usr%S(I,iPoint,1) = p%usr%S(I,iPoint,1)*SpecScale(1) @@ -1481,7 +1520,7 @@ SUBROUTINE GetUSRSpec(FileName, p, UnEc, ErrStat, ErrMsg) Indx = J+1 EXIT ELSEIF ( EqualRealNos( p%usr%f(I), p%usr%f(J) ) ) THEN - CALL SetErrStat(ErrID_Fatal, 'Error: user-defined spectra must contain unique frequencies.' , ErrStat, ErrMsg, 'GetUSRSpec') + CALL SetErrStat(ErrID_Fatal, 'Error: user-defined spectra must contain unique frequencies.' , ErrStat, ErrMsg, RoutineName) CALL Cleanup() RETURN ENDIF @@ -1548,6 +1587,7 @@ SUBROUTINE GetUSRTimeSeries(FileName, p, UnEc, ErrStat, ErrMsg) CHARACTER(*), parameter :: RoutineName = 'GetUSRTimeSeries' CHARACTER(200) :: FormStr + CHARACTER(200) :: TempWarn CHARACTER(1) :: tmpChar ErrStat = ErrID_None @@ -1681,12 +1721,29 @@ SUBROUTINE GetUSRTimeSeries(FileName, p, UnEc, ErrStat, ErrMsg) DO i=1,p%usr%nTimes + TempWarn = 'Error reading from time series line '//trim(num2lstr(i)) + READ( UnIn, *, IOSTAT=ErrStat2 ) p%usr%t(i), ( (p%usr%v(i,iPoint,iVec), iVec=1,p%usr%nComp), iPoint=1,p%usr%nPoints ) IF (ErrStat2 /=0) THEN - CALL SetErrStat( ErrID_Fatal, 'Error reading from time series line '//trim(num2lstr(i))//'.', ErrStat, ErrMsg, RoutineName) + CALL SetErrStat( ErrID_Fatal, trim(TempWarn)//'.', ErrStat, ErrMsg, RoutineName) CALL Cleanup() RETURN - END IF + END IF + + CALL CheckRealVar( p%usr%t(i), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + do iPoint=1,p%usr%nPoints + do iVec=1,p%usr%nComp + call CheckRealVar( p%usr%v(i,iPoint,iVec), TempWarn, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if + end do + end do + END DO IF (UnEc > 0 ) THEN @@ -1838,6 +1895,10 @@ SUBROUTINE ReadRAryDefault ( UnIn, Fil, RealAry, VarName, VarDescr, UnEc, Def, E ! Local declarations: INTEGER :: IOS ! I/O status returned from the read statement. + INTEGER :: i + INTEGER :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ReadRAryDefault' CALL ReadVar( UnIn, Fil, CharLine, VarName, VarDescr, ErrStat, ErrMsg, UnEc) !Maybe I should read this in explicitly... @@ -1870,7 +1931,14 @@ SUBROUTINE ReadRAryDefault ( UnIn, Fil, RealAry, VarName, VarDescr, UnEc, Def, E READ (CharLine,*,IOSTAT=IOS) RealAry(1) ! Try reading only the first element ENDIF - CALL CheckIOS ( IOS, Fil, VarName, NumType ) + CALL CheckIOS ( IOS, Fil, VarName, NumType, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + do i=1,size(RealAry) + CALL CheckRealVar( RealAry(i), VarName, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + Def = .FALSE. ENDIF @@ -1907,7 +1975,9 @@ SUBROUTINE ReadRVarDefault ( UnIn, Fil, RealVar, VarName, VarDescr, UnEc, Def, E ! Local declarations: INTEGER :: IOS ! I/O status returned from the read statement. - + INTEGER :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ReadRVarDefault' CALL ReadVar( UnIn, Fil, CharLine, VarName, VarDescr, ErrStat, ErrMsg, UnEc ) @@ -1945,12 +2015,16 @@ SUBROUTINE ReadRVarDefault ( UnIn, Fil, RealVar, VarName, VarDescr, UnEc, Def, E READ (CharLine,*,IOSTAT=IOS) RealVar - CALL CheckIOS ( IOS, Fil, VarName, NumType ) + CALL CheckIOS ( IOS, Fil, VarName, NumType, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL CheckRealVar( RealVar, VarName, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Def = .FALSE. IF ( PRESENT(IGNORESTR) ) IGNORESTR = .FALSE. + ENDIF @@ -1982,9 +2056,6 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) REAL(ReKi) :: TI(3) ! Turbulence intensity for scaling data REAL(ReKi) :: TmpU ! Max value of |V(:,:,1)-UHub| - INTEGER(B4Ki) :: CFirst - INTEGER(B4Ki) :: CLast - INTEGER(B4Ki) :: CStep INTEGER(B4Ki) :: II INTEGER(B4Ki) :: IT INTEGER(B4Ki) :: IY @@ -1998,7 +2069,7 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) INTEGER :: UBFFW ! I/O unit for BLADED FF data (*.wnd file). INTEGER :: UATWR ! I/O unit for AeroDyn tower data (*.twr file). - CHARACTER(200) :: FormStr ! String used to store format specifiers. + CHARACTER(200) :: FormStr ! String used to store format specifiers. ErrStat = ErrID_None @@ -2009,16 +2080,16 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) ! We need to take into account the shear across the grid in the sigma calculations for scaling the data, ! and ensure that 32.767*Usig >= |V-UHub| so that we don't get values out of the range of our scaling values ! in this BLADED-style binary output. TmpU is |V-UHub| + TmpU = MAX( ABS(MAXVAL(V(:,:,1))-p%UHub), ABS(MINVAL(V(:,:,1))-p%UHub) ) !Get the range of wind speed values for scaling in BLADED-format .wnd files NewUSig = MAX(USig,0.05*TmpU) ! Put normalizing factors into the summary file. The user can use them to ! tell a simulation program how to rescale the data. - TI(1) = MAX(100.0*Tolerance, NewUSig) / p%UHub - TI(2) = MAX(100.0*Tolerance, VSig) / p%UHub - TI(3) = MAX(100.0*Tolerance, WSig) / p%UHub + TI(2) = MAX(100.0*Tolerance, VSig, 0.05*ABS(MAXVAL(V(:,:,2))), 0.05*ABS(MINVAL(V(:,:,2))) ) / p%UHub ! put the abs() after the maxval() and minval() to avoid stack-overflow issues with large wind files + TI(3) = MAX(100.0*Tolerance, WSig, 0.05*ABS(MAXVAL(V(:,:,3))), 0.05*ABS(MINVAL(V(:,:,3))) ) / p%UHub ! put the abs() after the maxval() and minval() to avoid stack-overflow issues with large wind files WRITE (p%US,"(//,'Normalizing Parameters for Binary Data (approximate statistics):',/)") @@ -2030,19 +2101,20 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) WRITE (p%US,'()') WRITE (p%US,FormStr) 'Height Offset', ( p%grid%HubHt - p%grid%GridHeight / 2.0 - p%grid%Zbottom ), ' m' - WRITE (p%US,FormStr) 'Grid Base ', p%grid%Zbottom, ' m' + WRITE (p%US,FormStr) 'Grid Base ', p%grid%Zbottom, ' m' WRITE (p%US,'()' ) - IF ( p%grid%Periodic ) THEN - WRITE (p%US,'( A)' ) 'Creating a PERIODIC output file.' - END IF +IF ( p%grid%Periodic ) THEN + WRITE (p%US,'( A)' ) 'Creating a PERIODIC output file.' +END IF + WRITE (p%US,'( A)' ) 'Creating a BLADED LEFT-HAND RULE output file.' ! Calculate some numbers for normalizing the data. - U_C1 = 1000.0/( p%UHub*TI(1) ) - U_C2 = 1000.0/TI(1) - V_C = 1000.0/( p%UHub*TI(2) ) - W_C = 1000.0/( p%UHub*TI(3) ) + U_C1 = 1000.0/( p%UHub*TI(1) ) + U_C2 = 1000.0/TI(1) + V_C = -1000.0/( p%UHub*TI(2) ) ! Bladed convention is positive V is pointed along negative Y (IEC turbine coordinate) + W_C = 1000.0/( p%UHub*TI(3) ) IF ( p%WrFile(FileExt_WND) ) THEN @@ -2085,19 +2157,6 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) WRITE (UBFFW) INT( 0 , B4Ki ) ! the longitudinal length scale of the vertical component, not used - ! Compute parameters for ordering output for FF AeroDyn files. (This is for BLADED compatibility.) - - IF ( p%grid%Clockwise ) THEN - CFirst = p%grid%NumGrid_Y - CLast = 1 - CStep = -1 - ELSE - CFirst = 1 - CLast = p%grid%NumGrid_Y - CStep = 1 - ENDIF - - ! Loop through time. DO IT=1,p%grid%NumOutSteps !Use only the number of timesteps requested originally @@ -2105,7 +2164,7 @@ SUBROUTINE WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) ! Write out grid data in binary form. IP = 1 DO IZ=1,p%grid%NumGrid_Z - DO IY=CFirst,CLast,CStep + DO IY=1,p%grid%NumGrid_Y II = ( IZ - 1 )*p%grid%NumGrid_Y + IY @@ -2398,11 +2457,131 @@ SUBROUTINE WrBinTURBSIM(p, V, ErrStat, ErrMsg) END SUBROUTINE WrBinTURBSIM !======================================================================= +SUBROUTINE WrBinHAWC( p, V, USig, VSig, WSig, ErrStat, ErrMsg) + ! passed variables + TYPE(TurbSim_ParameterType), INTENT(IN) :: p !< TurbSim's parameters + REAL(ReKi), INTENT(IN) :: V (:,:,:) !< THe wind-speed array, with the mean added and the field rotated. (NumSteps,NPoints,3). + REAL(ReKi), INTENT(IN) :: USig !< Standard deviation of U + REAL(ReKi), INTENT(IN) :: VSig !< Standard deviation of V + REAL(ReKi), INTENT(IN) :: WSig !< Standard deviation of W + INTEGER(IntKi), intent( out) :: ErrStat !< Error level + CHARACTER(*), intent( out) :: ErrMsg !< Message describing error + + ! local variables + CHARACTER(*), PARAMETER :: Comp(3) = (/'u','v','w'/) + INTEGER(IntKi) :: IC, IT, IY, IZ, II, IH, IPoint + INTEGER(IntKi) :: UnWind + + + REAL(ReKi), ALLOCATABLE :: TmpV(:,:,:) ! This array holds velocities with the wind direction added (with zero mean) + REAL(ReKi), PARAMETER :: FileSigmas(3) = (/ 1.0, 0.8, 0.5 /) ! These are the ratios we will use for each file generated for HAWC2 + REAL(ReKi) :: ScaleFactors(3) + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'WrBinHAWC' + CHARACTER(1024) :: RootWithoutPathName + + ErrStat = ErrID_None + ErrMsg = "" + + CALL GetNewUnit( UnWind, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + ! calculate factors (for workaround in HAWC2); factor = Target / actual + ScaleFactors = (/ USig, VSig, WSig /) + do ic=1,3 + if (.not. EqualRealNos( ScaleFactors(ic), 0.0_ReKi ) ) then + ScaleFactors(ic) = FileSigmas(ic) / ScaleFactors(ic) + else + ScaleFactors(ic) = 1.0_ReKi + end if + end do + + !............................................ + ! write the summary file + !............................................ + ic = INDEX( p%RootName, '\', BACK=.TRUE. ) + ic = MAX( ic, INDEX( p%RootName, '/', BACK=.TRUE. ) ) + RootWithoutPathName = p%RootName((ic+1):) + + CALL OpenFOutFile ( UnWind, trim(p%RootName)//'.hawc', ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + WRITE (UnWind,"( / '; These full-field turbulence files were generated by ' , A , ' on ' , A , ' at ' , A , '.' )" ) TRIM(GetNVD(TurbSim_Ver)), CurDate(), CurTime() + + WRITE( UnWind, '()' ) + WRITE( UnWind, '(A)' ) '; the following factor_scaling is required to obtain the original data:' + WRITE( UnWind, '(A, 3(1x,F15.5) )' ) '; factor_scaling', 1.0_ReKi / ScaleFactors + WRITE( UnWind, '()' ) + WRITE( UnWind, '(A)' ) 'begin mann;' + + DO IC = 1,3 + WRITE( UnWind, '(2x,A, T30, A, " ;")' ) 'filename_'//Comp(IC), trim(RootWithoutPathName)//'-'//Comp(IC)//'.bin' + END DO + WRITE( UnWind, '(2x,A, T30, I8, 1x, F15.5, " ;")' ) 'box_dim_u', p%grid%NumSteps, p%UHub*p%grid%TimeStep ! Note: these files have to be periodic, so I'm going to output all of the steps. + WRITE( UnWind, '(2x,A, T30, I8, 1x, F15.5, " ;")' ) 'box_dim_v', p%grid%NumGrid_Y, p%grid%GridRes_Y + WRITE( UnWind, '(2x,A, T30, I8, 1x, F15.5, " ;")' ) 'box_dim_w', p%grid%NumGrid_Z, p%grid%GridRes_Z + WRITE( UnWind, '(A)' ) 'end mann;' + CLOSE ( UnWind ) + + !............................................ + ! write the binary files for each component + !............................................ + + ! temp array to store rotated wind speeds + CALL AllocAry( TmpV, p%grid%NumSteps, p%grid%NumGrid_Y*p%grid%NumGrid_Z, 3, 'TmpV', ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! Create temp file for easier writing (originally added vertical wind component here, first): + DO IT = 1,p%grid%NumSteps + + IH = 1 + DO IY=p%grid%NumGrid_Y,1,-1 + DO IZ=1,p%grid%NumGrid_Z + + II = (IZ-1)*p%grid%NumGrid_Y + IY + IPoint = p%grid%GridPtIndx(II) + + TmpV(IT,IH,:) = V(IT,IPoint,:) + ! subtract the mean wind speed from the u-component + TmpV(IT,IH,1) = TmpV(IT,IH,1) - p%UHub + + IH = IH+1 + + END DO + END DO + + END DO + + + + DO IC = 1,3 + CALL WrScr ( ' Generating HAWC2 binary time-series file "'//trim(p%RootName)//'-'//Comp(ic)//'.bin"' ) + + CALL OpenBOutFile ( UnWind, trim(p%RootName)//'-'//Comp(ic)//'.bin', ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) EXIT ! exit this do loop to deallocate array + + DO IT = 1,p%grid%NumSteps + + WRITE( UnWind, IOSTAT=ErrStat2 ) REAL( TmpV(IT,:,IC) * ScaleFactors(IC), SiKi ) + + END DO + + CLOSE ( UnWind ) + END DO + + IF (ALLOCATED(TmpV)) DEALLOCATE(TmpV) + + END SUBROUTINE WrBinHAWC +!======================================================================= SUBROUTINE WrFormattedFF(RootName, p_grid, UHub, V ) IMPLICIT NONE - CHARACTER(*), intent(in ) :: RootName ! Rootname of output file + CHARACTER(*), INTENT(IN ) :: RootName ! Rootname of output file TYPE(Grid_ParameterType), INTENT(IN) :: p_grid REAL(ReKi), INTENT(IN) :: UHub ! The steady hub-height velocity REAL(ReKi), INTENT(IN) :: V (:,:,:) ! The Velocities to write to a file @@ -2661,14 +2840,12 @@ SUBROUTINE WrSum_SpecModel(p, U, HWindDir, VWindDir, ErrStat, ErrMsg ) HalfRotDiam = 0.5*p%grid%RotorDiameter CALL getVelocity(p, p%UHub,p%grid%HubHt, p%grid%HubHt+HalfRotDiam, U_zt, ErrStat, ErrMsg) !Velocity at the top of rotor -CALL getVelocity(p, p%UHub,p%grid%HubHt, p%grid%HubHt-HalfRotDiam, U_zb, ErrStat, ErrMsg) !Velocity at the bottom of the rotor IF ( TRIM(p%met%WindProfileType) /= 'PL' .AND. TRIM(p%met%WindProfileType) /= 'IEC' ) THEN -!SELECT CASE ( TRIM(p%met%WindProfileType) ) -! CASE ('JET','LOG','H2L','USR','API', 'TS') !i.e., not PL or IEC - p%met%PLexp = LOG( U_zt/U_zb ) / LOG( (p%grid%HubHt+HalfRotDiam)/(p%grid%HubHt-HalfRotDiam) ) -!END SELECT + CALL getVelocity(p, p%UHub,p%grid%HubHt, p%grid%HubHt , U_zb, ErrStat, ErrMsg) !Velocity at hub/reference height + p%met%PLexp = LOG( U_zt/U_zb ) / LOG( (p%grid%HubHt+HalfRotDiam)/(p%grid%HubHt) ) END IF +CALL getVelocity(p, p%UHub,p%grid%HubHt, p%grid%HubHt-HalfRotDiam, U_zb, ErrStat, ErrMsg) !Velocity at bottom of the rotor WRITE(p%US,'()') ! A BLANK LINE @@ -2681,7 +2858,7 @@ SUBROUTINE WrSum_SpecModel(p, U, HWindDir, VWindDir, ErrStat, ErrMsg ) WRITE (p%US,FormStr) "Jet height ", p%met%ZJetMax, " m" WRITE (p%US,FormStr) "Jet wind speed ", p%met%UJetMax, " m/s" WRITE (p%US,FormStr) "Upper limit of observed jet wind speed ", UTmp, " m/s" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" IF ( UTmp < p%met%UJetMax ) THEN CALL SetErrStat( ErrID_Warn, 'The computed jet wind speed is larger than the ' & @@ -2690,11 +2867,11 @@ SUBROUTINE WrSum_SpecModel(p, U, HWindDir, VWindDir, ErrStat, ErrMsg ) CASE ('LOG') WRITE (p%US,FormStr2) "Wind profile type ", "Logarithmic" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" CASE ('H2L') WRITE (p%US,FormStr2) "Velocity profile type ", "Logarithmic (H2L)" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" CASE ('PL') WRITE (p%US,FormStr2) "Wind profile type ", "Power law" @@ -2702,16 +2879,16 @@ SUBROUTINE WrSum_SpecModel(p, U, HWindDir, VWindDir, ErrStat, ErrMsg ) CASE ('USR') WRITE (p%US,FormStr2) "Wind profile type ", "Linear interpolation of user-defined profile" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" CASE ('TS') WRITE (p%US,FormStr2) "Wind profile type ", "Linear interpolation of user-defined profile generated by time-series data" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" CASE ('API') !bjj : fix me:!!! WRITE (p%US,FormStr2) "Wind profile type ", "API" - WRITE (p%US,FormStr) "Equivalent power law exponent across rotor disk ", p%met%PLexp, "" + WRITE (p%US,FormStr) "Equivalent power law exponent (upper rotor disk)", p%met%PLexp, "" CASE DEFAULT WRITE (p%US,FormStr2) "Wind profile type ", "Power law on rotor disk, logarithmic elsewhere" @@ -3577,9 +3754,9 @@ SUBROUTINE WrSum_EchoInputs(p ) WRITE (p%US,"( L10 , 2X , 'Output AeroDyn FF files?' )" ) p%WrFile(FileExt_BTS) WRITE (p%US,"( L10 , 2X , 'Output BLADED FF files?' )" ) p%WrFile(FileExt_WND) WRITE (p%US,"( L10 , 2X , 'Output tower data?' )" ) p%WrFile(FileExt_TWR) + WRITE (p%US,"( L10 , 2X , 'Output HAWC FF files?' )" ) p%WrFile(FileExt_HAWC) WRITE (p%US,"( L10 , 2X , 'Output formatted FF files?' )" ) p%WrFile(FileExt_UVW) WRITE (p%US,"( L10 , 2X , 'Output coherent turbulence time step file?' )") p%WrFile(FileExt_CTS) - WRITE (p%US,"( L10 , 2X , 'Clockwise rotation when looking downwind?' )" ) p%grid%Clockwise SELECT CASE ( p%IEC%ScaleIEC ) CASE (0) @@ -3949,6 +4126,8 @@ SUBROUTINE ProcessLine_IECturbc(Line, IsIECModel, IECstandard, IECedition, IECed NumTurbInp = .TRUE. IECTurbC = "" + CALL CheckRealVar( PerTurbInt, 'IECTurbC/PerTurbInt', ErrStat, ErrMsg ) + ELSE ! Let's use one of the standard turbulence values (A or B or C). @@ -5293,7 +5472,8 @@ SUBROUTINE DefaultMetBndryCndtns(p) p%met%WindProfileType = 'API' ! ADDED BY YG CASE DEFAULT - p%met%WindProfileType = 'IEC' +! p%met%WindProfileType = 'IEC' + p%met%WindProfileType = 'PL' END SELECT diff --git a/modules/turbsim/src/TSsubs.f90 b/modules/turbsim/src/TSsubs.f90 index ebb48b81ab..27c82ea632 100644 --- a/modules/turbsim/src/TSsubs.f90 +++ b/modules/turbsim/src/TSsubs.f90 @@ -1144,8 +1144,8 @@ SUBROUTINE CalcTargetPSD(p, S, U, ErrStat, ErrMsg) DO iPoint=1+p%usr%NPoints,p%grid%NPoints - CALL Spec_TimeSer( p, p%grid%Z(iPoint), U(iPoint), LastIndex, SSVS ) - S(:,iPoint,:) = SSVS*HalfDelF + CALL Spec_TimeSer( p, p%grid%Z(iPoint), U(iPoint), LastIndex, SSVS ) + S(:,iPoint,:) = SSVS*HalfDelF ENDDO CASE ( SpecModel_USRVKM ) @@ -1808,7 +1808,7 @@ SUBROUTINE ScaleTimeSeries(p, V, ErrStat, ErrMsg) SpecModel_USRVKM, & SpecModel_TIDAL, & SpecModel_RIVER, & - SpecModel_USER ) ! Do reynolds stress for HYDRO also. + SpecModel_USER ) CALL TimeSeriesScaling_ReynoldsStress(p, V, ErrStat, ErrMsg) @@ -1868,7 +1868,7 @@ SUBROUTINE TimeSeriesScaling_IEC(p, V) ELSE ! Scale each point individually - DO Indx = 1,p%grid%NPoints + DO Indx = 1,p%grid%NPoints CGridSum = 0.0 CGridSum2 = 0.0 @@ -2159,7 +2159,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL GetNewUnit( UnOut ) WRITE (p%US,"( // 'You have requested that the following file(s) be generated:' / )") -! CALL WrScr1 ( ' You have requested that the following file(s) be generated:' ) IF ( p%WrFile(FileExt_BIN) ) THEN @@ -2169,7 +2168,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".bin (binary hub-height turbulence-parameter file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.bin (binary hub-height turbulence-parameter file)' ) ENDIF @@ -2180,7 +2178,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US, "( 3X ,'"//TRIM( p%RootName)//".dat (formatted turbulence-parameter file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.dat (formatted turbulence-parameter file)' ) ENDIF @@ -2191,7 +2188,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".hh (AeroDyn hub-height file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.hh (AeroDyn hub-height file)' ) ENDIF @@ -2202,7 +2198,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".bts (AeroDyn/TurbSim full-field wind file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.bts (AeroDyn/TurbSim full-field wind file)' ) ENDIF @@ -2213,7 +2208,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".wnd (AeroDyn/BLADED full-field wnd file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.wnd (AeroDyn/BLADED full-field wnd file)' ) ENDIF @@ -2224,7 +2218,6 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".twr (binary tower file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.twr (binary tower file)' ) ENDIF @@ -2235,18 +2228,22 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".cts (coherent turbulence time step file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.cts (coherent turbulence time step file)' ) + ENDIF + + IF ( p%WrFile(FileExt_HAWC) ) THEN + WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//"-u.bin (HAWC binary full-field u-component file)' )") + + WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//"-v.bin (HAWC binary full-field v-component file)' )") + + WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//"-w.bin (HAWC binary full-field w-component file)' )") ENDIF IF ( p%WrFile(FileExt_UVW) ) THEN WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".u (formatted full-field U-component file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.u (formatted full-field U-component file)' ) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".v (formatted full-field V-component file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.v (formatted full-field V-component file)' ) WRITE (p%US,"( 3X ,'"//TRIM( p%RootName)//".w (formatted full-field W-component file)' )") -! CALL WrScr ( ' '//TRIM( p%RootName)//'.w (formatted full-field W-component file)' ) ENDIF ELSE @@ -2255,7 +2252,7 @@ SUBROUTINE TS_ValidateInput(P, ErrStat, ErrMsg) ! WARN if using a large grid and not creating ff output files IF ( p%grid%NumGrid_Y*p%grid%NumGrid_Z > 250 ) THEN - IF (.NOT. p%WrFile(FileExt_WND) .AND. .NOT. p%WrFile(FileExt_BTS) .AND. .NOT. p%WrFile(FileExt_UVW) ) THEN + IF (.NOT. p%WrFile(FileExt_WND) .AND. .NOT. p%WrFile(FileExt_BTS) .AND. .NOT. p%WrFile(FileExt_HAWC) .AND. .NOT. p%WrFile(FileExt_UVW) ) THEN CALL SetErrStat( ErrID_Warn, 'You are using a large number of grid points but are not generating full-field output files.'//& ' The simulation will run faster if you reduce the number of points on the grid.', ErrStat, ErrMsg, RoutineName) diff --git a/modules/turbsim/src/TurbSim.f90 b/modules/turbsim/src/TurbSim.f90 index e07223fa27..5aa65491aa 100644 --- a/modules/turbsim/src/TurbSim.f90 +++ b/modules/turbsim/src/TurbSim.f90 @@ -83,7 +83,6 @@ PROGRAM TurbSim INTEGER(IntKi) :: ErrStat ! allocation status CHARACTER(MaxMsgLen) :: ErrMsg ! error message CHARACTER(200) :: InFile ! Name of the TurbSim input file. -CHARACTER(200) :: git_commit ! String containing the current git commit hash CHARACTER(20) :: FlagArg ! flag argument from command line @@ -106,10 +105,10 @@ PROGRAM TurbSim ! Display the copyright notice CALL DispCopyrightLicense( TurbSim_Ver%Name ) ! Obtain OpenFAST git commit hash - git_commit = QueryGitVersion() + TurbSim_Ver%Ver = 'from OpenFAST-'//TRIM(QueryGitVersion()) ! Tell our users what they're running - CALL WrScr( ' Running '//TRIM( TurbSim_Ver%Name )//' a part of OpenFAST - '//TRIM(git_Commit)//NewLine//' linked with '//TRIM( NWTC_Ver%Name )//NewLine ) - + CALL WrScr( ' Running '//TRIM( GetNVD(TurbSim_Ver) )//NewLine ) + CALL GetRoot( InFile, p%RootName ) ! Open input file and summary file. @@ -311,7 +310,7 @@ PROGRAM TurbSim !.................................................................................................................................. ! Are we generating binary FF files? -IF ( p%WrFile(FileExt_BTS) .OR. p%WrFile(FileExt_WND) ) THEN +IF ( p%WrFile(FileExt_BTS) .OR. p%WrFile(FileExt_WND) .OR. p%WrFile(FileExt_HAWC) ) THEN CALL WrSum_InterpolatedHubStats(p, V) IF ( p%WrFile(FileExt_BTS) ) THEN @@ -323,6 +322,12 @@ PROGRAM TurbSim CALL WrBinBLADED(p, V, USig, VSig, WSig, ErrStat, ErrMsg) CALL CheckError(ErrStat, ErrMsg) END IF + + IF ( p%WrFile(FileExt_HAWC) ) THEN + CALL WrBinHAWC( p, V, USig, VSig, WSig, ErrStat, ErrMsg ) + CALL CheckError(ErrStat, ErrMsg) + END IF + END IF diff --git a/modules/turbsim/src/TurbSim_Types.f90 b/modules/turbsim/src/TurbSim_Types.f90 index 3e99754b08..c4a6071032 100644 --- a/modules/turbsim/src/TurbSim_Types.f90 +++ b/modules/turbsim/src/TurbSim_Types.f90 @@ -3,7 +3,7 @@ MODULE TurbSim_Types use NWTC_Library - TYPE(ProgDesc), PARAMETER :: TurbSim_Ver = ProgDesc( 'TurbSim', '', '' ) + TYPE(ProgDesc) :: TurbSim_Ver = ProgDesc( 'TurbSim', '', '' ) LOGICAL, PARAMETER :: MVK = .FALSE. ! This parameter has been added to replace the NON-STANDARD compiler directive previously used LOGICAL, PARAMETER :: PeriodicY = .FALSE. !.TRUE. @@ -54,7 +54,8 @@ MODULE TurbSim_Types INTEGER(IntKi), PARAMETER :: FileExt_UVW = 6 ! .u, .v, .w files : formatted FF data (Traditional SNLWIND-3D format) [WrFMTFF] INTEGER(IntKi), PARAMETER :: FileExt_CTS = 7 ! .cts file : coherent turbulence INTEGER(IntKi), PARAMETER :: FileExt_TWR = 8 ! .twr file : AeroDyn tower data (binary) - INTEGER(IntKi), PARAMETER :: NumFileFmt = 8 ! TOTAL number of output file formats (used to dimension array) + INTEGER(IntKi), PARAMETER :: FileExt_HAWC = 9 ! -u.bin, -v.bin, -w.bin .hawc files: binary HAWC FF data [WrHAWCFF] + INTEGER(IntKi), PARAMETER :: NumFileFmt = 9 ! TOTAL number of output file formats (used to dimension array) ! other parameters: REAL(ReKi), PARAMETER :: ZJetMax_UB = 490.0_ReKi ! upper bound on height where jet maximum occurs @@ -136,7 +137,6 @@ MODULE TurbSim_Types INTEGER(IntKi) :: NumOutSteps ! Number of output time steps. LOGICAL :: Periodic ! Flag to indicate that output files must contain exactly one full (time) period - LOGICAL :: Clockwise ! Flag to indicate clockwise rotation when looking downwind. end type Grid_ParameterType diff --git a/modules/version/CMakeLists.txt b/modules/version/CMakeLists.txt index 1a1b0af02d..34a7891b3e 100644 --- a/modules/version/CMakeLists.txt +++ b/modules/version/CMakeLists.txt @@ -28,6 +28,8 @@ endif() add_definitions(-DGIT_VERSION_INFO="${GIT_DESCRIBE}") add_library(versioninfolib src/VersionInfo.f90) +target_link_libraries(versioninfolib nwtclibs) + install(TARGETS versioninfolib EXPORT "${CMAKE_PROJECT_NAME}Libraries" diff --git a/modules/version/README.md b/modules/version/README.md index f2efaabd76..0d79b7d4f8 100644 --- a/modules/version/README.md +++ b/modules/version/README.md @@ -18,3 +18,9 @@ For example, ``OpenFAST-v1.0.0-123-gabcd1234-dirty`` describes OpenFAST as: build [the ``-g`` is for ``git``] - abcd1234 is the first 8 characters of the current commit hash - dirty denotes that local changes have been made but not committed + +To make use of version information when checking command-line arguments, +the `CheckArgs` routine that was previously in NWTC_Library has been moved +to this module. This ensures that the version information does not have to +be one of the first modules to be compiled. (The goal is that NWTC Library +does not depend on the VersionInfo module.) diff --git a/modules/version/src/VersionInfo.f90 b/modules/version/src/VersionInfo.f90 index 27dbc73e7b..1f03e97a90 100644 --- a/modules/version/src/VersionInfo.f90 +++ b/modules/version/src/VersionInfo.f90 @@ -20,6 +20,7 @@ !********************************************************************************************************************************** MODULE VersionInfo + use NWTC_Library implicit none contains @@ -42,4 +43,291 @@ FUNCTION QueryGitVersion() RETURN END FUNCTION QueryGitVersion + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This function returns a string describing the glue code and some of the compilation options we're using. +FUNCTION GetVersion(ThisProgVer, Cmpl4SFun, Cmpl4LV) + + ! Passed Variables: + + TYPE(ProgDesc), INTENT( IN ) :: ThisProgVer !< program name/date/version description + LOGICAL, INTENT(IN), OPTIONAL :: Cmpl4SFun + LOGICAL, INTENT(IN), OPTIONAL :: Cmpl4LV + CHARACTER(1024) :: GetVersion !< String containing a description of the compiled precision. + + CHARACTER(200) :: git_commit + + GetVersion = TRIM(GetNVD(ThisProgVer))//', compiled' + + if (present(Cmpl4SFun)) then + IF ( Cmpl4SFun ) THEN ! FAST has been compiled as an S-Function for Simulink + GetVersion = TRIM(GetVersion)//' as a DLL S-Function for Simulink' + ENDIF + endif + + if (present(Cmpl4LV)) then + IF ( Cmpl4LV ) THEN ! FAST has been compiled as a DLL for Labview + GetVersion = TRIM(GetVersion)//' as a DLL for LabVIEW' + ENDIF + endif + + GetVersion = TRIM(GetVersion)//' as a '//TRIM(Num2LStr(BITS_IN_ADDR))//'-bit application using' + + ! determine precision + + IF ( ReKi == SiKi ) THEN ! Single precision + GetVersion = TRIM(GetVersion)//' single' + ELSEIF ( ReKi == R8Ki ) THEN ! Double precision + GetVersion = TRIM(GetVersion)// ' double' + ELSE ! Unknown precision + GetVersion = TRIM(GetVersion)//' unknown' + ENDIF + + +! GetVersion = TRIM(GetVersion)//' precision with '//OS_Desc + GetVersion = TRIM(GetVersion)//' precision' + + ! add git info + git_commit = QueryGitVersion() + GetVersion = TRIM(GetVersion)//' at commit '//git_commit + + RETURN +END FUNCTION GetVersion + +!======================================================================= +!> + SUBROUTINE DispCompileRuntimeInfo(name) +#ifdef _OPENMP + USE OMP_LIB +#endif +#ifdef HAS_FORTRAN2008_FEATURES + USE iso_fortran_env, ONLY: compiler_version +#endif + CHARACTER(*), intent(in) :: name + CHARACTER(200) :: compiler_version_str + CHARACTER(200) :: git_commit, architecture, compiled_precision + CHARACTER(200) :: execution_date, execution_time, execution_zone + +! name = ProgName + git_commit = QueryGitVersion() + architecture = TRIM(Num2LStr(BITS_IN_ADDR))//' bit' + IF (ReKi == SiKi) THEN + compiled_precision = 'single' + ELSE IF (ReKi == R8Ki) THEN + compiled_precision = 'double' + ELSE + compiled_precision = 'unknown' + END IF + +#if defined(HAS_FORTRAN2008_FEATURES) + compiler_version_str = compiler_version() +#elif defined(__INTEL_COMPILER) + compiler_version_str = 'Intel(R) Fortran Compiler '//num2lstr(__INTEL_COMPILER) +#else + compiler_version_str = OS_Desc +#endif + + CALL WrScr(trim(name)//'-'//trim(git_commit)) + CALL WrScr('Compile Info:') + call wrscr(' - Compiler: '//trim(compiler_version_str)) + CALL WrScr(' - Architecture: '//trim(architecture)) + CALL WrScr(' - Precision: '//trim(compiled_precision)) +#ifdef _OPENMP + !$OMP PARALLEL default(shared) + if (omp_get_thread_num()==0) then + call WrScr(' - OpenMP: Yes, number of threads: '//trim(Num2LStr(omp_get_num_threads()))//'/'//trim(Num2LStr(omp_get_max_threads()))) + endif + !$OMP END PARALLEL +#else + call WrScr(' - OpenMP: No') +#endif + CALL WrScr(' - Date: '//__DATE__) + CALL WrScr(' - Time: '//__TIME__) + ! call wrscr(' - Options: '//trim(compiler_options())) + + CALL DATE_AND_TIME(execution_date, execution_time, execution_zone) + + CALL WrScr('Execution Info:') + CALL WrScr(' - Date: '//TRIM(execution_date(5:6)//'/'//execution_date(7:8)//'/'//execution_date(1:4))) + CALL WrScr(' - Time: '//TRIM(execution_time(1:2)//':'//execution_time(3:4)//':'//execution_time(5:6))//TRIM(execution_zone)) + CALL WrScr('') + + END SUBROUTINE DispCompileRuntimeInfo + +!======================================================================= +!> This subroutine checks for command-line arguments. + SUBROUTINE CheckArgs ( Arg1, ErrStat, Arg2, Flag, InputArgArray ) + + ! Argument declarations: + CHARACTER(*), INTENT(INOUT) :: Arg1 !< The first non-flag argument; generally, the name of the input file. + INTEGER, INTENT( OUT), OPTIONAL :: ErrStat !< An optional argument for catching errors; if present, program does not abort on error. + CHARACTER(*), INTENT( OUT), OPTIONAL :: Arg2 !< An optional 2nd non-flag argument. + CHARACTER(*), INTENT( OUT), OPTIONAL :: Flag !< An optional flag argument; the first argument starting with a switch character. + CHARACTER(*), INTENT(IN ), DIMENSION(:), OPTIONAL :: InputArgArray !< An optional argument containing the arguments to parse; primarily used for unit testing. + + ! Local declarations: + INTEGER :: I, J ! Iterator variables + CHARACTER(1024) :: Arg, FlagIter + CHARACTER(1024), DIMENSION(:), ALLOCATABLE :: ArgArray, TempArray, Flags + LOGICAL :: FirstArgumentSet, SecondArgumentSet + + FirstArgumentSet = .FALSE. + SecondArgumentSet = .FALSE. + + IF ( PRESENT(Arg2) ) Arg2 = "" + IF ( PRESENT(Flag) ) Flag = "" + + ! Save all arguments in a single argument array; this is primarily used to enable unit testing + IF ( PRESENT(InputArgArray) ) THEN + ALLOCATE( ArgArray( SIZE(InputArgArray) ) ) + ArgArray = InputArgArray + ELSE + ALLOCATE( ArgArray( COMMAND_ARGUMENT_COUNT() ) ) + DO I = 1, SIZE(ArgArray) + CALL GET_COMMAND_LINE_ARG( I, ArgArray(I) ) + END DO + END IF + + ! Early return if no arguments and no default input file given + IF ( SIZE(ArgArray) == 0 .AND. LEN( TRIM(Arg1) ) == 0 ) THEN + CALL INVALID_SYNTAX( 'no command-line arguments given.' ) + CALL CLEANUP() + RETURN + END IF + + ! Split arguments into flags and non-flags + ALLOCATE( Flags(0) ) + DO I = 1, SIZE(ArgArray) + Arg = TRIM(ArgArray(I)) + IF ( IsFlag(Arg) ) THEN + ! This is how we can dynamically resize an array in Fortran... + ! Dont do this where performance matters. + ALLOCATE( TempArray( SIZE(Flags) + 1 ) ) + DO J = 1, SIZE(Flags) + TempArray(J) = Flags(J) + END DO + TempArray(SIZE(Flags) + 1) = TRIM(Arg) + DEALLOCATE(Flags) + CALL MOVE_ALLOC(TempArray, Flags) + ELSE IF ( .NOT. FirstArgumentSet ) THEN + Arg1 = TRIM(Arg) + FirstArgumentSet = .TRUE. + ELSE IF ( .NOT. SecondArgumentSet ) THEN + Arg2 = TRIM(Arg) + SecondArgumentSet = .True. + ELSE + CALL INVALID_SYNTAX( 'too many command-line arguments given.' ) + CALL CLEANUP() + RETURN + END IF + END DO + + DO I = 1, SIZE(Flags) + + FlagIter = Flags(I)(2:) ! This results in the flag without the switch character + CALL Conv2UC( FlagIter ) + IF ( PRESENT(Flag) ) Flag = FlagIter + + SELECT CASE ( TRIM(FlagIter) ) + + CASE ('H') + CALL DispCopyrightLicense( ProgName ) + CALL DispCompileRuntimeInfo( ProgName ) + CALL NWTC_DisplaySyntax( Arg1, ProgName ) + IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None + CALL CLEANUP() + RETURN + + CASE ('V', 'VERSION') + CALL DispCopyrightLicense( ProgName ) + CALL DispCompileRuntimeInfo( ProgName ) + IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None + CALL CLEANUP() + RETURN + + CASE ('RESTART') + IF ( FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN + Arg2 = Arg1 + Arg1 = "" + END IF + IF ( .NOT. FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN + CALL INVALID_SYNTAX( 'the restart capability requires at least one argument: -restart ' ) + CALL CLEANUP() + RETURN + END IF + + CASE ('VTKLIN') + IF ( FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN + Arg2 = Arg1 + Arg1 = "" + END IF + IF ( .NOT. FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN + CALL INVALID_SYNTAX( 'the restart capability for vtk mode shapes requires at least one argument: -vtklin ' ) + CALL CLEANUP() + RETURN + END IF + + CASE DEFAULT + CALL INVALID_SYNTAX( 'unknown command-line argument given: '//TRIM(FlagIter) ) + CALL CLEANUP() + RETURN + + END SELECT + + END DO + + IF ( PRESENT( ErrStat ) ) ErrStat = ErrID_None + CALL CLEANUP() + + RETURN + + CONTAINS + SUBROUTINE CLEANUP() + IF ( ALLOCATED(ArgArray) ) DEALLOCATE(ArgArray) + IF ( ALLOCATED(Flags) ) DEALLOCATE(Flags) + IF ( ALLOCATED(TempArray) ) DEALLOCATE(TempArray) + END SUBROUTINE + + SUBROUTINE INVALID_SYNTAX(ErrorMessage) + + CHARACTER(*), INTENT(IN) :: ErrorMessage + + CALL DispCopyrightLicense( ProgName ) + CALL DispCompileRuntimeInfo( ProgName ) + CALL NWTC_DisplaySyntax( Arg1, ProgName ) + CALL ProgAbort( ' Invalid syntax: '//TRIM(ErrorMessage), PRESENT(ErrStat) ) + IF ( PRESENT(ErrStat) ) ErrStat = ErrID_Fatal + + END SUBROUTINE + + SUBROUTINE GET_COMMAND_LINE_ARG(ArgIndex, ArgGiven) + + INTEGER, INTENT(IN) :: ArgIndex !< Index location of the argument to get. + CHARACTER(1024), INTENT(OUT) :: ArgGiven !< The gotten command-line argument. + INTEGER :: Error !< Indicates if there was an error getting an argument. + + CALL GET_COMMAND_ARGUMENT( ArgIndex, ArgGiven, STATUS=Error ) + ArgGiven = TRIM(ArgGiven) + IF ( Error /= 0 ) THEN + CALL ProgAbort ( ' Error getting command-line argument #'//TRIM( Int2LStr( ArgIndex ) )//'.', PRESENT(ErrStat) ) + IF ( PRESENT(ErrStat) ) ErrStat = ErrID_Fatal + END IF + + END SUBROUTINE + + FUNCTION IsFlag(ArgString) + + CHARACTER(*), INTENT(IN) :: ArgString + LOGICAL :: IsFlag + + IF ( ArgString(1:1) == SwChar .OR. ArgString(1:1) == '-' ) THEN + IsFlag = .TRUE. + ELSE + IsFlag = .FALSE. + END IF + + END FUNCTION + + END SUBROUTINE CheckArgs + END MODULE diff --git a/modules/version/tests/VersionInfo_test_tools.F90 b/modules/version/tests/VersionInfo_test_tools.F90 new file mode 100644 index 0000000000..30e67ae0f7 --- /dev/null +++ b/modules/version/tests/VersionInfo_test_tools.F90 @@ -0,0 +1,27 @@ +module versioninfo_test_tools + +use NWTC_IO + +implicit none + +#ifdef _WIN32 + character(9), parameter :: nullfile="NUL" + character(11), parameter :: terminal="CON" +#else + character(9), parameter :: nullfile="/dev/null" + character(11), parameter :: terminal="/dev/stdout" +#endif + +integer, parameter :: stdout=CU + +contains + +subroutine hide_terminal_output() + open(unit=stdout, file=trim(nullfile)) +end subroutine + +subroutine show_terminal_output() + open(unit=stdout, file=terminal, status="old") +end subroutine + +end module diff --git a/modules/nwtc-library/tests/test_NWTC_IO_CheckArgs.F90 b/modules/version/tests/test_VersionInfo_CheckArgs.F90 similarity index 99% rename from modules/nwtc-library/tests/test_NWTC_IO_CheckArgs.F90 rename to modules/version/tests/test_VersionInfo_CheckArgs.F90 index 49b4d207e1..78e0b7722b 100644 --- a/modules/nwtc-library/tests/test_NWTC_IO_CheckArgs.F90 +++ b/modules/version/tests/test_VersionInfo_CheckArgs.F90 @@ -1,13 +1,13 @@ -module test_NWTC_IO_CheckArgs +module test_VersionInfo_CheckArgs use pFUnit_mod - use NWTC_IO - use nwtc_library_test_tools + use VersionInfo + use versioninfo_test_tools implicit none -contains - + contains + ! PASSING CASES ! ************************************************************************ diff --git a/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 114b3d8771..38451a4247 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -94,6 +94,11 @@ foreach(turbineDirectory 5MW_Baseline AOC AWT27 SWRT UAE_VI WP_Baseline) DESTINATION "${CTEST_BINARY_DIR}/glue-codes/openfast/") endforeach() +foreach(turbineDirectory 5MW_Baseline) + file(COPY "${CMAKE_CURRENT_LIST_DIR}/r-test/glue-codes/openfast/${turbineDirectory}" + DESTINATION "${CTEST_BINARY_DIR}/glue-codes/python/") +endforeach() + ## fastfarm seed foreach(turbineDirectory 5MW_Baseline) file(COPY "${CMAKE_CURRENT_LIST_DIR}/r-test/glue-codes/fast-farm/${turbineDirectory}" @@ -123,6 +128,23 @@ add_custom_command( COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON_OC3/build/DISCON_OC3Hywind.dll" "${of_dest}" ) +set(ofpy_dest "${CTEST_BINARY_DIR}/glue-codes/python/5MW_Baseline/ServoData/") +add_custom_command( + OUTPUT "${ofpy_dest}/DISCON.dll" + DEPENDS DISCON + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON/build/DISCON.dll" "${ofpy_dest}" +) +add_custom_command( + OUTPUT "${ofpy_dest}/DISCON_ITIBarge.dll" + DEPENDS DISCON_ITIBarge + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON_ITI/build/DISCON_ITIBarge.dll" "${ofpy_dest}" +) +add_custom_command( + OUTPUT "${ofpy_dest}/DISCON_OC3Hywind.dll" + DEPENDS DISCON_OC3Hywind + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON_OC3/build/DISCON_OC3Hywind.dll" "${ofpy_dest}" +) + set(ff_dest "${CTEST_BINARY_DIR}/glue-codes/fast-farm/5MW_Baseline/ServoData/") add_custom_command( OUTPUT "${ff_dest}/DISCON_WT1.dll" @@ -141,13 +163,32 @@ add_custom_command( ) add_custom_target( - regression_tests + regression_test_controllers DEPENDS - openfast "${of_dest}/DISCON.dll" "${of_dest}/DISCON_ITIBarge.dll" "${of_dest}/DISCON_OC3Hywind.dll" + "${ofpy_dest}/DISCON.dll" + "${ofpy_dest}/DISCON_ITIBarge.dll" + "${ofpy_dest}/DISCON_OC3Hywind.dll" "${ff_dest}/DISCON_WT1.dll" "${ff_dest}/DISCON_WT2.dll" "${ff_dest}/DISCON_WT3.dll" ) + +add_custom_target( + regression_tests + DEPENDS + openfast + regression_test_controllers +) + +add_custom_target( + regression_test_module_drivers + DEPENDS + aerodyn_driver + beamdyn_driver + hydrodyn_driver + inflowwind_driver + subdyn_driver +) \ No newline at end of file diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index caa9a352ac..7542433367 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -38,14 +38,21 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TEST set(RUN_VERBOSE_FLAG "") if(CTEST_RUN_VERBOSE_FLAG) - set(RUN_VERBOSE_FLAG "-v") + set(RUN_VERBOSE_FLAG "-v") endif() + set(TESTDIR ${TESTNAME}) + + set(extra_args ${ARGN}) + list(LENGTH extra_args n_args) + if(n_args EQUAL 1) + set(TESTDIR ${extra_args}) + endif() add_test( ${TESTNAME} ${PYTHON_EXECUTABLE} ${TEST_SCRIPT} - ${TESTNAME} + ${TESTDIR} ${EXECUTABLE} ${SOURCE_DIRECTORY} # openfast source directory ${BUILD_DIRECTORY} # build directory for test @@ -72,6 +79,14 @@ function(of_regression TESTNAME LABEL) regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(of_regression) +function(of_cpp_regression TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastRegressionCase.py") + set(OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast_cpp") + set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") + set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} "${TESTNAME}_cpp" "${LABEL}" ${TESTNAME}) +endfunction(of_cpp_regression) + # openfast aeroacoustic function(of_regression_aeroacoustic TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastAeroAcousticRegressionCase.py") @@ -99,14 +114,23 @@ function(of_regression_linear TESTNAME LABEL) regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(of_regression_linear) -# openfast c-interface -function(of_regression_cpp TESTNAME LABEL) +# openfast C++ interface +function(of_cpp_interface_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastCppRegressionCase.py") 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}") -endfunction(of_regression_cpp) +endfunction(of_cpp_interface_regression) + +# openfast Python-interface +function(of_regression_py TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executePythonRegressionCase.py") + 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}") +endfunction(of_regression_py) # aerodyn function(ad_regression TESTNAME LABEL) @@ -135,6 +159,15 @@ function(hd_regression TESTNAME LABEL) regression(${TEST_SCRIPT} ${HYDRODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(hd_regression) +# hydrodyn-Py +function(hd_py_regression TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeHydrodynPyRegressionCase.py") + 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}") +endfunction(hd_py_regression) + # subdyn function(sd_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeSubdynRegressionCase.py") @@ -162,6 +195,14 @@ function(ifw_py_regression TESTNAME LABEL) regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(ifw_py_regression) +# # Python-based OpenFAST Library tests +# function(py_openfast_library_regression TESTNAME LABEL) +# set(test_module "${CMAKE_SOURCE_DIR}/modules/openfast-library/tests/test_openfast_library.py") +# set(input_file "${CMAKE_SOURCE_DIR}/reg_tests/r-test/glue-codes/openfast/5MW_OC4Jckt_ExtPtfm/5MW_OC4Jckt_ExtPtfm.fst") +# add_test(${TESTNAME} ${PYTHON_EXECUTABLE} ${test_module} ${input_file} ) +# endfunction(py_openfast_library_regression) + + #=============================================================================== # Regression tests #=============================================================================== @@ -195,13 +236,32 @@ of_regression("5MW_Land_BD_DLL_WTurb" "openfast;beamdyn;aerodyn of_regression("5MW_OC4Jckt_ExtPtfm" "openfast;elastodyn;extptfm") of_regression("HelicalWake_OLAF" "openfast;aerodyn15;olaf") of_regression("EllipticalWing_OLAF" "openfast;aerodyn15;olaf") -of_regression("StC_test_OC4Semi" "openfast;servodyn;hydrodyn;moordyn;offshore") +of_regression("StC_test_OC4Semi" "openfast;servodyn;hydrodyn;moordyn;offshore;stc") # OpenFAST C++ API test if(BUILD_OPENFAST_CPP_API) - of_regression_cpp("5MW_Land_DLL_WTurb_cpp" "openfast;cpp") + of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;openfastlib;cpp") endif() +# # Python-based OpenFAST Library unit tests +# if(BUILD_SHARED_LIBS) +# py_openfast_library_regression("py_openfastlib" "python;openfastlib") +# endif() + +# OpenFAST C++ Driver test +# This tests the FAST Library and FAST_Library.h +of_cpp_regression("AWT_YFree_WSt" "openfast;openfastlib;cpp;elastodyn;aerodyn15;servodyn") + +# OpenFAST Python API test +of_regression_py("5MW_Land_DLL_WTurb_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn") +of_regression_py("5MW_ITIBarge_DLL_WTurb_WavesIrr_py" "openfast;openfastlib;python;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_OC3Spar_DLL_WTurb_WavesIrr_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_OC4Semi_WSt_WavesWN_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn;offshore") +of_regression_py("5MW_Land_BD_DLL_WTurb_py" "openfast;openfastlib;python;beamdyn;aerodyn15;servodyn") +of_regression_py("HelicalWake_OLAF_py" "openfast;openfastlib;python;aerodyn15;olaf") +of_regression_py("EllipticalWing_OLAF_py" "openfast;openfastlib;python;aerodyn15;olaf") + # AeroAcoustic regression test of_regression_aeroacoustic("IEA_LB_RWT-AeroAcoustics" "openfast;aerodyn15;aeroacoustics") @@ -211,6 +271,8 @@ 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") # FAST Farm regression tests if(BUILD_FASTFARM) @@ -248,6 +310,9 @@ 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") +# HydroDyn-Py regression tests +hd_py_regression("hd_py_5MW_OC4Semi_WSt_WavesWN" "hydrodyn;offshore;python") + # SubDyn regression tests sd_regression("SD_Cable_5Joints" "subdyn;offshore") sd_regression("SD_PendulumDamp" "subdyn;offshore") diff --git a/reg_tests/executeHydrodynPyRegressionCase.py b/reg_tests/executeHydrodynPyRegressionCase.py new file mode 100644 index 0000000000..6f8107cd4a --- /dev/null +++ b/reg_tests/executeHydrodynPyRegressionCase.py @@ -0,0 +1,144 @@ +# +# Copyright 2017 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. +# + +""" + This program executes HydroDyn and a regression test for a single test case. + The test data is contained in a git submodule, r-test, which must be initialized + prior to running. See the r-test README or OpenFAST documentation for more info. + + Get usage with: `executeHydrodynRegressionCase.py -h` +""" + +import os +import sys +basepath = os.path.dirname(__file__) +sys.path.insert(0, os.path.sep.join([basepath, "lib"])) +import argparse +import shutil +import glob +import subprocess +import rtestlib as rtl +import openfastDrivers +import pass_fail +from errorPlotting import exportCaseSummary + +##### Main program + +### Store the python executable for future python calls +pythonCommand = sys.executable + +### Verify input arguments +parser = argparse.ArgumentParser(description="Executes HydroDyn and a regression test for a single test case.") +parser.add_argument("caseName", metavar="Case-Name", type=str, nargs=1, help="The name of the test case.") +parser.add_argument("executable", metavar="HydroDyn-Python", type=str, nargs=1, help="The path to the Python executable.") +parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") +parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") +parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") +parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") +parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("-p", "-plot", dest="plot", default=False, metavar="Plotting-Flag", type=bool, nargs="?", help="bool to include matplotlib plots in failed cases") +parser.add_argument("-n", "-no-exec", dest="noExec", default=False, metavar="No-Execution", type=bool, nargs="?", help="bool to prevent execution of the test cases") +parser.add_argument("-v", "-verbose", dest="verbose", default=False, metavar="Verbose-Flag", type=bool, nargs="?", help="bool to include verbose system output") + +args = parser.parse_args() + +caseName = args.caseName[0] +executable = args.executable[0] +sourceDirectory = args.sourceDirectory[0] +buildDirectory = args.buildDirectory[0] +tolerance = args.tolerance[0] +plotError = args.plot if args.plot is False else True +noExec = args.noExec if args.noExec is False else True +verbose = args.verbose if args.verbose is False else True + +# validate inputs +rtl.validateExeOrExit(executable) +rtl.validateDirOrExit(sourceDirectory) +if not os.path.isdir(buildDirectory): + os.makedirs(buildDirectory) + +### Build the filesystem navigation variables for running the test case +regtests = os.path.join(sourceDirectory, "reg_tests") +lib = os.path.join(regtests, "lib") +rtest = os.path.join(regtests, "r-test") +moduleDirectory = os.path.join(rtest, "modules", "hydrodyn") +inputsDirectory = os.path.join(moduleDirectory, caseName) +targetOutputDirectory = os.path.join(inputsDirectory) +testBuildDirectory = os.path.join(buildDirectory, caseName) + +# verify all the required directories exist +if not os.path.isdir(rtest): + rtl.exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) +if not os.path.isdir(targetOutputDirectory): + rtl.exitWithError("The test data outputs directory, {}, does not exist. Try running `git submodule update`".format(targetOutputDirectory)) +if not os.path.isdir(inputsDirectory): + rtl.exitWithError("The test data inputs directory, {}, does not exist. Verify your local repository is up to date.".format(inputsDirectory)) + +# create the local output directory if it does not already exist +# and initialize it with input files for all test cases +if not os.path.isdir(testBuildDirectory): + os.makedirs(testBuildDirectory) + for file in glob.glob(os.path.join(inputsDirectory,"*py")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + for file in glob.glob(os.path.join(inputsDirectory,"hd_*inp")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + for file in glob.glob(os.path.join(inputsDirectory,"*dat")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + +### Run HydroDyn on the test case +if not noExec: + caseInputFile = os.path.join(testBuildDirectory, "hydrodyn_driver.py") + returnCode = openfastDrivers.runHydrodynDriverCase(caseInputFile, executable) + if returnCode != 0: + rtl.exitWithError("") + +### Build the filesystem navigation variables for running the regression test +localOutFile = os.path.join(testBuildDirectory, "hd_py.out") +baselineOutFile = os.path.join(targetOutputDirectory, "hd_py.out") +rtl.validateFileOrExit(localOutFile) +rtl.validateFileOrExit(baselineOutFile) + +testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) +performance = pass_fail.calculateNorms(testData, baselineData) +normalizedNorm = performance[:, 1] + +# export all case summaries +results = list(zip(testInfo["attribute_names"], [*performance])) +results_max = performance.max(axis=0) +exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) + +# failing case +if not pass_fail.passRegressionTest(normalizedNorm, tolerance): + if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] + failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] + failResults = [res for i, res in enumerate(results) if i in ixFailChannels] + for channel in failChannels: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error.msg)) + finalizePlotDirectory(localOutFile, failChannels, caseName) + sys.exit(1) + +# passing case +sys.exit(0) diff --git a/reg_tests/executeOpenfastCppRegressionCase.py b/reg_tests/executeOpenfastCppRegressionCase.py index d467d1ac2e..03f9cccc2b 100644 --- a/reg_tests/executeOpenfastCppRegressionCase.py +++ b/reg_tests/executeOpenfastCppRegressionCase.py @@ -133,7 +133,6 @@ def ignoreBaselineItems(directory, contents): if not noExec: cwd = os.getcwd() os.chdir(testBuildDirectory) - print("** CWD: ", os.getcwd()) caseInputFile = os.path.abspath("cDriver.yaml") returnCode = openfastDrivers.runOpenfastCase(caseInputFile, executable) if returnCode != 0: diff --git a/reg_tests/executePythonRegressionCase.py b/reg_tests/executePythonRegressionCase.py new file mode 100644 index 0000000000..58c2599290 --- /dev/null +++ b/reg_tests/executePythonRegressionCase.py @@ -0,0 +1,199 @@ +# +# Copyright 2017 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. +# + +""" + This program executes OpenFAST via the Python interface, and checks the results + in a regression test for a single test case. + The test data is contained in a git submodule, r-test, which must be initialized + prior to running. See the r-test README or OpenFAST documentation for more info. + + Get usage with: `executePythonRegressionCase.py -h` +""" + +import os +import sys +basepath = os.path.sep.join(sys.argv[0].split(os.path.sep)[:-1]) if os.path.sep in sys.argv[0] else "." +sys.path.insert(0, os.path.sep.join([basepath, "lib"])) +sys.path.insert(0, os.path.sep.join([basepath, "..", "glue-codes", "python"])) +import platform +import argparse +import shutil +import subprocess +import rtestlib as rtl +import openfastDrivers +import pass_fail +from errorPlotting import exportCaseSummary +import openfast_library + +##### Helper functions +def ignoreBaselineItems(directory, contents): + itemFilter = ['linux-intel', 'linux-gnu', 'macos-gnu', 'windows-intel'] + caught = [] + for c in contents: + if c in itemFilter: + caught.append(c) + return tuple(caught) + +##### Main program + +### Store the python executable for future python calls +pythonCommand = sys.executable + +### Verify input arguments +parser = argparse.ArgumentParser(description="Executes OpenFAST and a regression test for a single test case.") +parser.add_argument("caseName", metavar="Case-Name", type=str, nargs=1, help="The name of the test case.") +parser.add_argument("executable", metavar="NotUsed", type=str, nargs=1, help="Not used in this script, but kept for API compatibility.") +parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") +parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") +parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") +parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") +parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +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") + +args = parser.parse_args() + +caseName = args.caseName[0].replace("_py", "") +sourceDirectory = args.sourceDirectory[0] +buildDirectory = args.buildDirectory[0] +tolerance = args.tolerance[0] +systemName = args.systemName[0] +compilerId = args.compilerId[0] +plotError = args.plot +noExec = args.noExec +verbose = args.verbose + +# validate inputs +rtl.validateDirOrExit(sourceDirectory) +if not os.path.isdir(buildDirectory): + os.makedirs(buildDirectory) + +### Map the system and compiler configurations to a solution set +# Internal names -> Human readable names +systemName_map = { + "darwin": "macos", + "linux": "linux", + "windows": "windows" +} +compilerId_map = { + "gnu": "gnu", + "intel": "intel" +} +# Build the target output directory name or choose the default +supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] +targetSystem = systemName_map.get(systemName.lower(), "") +targetCompiler = compilerId_map.get(compilerId.lower(), "") +outputType = os.path.join(targetSystem+"-"+targetCompiler) +if outputType not in supportedBaselines: + outputType = supportedBaselines[0] +print("-- Using gold standard files with machine-compiler type {}".format(outputType)) + +### Build the filesystem navigation variables for running openfast on the test case +regtests = os.path.join(sourceDirectory, "reg_tests") +lib = os.path.join(regtests, "lib") +rtest = os.path.join(regtests, "r-test") +moduleDirectory = os.path.join(rtest, "glue-codes", "openfast") +inputsDirectory = os.path.join(moduleDirectory, caseName) +targetOutputDirectory = os.path.join(inputsDirectory, outputType) +testBuildDirectory = os.path.join(buildDirectory, caseName) + +# verify all the required directories exist +if not os.path.isdir(rtest): + rtl.exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) +if not os.path.isdir(targetOutputDirectory): + rtl.exitWithError("The test data outputs directory, {}, does not exist. Try running `git submodule update`".format(targetOutputDirectory)) +if not os.path.isdir(inputsDirectory): + rtl.exitWithError("The test data inputs directory, {}, does not exist. Verify your local repository is up to date.".format(inputsDirectory)) + +# create the local output directory if it does not already exist +# and initialize it with input files for all test cases +for data in ["AOC", "AWT27", "SWRT", "UAE_VI", "WP_Baseline"]: + dataDir = os.path.join(buildDirectory, data) + if not os.path.isdir(dataDir): + shutil.copytree(os.path.join(moduleDirectory, data), dataDir) + +dst = os.path.join(buildDirectory, "5MW_Baseline") +src = os.path.join(moduleDirectory, "5MW_Baseline") +if not os.path.isdir(dst): + shutil.copytree(src, dst) +else: + names = os.listdir(src) + for name in names: + if name == "ServoData": + continue + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + if os.path.isdir(srcname): + if not os.path.isdir(dstname): + shutil.copytree(srcname, dstname) + else: + shutil.copy2(srcname, dstname) + +if not os.path.isdir(testBuildDirectory): + shutil.copytree(inputsDirectory, testBuildDirectory, ignore=ignoreBaselineItems) + +### Run openfast on the test case +if not noExec: + caseInputFile = os.path.join(testBuildDirectory, caseName + ".fst") + openfastlib_path = os.path.join(buildDirectory, "..", "..", "..", "modules", "openfast-library", "libopenfastlib") + if platform.system() == 'Linux': + openfastlib_path += ".so" + elif platform.system() == 'Darwin': + openfastlib_path += ".dylib" + elif platform.system() == 'Windows': + openfastlib_path += ".dll" + else: + raise SystemError("Platform could not be determined: platform.system -> {}".format(platform.system())) + + openfastlib = openfast_library.FastLibAPI(openfastlib_path, caseInputFile) + openfastlib.fast_run() + + output_channel_names = openfastlib.output_channel_names + +### Build the filesystem navigation variables for running the regression test +baselineOutFile = os.path.join(targetOutputDirectory, caseName + ".outb") +rtl.validateFileOrExit(baselineOutFile) + +testInfo = { + "attribute_names": output_channel_names +} +testData = openfastlib.output_values +baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) +performance = pass_fail.calculateNorms(testData, baselineData) +normalizedNorm = performance[:, 1] + +# export all case summaries +results = list(zip(testInfo["attribute_names"], [*performance])) +results_max = performance.max(axis=0) +exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) + +# failing case +if not pass_fail.passRegressionTest(normalizedNorm, tolerance): + if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + + sys.exit(1) + +# passing case +sys.exit(0) diff --git a/reg_tests/lib/fast_io.py b/reg_tests/lib/fast_io.py index 9a2b3d0fb0..5ea220657c 100644 --- a/reg_tests/lib/fast_io.py +++ b/reg_tests/lib/fast_io.py @@ -64,10 +64,6 @@ def load_ascii_output(filename): info['attribute_names'] = header[6].split() info['attribute_units'] = [unit[1:-1] for unit in header[7].split()] #removing "()" data = np.array([line.split() for line in f.readlines()], dtype=np.float) - if np.any(np.isnan(data)): - raise ValueError("NaN found in test data: {}".format(filename)) - if np.any(np.isinf(data)): - raise ValueError("Infinity found in test data: {}".format(filename)) return data, info def load_binary_output(filename): diff --git a/reg_tests/lib/openfastDrivers.py b/reg_tests/lib/openfastDrivers.py index 751c6c492a..a9c92de172 100644 --- a/reg_tests/lib/openfastDrivers.py +++ b/reg_tests/lib/openfastDrivers.py @@ -67,14 +67,14 @@ def runBeamdynDriverCase(inputFile, executable, verbose=False): return _runGenericCase(inputFile, executable, verbose) def runHydrodynDriverCase(inputFile, executable, verbose=False): - caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) - os.chdir(caseDirectory) - return _runGenericCase(inputFile, executable, verbose) + caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) + os.chdir(caseDirectory) + return _runGenericCase(inputFile, executable, verbose) def runSubdynDriverCase(inputFile, executable, verbose=False): - caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) - os.chdir(caseDirectory) - return _runGenericCase(inputFile, executable, verbose) + caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) + os.chdir(caseDirectory) + return _runGenericCase(inputFile, executable, verbose) def runInflowwindDriverCase(inputFile, executable, verbose=False): caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) diff --git a/reg_tests/lib/pass_fail.py b/reg_tests/lib/pass_fail.py index 51daa17f46..3bfdf0062a 100644 --- a/reg_tests/lib/pass_fail.py +++ b/reg_tests/lib/pass_fail.py @@ -31,6 +31,10 @@ def readFASTOut(fastoutput): rtl.exitWithError("Error: {}".format(e)) def passRegressionTest(norm, tolerance): + if np.any(np.isnan(norm)): + return False + if np.any(np.isinf(norm)): + return False return True if max(norm) < tolerance else False def maxnorm(data, axis=0): diff --git a/reg_tests/r-test b/reg_tests/r-test index d90ac2a3c1..166b0a439d 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit d90ac2a3c1b1abf59a1634f8642c96b2ca34c4c7 +Subproject commit 166b0a439d9defa02ea21a0a32fc30fce88dfede diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 4339b0c437..3278ec162e 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -73,8 +73,9 @@ add_subdirectory("beamdyn") add_subdirectory("nwtc-library") add_subdirectory("aerodyn") add_subdirectory("inflowwind") +add_subdirectory("version") add_custom_target( unit_tests - DEPENDS beamdyn_utest nwtc_library_utest fvw_utest inflowwind_utest + DEPENDS beamdyn_utest nwtc_library_utest fvw_utest inflowwind_utest versioninfo_utest ) diff --git a/unit_tests/nwtc-library/CMakeLists.txt b/unit_tests/nwtc-library/CMakeLists.txt index a78dda84b2..cb338b649f 100644 --- a/unit_tests/nwtc-library/CMakeLists.txt +++ b/unit_tests/nwtc-library/CMakeLists.txt @@ -32,7 +32,6 @@ include_directories( set(testlist NWTC_Library_test_tools - test_NWTC_IO_CheckArgs test_NWTC_IO_FileInfo test_NWTC_RandomNumber ) diff --git a/unit_tests/version/CMakeLists.txt b/unit_tests/version/CMakeLists.txt new file mode 100644 index 0000000000..7c7ced8c0a --- /dev/null +++ b/unit_tests/version/CMakeLists.txt @@ -0,0 +1,64 @@ +# +# Copyright 2017 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. +# + +# Tell CMake not to look for this file to exist since its generated by pFUnit during compile +set_source_files_properties(${pfunit_directory}/include/driver.F90 PROPERTIES GENERATED 1) + +set(module_name "versioninfo") +set(module_directory "version") +set(module_library "versioninfolib") + +file(MAKE_DIRECTORY ${build_testdirectory}/${module_directory}) +file(WRITE ${build_testdirectory}/${module_directory}/testSuites.inc "") + +include_directories( + ${PROJECT_SOURCE_DIR} + ${pfunit_directory}/mod + ${build_testdirectory}/${module_directory} +) + +set(testlist + VersionInfo_test_tools + test_VersionInfo_CheckArgs +) +foreach(test ${testlist}) + set(test_dependency pfunit ${source_modulesdirectory}/${module_directory}/tests/${test}.F90) + add_custom_command( + OUTPUT ${build_testdirectory}/${module_directory}/${test}.F90 + COMMAND ${PYTHON_EXECUTABLE} ${pfunit_directory}/bin/pFUnitParser.py ${source_modulesdirectory}/${module_directory}/tests/${test}.F90 ${build_testdirectory}/${module_directory}/${test}.F90 + DEPENDS ${test_dependency} + ) + set(test_sources ${test_sources} ${build_testdirectory}/${module_directory}/${test}.F90) + file(APPEND ${build_testdirectory}/${module_directory}/testSuites.inc "ADD_TEST_SUITE(${test}_suite)\n") +endforeach() + +add_executable( + ${module_name}_utest + ${pfunit_directory}/include/driver.F90 + ${test_sources} +) + +target_link_libraries( + ${module_name}_utest + ${pfunit_directory}${pfunit_lib} + ${module_library} +) + +add_test( + ${module_name}_utest + ${PROJECT_BINARY_DIR}/${module_directory}/${module_name}_utest +) + diff --git a/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.sln b/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.sln new file mode 100644 index 0000000000..2c9e9c94f2 --- /dev/null +++ b/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30503.244 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{A2215CCC-531E-454C-A1F0-E502FB697697}") = "HydroDynDriver_c_lib.dll", "HydroDynDriver_c_lib.vfproj", "{FDA4A02B-B3A7-4D06-847C-941BE44E76FB}" + ProjectSection(ProjectDependencies) = postProject + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} = {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FAST_Registry", "..\Registry\FAST_Registry.vcxproj", "{DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug_Double|Win32 = Debug_Double|Win32 + Debug_Double|x64 = Debug_Double|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release_Double|Win32 = Release_Double|Win32 + Release_Double|x64 = Release_Double|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug_Double|Win32.ActiveCfg = Debug_Double|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug_Double|Win32.Build.0 = Debug_Double|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug_Double|x64.ActiveCfg = Debug_Double|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug_Double|x64.Build.0 = Debug_Double|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug|Win32.ActiveCfg = Debug|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug|Win32.Build.0 = Debug|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug|x64.ActiveCfg = Debug|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Debug|x64.Build.0 = Debug|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release_Double|Win32.ActiveCfg = Release_Double|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release_Double|Win32.Build.0 = Release_Double|Win32 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release_Double|x64.ActiveCfg = Release_Double|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release_Double|x64.Build.0 = Release_Double|x64 + {FDA4A02B-B3A7-4D06-847C-941BE44E76FB}.Release|Win32.ActiveCfg = Release|Win32 + {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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.vfproj b/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.vfproj new file mode 100644 index 0000000000..ae2211356e --- /dev/null +++ b/vs-build/HydroDyn_c_lib/HydroDynDriver_c_lib.vfproj @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vs-build/ReadMe.md b/vs-build/ReadMe.md index eafadb0588..9753796fe0 100644 --- a/vs-build/ReadMe.md +++ b/vs-build/ReadMe.md @@ -15,6 +15,7 @@ The following solution files are available for code development on Windows using - Wind/Wave conditions: - [TurbSim](TurbSim/TurbSim.sln) Generates wind files - [InflowWind driver](InflowWind/InflowWind_driver.sln) Reads and interpolates existing wind files + - [InflowWind c binding](InflowWind/InflowWind_c_binding.sln) Creates a library (DLL/so) of the InflowWind routines that can be called from a C interface. **TO DO: Combine this with InflowWind driver for easier maintenance** - [HydroDyn driver](HydroDyn/HydroDynDriver.sln) - Other: - [Discon](Discon/Discon.sln)