diff --git a/.github/actions/cmake-config/action.yml b/.github/actions/cmake-config/action.yml new file mode 100644 index 0000000000..2ddb93a653 --- /dev/null +++ b/.github/actions/cmake-config/action.yml @@ -0,0 +1,18 @@ +name: 'Configure CMake' +description: 'Configure the CMake project' +author: 'Rafael Mudafort https://github.com/rafmudaf' + +inputs: + build-type: + description: 'Set the CMake build type: Release (-O3); RelWithDebInfo (-O2 -g); Debug (-g)' + default: 'Release' + additional-flags: + description: 'Additional flags to pass directly to the CMake command' + default: '' + +runs: + using: 'composite' + steps: + - run: cmake .. -DCMAKE_BUILD_TYPE=${{ inputs.build-type }} ${{ inputs.additional-flags }} + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/compile-and-test/Dockerfile b/.github/actions/compile-and-test/Dockerfile deleted file mode 100644 index 8a6084bb6c..0000000000 --- a/.github/actions/compile-and-test/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright 2016 National Renewable Energy Laboratory -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -FROM rafmudaf/openfast-ubuntu:dev - -# Move into the openfast directory -WORKDIR /openfast - -COPY entrypoint.sh /entrypoint.sh - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/compile-and-test/action.yml b/.github/actions/compile-and-test/action.yml deleted file mode 100644 index 572382f438..0000000000 --- a/.github/actions/compile-and-test/action.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: 'Compile and test' -description: 'Compile OpenFAST and run the tests' -author: 'NREL' -# inputs: -# build-type: -# description: 'Set the CMake build type: Release (-O3); RelWithDebInfo (-O2 -g); Debug (-g)' -# default: 'Release' -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/.github/actions/compile-and-test/entrypoint.sh b/.github/actions/compile-and-test/entrypoint.sh deleted file mode 100755 index 21be246f9b..0000000000 --- a/.github/actions/compile-and-test/entrypoint.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -verbosecommand() { echo ">>> $1" && eval $1 && echo "<<<"; } - -# Configure Bash to exit if any command returns an error -set -e - -verbosecommand "cd /openfast" - -repo="OpenFAST" -echo "GITHUB_EVENT_NAME: ${GITHUB_EVENT_NAME}" -if [[ "${GITHUB_EVENT_NAME}" != "pull_request" ]]; then - repo=${GITHUB_ACTOR} -fi -# Create a branch "CI" at the current commit from the GH Actor's fork. -verbosecommand "git fetch https://github.com/${repo}/openfast ${GITHUB_REF}:CI" -verbosecommand "git checkout CI" -verbosecommand "git submodule update" - -# Display the current git info -echo "*** git-status from openfast:" -verbosecommand "git status" - -echo "*** git-log from openfast:" -verbosecommand "git log -1" - -verbosecommand "cd /openfast/reg_tests/r-test" -echo "*** git-status from r-test:" -verbosecommand "git status" - -echo "*** git-log from r-test:" -verbosecommand "git log -1" - -verbosecommand "cd /openfast" - -# Display the differences between this commit and `dev` -echo "*** git-diff from ${GITHUB_REF} to dev:" -verbosecommand "git diff dev --numstat" - -# Move into the "build" directory, remove the old reg tests, and compile -verbosecommand "cd /openfast/build" -verbosecommand "rm -rf reg_tests" -verbosecommand "cmake .." -verbosecommand "make -j4 install" - -# Run the tests - -# NWTC Library tests -verbosecommand "ctest -VV -R nwtc_library_utest" - -# BeamDyn-specific tests -verbosecommand "ctest -VV -j7 -R bd_" -verbosecommand "ctest -VV -R beamdyn_utest" - -# OLAF free vortex wake tests -ctest -VV -R fvw_utest - -# OpenFAST linearization tests -# Dont run these in parallel, copying the case files can fail in a race condition -# Exclude the Ideal_Beam test cases -# - They fail consistently in the Docker container when run on GitHub, -# but pass everywhere else including running the same Docker image locally -verbosecommand "ctest -VV -L linear -E Ideal" - -# Subset of OpenFAST regression tests; do not run -## - 9, 16 because they're very sensitive -## - 19, 20 because theyre too long -## - 17, 22, 23 because we dont know why they fail :( -verbosecommand "ctest -VV -j8 -I 1,1,1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,21,24,25,26,27,28,29" diff --git a/.github/actions/compile/action.yml b/.github/actions/compile/action.yml new file mode 100644 index 0000000000..243026586c --- /dev/null +++ b/.github/actions/compile/action.yml @@ -0,0 +1,15 @@ +name: 'Compile OpenFAST' +description: 'Compile part or all of OpenFAST' +author: 'Rafael Mudafort https://github.com/rafmudaf' + +inputs: + build-target: + description: 'Which targets to compile' + default: 'install' + +runs: + using: 'composite' + steps: + - run: make -j4 ${{ inputs.build-target }} + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/git-update/action.yml b/.github/actions/git-update/action.yml new file mode 100644 index 0000000000..c2f1484a62 --- /dev/null +++ b/.github/actions/git-update/action.yml @@ -0,0 +1,22 @@ +name: 'Update the existin OpenFAST project in the Docker image' +description: 'Workaround to avoid recompiling every component since the Docker image has the latest "dev" branch precompiled.' +author: 'Rafael Mudafort https://github.com/rafmudaf' + +inputs: + repository: + description: 'The GitHub repository that is taking action.' + required: true + ref: + description: 'The branch or tag ref that triggered the action.' + required: true + +runs: + using: 'composite' + steps: + - run: | + git config --global user.email "openfast@github_actions.ci" + git config --global user.name "OpenFAST Continuous Integration" + git pull --no-verify https://github.com/${{ inputs.repository }} ${{ inputs.ref }} + git submodule update + working-directory: "/openfast/" + shell: bash diff --git a/.github/actions/tests-gluecode-openfast/action.yml b/.github/actions/tests-gluecode-openfast/action.yml new file mode 100644 index 0000000000..5b83dc96c4 --- /dev/null +++ b/.github/actions/tests-gluecode-openfast/action.yml @@ -0,0 +1,21 @@ +name: 'OpenFAST glue code tests' +description: 'Run tests focused on the OpenFAST glue code' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: 'composite' + steps: + - run: | + ctest -VV -L linear -E Ideal + ctest -VV -j8 -I 1,1,1,2,3,4,5,6,7,8,10,11,12,13,14,15,17,18,21,22,23,24,25,26,27,28,29 + working-directory: "/openfast/build" + shell: bash + +# OpenFAST linearization tests +# Dont run these in parallel, copying the case files can fail in a race condition +# Exclude the Ideal_Beam test cases +# - They fail consistently in the Docker container when run on GitHub, +# but pass everywhere else including running the same Docker image locally + +# Subset of OpenFAST regression tests; do not run +# - 9, 16 because they're very sensitive +# - 19, 20 because they're too long diff --git a/.github/actions/tests-module-aerodyn/action.yml b/.github/actions/tests-module-aerodyn/action.yml new file mode 100644 index 0000000000..7b2e332f56 --- /dev/null +++ b/.github/actions/tests-module-aerodyn/action.yml @@ -0,0 +1,9 @@ +name: 'AeroDyn module tests' +description: 'Run tests specific to the AeroDyn module' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: "composite" + steps: + - run: ctest -VV -R fvw_utest + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/tests-module-beamdyn/action.yml b/.github/actions/tests-module-beamdyn/action.yml new file mode 100644 index 0000000000..bc5d6165fa --- /dev/null +++ b/.github/actions/tests-module-beamdyn/action.yml @@ -0,0 +1,11 @@ +name: 'BeamDyn module tests' +description: 'Run tests specific to the BeamDyn module' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: "composite" + steps: + - run: | + ctest -VV -j7 -R bd_ + ctest -VV -R beamdyn_utest + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/tests-module-hydrodyn/action.yml b/.github/actions/tests-module-hydrodyn/action.yml new file mode 100644 index 0000000000..5675671746 --- /dev/null +++ b/.github/actions/tests-module-hydrodyn/action.yml @@ -0,0 +1,9 @@ +name: 'HydroDyn module tests' +description: 'Run tests specific to the HydroDyn module' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: "composite" + steps: + - run: ctest -VV -j7 -hd_ + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/tests-module-inflowwind/action.yml b/.github/actions/tests-module-inflowwind/action.yml new file mode 100644 index 0000000000..93a7e14b5f --- /dev/null +++ b/.github/actions/tests-module-inflowwind/action.yml @@ -0,0 +1,9 @@ +name: 'InflowWind module tests' +description: 'Run tests specific to the InflowWind module' +author: 'Rafael Mudafort https://github.com/rafmudaf' +runs: + using: "composite" + steps: + - run: ctest -VV -R inflowwind_utest + working-directory: "/openfast/build" + shell: bash diff --git a/.github/actions/tests-module-nwtclibrary/action.yml b/.github/actions/tests-module-nwtclibrary/action.yml new file mode 100644 index 0000000000..e26b0d99dc --- /dev/null +++ b/.github/actions/tests-module-nwtclibrary/action.yml @@ -0,0 +1,9 @@ +name: 'NWTC Library 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 nwtc_library_utest + working-directory: "/openfast/build" + shell: bash diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml new file mode 100644 index 0000000000..163fbf9f46 --- /dev/null +++ b/.github/workflows/automated-dev-tests.yml @@ -0,0 +1,81 @@ + +name: 'Development Pipeline' + +on: + push: + + pull_request: + types: [opened, synchronize] #labeled, assigned] + +# runs-on: ${{ matrix.os }} +# strategy: +# matrix: +# os: [macOS-10.14, ubuntu-18.04] + +jobs: + build-and-test: + + # Do not run if: + # - Branch name contains "docs/" + if: "!contains(github.ref, 'docs/')" + + runs-on: ubuntu-latest + container: + image: rafmudaf/openfast-ubuntu:dev + steps: + - name: Checkout + uses: actions/checkout@main + with: + submodules: recursive + - name: Git Update + uses: ./.github/actions/git-update + with: + repository: $GITHUB_REPOSITORY + ref: $GITHUB_REF + + - name: Configure CMake + uses: ./.github/actions/cmake-config + with: + build-type: RelWithDebInfo + additional-flags: -DBUILD_TESTING=ON -DCTEST_PLOT_ERRORS=ON + + - name: Compile Unit Tests + uses: ./.github/actions/compile + with: + build-target: 'unit_tests' + - name: Compile Drivers + uses: ./.github/actions/compile + with: + build-target: 'beamdyn_driver hydrodyn_driver' + - name: Compile OpenFAST + # if: contains(github.event.head_commit.message, 'Action - Test All') || contains(github.event.pull_request.labels.*.name, 'Action - Test All') + uses: ./.github/actions/compile + with: + build-target: 'install' + + - name: 'Run NWTC Library tests' + uses: ./.github/actions/tests-module-nwtclibrary + - name: 'Run AeroDyn tests' + uses: ./.github/actions/tests-module-aerodyn + - name: 'Run BeamDyn tests' + uses: ./.github/actions/tests-module-beamdyn + - name: 'Run InflowWind tests' + uses: ./.github/actions/tests-module-inflowwind + - 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 + + - name: 'If failure, post test files' + uses: actions/upload-artifact@v2 + if: failure() + with: + name: test-results + path: | + build/reg_tests/modules + build/reg_tests/glue-codes/openfast + !build/reg_tests/glue-codes/openfast/5MW_Baseline + !build/reg_tests/glue-codes/openfast/AOC + !build/reg_tests/glue-codes/openfast/AWT27 + !build/reg_tests/glue-codes/openfast/SWRT + !build/reg_tests/glue-codes/openfast/UAE_VI + !build/reg_tests/glue-codes/openfast/WP_Baseline diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml deleted file mode 100644 index edd35ff242..0000000000 --- a/.github/workflows/continuous-integration-workflow.yml +++ /dev/null @@ -1,22 +0,0 @@ - -name: OpenFAST Build and Test - -on: [push, pull_request] - -# runs-on: ${{ matrix.os }} -# strategy: -# matrix: -# os: [macOS-10.14, ubuntu-18.04] -# runs-on: docker://rafmudaf/openfast-ubuntu:alpha - -jobs: - build-and-test: - runs-on: ubuntu-latest - name: OpenFAST tests on Ubuntu - steps: - - name: Checkout - uses: actions/checkout@main - with: - submodules: recursive - - name: Build and test step - uses: ./.github/actions/compile-and-test diff --git a/cmake/OpenfastFortranOptions.cmake b/cmake/OpenfastFortranOptions.cmake index 231c4f8008..b39183c58c 100644 --- a/cmake/OpenfastFortranOptions.cmake +++ b/cmake/OpenfastFortranOptions.cmake @@ -107,6 +107,11 @@ macro(set_fast_gfortran) #set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ffree-line-length-none -cpp -fopenmp") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ffree-line-length-none -cpp") + # Disable stack reuse within routines: issues seen with gfortran 9.x, but others may also exhibit + # see section 3.16 of https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc.pdf + # and https://github.com/OpenFAST/openfast/pull/595 + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fstack-reuse='none'") + # Deal with Double/Single precision if (DOUBLE_PRECISION) add_definitions(-DOPENFAST_DOUBLE_PRECISION) diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index 109f79949d..461e96fa46 100644 Binary files a/docs/OtherSupporting/OutListParameters.xlsx and b/docs/OtherSupporting/OutListParameters.xlsx differ diff --git a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat new file mode 100644 index 0000000000..e2d414dda5 --- /dev/null +++ b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver-timeseries.dat @@ -0,0 +1,11 @@ +Example Time-Series Input File for UnsteadyAero Driver + + +This file has 8 header lines followed by three columns of data: + + +Time Angle of Attack VRel omega +(s) (deg) (m/s) (rad/s^2) +0.0 0 10 0 +0.01 0 10 0 +0.02 0 10 0 diff --git a/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.inp b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.inp new file mode 100644 index 0000000000..1bef7307a3 --- /dev/null +++ b/docs/source/user/aerodyn-dynamicStall/examples/UA-driver.inp @@ -0,0 +1,25 @@ +UnsteadyAero Driver file for Unit NACA. k = 0.077 +------------------------------------------------------------------------------- +FALSE Echo - Echo the input file data (flag) +---------------------- ENVIRONMENTAL CONDITIONS ------------------------------- + 340.29 SpdSound - Speed of sound (m/s) +---------------------- UNSTEADYAERO ------------------------------------------- +"05014051_NACA" OutRootName - The name which prefixes all UnsteadyAero generated files (quoted string) + 40.36 InflowVel - Inflow velocity (m/s) + 1.48 Re - Reynolds number in millions (-) + 3 UAMod - Unsteady Aero Model Switch: 2 - Gonzalez’s variant (changes in Cn,Cc,Cm); 3 - Minnema/Pierce variant (changes in Cc and Cm) +TRUE Flookup – Flag to indicate whether a lookup for f’ will be calculated (TRUE) or whether best-fit exponential equations will be used (FALSE); if FALSE S1-S4 must be provided in airfoil input files +------------------- AIRFOIL PROPERTIES ---------------------------------------- +"05000051_AD15.dat" AirFoil - Airfoil table + 0.55 Chord - Chord length (m) +TRUE UseCm - Use Cm data in airfoil table +------------------- SIMULATION CONTROL ---------------------------------------- + 1 SimMod - Simulation model [ 1 - use reduced frequency model, 2 - use time series data stored in the TimeInputs file and ignore the remaining parameters ] + 3 NCycles - Number of angle-of-attack oscillations (cosine function) over the length of the simulation (-) + 720 StepsPerCycle - Number of timesteps per cycle (-) + 1.8 Frequency - Frequency for the airfoil oscillations (Hz) + 9.685 Amplitude - Amplitude of the oscillations (deg) + 15.195 Mean - Cycle mean (deg) + -180 Phase - Initial phase (num steps) +"UA-driver-timeseries.dat" InputsFile - Time series data in an ASCII input file (whitespace-separated data). 8 header lines, followed by column data. First column is time (sec), second column is angle-of-attack (deg), third column is InflowVel (m/s) +"END" of driver input file diff --git a/docs/source/user/aerodyn/appendix.rst b/docs/source/user/aerodyn/appendix.rst index a4a84509c5..add85ba4c0 100644 --- a/docs/source/user/aerodyn/appendix.rst +++ b/docs/source/user/aerodyn/appendix.rst @@ -15,7 +15,13 @@ In this appendix we describe the AeroDyn input-file structure and provide exampl The driver input file is only needed for the standalone version of AeroDyn and contains inputs normally generated by OpenFAST, and necessary to control the aerodynamic simulation for uncoupled models. -2) AeroDyn Primary Input File +2) AeroDyn Driver Timeseries Input File +:download:`(driver timeseries input file example) `: +The timeseries input file for a case in the AeroDyn driver allows the parameters +to vary with time. This feature can be useful for debugging the aerodynamic response +outside of OpenFAST. + +3) AeroDyn Primary Input File :download:`(primary input file example) `: The primary AeroDyn input file defines modeling options, environmental conditions (except freestream flow), airfoils, tower nodal discretization and properties, as well as output file specifications. @@ -24,12 +30,12 @@ The file is organized into several functional sections. Each section correspond The input file begins with two lines of header information which is for your use, but is not used by the software. -3) Airfoil Data Input File +4) Airfoil Data Input File :download:`(airfoil data input file example) `: The airfoil data input files themselves (one for each airfoil) include tables containing coefficients of lift force, drag force, and pitching moment versus AoA, as well as UA model parameters. In these files, any line whose first non-blank character is an exclamation point (!) is ignored (for inserting comment lines). The non-comment lines should appear within the file in order, but comment lines may be intermixed as desired for reading clarity. -4) Balde Data Input File +5) Blade Data Input File :download:`(blade data input file example) `: The blade data input file contains the nodal discretization, geometry, twist, chord, and airfoil identifier for a blade. Separate files are used for each blade, which permits modeling of aerodynamic imbalances. diff --git a/docs/source/user/aerodyn/examples/ad_airfoil_example.inp b/docs/source/user/aerodyn/examples/ad_airfoil_example.inp index 131c49aa1f..5959ae5f4b 100644 --- a/docs/source/user/aerodyn/examples/ad_airfoil_example.inp +++ b/docs/source/user/aerodyn/examples/ad_airfoil_example.inp @@ -79,6 +79,7 @@ 0.996141 0.000290 1.000000 0.000000 ! ------------------------------------------------------------------------------ +"unused" BL_file ! The file name including the boundary layer characteristics of the profile. Ignored if the aeroacoustic module is not called. 1 NumTabs ! Number of airfoil tables in this file. ! ------------------------------------------------------------------------------ ! data for table 1 @@ -118,7 +119,7 @@ true InclUAdata ! Is unsteady aerodynamics data included in this 0 k1_hat ! Constant in the expression of Cc due to leading edge vortex effects. [ignored if UAMod<>1] "Default" x_cp_bar ! Constant in the expression of \hat(x)_cp^v. [ignored if UAMod<>1, default = 0.2] "DEFAULT" UACutout ! Angle of attack above which unsteady aerodynamics are disabled (deg). [Specifying the string "Default" sets UACutout to 45 degrees] -"DEFAULT" filtCutOff ! Cut-off frequency (-3 dB corner frequency) for low-pass filtering the AoA input to UA, as well as the 1st and 2nd derivatives (Hz)… +"DEFAULT" filtCutOff ! Reduced frequency cut-off for low-pass filtering the AoA input to UA, as well as the 1st and 2nd derivatives (-) [default = 0.5] !........................................ ! Table of aerodynamics coefficients 63 NumAlf ! Number of data lines in the following table diff --git a/docs/source/user/aerodyn/examples/ad_driver_example.inp b/docs/source/user/aerodyn/examples/ad_driver_example.inp index 93979601a0..cb10dc9c38 100644 --- a/docs/source/user/aerodyn/examples/ad_driver_example.inp +++ b/docs/source/user/aerodyn/examples/ad_driver_example.inp @@ -16,8 +16,8 @@ True TabDel - When generating formatted output (OutForm=True), "ES10.3E2" OutFmt - Format used for text tabular output, excluding the time channel. Resulting field should be 10 characters. (quoted string) True Beep - Beep on exit (flag) ----- Combined-Case Analysis ------------------------------------------------- - 1 NumCases - Number of cases to run + 2 NumCases - Number of cases to run WndSpeed ShearExp RotSpd Pitch Yaw dT Tmax (m/s) (-) (rpm) (deg) (deg) (s) (s) 5.0000000E+00 0.0000000E+00 7.1900000E+01 3.0000000E+00 0.0000000E+00 3.9700000E-02 8.3450000E-01 - +@ADTimeSeriesInput.dat diff --git a/docs/source/user/aerodyn/examples/ad_driver_timeseries_example.inp b/docs/source/user/aerodyn/examples/ad_driver_timeseries_example.inp new file mode 100644 index 0000000000..6c091d0d2c --- /dev/null +++ b/docs/source/user/aerodyn/examples/ad_driver_timeseries_example.inp @@ -0,0 +1,15 @@ +Time WndSpeed ShearExp RotSpd Pitch Yaw +(s) (m/s) (-) (rpm) (deg) (deg) +0.0 4.00000000 0.00000000 2.0 0.00000000 100.00000000 +0.05 4.00000000 0.00000000 2.0 0.00000000 90.00000000 +0.10 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.15 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.20 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.25 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.30 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.35 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.40 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.45 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.50 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.55 4.00000000 0.00000000 2.0 0.00000000 80.00000000 +0.60 4.00000000 0.00000000 2.0 0.00000000 80.00000000 \ No newline at end of file diff --git a/docs/source/user/aerodyn/input.rst b/docs/source/user/aerodyn/input.rst index 736ff09492..7c78c68506 100644 --- a/docs/source/user/aerodyn/input.rst +++ b/docs/source/user/aerodyn/input.rst @@ -65,9 +65,7 @@ improved tower clearance. The I/O SETTINGS section controls the creation of the results file. If ``OutFileRoot`` is specified, the results file will have the filename -*OutFileRoot.#.out*, where the ‘\ *#*\ ’ character is an integer -number corresponding to a test case line found in the COMBINED-CASE -ANALYSIS section described below. If an empty string is provided for +*OutFileRoot.out*. If an empty string is provided for ``OutFileRoot``, then the driver file’s root name will be used instead. If ``TabDel`` is ``TRUE``, a TAB character is used between columns in the output file; if FALSE, fixed-width is used otherwise. @@ -115,6 +113,19 @@ match the time step for the aerodynamic calculations (``DTAero``) as specified in the primary AeroDyn input file, and ``Tmax`` is the total simulation time. +Note that ``dT`` should be the same for each of the cases listed in the +COMBINED-CASE ANALYSIS section. All of the cases will be output to the same +file, with a ``Case`` column listed next to the ``Time`` output column +for help with data processing. + +For further debugging capability, the AeroDyn driver now also has the +ability to read the combined case input data as a time-history file. +In place of a row in the COMBINED-CASE ANALYSIS table, a separate input file +can be listed instead. The name of the file should be preceded with the ``@`` +character, to indicate the data is a time-history file in a separate text +input file. An example is provided in +:numref:`ad_appendix` + AeroDyn Primary Input File -------------------------- @@ -340,7 +351,7 @@ Specify the number of airfoil data input files to be used using file names should be in quotations and can contain an absolute path or a relative path e.g., “C:\\airfoils\\S809_CLN_298.dat” or “airfoils\\S809_CLN_298.dat”. If you use relative paths, it is -relative to the location of the current working directory. The blade +relative to the location of the file in which it is specified. The blade data input files will reference these airfoil data using their line identifier, where the first airfoil file is numbered 1 and the last airfoil file is numbered ``NumAFfiles``. @@ -395,7 +406,9 @@ running AeroDyn standalone, or by the OpenFAST program when running a coupled simulation. See section 5.2 for summary file details. AeroDyn can output aerodynamic and kinematic quantities at up to nine -nodes along the tower and up to nine nodes along each blade. +nodes specified along the tower and up to nine nodes along each blade. +For outputs at every blade node, see :numref:`AD-Nodal-Outputs`. + ``NBlOuts`` specifies the number of blade nodes that output is requested for (0 to 9) and ``BlOutNd`` on the next line is a list ``NBlOuts`` long of node numbers between 1 and ``NumBlNds`` @@ -447,7 +460,7 @@ complete list of possible output parameters. .. _airfoil_data_input_file: Airfoil Data Input File -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- The airfoil data input files themselves (one for each airfoil) include tables containing coefficients of lift force, drag force, and pitching @@ -464,7 +477,7 @@ pitching-moment, and minimum pressure coefficients as a function of AoA. When ``InterpOrd`` is 1, linear interpolation is used; when ``InterpOrd`` is 3, the data will be interpolated with cubic splines; if the keyword ``DEFAULT`` is entered in place of a numerical value, -``InterpOrd`` is set to 3. +``InterpOrd`` is set to 1. ``NonDimArea`` is the nondimensional airfoil area (normalized by the local ``BlChord`` squared), but is currently unused by AeroDyn. @@ -481,6 +494,9 @@ exterior shape of the airfoil. The airfoil shape is currently unused by AeroDyn, but when AeroDyn is coupled to OpenFAST, the airfoil shape will be used by OpenFAST for blade surface visualization when enabled. +``BL_file`` is the name of the file containing boundary-layer characteristics +of the profile. It is ignored if the aeroacoustic module is not used. + Specify the number of Reynolds number- or aerodynamic-control setting-dependent tables of data for the given airfoil via the ``NumTabs`` setting. The remaining parameters in the @@ -635,11 +651,11 @@ input file): UA are disabled; if the keyword ``DEFAULT`` is entered in place of a numerical value, ``UACutOut`` is set to 45. -- ``filtCutOff`` is the cut-off frequency (-3 dB corner frequency) - (in Hz) of the low-pass filter applied to the AoA input to UA, as +- ``filtCutOff`` is the cut-off reduced frequency + of the low-pass filter applied to the AoA input to UA, as well as to the pitch rate and pitch acceleration derived from AoA within UA; if the keyword ``DEFAULT`` is entered in place of a - numerical value, ``filtCutOff`` is set to 20. + numerical value, ``filtCutOff`` is set to 0.5. ``NumAlf`` is the number of distinct AoA entries and determines the number of rows in the subsequent table of static airfoil coefficients; @@ -651,8 +667,13 @@ interpolate on AoA using the data provided via linear interpolation or via cubic splines, depending on the setting of input ``InterpOrd`` above. If ``AFTabMod`` is set to ``1``, only the first airfoil table in each file will be used. If ``AFTabMod`` is set to ``2``, AeroDyn will find the -airfoil table that bounds the computed Reynolds number, and linearly interpolate -between the tables, using the logarithm of the Reynolds numbers. +airfoil tables that bound the computed Reynolds number, +and linearly interpolate between the tables, using the logarithm of the Reynolds numbers. +If ``AFTabMod`` is set to ``3``, it will find the bounding airfoil +tables based on the ``UserProp`` field and linearly interpolate the tables +based on it. Note that OpenFAST currently sets the ``UserProp`` input value to ``0`` +unless the DLL controller is used and sets the value, +so using this feature may require a code change. For each AoA, you must set the AoA (in degrees), ``alpha``, the lift-force coefficient, ``Coefs``\ (:,1), the drag-force coefficient, @@ -675,8 +696,7 @@ minimum pressure coefficients may be absent from the file. .. _blade_data_input_file: Blade Data Input File -~~~~~~~~~~~~~~~~~~~~~ - +--------------------- The blade data input file contains the nodal discretization, geometry, twist, chord, and airfoil identifier for a blade. Separate files are diff --git a/docs/source/user/api_change.rst b/docs/source/user/api_change.rst index 75528c183f..043052482f 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -9,7 +9,7 @@ The changes are tabulated according to the module input file, line number, and f The line number corresponds to the resulting line number after all changes are implemented. Thus, be sure to implement each in order so that subsequent line numbers are correct. -OpenFAST v2.3.0 to OpenFAST `dev` +OpenFAST v2.4.0 to OpenFAST `dev` --------------------------------- ============== ==== ================== ============================================================================================================================================================================= @@ -37,7 +37,14 @@ IfW driver 9 WrVTK false WrVTK - Convert all data to InflowWind 7 VFlowAng 0 VFlowAng - Upflow angle (degrees) (not used for native Bladed format WindType=7) ============== ==== ================== ============================================================================================================================================================================= -\*non-comment line count +Modified in OpenFAST `dev` +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Module Line Flag Name Example 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 derivatives (-) [default = 0.5] +============== ==== ================== ============================================================================================================================================================================= + +\*non-comment line count, excluding lines contained if NumCoords is not 0. Additional nodal output channels added for :ref:`AeroDyn15`, :ref:`BeamDyn`, and :ref:`ElastoDyn`. diff --git a/glue-codes/openfast-cpp/CMakeLists.txt b/glue-codes/openfast-cpp/CMakeLists.txt index aecb5f77d3..c4dab07b42 100644 --- a/glue-codes/openfast-cpp/CMakeLists.txt +++ b/glue-codes/openfast-cpp/CMakeLists.txt @@ -14,6 +14,10 @@ # limitations under the License. # +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + cmake_policy(SET CMP0074 NEW) +endif() + set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/glue-codes/simulink/examples/Run_OpenLoop.m b/glue-codes/simulink/examples/Run_OpenLoop.m index c8425596bf..2df5fb485c 100644 --- a/glue-codes/simulink/examples/Run_OpenLoop.m +++ b/glue-codes/simulink/examples/Run_OpenLoop.m @@ -1,32 +1,12 @@ -% make sure the FASTv8\bin directory is in the MATLAB path +% make sure the OpenFAST directory where the FAST_SFunc.mex* file is located +% is in the MATLAB path (also make sure any other OpenFAST library files that +% are needed are on the MATLAB path) % (relative path names are not recommended in addpath()): -% addpath('C:\Users\bjonkman\Documents\CAETools\FASTv8\bin'); +% addpath('../../../build/bin'); % install location for Windows Visual Studio builds +% addpath(genpath('../../../install')); % cmake default install location +% these variables are defined in the OpenLoop model's FAST_SFunc block: +FAST_InputFileName = '../../../reg_tests/r-test/glue-codes/openfast/5MW_Land_DLL_WTurb/5MW_Land_DLL_WTurb.fst'; +TMax = 60; % seconds -CertTest_Dir = '..\..\CertTest'; - -CertTest_TMax=[20, 20, 20, 70, 30, ... - 35, 70, 20, 40, 25, ... - 20, 20, 40, 0, 20, ... - 20, 70, 60, 60, 60, ... - 60, 60, 60, 60, 60, ... - 20 ]; - - for iTest = [1:13 15:26] - - %------------------------------------------------------------------ - % Set up and run the Simulink OpenLoop model - %------------------------------------------------------------------ - - FileRoot = sprintf( 'Test%02.0f', iTest ); - - disp('***********************************************'); - disp( ['FAST_SFunc certification test for ' FileRoot] ); - disp('***********************************************'); - - FAST_InputFileName = [CertTest_Dir filesep FileRoot '.fst']; - TMax = CertTest_TMax(iTest); - - sim('OpenLoop.mdl',[0,TMax]); - - end \ No newline at end of file +sim('OpenLoop.mdl',[0,TMax]); diff --git a/glue-codes/simulink/examples/Run_Test01_SIG.m b/glue-codes/simulink/examples/Run_Test01_SIG.m index 137f304cd2..77b9062c42 100644 --- a/glue-codes/simulink/examples/Run_Test01_SIG.m +++ b/glue-codes/simulink/examples/Run_Test01_SIG.m @@ -1,17 +1,17 @@ -% make sure the FASTv8\bin directory is in the MATLAB path +% make sure the OpenFAST directory where the FAST_SFunc.mex* file is located +% is in the MATLAB path (also make sure any other OpenFAST library files that +% are needed are on the MATLAB path) % (relative path names are not recommended in addpath()): -% cd ..\..\ -% FASTv8_root_directory = pwd; -% cd Simulink\Samples -% addpath([ FASTv8_root_directory '\bin']); +% addpath('../../../build/bin'); % install location for Windows Visual Studio builds +% addpath(genpath('../../../install')); % cmake default install location % Simple Induction Generator Example ====================================== % To model a simple induction generator in Simulink use model Test01_SIG.mdl. % The following parameters duplicate those used in Certification Test #01. -% Change Test01.fst as follows: -% set VSContrl = 4 in ..\..\CertTest\AWT27\Test01_ServoDyn.dat +% Change AWT_YFix_WSt.fst (formerly Test01.fst) as follows: +% set VSContrl = 4 in ../../../reg_tests/r-test/glue-codes/openfast/AWT_YFix_WSt/AWT_YFix_WSt_ServoDyn.dat GenEff = 100.0; % - Generator efficiency [ignored by the Thevenin and user-defined generator models] (%) @@ -28,11 +28,12 @@ % parameters required for the S-Function block: -FAST_InputFileName = '..\..\CertTest\Test01.fst'; +OpenFASTRoot = '../../../reg_tests/r-test/glue-codes/openfast/AWT_YFix_WSt/'; +FAST_InputFileName = [ OpenFASTRoot 'AWT_YFix_WSt.fst' ]; TMax = 20; % run the model sim('Test01_SIG.mdl',[0,TMax]); % look at results: -% PlotFASToutput({'../../CertTest/Test01.SFunc.out','../../CertTest/Test01.out'},{'SFunc','exe'}); \ No newline at end of file +% PlotFASToutput({[ OpenFASTRoot 'AWT_YFix_WSt.SFunc.out'],[ OpenFASTRoot 'windows-intel/AWT_YFix_WSt.out']},{'SFunc','exe'}); \ No newline at end of file diff --git a/glue-codes/simulink/src/create_FAST_SFunc.m b/glue-codes/simulink/src/create_FAST_SFunc.m index f97fb2b41e..1892c1846b 100644 --- a/glue-codes/simulink/src/create_FAST_SFunc.m +++ b/glue-codes/simulink/src/create_FAST_SFunc.m @@ -58,13 +58,13 @@ fprintf( 'Creating %s\n\n', [outDir filesep mexname '.' mexext] ); mex('-largeArrayDims', ... + ... % '-v', ... %add this line for "verbose" output (for debugging) ['-L' libDir], ... ['-l' libName], ... ['-I' includeDir], ... '-I../../../modules/supercontroller/src', ... % needed for visual studio builds to find "SuperController_Types.h" '-I../../../modules/openfoam/src', ... % needed for visual studio builds to find "OpenFOAM_Types.h" '-outdir', outDir, ... - 'COMPFLAGS=$COMPFLAGS -MT -D', ... - ['S_FUNCTION_NAME=' mexname], ... + ['COMPFLAGS=$COMPFLAGS -MT -DS_FUNCTION_NAME=' mexname], ... '-output', mexname, ... 'FAST_SFunc.c'); diff --git a/modules/aerodyn/src/AeroAcoustics_IO.f90 b/modules/aerodyn/src/AeroAcoustics_IO.f90 index 742d1235c5..76e4e02c68 100644 --- a/modules/aerodyn/src/AeroAcoustics_IO.f90 +++ b/modules/aerodyn/src/AeroAcoustics_IO.f90 @@ -474,6 +474,7 @@ SUBROUTINE ReadBLTables( InputFile,BL_Files,InputFileData, nAirfoils, ErrStat, E InputFileData%AoAListBL(iAoA)= Buffer(iAoA, 1) ! AoA enddo endif + if (UnIn > 0) CLOSE(UnIn) enddo CALL Cleanup( ) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 34a4dc9478..58a11dfbdd 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -287,7 +287,7 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call Cleanup() return end if - + !............................................................................................ ! Define and initialize inputs here !............................................................................................ @@ -459,13 +459,14 @@ subroutine AD_ReInit(p, x, xd, z, OtherState, m, Interval, ErrStat, ErrMsg ) if ( .not. EqualRealNos(p%DT, interval) ) then call SetErrStat( ErrID_Fatal, 'When AD is reinitialized, DT must not change.', ErrStat, ErrMsg, RoutineName ) + return ! we could get around this by figuring out what needs to change when we modify the dt parameter... probably just some unused-parameters ! and the UA filter end if if (p%WakeMod /= WakeMod_FVW) & - call BEMT_ReInit(p%BEMT,x%BEMT,xd%BEMT,z%BEMT,OtherState%BEMT,m%BEMT,p%AFI) - + call BEMT_ReInit(p%BEMT,x%BEMT,xd%BEMT,z%BEMT,OtherState%BEMT,m%BEMT,p%AFI,ErrStat,ErrMsg) + end subroutine AD_ReInit !---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes (allocates) the misc variables for use during the simulation. @@ -493,7 +494,7 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) call AllocAry( m%WithoutSweepPitchTwist, 3_IntKi, 3_IntKi, p%NumBlNds, p%numBlades, 'OtherState%WithoutSweepPitchTwist', ErrStat2, ErrMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - + call allocAry( m%SigmaCavit, p%NumBlNds, p%numBlades, 'm%SigmaCavit', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( m%SigmaCavitCrit, p%NumBlNds, p%numBlades, 'm%SigmaCavitCrit', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( m%CavitWarnSet, p%NumBlNds, p%numBlades, 'm%CavitWarnSet', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -507,7 +508,7 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) return end if m%AllOuts = 0.0_ReKi - + ! save these tower calculations for output: call AllocAry( m%W_Twr, p%NumTwrNds, 'm%W_Twr', ErrStat2, ErrMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) @@ -846,6 +847,8 @@ subroutine Init_u( u, p, InputFileData, InitInp, errStat, errMsg ) ,Orientation = .true. & ,TranslationDisp = .true. & ,TranslationVel = .true. & + ,RotationVel = .true. & + ,TranslationAcc = .true. & ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) @@ -919,18 +922,18 @@ subroutine SetParameters( InitInp, InputFileData, p, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - p%DT = InputFileData%DTAero + p%DT = InputFileData%DTAero p%WakeMod = InputFileData%WakeMod p%TwrPotent = InputFileData%TwrPotent p%TwrShadow = InputFileData%TwrShadow p%TwrAero = InputFileData%TwrAero p%CavitCheck = InputFileData%CavitCheck p%Gravity = InitInp%Gravity - + - if (InitInp%Linearize) then - p%FrozenWake = InputFileData%FrozenWake + if (InitInp%Linearize .and. InputFileData%WakeMod == WakeMod_BEMT) then + p%FrozenWake = InputFileData%FrozenWake else p%FrozenWake = .FALSE. end if @@ -1086,7 +1089,7 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat end if ! set values of m%BEMT_u(2) from inputs interpolated at t+dt: - ! NOTE: framework has t+dt at u(1) + ! NOTE: this is different than OpenFAST, which has t+dt at u(1) call AD_Input_ExtrapInterp(u,utimes,uInterp,t+p%DT, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1094,7 +1097,7 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ! set values of m%BEMT_u(1) from inputs (uInterp) interpolated at t: - ! NOTE: framework has t at u(2) + ! NOTE: this is different than OpenFAST, which has t at u(2) ! I'm doing this second in case we want the other misc vars at t as before, but I don't think it matters call AD_Input_ExtrapInterp(u,utimes,uInterp, t, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1105,7 +1108,7 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat if (p%WakeMod /= WakeMod_FVW) then ! Call into the BEMT update states NOTE: This is a non-standard framework interface!!!!! GJH - ! Also note BEMT_u(1) and BEMT_u(2) are not following the framework convention for t+dt, t + ! Also note BEMT_u(1) and BEMT_u(2) are not following the OpenFAST convention for t+dt, t call BEMT_UpdateStates(t, n, m%BEMT_u(1), m%BEMT_u(2), p%BEMT, x%BEMT, xd%BEMT, z%BEMT, OtherState%BEMT, p%AFI, m%BEMT, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1168,7 +1171,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, LOGICAL, OPTIONAL, INTENT(IN ) :: NeedWriteOutput !< Flag to determine if WriteOutput values need to be calculated in this call - ! NOTE: there are inconsistencies in the usage of m%BEMT_u(i) from the way the framework is setup + ! NOTE: m%BEMT_u(i) indices are set differently from the way OpenFAST typically sets up the u and uTimes arrays integer, parameter :: indx = 1 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt integer(intKi) :: i integer(intKi) :: j @@ -1224,7 +1227,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, CALL FVW_CalcOutput( t, m%FVW_u(1), p%FVW, x%FVW, xd%FVW, z%FVW, OtherState%FVW, p%AFI, m%FVW_y, m%FVW, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call SetOutputsFromFVW( u, p, OtherState, xd, m, y, ErrStat2, ErrMsg2 ) + call SetOutputsFromFVW( u, p, OtherState, x, xd, m, y, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif @@ -1232,7 +1235,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, call ADTwr_CalcOutput(p, u, m, y, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end if - + 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 @@ -1340,6 +1343,42 @@ subroutine AD_CalcConstrStateResidual( Time, u, p, x, xd, z, OtherState, m, z_re end subroutine AD_CalcConstrStateResidual !---------------------------------------------------------------------------------------------------------------------------------- +subroutine AD_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) +! Tight coupling routine for computing derivatives of continuous states +!.................................................................................................................................. + + REAL(DbKi), INTENT(IN ) :: t ! Current simulation time in seconds + TYPE(AD_InputType), INTENT(IN ) :: u ! Inputs at t + TYPE(AD_ParameterType), INTENT(IN ) :: p ! Parameters + TYPE(AD_ContinuousStateType), INTENT(IN ) :: x ! Continuous states at t + TYPE(AD_DiscreteStateType), INTENT(IN ) :: xd ! Discrete states at t + TYPE(AD_ConstraintStateType), INTENT(IN ) :: z ! Constraint states at t + TYPE(AD_OtherStateType), INTENT(IN ) :: OtherState ! Other states at t + TYPE(AD_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization variables + TYPE(AD_ContinuousStateType), INTENT(INOUT) :: dxdt ! Continuous state derivatives at t + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + ! local variables + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(*), PARAMETER :: RoutineName = 'AD_CalcContStateDeriv' + + INTEGER(IntKi), parameter :: InputIndex = 1 + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + call SetInputs(p, u, m, InputIndex, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + call BEMT_CalcContStateDeriv( t, m%BEMT_u(InputIndex), p%BEMT, x%BEMT, xd%BEMT, z%BEMT, OtherState%BEMT, m%BEMT, dxdt%BEMT, p%AFI, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + +END SUBROUTINE AD_CalcContStateDeriv +!---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine converts the AeroDyn inputs into values that can be used for its submodules. It calculates the disturbed inflow !! on the blade if tower shadow or tower influence are enabled, then uses these values to set m%BEMT_u(indx). subroutine SetInputs(p, u, m, indx, errStat, errMsg) @@ -1386,13 +1425,15 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - real(ReKi) :: x_hat(3) - real(ReKi) :: y_hat(3) - real(ReKi) :: x_hat_disk(3) - real(ReKi) :: y_hat_disk(3) - real(ReKi) :: z_hat_disk(3) + real(R8Ki) :: x_hat(3) + real(R8Ki) :: y_hat(3) + real(R8Ki) :: z_hat(3) + real(R8Ki) :: x_hat_disk(3) + real(R8Ki) :: y_hat_disk(3) + real(R8Ki) :: z_hat_disk(3) real(ReKi) :: tmp(3) real(ReKi) :: tmp_sz, tmp_sz_y + real(ReKi) :: rmax real(R8Ki) :: thetaBladeNds(p%NumBlNds,p%NumBlades) real(R8Ki) :: Azimuth(p%NumBlades) @@ -1402,7 +1443,8 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'SetInputsForBEMT' - + ! note ErrStat and ErrMsg are set in GeomWithoutSweepPitchTwist: + ! Get disk average values and orientations call DiskAvgValues(p, u, m, x_hat_disk, y_hat_disk, z_hat_disk, Azimuth) call GeomWithoutSweepPitchTwist(p,u,m,thetaBladeNds,ErrStat,ErrMsg) @@ -1444,6 +1486,16 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%BEMT_u(indx)%Vx(j,k) = dot_product( tmp, x_hat ) ! normal component (normal to the plane, not chord) of the inflow velocity of the jth node in the kth blade m%BEMT_u(indx)%Vy(j,k) = dot_product( tmp, y_hat ) ! tangential component (tangential to the plane, not chord) of the inflow velocity of the jth node in the kth blade + + + !jmj says omega_z and PitchRate are the same things + ! inputs for DBEMT (DBEMT_Mod == DBEMT_cont_tauConst) + if (allocated(m%BEMT_u(indx)%Vx_elast_dot)) then + m%BEMT_u(indx)%Vx_elast_dot(j,k) = dot_product( u%BladeMotion(k)%TranslationAcc(:,j), x_hat ) ! normal component (normal to the plane, not chord) of the inflow velocity of the jth node in the kth blade + m%BEMT_u(indx)%Vy_elast_dot(j,k) = dot_product( u%BladeMotion(k)%TranslationAcc(:,j), y_hat ) ! tangential component (tangential to the plane, not chord) of the inflow velocity of the jth node in the kth blade + end if + ! inputs for CUA (and CDBEMT): + m%BEMT_u(indx)%omega_z(j,k) = dot_product( u%BladeMotion(k)%RotationVel( :,j), m%WithoutSweepPitchTwist(3,:,j,k) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade end do !j=nodes end do !k=blades @@ -1468,15 +1520,29 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%BEMT_u(indx)%UserProp = u%UserProp + ! ................ TSR ..................... + + if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then + m%BEMT_u(indx)%TSR = 0.0_ReKi + else + rmax = 0.0_ReKi + do k=1,min(p%NumBlades,MaxBl) + do j=1,p%NumBlNds + rmax = max(rmax, m%BEMT_u(indx)%rLocal(j,k) ) + end do !j=nodes + end do !k=blades + m%BEMT_u(indx)%TSR = m%BEMT_u(indx)%omega * rmax / m%V_dot_x + end if + end subroutine SetInputsForBEMT - +!---------------------------------------------------------------------------------------------------------------------------------- subroutine DiskAvgValues(p, u, m, x_hat_disk, y_hat_disk, z_hat_disk, Azimuth) type(AD_ParameterType), intent(in ) :: p !< AD parameters type(AD_InputType), intent(in ) :: u !< AD Inputs at Time type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables - real(ReKi), intent( out) :: x_hat_disk(3) - real(ReKi), intent( out) :: y_hat_disk(3) - real(ReKi), intent( out) :: z_hat_disk(3) + real(R8Ki), intent( out) :: x_hat_disk(3) + real(R8Ki), intent( out) :: y_hat_disk(3) + real(R8Ki), intent( out) :: z_hat_disk(3) real(R8Ki), intent( out) :: Azimuth(p%NumBlades) real(ReKi) :: z_hat(3) real(ReKi) :: tmp(3) @@ -1520,6 +1586,7 @@ subroutine DiskAvgValues(p, u, m, x_hat_disk, y_hat_disk, z_hat_disk, Azimuth) end if end do end subroutine DiskAvgValues +!---------------------------------------------------------------------------------------------------------------------------------- subroutine GeomWithoutSweepPitchTwist(p,u,m,thetaBladeNds,ErrStat,ErrMsg) type(AD_ParameterType), intent(in ) :: p !< AD parameters type(AD_InputType), intent(in ) :: u !< AD Inputs at Time @@ -1588,9 +1655,9 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) integer(IntKi), intent( out) :: ErrStat !< Error status of the operation character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None - real(ReKi) :: x_hat_disk(3) - real(ReKi) :: y_hat_disk(3) - real(ReKi) :: z_hat_disk(3) + real(R8Ki) :: x_hat_disk(3) + real(R8Ki) :: y_hat_disk(3) + real(R8Ki) :: z_hat_disk(3) real(R8Ki) :: thetaBladeNds(p%NumBlNds,p%NumBlades) real(R8Ki) :: Azimuth(p%NumBlades) @@ -1720,11 +1787,11 @@ end subroutine SetOutputsFromBEMT !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine converts outputs from FVW (stored in m%FVW_y) into values on the AeroDyn BladeLoad output mesh. -subroutine SetOutputsFromFVW(u, p, OtherState, xd, m, y, ErrStat, ErrMsg) - use BEMTUnCoupled, only: Compute_UA_AirfoilCoefs +subroutine SetOutputsFromFVW(u, p, OtherState, x, xd, m, y, ErrStat, ErrMsg) TYPE(AD_InputType), intent(in ) :: u !< Inputs at Time t type(AD_ParameterType), intent(in ) :: p !< AD parameters type(AD_OtherStateType), intent(in ) :: OtherState !< OtherState + type(AD_ContinuousStateType),intent(in ) :: x !< continuous states type(AD_DiscreteStateType),intent(in ) :: xd !< Discrete states type(AD_OutputType), intent(inout) :: y !< AD outputs type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables @@ -1751,12 +1818,13 @@ subroutine SetOutputsFromFVW(u, p, OtherState, xd, m, y, ErrStat, ErrMsg) real(ReKi) :: Cx, Cy real(ReKi) :: Cl_Static, Cd_Static, Cm_Static real(ReKi) :: Cl_dyn, Cd_dyn, Cm_dyn + type(UA_InputType) :: u_UA integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - ErrStat2 = 0 - ErrMsg2 = "" + ErrStat = 0 + ErrMsg = "" ! zero forces force(3) = 0.0_ReKi @@ -1782,18 +1850,33 @@ subroutine SetOutputsFromFVW(u, p, OtherState, xd, m, y, ErrStat, ErrMsg) Cd_Static = AFI_interp%Cd Cm_Static = AFI_interp%Cm - if (m%FVW%UA_Flag) then - if ((OtherState%FVW%UA_Flag(j,k)) .and. ( .not. EqualRealNos(Vrel,0.0_ReKi) ) ) then - m%FVW%m_UA%iBladeNode = j - m%FVW%m_UA%iBlade = k - call Compute_UA_AirfoilCoefs( alpha, Vrel, Re, 0.0_ReKi, p%AFI(p%FVW%AFindx(j,k)), m%FVW%p_UA, xd%FVW%UA, OtherState%FVW%UA, m%FVW%y_UA, m%FVW%m_UA, Cl_dyn, Cd_dyn, Cm_dyn, ErrStat, ErrMsg) - if(ErrStat/=ErrID_None) print*,'UA CalcOutput:', trim(ErrMsg) - end if - end if ! Set dynamic to the (will be same as static if UA_Flag is false) Cl_dyn = AFI_interp%Cl Cd_dyn = AFI_interp%Cd Cm_dyn = AFI_interp%Cm + + if (m%FVW%UA_Flag) then + if ((OtherState%FVW%UA_Flag(j,k)) .and. ( .not. EqualRealNos(Vrel,0.0_ReKi) ) ) then + + ! ....... compute inputs to UA ........... + u_UA%alpha = alpha + u_UA%U = Vrel + u_UA%Re = Re + u_UA%UserProp = 0.0_ReKi ! FIX ME + + ! FIX ME: this is copied 3 times!!!! + u_UA%v_ac(1) = sin(u_UA%alpha)*u_UA%U + u_UA%v_ac(2) = cos(u_UA%alpha)*u_UA%U + u_UA%omega = dot_product( u%BladeMotion(k)%RotationVel( :,j), m%WithoutSweepPitchTwist(3,:,j,k) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade + + call UA_CalcOutput(j, k, u_UA, m%FVW%p_UA, x%FVW%UA, xd%FVW%UA, OtherState%FVW%UA, p%AFI(p%FVW%AFindx(j,k)), m%FVW%y_UA, m%FVW%m_UA, errStat2, errMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'SetOutputsFromFVW') + Cl_dyn = m%FVW%y_UA%Cl + Cd_dyn = m%FVW%y_UA%Cd + Cm_dyn = m%FVW%y_UA%Cm + + end if + end if cp = cos(phi) sp = sin(phi) @@ -1862,7 +1945,7 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) if (NumBl > MaxBl .or. NumBl < 1) call SetErrStat( ErrID_Fatal, 'Number of blades must be between 1 and '//trim(num2lstr(MaxBl))//'.', ErrSTat, ErrMsg, RoutineName ) if (InputFileData%DTAero <= 0.0) call SetErrStat ( ErrID_Fatal, 'DTAero must be greater than zero.', ErrStat, ErrMsg, RoutineName ) if (InputFileData%WakeMod /= WakeMod_None .and. InputFileData%WakeMod /= WakeMod_BEMT .and. InputFileData%WakeMod /= WakeMod_DBEMT .and. InputFileData%WakeMod /= WakeMod_FVW) then - call SetErrStat ( ErrID_Fatal, 'WakeMod must be value of '//trim(num2lstr(WakeMod_None))//' (none), '//trim(num2lstr(WakeMod_BEMT))//' (BEMT), '// & + call SetErrStat ( ErrID_Fatal, 'WakeMod must be '//trim(num2lstr(WakeMod_None))//' (none), '//trim(num2lstr(WakeMod_BEMT))//' (BEMT), '// & trim(num2lstr(WakeMod_DBEMT))//' (DBEMT), or '//trim(num2lstr(WakeMod_FVW))//' (FVW).',ErrStat, ErrMsg, RoutineName ) end if @@ -1881,7 +1964,7 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) if (InputFileData%Patm <= 0.0) call SetErrStat ( ErrID_Fatal, 'The atmospheric pressure (Patm) must be greater than zero.', ErrStat, ErrMsg, RoutineName ) if (InputFileData%FluidDepth <= 0.0) call SetErrStat ( ErrID_Fatal, 'Fluid depth (FluidDepth) must be greater than zero', ErrStat, ErrMsg, RoutineName ) - + ! BEMT/DBEMT inputs ! bjj: these checks should probably go into BEMT where they are used... @@ -2013,11 +2096,17 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) !.................. if (InitInp%Linearize) then if (InputFileData%AFAeroMod /= AFAeroMod_Steady) then - call SetErrStat( ErrID_Fatal, 'Steady blade airfoil aerodynamics must be used for linearization. Set AFAeroMod=1.', ErrStat, ErrMsg, RoutineName ) + if (InputFileData%UAMod /= UA_HGM) then + call SetErrStat( ErrID_Fatal, 'When AFAeroMod=2, UAMod must be 4 for linearization. Set AFAeroMod=1 or UAMod=4.', ErrStat, ErrMsg, RoutineName ) + end if end if - if (InputFileData%WakeMod == WakeMod_DBEMT .or. InputFileData%WakeMod == WakeMod_FVW) then - call SetErrStat( ErrID_Fatal, 'DBEMT and FVW cannot currently be used for linearization. Set WakeMod=0 or WakeMod=1.', ErrStat, ErrMsg, RoutineName ) + if (InputFileData%WakeMod == WakeMod_FVW) then + call SetErrStat( ErrID_Fatal, 'FVW cannot currently be used for linearization. Set WakeMod=0 or WakeMod=1.', ErrStat, ErrMsg, RoutineName ) + else if (InputFileData%WakeMod == WakeMod_DBEMT) then + if (InputFileData%DBEMT_Mod /= DBEMT_cont_tauConst) then + call SetErrStat( ErrID_Fatal, 'DBEMT requires the continuous formulation with constant tau1 for linearization. Set DBEMT_Mod=3 or set WakeMod to 0 or 1.', ErrStat, ErrMsg, RoutineName ) + end if end if end if @@ -2104,7 +2193,7 @@ SUBROUTINE Init_AFIparams( InputFileData, p_AFI, UnEc, NumBl, ErrStat, ErrMsg ) do File = 1,InputFileData%NumAFfiles if (fileUsed(File)) then - call UA_ValidateAFI(p_AFI(File), InputFileData%AFNames(File), ErrStat2, ErrMsg2) + call UA_ValidateAFI(InputFileData%UAMod, p_AFI(File), InputFileData%AFNames(File), ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2, ErrStat, ErrMsg, RoutineName) if (errStat >= AbortErrLev) return end if @@ -2297,7 +2386,7 @@ SUBROUTINE Init_BEMTmodule( InputFileData, u_AD, u, p, x, xd, z, OtherState, y, if (EqualRealNos(InitInp%zHub(k),0.0_ReKi) ) & call SetErrStat( ErrID_Fatal, "zHub for blade "//trim(num2lstr(k))//" is zero.", ErrStat, ErrMsg, RoutineName) - ! zLocal is the istance along blade curve -- NOTE: this is an approximation. + ! zLocal is the distance along blade curve -- NOTE: this is an approximation. InitInp%zLocal(1,k) = InitInp%zHub(k) + TwoNorm( u_AD%BladeMotion(k)%Position(:,1) - u_AD%BladeRootMotion(k)%Position(:,1) ) do j=2,p%NumBlNds InitInp%zLocal(j,k) = InitInp%zLocal(j-1,k) + TwoNorm( u_AD%BladeMotion(k)%Position(:,j) - u_AD%BladeMotion(k)%Position(:,j-1) ) @@ -3167,16 +3256,17 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM ! local variables TYPE(AD_OutputType) :: y_p TYPE(AD_OutputType) :: y_m - TYPE(AD_ContinuousStateType) :: x_copy - TYPE(AD_DiscreteStateType) :: xd_copy + TYPE(AD_ContinuousStateType) :: x_p + TYPE(AD_ContinuousStateType) :: x_m + TYPE(AD_ContinuousStateType) :: x_init TYPE(AD_ConstraintStateType) :: z_copy TYPE(AD_OtherStateType) :: OtherState_copy - TYPE(AD_InputType) :: u_perturb(1) + TYPE(AD_OtherStateType) :: OtherState_init + TYPE(AD_InputType) :: u_perturb REAL(R8Ki) :: delta_p, delta_m ! delta change in input - INTEGER(IntKi) :: i, j, k, n + INTEGER(IntKi) :: i integer, parameter :: indx = 1 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt - integer, parameter :: op_indx = 2 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt or the input at OP integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'AD_JacobianPInput' @@ -3187,24 +3277,40 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM ErrStat = ErrID_None ErrMsg = '' - - ! get OP values here: - !call AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat2, ErrMsg2 ) - call SetInputsForBEMT(p, u, m, indx, errStat2, errMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call BEMT_CopyInput( m%BEMT_u(indx), m%BEMT_u(op_indx), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! copy the BEMT OP inputs to a temporary location that won't be overwritten - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - + ! get OP values here (i.e., set inputs for BEMT): if ( p%FrozenWake ) then - ! compare arguments with call to BEMT_CalcOutput - call computeFrozenWake(m%BEMT_u(op_indx), p%BEMT, m%BEMT_y, m%BEMT ) + call SetInputs(p, u, m, indx, 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 + + ! compare m%BEMT_y arguments with call to BEMT_CalcOutput + call computeFrozenWake(m%BEMT_u(indx), p%BEMT, m%BEMT_y, m%BEMT ) m%BEMT%UseFrozenWake = .true. end if + + + call AD_CopyContState( x, x_init, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AD_CopyOtherState( OtherState, OtherState_init, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + + ! initialize x_init so that we get accurrate values for first step + if (.not. OtherState%BEMT%nodesInitialized ) then + call SetInputs(p, u, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call BEMT_InitStates(t, m%BEMT_u(indx), p%BEMT, x_init%BEMT, xd%BEMT, z%BEMT, OtherState_init%BEMT, m%BEMT, p%AFI, ErrStat2, ErrMsg2 ) ! changes values only if states haven't been initialized + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + ! make a copy of the inputs to perturb - call AD_CopyInput( u, u_perturb(1), MESH_NEWCOPY, ErrStat2, ErrMsg2) + call AD_CopyInput( u, u_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() @@ -3232,13 +3338,9 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM call AD_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! make a copy of the states to perturb - call AD_CopyContState( x, x_copy, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_CopyDiscState( xd, xd_copy, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AD_CopyConstrState( z, z_copy, MESH_NEWCOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_CopyOtherState( OtherState, OtherState_copy, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call AD_CopyOtherState( OtherState_init, OtherState_copy, MESH_NEWCOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then @@ -3249,52 +3351,53 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM do i=1,size(p%Jac_u_indx,1) ! get u_op + delta_p u - call AD_CopyInput( u, u_perturb(1), MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, 1, u_perturb(1), delta_p ) + call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_u( p, i, 1, u_perturb, delta_p ) - call AD_CopyContState( x, x_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_CopyDiscState( xd, xd_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AD_CopyConstrState( z, z_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_CopyOtherState( OtherState, OtherState_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - - call AD_UpdateStates( t, 1, u_perturb, (/t/), p, x_copy, xd_copy, z_copy, OtherState_copy, m, errStat2, errMsg2 ) + call AD_CopyOtherState( OtherState_init, OtherState_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! get updated z%phi values: + !call AD_UpdateStates( t, 1, (/u_perturb/), (/t/), p, x_copy, xd_copy, z_copy, OtherState_copy, m, errStat2, errMsg2 ) + ! call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + !bjj: this is what we want to do instead of the overkill of calling AD_UpdateStates + call SetInputs(p, u_perturb, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call UpdatePhi( m%BEMT_u(indx), p%BEMT, z_copy%BEMT%phi, p%AFI, m%BEMT, OtherState_copy%BEMT%ValidPhi, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! compute y at u_op + delta_p u - call AD_CalcOutput( t, u_perturb(1), p, x_copy, xd_copy, z_copy, OtherState_copy, y_p, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call AD_CalcOutput( t, u_perturb, p, x_init, xd, z_copy, OtherState_copy, y_p, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later ! get u_op - delta_m u - call AD_CopyInput( u, u_perturb(1), MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, -1, u_perturb(1), delta_m ) + call Perturb_u( p, i, -1, u_perturb, delta_m ) - call AD_CopyContState( x, x_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_CopyDiscState( xd, xd_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AD_CopyConstrState( z, z_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call AD_CopyOtherState( OtherState, OtherState_copy, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AD_UpdateStates( t, 1, u_perturb, (/t/), p, x_copy, xd_copy, z_copy, OtherState_copy, m, errStat2, errMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - + ! get updated z%phi values: + !call AD_UpdateStates( t, 1, (/u_perturb/), (/t/), p, x_copy, xd_copy, z_copy, OtherState_copy, m, errStat2, errMsg2 ) + ! call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call SetInputs(p, u_perturb, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call UpdatePhi( m%BEMT_u(indx), p%BEMT, z_copy%BEMT%phi, p%AFI, m%BEMT, OtherState_copy%BEMT%ValidPhi, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! compute y at u_op - delta_m u - call AD_CalcOutput( t, u_perturb(1), p, x_copy, xd_copy, z_copy, OtherState_copy, y_m, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call AD_CalcOutput( t, u_perturb, p, x_init, xd, z_copy, OtherState_copy, y_m, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get central difference: + ! get central difference: call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,i) ) end do @@ -3308,7 +3411,59 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM END IF IF ( PRESENT( dXdu ) ) THEN - if (allocated(dXdu)) deallocate(dXdu) + + ! Calculate the partial derivative of the continuous state functions (X) with respect to the inputs (u) here: + + ! allocate dXdu if necessary + if (.not. allocated(dXdu)) then + call AllocAry(dXdu, size(p%dx), size(p%Jac_u_indx,1), 'dXdu', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + end if + + + do i=1,size(p%Jac_u_indx,1) + + ! get u_op + delta u + call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_u( p, i, 1, u_perturb, delta_p ) + + ! compute x at u_op + delta u + ! note that this routine updates z%phi instead of using the actual state value, so we don't need to call UpdateStates/UpdatePhi here to get z_op + delta_z: + call AD_CalcContStateDeriv( t, u_perturb, p, x_init, xd, z, OtherState_init, m, x_p, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + ! get u_op - delta u + call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_u( p, i, -1, u_perturb, delta_m ) + + ! compute x at u_op - delta u + ! note that this routine updates z%phi instead of using the actual state value, so we don't need to call UpdateStates here to get z_op + delta_z: + call AD_CalcContStateDeriv( t, u_perturb, p, x_init, xd, z, OtherState_init, m, x_m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + ! get central difference: + + ! we may have had an error allocating memory, so we'll check + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + + ! get central difference: + call Compute_dX( p, x_p, x_m, delta_p, delta_m, dXdu(:,i) ) + + end do + + call AD_DestroyContState( x_p, ErrStat2, ErrMsg2 ) ! we don't need this any more + call AD_DestroyContState( x_m, ErrStat2, ErrMsg2 ) ! we don't need this any more END IF IF ( PRESENT( dXddu ) ) THEN @@ -3324,26 +3479,27 @@ SUBROUTINE AD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM subroutine cleanup() m%BEMT%UseFrozenWake = .false. - call AD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) - call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) - call AD_DestroyContState( x_copy, ErrStat2, ErrMsg2) - call AD_DestroyDiscState( xd_copy, ErrStat2, ErrMsg2) + call AD_DestroyOutput( y_p, ErrStat2, ErrMsg2) + call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2) + call AD_DestroyContState( x_p, ErrStat2, ErrMsg2) + call AD_DestroyContState( x_m, ErrStat2, ErrMsg2) + call AD_DestroyContState( x_init, ErrStat2, ErrMsg2) call AD_DestroyConstrState( z_copy, ErrStat2, ErrMsg2) call AD_DestroyOtherState( OtherState_copy, ErrStat2, ErrMsg2) + call AD_DestroyOtherState( OtherState_init, ErrStat2, ErrMsg2) - call AD_DestroyInput( u_perturb(1), ErrStat2, ErrMsg2 ) + call AD_DestroyInput( u_perturb, ErrStat2, ErrMsg2 ) end subroutine cleanup END SUBROUTINE AD_JacobianPInput !---------------------------------------------------------------------------------------------------------------------------------- !> 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 derivatives dY/du, dX/du, dXd/du, and dZ/du are returned. -SUBROUTINE AD_JacobianPInput_orig( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdu, dXdu, dXddu, dZdu) -! This routine should be used instead of AD_JacobianPInput iff `OLD_AD_LINEAR` is defined in the FAST glue code. +!! with respect to the continuous states (x). The partial derivatives dY/dx, dX/dx, dXd/dx, and dZ/dx are returned. +SUBROUTINE AD_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(AD_InputType), INTENT(INOUT) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) + TYPE(AD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) TYPE(AD_ParameterType), INTENT(IN ) :: p !< Parameters TYPE(AD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point TYPE(AD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point @@ -3352,79 +3508,92 @@ SUBROUTINE AD_JacobianPInput_orig( t, u, p, x, xd, z, OtherState, y, m, ErrStat, TYPE(AD_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. + !! connectivity) does not have to be recalculated for dYdx. 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 - 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 the inputs (u) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dXddu(:,:) !< Partial derivatives of discrete state functions (Xd) with - !! respect to the inputs (u) [intent in to avoid deallocation] - REAL(R8Ki), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: dZdu(:,:) !< Partial derivatives of constraint state functions (Z) with - !! respect to the inputs (u) [intent in to avoid deallocation] - ! local variables + 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 TYPE(AD_OutputType) :: y_p TYPE(AD_OutputType) :: y_m - TYPE(AD_ConstraintStateType) :: z_p - TYPE(AD_ConstraintStateType) :: z_m - TYPE(AD_InputType) :: u_perturb - REAL(R8Ki) :: delta_p, delta_m ! delta change in input - INTEGER(IntKi) :: i, j, k, n - logical :: ValidInput_p - logical :: ValidInput_m + TYPE(AD_ContinuousStateType) :: x_p + TYPE(AD_ContinuousStateType) :: x_m + TYPE(AD_ContinuousStateType) :: x_perturb + TYPE(AD_ContinuousStateType) :: x_init + TYPE(AD_OtherStateType) :: OtherState_init + REAL(R8Ki) :: delta_p, delta_m ! delta change in state + INTEGER(IntKi) :: i, k integer, parameter :: indx = 1 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt - integer, parameter :: op_indx = 2 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt or the input at OP integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'AD_JacobianPInput' - + character(*), parameter :: RoutineName = 'AD_JacobianPContState' + ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = '' - - ! get OP values here: - !call AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat2, ErrMsg2 ) - call SetInputsForBEMT(p, u, m, indx, errStat2, errMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call BEMT_CopyInput( m%BEMT_u(indx), m%BEMT_u(op_indx), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! copy the BEMT OP inputs to a temporary location that won't be overwritten - 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 - - - if ( p%FrozenWake ) then - ! compare arguments with call to BEMT_CalcOutput - call computeFrozenWake(m%BEMT_u(op_indx), p%BEMT, m%BEMT_y, m%BEMT ) + + if ( p%FrozenWake ) then + call SetInputs(p, u, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! compare arguments with call to BEMT_CalcOutput + call computeFrozenWake(m%BEMT_u(indx), p%BEMT, m%BEMT_y, m%BEMT ) m%BEMT%UseFrozenWake = .true. end if - - - ! make a copy of the inputs to perturb - call AD_CopyInput( u, u_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2) + + + call AD_CopyContState( x, x_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call AD_CopyContState( x, x_init, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AD_CopyOtherState( OtherState, OtherState_init, MESH_NEWCOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then call cleanup() return end if + + ! initialize x_init so that we get accurrate values for + if (.not. OtherState%BEMT%nodesInitialized ) then + call SetInputs(p, u, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call BEMT_InitStates(t, m%BEMT_u(indx), p%BEMT, x_init%BEMT, xd%BEMT, z%BEMT, OtherState_init%BEMT, m%BEMT, p%AFI, ErrStat2, ErrMsg2 ) ! changes values only if states haven't been initialized + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + IF ( PRESENT( dYdx ) ) THEN - IF ( PRESENT( dYdu ) ) THEN - ! Calculate the partial derivative of the output functions (Y) with respect to the inputs (u) here: - - ! allocate dYdu - if (.not. allocated(dYdu) ) then - call AllocAry(dYdu,p%Jac_ny, size(p%Jac_u_indx,1),'dYdu', ErrStat2, ErrMsg2) - call setErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! Calculate the partial derivative of the output functions (Y) with respect to the continuous states (x) here: + + ! allocate dYdx if necessary + if (.not. allocated(dYdx)) then + call AllocAry(dYdx, p%Jac_ny, size(p%dx), 'dYdx', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() return end if end if - ! make a copy of outputs because we will need two for the central difference computations (with orientations) call AD_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2) @@ -3435,62 +3604,34 @@ SUBROUTINE AD_JacobianPInput_orig( t, u, p, x, xd, z, OtherState, y, m, ErrStat, call cleanup() return end if + + do i=1,size(p%dx) - do i=1,size(p%Jac_u_indx,1) - - ! get u_op + delta_p u - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + ! get x_op + delta_p x + call AD_CopyContState( x_init, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, 1, u_perturb, delta_p ) + call Perturb_x( p, i, 1, x_perturb, delta_p ) - ! we need to see if these perturbed inputs put us in different solution regions: - call SetInputsForBEMT(p, u_perturb, m, indx, 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 - ValidInput_p = CheckBEMTInputPerturbations( p, m ) - - ! if so, we do a 1-sided difference: - if (.not. ValidInput_p) then - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - delta_p = 0.0_R8Ki - end if - - - ! compute y at u_op + delta_p u - call AD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_p, m, ErrStat2, ErrMsg2 ) + + ! compute y at x_op + delta_p x + ! NOTE: z_op is the same as z because x_perturb does not affect the values of phi, thus I am not updating the states or calling UpdatePhi to get z_perturb. + call AD_CalcOutput( t, u, p, x_perturb, xd, z, OtherState_init, y_p, m, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get u_op - delta_m u - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + ! get x_op - delta_m x + call AD_CopyContState( x_init, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, -1, u_perturb, delta_m ) - - ! we need to see if these perturbed inputs put us in different solution regions: - call SetInputsForBEMT(p, u_perturb, m, indx, 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 - ValidInput_m = CheckBEMTInputPerturbations( p, m ) - - ! if so, we do a 1-sided difference: - if (.not. ValidInput_m) then - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - delta_m = 0.0_R8Ki - if (.not. ValidInput_p) then - call SetErrStat(ErrID_Fatal,'Both sides of central difference equation change solution region. '// & - 'dYdu cannot be calculated for column '//trim(num2lstr(i))//'.',ErrStat,ErrMsg,RoutineName) - return - end if - end if + call Perturb_x( p, i, -1, x_perturb, delta_m ) - - ! compute y at u_op - delta_m u - call AD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_m, m, ErrStat2, ErrMsg2 ) + ! compute y at x_op - delta_m x + ! NOTE: z_op is the same as z because x_perturb does not affect the values of phi, thus I am not updating the states or calling UpdatePhi to get z_perturb. + call AD_CalcOutput( t, u, p, x_perturb, xd, z, OtherState_init, y_m, m, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later ! get central difference: - call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdu(:,i) ) + call Compute_dY( p, y_p, y_m, delta_p, delta_m, dYdx(:,i) ) end do @@ -3500,96 +3641,54 @@ SUBROUTINE AD_JacobianPInput_orig( t, u, p, x, xd, z, OtherState, y, m, ErrStat, return end if call AD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) ! we don't need this any more - call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more - - - END IF + call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more - IF ( PRESENT( dXdu ) ) THEN - if (allocated(dXdu)) deallocate(dXdu) END IF - IF ( PRESENT( dXddu ) ) THEN - if (allocated(dXddu)) deallocate(dXddu) - END IF + IF ( PRESENT( dXdx ) ) THEN - IF ( PRESENT( dZdu ) ) THEN + ! Calculate the partial derivative of the continuous state functions (X) with respect to the continuous states (x) here: - call CheckLinearizationInput(p%BEMT, m%BEMT_u(op_indx), z%BEMT, m%BEMT, OtherState%BEMT, ErrStat2, ErrMsg2) - call setErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if - - - ! Calculate the partial derivative of the constraint state functions (Z) with respect to the inputs (u) here: + ! allocate and set dXdx - ! allocate dZdu - if (.not. allocated(dZdu)) then - call AllocAry(dZdu,size(z%BEMT%phi), size(p%Jac_u_indx,1),'dZdu', ErrStat2, ErrMsg2) - call setErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! Calculate the partial derivative of the continuous state functions (X) with respect to the inputs (u) here: + + ! allocate dXdx if necessary + if (.not. allocated(dXdx)) then + call AllocAry(dXdx, size(p%dx), size(p%dx), 'dXdx', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() return - end if + end if end if - - do i=1,size(p%Jac_u_indx,1) - ! get u_op + delta_p u - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, 1, u_perturb, delta_p ) - - ! we need to see if these perturbed inputs put us in different solution regions: - call SetInputsForBEMT(p, u_perturb, m, indx, 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 - ValidInput_p = CheckBEMTInputPerturbations( p, m ) - - ! if so, we do a 1-sided difference: - if (.not. ValidInput_p) then - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - delta_p = 0.0_R8Ki - end if + do i=1,size(p%dx,1) - - ! compute z_p at u_op + delta_p u - call AD_CalcConstrStateResidual( t, u_perturb, p, x, xd, z, OtherState, m, z_p, ErrStat2, ErrMsg2 ) + ! get x_op + delta x + call AD_CopyContState( x_init, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_x( p, i, 1, x_perturb, delta_p ) + + ! compute X at x_op + delta x + ! NOTE: z_op is the same as z because x_perturb does not affect the values of phi, thus I am not updating the states or calling UpdatePhi to get z_perturb. + call AD_CalcContStateDeriv( t, u, p, x_perturb, xd, z, OtherState_init, m, x_p, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get u_op - delta_m u - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call Perturb_u( p, i, -1, u_perturb, delta_m ) - - ! we need to see if these perturbed inputs put us in different solution regions: - call SetInputsForBEMT(p, u_perturb, m, indx, 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 - ValidInput_m = CheckBEMTInputPerturbations( p, m ) - - ! if so, we do a 1-sided difference: - if (.not. ValidInput_m) then - call AD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - delta_m = 0.0_R8Ki - if (.not. ValidInput_p) then - call SetErrStat(ErrID_Fatal,'Both sides of central difference equation change solution region. '// & - 'dYdu cannot be calculated for column '//trim(num2lstr(i))//'.',ErrStat,ErrMsg,RoutineName) - return - end if - end if + ! get x_op - delta x + call AD_CopyContState( x_init, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_x( p, i, -1, x_perturb, delta_m ) - - ! compute z_m at u_op - delta_m u - call AD_CalcConstrStateResidual( t, u_perturb, p, x, xd, z, OtherState, m, z_m, ErrStat2, ErrMsg2 ) + ! compute x at u_op - delta u + ! NOTE: z_op is the same as z because x_perturb does not affect the values of phi, thus I am not updating the states or calling UpdatePhi to get z_perturb. + call AD_CalcContStateDeriv( t, u, p, x_perturb, xd, z, OtherState_init, m, x_m, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get central difference: + ! get central difference: ! we may have had an error allocating memory, so we'll check if (ErrStat>=AbortErrLev) then @@ -3597,91 +3696,15 @@ SUBROUTINE AD_JacobianPInput_orig( t, u, p, x, xd, z, OtherState, y, m, ErrStat, return end if - - do k=1,p%NumBlades ! size(z%BEMT%Phi,2) - do j=1,p%NumBlNds ! size(z%BEMT%Phi,1) - n = (k-1)*p%NumBlNds + j - dZdu(n,i) = z_p%BEMT%Phi(j,k) - z_m%BEMT%Phi(j,k) - end do - end do - - dZdu(:,i) = dZdu(:,i) / (delta_p + delta_m) - + ! get central difference: + call Compute_dX( p, x_p, x_m, delta_p, delta_m, dXdx(:,i) ) + end do - - call AD_DestroyConstrState( z_p, ErrStat2, ErrMsg2 ) ! we don't need this any more - call AD_DestroyConstrState( z_m, ErrStat2, ErrMsg2 ) ! we don't need this any more - - END IF + + call AD_DestroyContState( x_p, ErrStat2, ErrMsg2 ) ! we don't need this any more + call AD_DestroyContState( x_m, ErrStat2, ErrMsg2 ) ! we don't need this any more - call cleanup() -contains - subroutine cleanup() - m%BEMT%UseFrozenWake = .false. - call AD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) - call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) - call AD_DestroyConstrState( z_p, ErrStat2, ErrMsg2 ) - call AD_DestroyConstrState( z_m, ErrStat2, ErrMsg2 ) - call AD_DestroyInput( u_perturb, ErrStat2, ErrMsg2 ) - end subroutine cleanup - -END SUBROUTINE AD_JacobianPInput_orig -!---------------------------------------------------------------------------------------------------------------------------------- -!> 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. -SUBROUTINE AD_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(AD_InputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) - TYPE(AD_ParameterType), INTENT(IN ) :: p !< Parameters - TYPE(AD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point - TYPE(AD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at operating point - TYPE(AD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at operating point - TYPE(AD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at operating point - TYPE(AD_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(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 - 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] - - - ! Initialize ErrStat - - ErrStat = ErrID_None - ErrMsg = '' - - - - 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 - - END IF - - IF ( PRESENT( dXdx ) ) THEN - - ! Calculate the partial derivative of the continuous state functions (X) with respect to the continuous states (x) here: - - ! allocate and set dXdx - END IF IF ( PRESENT( dXddx ) ) THEN @@ -3701,6 +3724,20 @@ SUBROUTINE AD_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, END IF + call cleanup() +contains + subroutine cleanup() + m%BEMT%UseFrozenWake = .false. + + call AD_DestroyOutput( y_p, ErrStat2, ErrMsg2) + call AD_DestroyOutput( y_m, ErrStat2, ErrMsg2) + call AD_DestroyContState( x_p, ErrStat2, ErrMsg2) + call AD_DestroyContState( x_m, ErrStat2, ErrMsg2) + + call AD_DestroyContState( x_perturb, ErrStat2, ErrMsg2 ) + call AD_DestroyContState( x_init, ErrStat2, ErrMsg2 ) + call AD_DestroyOtherState( OtherState_init, ErrStat2, ErrMsg2 ) + end subroutine cleanup END SUBROUTINE AD_JacobianPContState !---------------------------------------------------------------------------------------------------------------------------------- @@ -3836,7 +3873,7 @@ SUBROUTINE AD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat ! get OP values here: !call AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat2, ErrMsg2 ) ! (bjj: is this necessary? if not, still need to get BEMT inputs) - call SetInputsForBEMT(p, u, m, indx, errStat2, errMsg2) + call SetInputs(p, u, m, indx, errStat2, errMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later call BEMT_CopyInput( m%BEMT_u(indx), m%BEMT_u(op_indx), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! copy the BEMT OP inputs to a temporary location that won't be overwritten 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 @@ -3890,8 +3927,7 @@ SUBROUTINE AD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat ! need a check if F = 0 for this case: - if ( ( p%BEMT%UseTipLoss .and. EqualRealNos(p%BEMT%tipLossConst(j,k),0.0_ReKi) ) .or. & - ( p%BEMT%useHubLoss .and. EqualRealNos(p%BEMT%hubLossConst(j,k),0.0_ReKi) ) ) then + if ( p%BEMT%FixedInductions(j,k) ) then ! F is zero, we we need to skip this perturbation dYdz(:,i) = 0.0_ReKi else @@ -3971,8 +4007,7 @@ SUBROUTINE AD_JacobianPConstrState( t, u, p, x, xd, z, OtherState, y, m, ErrStat do j=1,p%NumBlNds ! size(z%BEMT%Phi,1) i = (k-1)*p%NumBlNds + j - if ( ( p%BEMT%UseTipLoss .and. EqualRealNos(p%BEMT%tipLossConst(j,k),0.0_ReKi) ) .or. & - ( p%BEMT%useHubLoss .and. EqualRealNos(p%BEMT%hubLossConst(j,k),0.0_ReKi) ) ) then + if ( p%BEMT%FixedInductions(j,k) ) then ! F is zero, we we need to skip this perturbation dZdz(:,i) = 0.0_ReKi dZdz(i,i) = 1.0_ReKi @@ -4065,6 +4100,7 @@ SUBROUTINE AD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'AD_GetOP' LOGICAL :: FieldMask(FIELDMASK_SIZE) + TYPE(AD_ContinuousStateType) :: dxdt ! Initialize ErrStat @@ -4107,6 +4143,8 @@ SUBROUTINE AD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, FieldMask(MASKID_TRANSLATIONDISP) = .true. FieldMask(MASKID_TRANSLATIONVel) = .true. + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TRANSLATIONAcc) = .true. do k=1,p%NumBlades call PackMotionMesh(u%BladeMotion(k), u_op, index, FieldMask=FieldMask) end do @@ -4154,11 +4192,102 @@ SUBROUTINE AD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, END IF IF ( PRESENT( x_op ) ) THEN + + if (.not. allocated(x_op)) then + call AllocAry(x_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx,'x_op',ErrStat2,ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + end if + index = 1 + ! set linearization operating points: + if (p%BEMT%DBEMT%lin_nx>0) then + do j=1,p%NumBlades ! size(x%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(x%BEMT%DBEMT%element,1) + do k=1,size(x%BEMT%DBEMT%element(i,j)%vind) + x_op(index) = x%BEMT%DBEMT%element(i,j)%vind(k) + index = index + 1 + end do + end do + end do + + do j=1,p%NumBlades ! size(x%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(x%BEMT%DBEMT%element,1) + do k=1,size(x%BEMT%DBEMT%element(i,j)%vind_dot) + x_op(index) = x%BEMT%DBEMT%element(i,j)%vind_dot(k) + index = index + 1 + end do + end do + end do + + end if + + if (p%BEMT%UA%lin_nx>0) then + do j=1,p%NumBlades ! size(x%BEMT%UA%element,2) + do i=1,p%NumBlNds ! size(x%BEMT%UA%element,1) + do k=1,size(x%BEMT%UA%element(i,j)%x) + x_op(index) = x%BEMT%UA%element(i,j)%x(k) + index = index + 1 + end do + end do + end do + + end if + END IF IF ( PRESENT( dx_op ) ) THEN + + if (.not. allocated(dx_op)) then + call AllocAry(dx_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx,'dx_op',ErrStat2,ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + end if + call AD_CalcContStateDeriv(t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then + call AD_DestroyContState( dxdt, ErrStat2, ErrMsg2) + return + end if + + index = 1 + ! set linearization operating points: + if (p%BEMT%DBEMT%lin_nx>0) then + + do j=1,p%NumBlades ! size(dxdt%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(dxdt%BEMT%DBEMT%element,1) + do k=1,size(dxdt%BEMT%DBEMT%element(i,j)%vind) + dx_op(index) = dxdt%BEMT%DBEMT%element(i,j)%vind(k) + index = index + 1 + end do + end do + end do + + do j=1,p%NumBlades ! size(dxdt%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(dxdt%BEMT%DBEMT%element,1) + do k=1,size(dxdt%BEMT%DBEMT%element(i,j)%vind_dot) + dx_op(index) = dxdt%BEMT%DBEMT%element(i,j)%vind_dot(k) + index = index + 1 + end do + end do + end do + + end if + + if (p%BEMT%UA%lin_nx>0) then + do j=1,p%NumBlades ! size(dxdt%BEMT%UA%element,2) + do i=1,p%NumBlNds ! size(dxdt%BEMT%UA%element,1) + do k=1,size(dxdt%BEMT%UA%element(i,j)%x) + dx_op(index) = dxdt%BEMT%UA%element(i,j)%x(k) + index = index + 1 + end do + end do + end do + end if + + call AD_DestroyContState( dxdt, ErrStat2, ErrMsg2) + END IF IF ( PRESENT( xd_op ) ) THEN @@ -4222,7 +4351,7 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return - InitOut%RotFrame_y = .false. ! default all to false, then set the true ones below (note that meshes are in the global, not rotating frame) + InitOut%RotFrame_y = .false. ! default all to false, then set the true ones below indx_next = 1 call PackLoadMesh_Names(y%TowerLoad, 'Tower', InitOut%LinNames_y, indx_next) @@ -4236,6 +4365,7 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) InitOut%LinNames_y(i+indx_next-1) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) !trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units end do + ! check for all the WriteOutput values that are functions of blade number: allocate( AllOut(0:MaxOutPts), STAT=ErrStat2 ) ! allocate starting at zero to account for invalid output channels if (ErrStat2 /=0 ) then @@ -4302,45 +4432,29 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) END SUBROUTINE Init_Jacobian_y !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine initializes the array that maps rows/columns of the Jacobian to specific mesh fields. -!! Do not change the order of this packing without changing corresponding parts of AD linearization ! -SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) +SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) - type(AD_InputFile) , intent(in ) :: InputFileData !< input file data (for default blade perturbation) + TYPE(AD_InputFile) , INTENT(IN ) :: InputFileData !< input file data (for default blade perturbation) TYPE(AD_ParameterType) , INTENT(INOUT) :: p !< parameters TYPE(AD_InputType) , INTENT(IN ) :: u !< inputs - TYPE(AD_OutputType) , INTENT(IN ) :: y !< outputs - TYPE(AD_MiscVarType) , INTENT(IN ) :: m !< miscellaneous variable TYPE(AD_InitOutputType) , INTENT(INOUT) :: InitOut !< Initialization output data (for Jacobian row/column names) INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< Error status of the operation CHARACTER(*) , INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'Init_Jacobian' - ! local variables: INTEGER(IntKi) :: i, j, k, index, index_last, nu, i_meshField REAL(ReKi) :: perturb, perturb_t, perturb_b(MaxBl) LOGICAL :: FieldMask(FIELDMASK_SIZE) CHARACTER(1), PARAMETER :: UVW(3) = (/'U','V','W'/) - - + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'Init_Jacobian_u' ErrStat = ErrID_None ErrMsg = "" - call Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) - - ! these matrices will be needed for linearization with frozen wake feature - if (p%FrozenWake) then - call AllocAry(m%BEMT%AxInd_op,p%NumBlNds,p%numBlades,'m%BEMT%AxInd_op', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(m%BEMT%TnInd_op,p%NumBlNds,p%numBlades,'m%BEMT%TnInd_op', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - end if - - ! determine how many inputs there are in the Jacobians nu = u%TowerMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities at each node + u%hubMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Rotation velocities at each node @@ -4348,7 +4462,7 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) + size( u%InflowOnTower) do i=1,p%NumBlades - nu = nu + u%BladeMotion(i)%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities at each node + nu = nu + u%BladeMotion(i)%NNodes * 15 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities + 3 Rotation velocities + 3 TranslationAcc at each node + u%BladeRootMotion(i)%NNodes * 3 ! 3 orientations at each node end do @@ -4421,17 +4535,25 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) !Module/Mesh/Field: u%BladeMotion(1)%TranslationDisp = 10; !Module/Mesh/Field: u%BladeMotion(1)%Orientation = 11; !Module/Mesh/Field: u%BladeMotion(1)%TranslationVel = 12; - !Module/Mesh/Field: u%BladeMotion(2)%TranslationDisp = 13; - !Module/Mesh/Field: u%BladeMotion(2)%Orientation = 14; - !Module/Mesh/Field: u%BladeMotion(2)%TranslationVel = 15; - !Module/Mesh/Field: u%BladeMotion(3)%TranslationDisp = 16; - !Module/Mesh/Field: u%BladeMotion(3)%Orientation = 17; - !Module/Mesh/Field: u%BladeMotion(3)%TranslationVel = 18; - do k=1,p%NumBlades - do i_meshField = 1,3 + !Module/Mesh/Field: u%BladeMotion(1)%RotationVel = 13; + !Module/Mesh/Field: u%BladeMotion(1)%TranslationAcc = 14; + + !Module/Mesh/Field: u%BladeMotion(2)%TranslationDisp = 15; + !Module/Mesh/Field: u%BladeMotion(2)%Orientation = 16; + !Module/Mesh/Field: u%BladeMotion(2)%TranslationVel = 17; + !Module/Mesh/Field: u%BladeMotion(2)%RotationVel = 18; + !Module/Mesh/Field: u%BladeMotion(2)%TranslationAcc = 19; + + !Module/Mesh/Field: u%BladeMotion(3)%TranslationDisp = 20; + !Module/Mesh/Field: u%BladeMotion(3)%Orientation = 21; + !Module/Mesh/Field: u%BladeMotion(3)%TranslationVel = 22; + !Module/Mesh/Field: u%BladeMotion(3)%RotationVel = 23; + !Module/Mesh/Field: u%BladeMotion(3)%TranslationAcc = 24; + do k=1,p%NumBlades + do i_meshField = 1,5 do i=1,u%BladeMotion(k)%NNodes do j=1,3 - p%Jac_u_indx(index,1) = 9 + i_meshField + (k-1)*3 + p%Jac_u_indx(index,1) = 9 + i_meshField + (k-1)*5 p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 @@ -4441,13 +4563,13 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) end do !i_meshField end do !k - !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 19; - !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 20; - !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 21; - do k=1,size(u%InflowOnBlade,3) ! p%NumBlades + !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 25; + !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 26; + !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 27; + do k=1,size(u%InflowOnBlade,3) ! p%NumBlades do i=1,size(u%InflowOnBlade,2) ! numNodes do j=1,3 - p%Jac_u_indx(index,1) = 18 + k + p%Jac_u_indx(index,1) = 24 + k p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 @@ -4455,10 +4577,10 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) end do !i end do !k - !Module/Mesh/Field: u%InflowOnTower(:,:) = 22; + !Module/Mesh/Field: u%InflowOnTower(:,:) = 28; do i=1,size(u%InflowOnTower,2) ! numNodes do j=1,3 - p%Jac_u_indx(index,1) = 22 + p%Jac_u_indx(index,1) = 28 p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 @@ -4469,7 +4591,7 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) !...................................... ! default perturbations, p%du: !...................................... - call allocAry( p%du, 22, 'p%du', ErrStat2, ErrMsg2) ! 22 = number of unique values in p%Jac_u_indx(:,1) + call allocAry( p%du, 28, 'p%du', ErrStat2, ErrMsg2) ! 28 = number of unique values in p%Jac_u_indx(:,1) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) perturb = 2*D2R @@ -4494,14 +4616,16 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) p%du(i_meshField) = perturb ! u%BladeRootMotion(k)%Orientation = 6+k, for k in [1, 3] end do do k=1,p%NumBlades - p%du(10 + (k-1)*3) = perturb_b(k) ! u%BladeMotion(k)%TranslationDisp = 10 + (k-1)*3 - p%du(11 + (k-1)*3) = perturb ! u%BladeMotion(k)%Orientation = 11 + (k-1)*3 - p%du(12 + (k-1)*3) = perturb_b(k) ! u%BladeMotion(k)%TranslationVel = 12 + (k-1)*3 + p%du(10 + (k-1)*5) = perturb_b(k) ! u%BladeMotion(k)%TranslationDisp = 10 + (k-1)*5 + p%du(11 + (k-1)*5) = perturb ! u%BladeMotion(k)%Orientation = 11 + (k-1)*5 + p%du(12 + (k-1)*5) = perturb_b(k) ! u%BladeMotion(k)%TranslationVel = 12 + (k-1)*5 + p%du(13 + (k-1)*5) = perturb ! u%BladeMotion(k)%RotationVel = 13 + (k-1)*5 + p%du(14 + (k-1)*5) = perturb_b(k) ! u%BladeMotion(k)%TranslationAcc = 14 + (k-1)*5 !bjj: is the correct???? end do - do k=1,p%NumBlades - p%du(18 + k) = perturb_b(k) ! u%InflowOnBlade(:,:,k) = 18 + k + do k=1,p%NumBlades + p%du(24 + k) = perturb_b(k) ! u%InflowOnBlade(:,:,k) = 24 + k end do - p%du(22) = perturb_t ! u%InflowOnTower(:,:) = 22 + p%du(28) = perturb_t ! u%InflowOnTower(:,:) = 22 !..................... @@ -4529,7 +4653,7 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) FieldMask(MASKID_RotationVel) = .true. call PackMotionMesh_Names(u%HubMotion, 'Hub', InitOut%LinNames_u, index, FieldMask=FieldMask) - index_last = index + index_last = index FieldMask = .false. FieldMask(MASKID_Orientation) = .true. do k = 1,p%NumBlades @@ -4538,7 +4662,9 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) FieldMask(MASKID_TRANSLATIONDISP) = .true. FieldMask(MASKID_TRANSLATIONVel) = .true. - do k=1,p%NumBlades + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TRANSLATIONAcc) = .true. + do k=1,p%NumBlades call PackMotionMesh_Names(u%BladeMotion(k), 'Blade '//trim(num2lstr(k)), InitOut%LinNames_u, index, FieldMask=FieldMask) end do @@ -4547,7 +4673,7 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) do j=1,3 InitOut%LinNames_u(index) = UVW(j)//'-component inflow on blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', m/s' index = index + 1 - end do + end do end do end do !InitOut%RotFrame_u(index_last:index-1) = .true. ! values on the mesh (and from IfW) are in global coordinates, thus not in the rotating frame @@ -4556,27 +4682,135 @@ SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) do j=1,3 InitOut%LinNames_u(index) = UVW(j)//'-component inflow on tower node '//trim(num2lstr(i))//', m/s' index = index + 1 - end do + end do end do - + + END SUBROUTINE Init_Jacobian_u +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) + + TYPE(AD_ParameterType) , INTENT(INOUT) :: p !< parameters + TYPE(AD_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 + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'Init_Jacobian_x' + + ! local variables: + INTEGER(IntKi) :: i, j, k + INTEGER(IntKi) :: nx + INTEGER(IntKi) :: nx1 + CHARACTER(25) :: NodeTxt + ErrStat = ErrID_None + ErrMsg = "" + + + nx = p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + if (nx==0) return + + ! allocate space for the row/column names and for perturbation sizes + CALL AllocAry(p%dx, nx, 'p%dx', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%LinNames_x, nx, 'LinNames_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%RotFrame_x, nx, 'RotFrame_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%DerivOrder_x, nx, 'DerivOrder_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + + ! All DBEMT continuous states are order = 2; UA states are order 1 + + ! set default perturbation sizes: p%dx + p%dx = 2.0_R8Ki * D2R_D + + ! set linearization output names: + nx1 = p%BEMT%DBEMT%lin_nx/2 + if (nx1>0) then + InitOut%DerivOrder_x(1:p%BEMT%DBEMT%lin_nx) = 2 + InitOut%RotFrame_x( 1:p%BEMT%DBEMT%lin_nx) = .true. + + k = 1 + do j=1,p%NumBlades ! size(x%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(x%BEMT%DBEMT%element,1) + NodeTxt = 'blade '//trim(num2lstr(j))//', node '//trim(num2lstr(i)) + InitOut%LinNames_x(k) = 'vind (axial) at '//trim(NodeTxt)//', m/s' + k = k + 1 + + InitOut%LinNames_x(k) = 'vind (tangential) at '//trim(NodeTxt)//', m/s' + k = k + 1 + end do + end do + + do i=1,nx1 + InitOut%LinNames_x(i+nx1) = 'First time derivative of '//trim(InitOut%LinNames_x(i))//'/s' + InitOut%RotFrame_x(i+nx1) = InitOut%RotFrame_x(i) + end do + end if + + if (p%BEMT%UA%lin_nx>0) then + InitOut%DerivOrder_x(1+p%BEMT%DBEMT%lin_nx:nx) = 1 + InitOut%RotFrame_x( 1+p%BEMT%DBEMT%lin_nx:nx) = .true. + + k = 1 + p%BEMT%DBEMT%lin_nx + do j=1,p%NumBlades ! size(x%BEMT%DBEMT%element,2) + do i=1,p%NumBlNds ! size(x%BEMT%DBEMT%element,1) + NodeTxt = 'blade '//trim(num2lstr(j))//', node '//trim(num2lstr(i)) + + InitOut%LinNames_x(k) = 'x1 '//trim(NodeTxt)//', rad' + k = k + 1 - !..................... - ! get names of linearized constraint states (though i don't think we really need them) - !..................... - call AllocAry(InitOut%LinNames_z, p%NumBlades*p%NumBlNds, 'LinNames_z', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call AllocAry(InitOut%RotFrame_z, p%NumBlades*p%NumBlNds, 'RotFrame_z', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return - InitOut%RotFrame_z = .true. + InitOut%LinNames_x(k) = 'x2 '//trim(NodeTxt)//', rad' + k = k + 1 + + InitOut%LinNames_x(k) = 'x3 '//trim(NodeTxt)//', -' + k = k + 1 + + InitOut%LinNames_x(k) = 'x4 '//trim(NodeTxt)//', -' + p%dx(k) = 0.001 ! x4 is a number between 0 and 1, so we need this to be small + k = k + 1 + end do + end do - index = 1 - do k=1,p%NumBlades ! size(z%BEMT%Phi,2) - do i=1,p%NumBlNds ! size(z%BEMT%Phi,1) - InitOut%LinNames_z(index) = 'phi at blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', rad' - index = index + 1 - end do - end do - + end if + +END SUBROUTINE Init_Jacobian_x +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine initializes the array that maps rows/columns of the Jacobian to specific mesh fields. +!! Do not change the order of this packing without changing corresponding parts of AD linearization ! +SUBROUTINE Init_Jacobian( InputFileData, p, u, y, m, InitOut, ErrStat, ErrMsg) + + type(AD_InputFile) , intent(in ) :: InputFileData !< input file data (for default blade perturbation) + TYPE(AD_ParameterType) , INTENT(INOUT) :: p !< parameters + TYPE(AD_InputType) , INTENT(IN ) :: u !< inputs + TYPE(AD_OutputType) , INTENT(IN ) :: y !< outputs + TYPE(AD_MiscVarType) , INTENT(IN ) :: m !< miscellaneous variable + TYPE(AD_InitOutputType) , INTENT(INOUT) :: InitOut !< Initialization output data (for Jacobian row/column names) + + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'Init_Jacobian' + + + ErrStat = ErrID_None + ErrMsg = "" + +!FIXME: add logic to check that p%NumBlades is not greater than MaxBl. Cannot linearize if that is true. + call Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) + + ! these matrices will be needed for linearization with frozen wake feature + if (p%FrozenWake) then + call AllocAry(m%BEMT%AxInd_op,p%NumBlNds,p%numBlades,'m%BEMT%AxInd_op', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(m%BEMT%TnInd_op,p%NumBlNds,p%numBlades,'m%BEMT%TnInd_op', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + call Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + call Init_Jacobian_x( p, InitOut, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END SUBROUTINE Init_Jacobian !---------------------------------------------------------------------------------------------------------------------------------- !> This routine perturbs the nth element of the u array (and mesh/field it corresponds to) @@ -4586,7 +4820,7 @@ SUBROUTINE Perturb_u( p, n, perturb_sign, u, du ) TYPE(AD_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(AD_InputType) , INTENT(INOUT) :: u !< perturbed ED inputs + TYPE(AD_InputType) , INTENT(INOUT) :: u !< perturbed AD inputs REAL( R8Ki ) , INTENT( OUT) :: du !< amount that specific input was perturbed @@ -4629,47 +4863,119 @@ SUBROUTINE Perturb_u( p, n, perturb_sign, u, du ) u%BladeMotion(1)%TranslationDisp(fieldIndx,node) = u%BladeMotion(1)%TranslationDisp(fieldIndx,node) + du * perturb_sign CASE (11) !Module/Mesh/Field: u%BladeMotion(1)%Orientation = 11; CALL PerturbOrientationMatrix( u%BladeMotion(1)%Orientation(:,:,node), du * perturb_sign, fieldIndx ) - CASE (12) !Module/Mesh/Field: u%BladeMotion(1)%TranslationVel = 12; + CASE (12) !Module/Mesh/Field: u%BladeMotion(1)%TranslationVel = 12; u%BladeMotion(1)%TranslationVel(fieldIndx,node) = u%BladeMotion(1)%TranslationVel(fieldIndx,node) + du * perturb_sign + CASE (13) !Module/Mesh/Field: u%BladeMotion(1)%RotationVel = 13; + u%BladeMotion(1)%RotationVel(fieldIndx,node) = u%BladeMotion(1)%RotationVel(fieldIndx,node) + du * perturb_sign + CASE (14) !Module/Mesh/Field: u%BladeMotion(1)%TranslationAcc = 14; + u%BladeMotion(1)%TranslationAcc(fieldIndx,node) = u%BladeMotion(1)%TranslationAcc(fieldIndx,node) + du * perturb_sign - CASE (13) !Module/Mesh/Field: u%BladeMotion(2)%TranslationDisp = 13; + CASE (15) !Module/Mesh/Field: u%BladeMotion(2)%TranslationDisp = 15; u%BladeMotion(2)%TranslationDisp( fieldIndx,node) = u%BladeMotion(2)%TranslationDisp( fieldIndx,node) + du * perturb_sign - CASE (14) !Module/Mesh/Field: u%BladeMotion(2)%Orientation = 14; + CASE (16) !Module/Mesh/Field: u%BladeMotion(2)%Orientation = 16; CALL PerturbOrientationMatrix( u%BladeMotion(2)%Orientation(:,:,node), du * perturb_sign, fieldIndx ) - CASE (15) !Module/Mesh/Field: u%BladeMotion(2)%TranslationVel = 15; + CASE (17) !Module/Mesh/Field: u%BladeMotion(2)%TranslationVel = 17; u%BladeMotion(2)%TranslationVel(fieldIndx,node) = u%BladeMotion(2)%TranslationVel(fieldIndx,node) + du * perturb_sign + CASE (18) !Module/Mesh/Field: u%BladeMotion(2)%RotationVel = 18; + u%BladeMotion(2)%RotationVel(fieldIndx,node) = u%BladeMotion(2)%RotationVel(fieldIndx,node) + du * perturb_sign + CASE (19) !Module/Mesh/Field: u%BladeMotion(2)%TranslationAcc = 19; + u%BladeMotion(2)%TranslationAcc(fieldIndx,node) = u%BladeMotion(2)%TranslationAcc(fieldIndx,node) + du * perturb_sign - CASE (16) !Module/Mesh/Field: u%BladeMotion(3)%TranslationDisp = 16; + CASE (20) !Module/Mesh/Field: u%BladeMotion(3)%TranslationDisp = 20; u%BladeMotion(3)%TranslationDisp( fieldIndx,node) = u%BladeMotion(3)%TranslationDisp( fieldIndx,node) + du * perturb_sign - CASE (17) !Module/Mesh/Field: u%BladeMotion(3)%Orientation = 17; + CASE (21) !Module/Mesh/Field: u%BladeMotion(3)%Orientation = 21; CALL PerturbOrientationMatrix( u%BladeMotion(3)%Orientation(:,:,node), du * perturb_sign, fieldIndx ) - CASE (18) !Module/Mesh/Field: u%BladeMotion(3)%TranslationVel = 18; + CASE (22) !Module/Mesh/Field: u%BladeMotion(3)%TranslationVel = 22; u%BladeMotion(3)%TranslationVel(fieldIndx,node) = u%BladeMotion(3)%TranslationVel(fieldIndx,node) + du * perturb_sign + CASE (23) !Module/Mesh/Field: u%BladeMotion(3)%RotationVel = 23; + u%BladeMotion(3)%RotationVel(fieldIndx,node) = u%BladeMotion(3)%RotationVel(fieldIndx,node) + du * perturb_sign + CASE (24) !Module/Mesh/Field: u%BladeMotion(3)%TranslationAcc = 24; + u%BladeMotion(3)%TranslationAcc(fieldIndx,node) = u%BladeMotion(3)%TranslationAcc(fieldIndx,node) + du * perturb_sign - CASE (19) !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 19; + CASE (25) !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 25; u%InflowOnBlade(fieldIndx,node,1) = u%InflowOnBlade(fieldIndx,node,1) + du * perturb_sign - CASE (20) !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 20; + CASE (26) !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 26; u%InflowOnBlade(fieldIndx,node,2) = u%InflowOnBlade(fieldIndx,node,2) + du * perturb_sign - CASE (21) !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 21; + CASE (27) !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 27; u%InflowOnBlade(fieldIndx,node,3) = u%InflowOnBlade(fieldIndx,node,3) + du * perturb_sign - CASE (22) !Module/Mesh/Field: u%InflowOnTower(:,:) = 22; + CASE (28) !Module/Mesh/Field: u%InflowOnTower(:,:) = 28; u%InflowOnTower(fieldIndx,node) = u%InflowOnTower(fieldIndx,node) + du * perturb_sign END SELECT END SUBROUTINE Perturb_u !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine perturbs the nth element of the u array (and mesh/field it corresponds to) +!! Do not change this without making sure subroutine aerodyn::init_jacobian is consistant with this routine! +SUBROUTINE Perturb_x( p, n, perturb_sign, x, dx ) + + TYPE(AD_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(AD_ContinuousStateType) , INTENT(INOUT) :: x !< perturbed AD continuous states + REAL( R8Ki ) , INTENT( OUT) :: dx !< amount that specific input was perturbed + + + ! local variables + INTEGER(IntKi) :: Blade ! loop over blade nodes + INTEGER(IntKi) :: BladeNode ! loop over blades + INTEGER(IntKi) :: StateIndex ! loop over blades + + + dx = p%dx( n ) + + if (n <= p%BEMT%DBEMT%lin_nx) then + + if (n <= p%BEMT%DBEMT%lin_nx/2) then ! x_p%BEMT%DBEMT%element(i,j)%vind, else x_p%BEMT%DBEMT%element(i,j)%vind_dot + call GetStateIndices( n, size(x%BEMT%DBEMT%element,2), size(x%BEMT%DBEMT%element,1), size(x%BEMT%DBEMT%element(1,1)%vind), Blade, BladeNode, StateIndex ) + x%BEMT%DBEMT%element(BladeNode,Blade)%vind(StateIndex) = x%BEMT%DBEMT%element(BladeNode,Blade)%vind(StateIndex) + dx * perturb_sign + else + call GetStateIndices( n - p%BEMT%DBEMT%lin_nx/2, size(x%BEMT%DBEMT%element,2), size(x%BEMT%DBEMT%element,1), size(x%BEMT%DBEMT%element(1,1)%vind_dot), Blade, BladeNode, StateIndex ) + x%BEMT%DBEMT%element(BladeNode,Blade)%vind_dot(StateIndex) = x%BEMT%DBEMT%element(BladeNode,Blade)%vind_dot(StateIndex) + dx * perturb_sign + endif + + else + call GetStateIndices( n - p%BEMT%DBEMT%lin_nx, size(x%BEMT%UA%element,2), size(x%BEMT%UA%element,1), size(x%BEMT%UA%element(1,1)%x), Blade, BladeNode, StateIndex ) + x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) = x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) + dx * perturb_sign + + end if + +contains + subroutine GetStateIndices( Indx, NumberOfBlades, NumberOfElementsPerBlade, NumberOfStatesPerElement, Blade, BladeNode, StateIndex ) + + integer(IntKi), intent(in ) :: Indx + integer(IntKi), intent(in ) :: NumberOfBlades !< how many blades (size of array) + integer(IntKi), intent(in ) :: NumberOfElementsPerBlade !< how many nodes per blades (size of array) + integer(IntKi), intent(in ) :: NumberOfStatesPerElement !< how many states at each blade element + + integer(IntKi), intent( out) :: Blade + integer(IntKi), intent( out) :: BladeNode + integer(IntKi), intent( out) :: StateIndex + + integer(IntKi) :: CheckNum + + + StateIndex = mod(Indx-1, NumberOfStatesPerElement ) + 1 ! returns a number in [1,NumberOfStatesPerElement] + + CheckNum = (Indx - StateIndex)/NumberOfStatesPerElement + BladeNode = mod(CheckNum, NumberOfElementsPerBlade ) + 1 ! returns a number in [1,NumberOfElementsPerBlade] + + Blade = (CheckNum - BladeNode + 1)/NumberOfElementsPerBlade + 1 + + end subroutine GetStateIndices +END SUBROUTINE 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 aerodyn::init_jacobian is consistant with this routine! SUBROUTINE Compute_dY(p, y_p, y_m, delta_p, delta_m, dY) TYPE(AD_ParameterType) , INTENT(IN ) :: p !< parameters - TYPE(AD_OutputType) , INTENT(IN ) :: y_p !< AD outputs at \f$ u + \Delta_p u \f$ or \f$ z + \Delta_p z \f$ (p=plus) - TYPE(AD_OutputType) , INTENT(IN ) :: y_m !< AD outputs at \f$ u - \Delta_m u \f$ or \f$ z - \Delta_m z \f$ (m=minus) - REAL(R8Ki) , INTENT(IN ) :: delta_p !< difference in inputs or states \f$ delta_p = \Delta_p u \f$ or \f$ delta_p = \Delta_p z \f$ - REAL(R8Ki) , INTENT(IN ) :: delta_m !< difference in inputs or states \f$ delta_m = \Delta_m u \f$ or \f$ delta_m = \Delta_m z \f$ - REAL(R8Ki) , INTENT(INOUT) :: dY(:) !< column of dYdu or dYdz: \f$ \frac{\partial Y}{\partial u_i} = \frac{y_p - y_m}{2 \, \Delta u}\f$ or \f$ \frac{\partial Y}{\partial z_i} = \frac{y_p - y_m}{2 \, \Delta z}\f$ + TYPE(AD_OutputType) , INTENT(IN ) :: y_p !< AD outputs at \f$ u + \Delta_p u \f$ or \f$ x + \Delta_p x \f$ (p=plus) + TYPE(AD_OutputType) , INTENT(IN ) :: y_m !< AD outputs at \f$ u - \Delta_m u \f$ or \f$ x - \Delta_m x \f$ (m=minus) + REAL(R8Ki) , INTENT(IN ) :: delta_p !< difference in inputs or states \f$ delta_p = \Delta_p u \f$ or \f$ delta_p = \Delta_p x \f$ + REAL(R8Ki) , INTENT(IN ) :: delta_m !< difference in inputs or states \f$ delta_m = \Delta_m u \f$ or \f$ delta_m = \Delta_m 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) :: k ! loop over blades @@ -4677,10 +4983,11 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta_p, delta_m, dY) - indx_first = 1 + indx_first = 1 call PackLoadMesh_dY(y_p%TowerLoad, y_m%TowerLoad, dY, indx_first) + do k=1,p%NumBlades - call PackLoadMesh_dY(y_p%BladeLoad(k), y_m%BladeLoad(k), dY, indx_first) + call PackLoadMesh_dY(y_p%BladeLoad(k), y_m%BladeLoad(k), dY, indx_first) end do @@ -4693,90 +5000,56 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta_p, delta_m, dY) END SUBROUTINE Compute_dY !---------------------------------------------------------------------------------------------------------------------------------- -FUNCTION CheckBEMTInputPerturbations( p, m ) RESULT(ValidPerturb) +!> This routine uses values of two continuous state types to compute an array of differences. +!! Do not change this packing without making sure subroutine aerodyn::init_jacobian is consistant with this routine! +SUBROUTINE Compute_dX(p, x_p, x_m, delta_p, delta_m, dX) + + TYPE(AD_ParameterType) , INTENT(IN ) :: p !< parameters + TYPE(AD_ContinuousStateType) , INTENT(IN ) :: x_p !< AD continuous states at \f$ u + \Delta_p u \f$ or \f$ x + \Delta_p x \f$ (p=plus) + TYPE(AD_ContinuousStateType) , INTENT(IN ) :: x_m !< AD continuous states at \f$ u - \Delta_m u \f$ or \f$ x - \Delta_m x \f$ (m=minus) + REAL(R8Ki) , INTENT(IN ) :: delta_p !< difference in inputs or states \f$ delta_p = \Delta_p u \f$ or \f$ delta_p = \Delta_p x \f$ + REAL(R8Ki) , INTENT(IN ) :: delta_m !< difference in inputs or states \f$ delta_m = \Delta_m u \f$ or \f$ delta_m = \Delta_m x \f$ + REAL(R8Ki) , INTENT(INOUT) :: dX(:) !< column of dXdu or dXdx: \f$ \frac{\partial Y}{\partial u_i} = \frac{y_p - y_m}{2 \, \Delta u}\f$ or \f$ \frac{\partial Y}{\partial x_i} = \frac{y_p - y_m}{2 \, \Delta x}\f$ + + ! local variables: + INTEGER(IntKi) :: i ! loop over blade nodes + INTEGER(IntKi) :: j ! loop over blades + INTEGER(IntKi) :: indx_first ! index indicating next value of dY to be filled - type(AD_ParameterType), intent(in ) :: p !< AD parameters - type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables - logical :: ValidPerturb !< if .true., the perturbation is valid; if false, invalid (and thus don't use it) - integer :: j,k + indx_first = 1 - integer, parameter :: indx = 1 ! index of perturbed input - integer, parameter :: indx_op = 2 ! index of operating point - real(ReKi) :: Vx_prod, Vy_prod + if (p%BEMT%DBEMT%lin_nx > 0) then - ValidPerturb = .true. + do j=1,size(x_p%BEMT%DBEMT%element,2) ! number of blades + do i=1,size(x_p%BEMT%DBEMT%element,1) ! number of nodes per blade + dX(indx_first:indx_first+1) = x_p%BEMT%DBEMT%element(i,j)%vind - x_m%BEMT%DBEMT%element(i,j)%vind + indx_first = indx_first + size(x_p%BEMT%DBEMT%element(i,j)%vind) !+= 2 + end do + end do - if ( p%BEMT%UseInduction ) then - if (p%FrozenWake ) then - - do k=1,p%NumBlades - do j=1,p%NumBlNds - - ! don't allow the input perturbations to change Vx or Vy so that Vx+AxInd_op=0 and Vy+TnInd_op=0 to - ! avoid ill-conditioning in CalcConstrStateResidual: - if ( VelocityIsZero( m%BEMT_u(indx)%Vx(j,k)+m%BEMT%AxInd_op(j,k) ) .and. & - VelocityIsZero( m%BEMT_u(indx)%Vy(j,k)+m%BEMT%TnInd_op(j,k) ) ) then - ValidPerturb = .false. - return - end if - - ! don't allow the input perturbations to change Vx or Vy so that Vx=0 or Vy=0 to - ! avoid division-by-zero errors in CalcOutput: - if ( VelocityIsZero( m%BEMT_u(indx)%Vx(j,k) ) .or. VelocityIsZero( m%BEMT_u(indx)%Vy(j,k) ) ) then - ValidPerturb = .false. - return - end if - - end do !j=nodes - end do !k=blades - - else ! not FrozenWake - - do k=1,p%NumBlades - do j=1,p%NumBlNds - - ! don't allow the input perturbations to change Vx or Vy far enough to switch sign (or go to zero) - ! so as to change solution regions. - Vx_prod = m%BEMT_u(indx)%Vx(j,k) * m%BEMT_u(indx_op)%Vx(j,k) - if ( Vx_prod <= 0.0_ReKi ) then - ValidPerturb = .false. - return - elseif ( VelocityIsZero( m%BEMT_u(indx)%Vx(j,k) ) .or. VelocityIsZero( m%BEMT_u(indx_op)%Vx(j,k) ) ) then - ValidPerturb = .false. - return - else - Vy_prod = m%BEMT_u(indx)%Vy(j,k) * m%BEMT_u(indx_op)%Vy(j,k) - if (Vy_prod <= 0.0_ReKi ) then - ValidPerturb = .false. - return - elseif ( VelocityIsZero( m%BEMT_u(indx)%Vy(j,k) ) .or. VelocityIsZero( m%BEMT_u(indx_op)%Vy(j,k) )) then - ValidPerturb = .false. - return - end if - end if - - end do !j=nodes - end do !k=blades - - end if - - else ! not UseInduction - - do k=1,p%NumBlades - do j=1,p%NumBlNds - - ! don't allow the input perturbations to change Vx or Vy so that Vx=0 and Vy=0: - if ( EqualRealNos( m%BEMT_u(indx)%Vx(j,k), 0.0_ReKi ) .and. EqualRealNos( m%BEMT_u(indx)%Vy(j,k), 0.0_ReKi ) ) then - ValidPerturb = .false. - return - end if - - end do !j=nodes - end do !k=blades + do j=1,size(x_p%BEMT%DBEMT%element,2) ! number of blades + do i=1,size(x_p%BEMT%DBEMT%element,1) ! number of nodes per blade + dX(indx_first:indx_first+1) = x_p%BEMT%DBEMT%element(i,j)%vind_dot - x_m%BEMT%DBEMT%element(i,j)%vind_dot + indx_first = indx_first + size(x_p%BEMT%DBEMT%element(i,j)%vind_dot) !+=2 + end do + end do end if - -END FUNCTION CheckBEMTInputPerturbations + + if (p%BEMT%UA%lin_nx>0) then + + do j=1,size(x_p%BEMT%UA%element,2) ! number of blades + do i=1,size(x_p%BEMT%UA%element,1) ! number of nodes per blade + dX(indx_first:indx_first+3) = x_p%BEMT%UA%element(i,j)%x - x_m%BEMT%UA%element(i,j)%x + indx_first = indx_first + size(x_p%BEMT%UA%element(i,j)%x) ! = index_first += 4 + end do + end do + + end if + + dX = dX / (delta_p + delta_m) + +END SUBROUTINE Compute_dX !---------------------------------------------------------------------------------------------------------------------------------- END MODULE AeroDyn diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index fc4c73684c..34ba3b9ff1 100644 --- a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 @@ -791,7 +791,7 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM else DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = -m%FVW%BN_UrelWind_s(1,IdxNode,IdxBlade) + y%WriteOutput( OutIdx ) = m%FVW%BN_UrelWind_s(1,IdxNode,IdxBlade) OutIdx = OutIdx + 1 END DO END DO @@ -820,7 +820,7 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds if (OtherState%BEMT%ValidPhi(IdxNode,IdxBlade)) then - y%WriteOutput( OutIdx ) = 0.0_ReKi + y%WriteOutput( OutIdx ) = 1.0_ReKi - m%BEMT%BEM_weight else y%WriteOutput( OutIdx ) = 1.0_ReKi end if diff --git a/modules/aerodyn/src/AeroDyn_Driver.f90 b/modules/aerodyn/src/AeroDyn_Driver.f90 index 43a2a527d1..7fbbe4929d 100644 --- a/modules/aerodyn/src/AeroDyn_Driver.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver.f90 @@ -34,7 +34,6 @@ program AeroDyn_Driver integer(IntKi) :: iCase ! loop counter (for driver case) integer(IntKi) :: nt ! loop counter (for time step) integer(IntKi) :: j ! loop counter (for array of inputs) - integer(IntKi) :: numSteps ! number of time steps in the simulation integer(IntKi) :: errStat ! Status of error message character(ErrMsgLen) :: errMsg ! Error message if ErrStat /= ErrID_None @@ -48,7 +47,11 @@ program AeroDyn_Driver !real(DbKi) :: SttsTime ! Amount of time between screen status messages (sec) !integer :: n_SttsTime ! Number of time steps between screen status messages (-) logical :: AD_Initialized - + + real(ReKi) :: RotAzimuth ! Rotor Azimuth (aligned with blade 1) + !real(ReKi) :: TeetAng ! Teeter angle + !real(ReKi) :: TeetAngVel ! Teeter angular velocity + errStat = ErrID_None @@ -69,26 +72,12 @@ program AeroDyn_Driver do iCase = 1, DvrData%NumCases - call WrScr( NewLine//'Running case '//trim(num2lstr(iCase))//' of '//trim(num2lstr(DvrData%NumCases))//'.' ) - - !dT = TwoPi/DvrData%Cases(iCase)%RotSpeed / DvrData%NumSect ! sec - - numSteps = ceiling( DvrData%Cases(iCase)%TMax / DvrData%Cases(iCase)%dT) - dT_Dvr = DvrData%Cases(iCase)%dT - - call WrScr (' WndSpeed='//trim(num2lstr(DvrData%Cases(iCase)%WndSpeed))//& - ' m/s; ShearExp='//trim(num2lstr(DvrData%Cases(iCase)%ShearExp))//& - '; RotSpeed='//trim(num2lstr(DvrData%Cases(iCase)%RotSpeed*RPS2RPM))//& - ' rpm; Pitch='//trim(num2lstr(DvrData%Cases(iCase)%Pitch*R2D))//& - ' deg; Yaw='//trim(num2lstr(DvrData%Cases(iCase)%Yaw*R2D))//& - ' deg; dT='//trim(num2lstr(DvrData%Cases(iCase)%dT))//& - ' s; Tmax='//trim(num2lstr(DvrData%Cases(iCase)%Tmax))//& - ' s; numSteps='//trim(num2lstr(numSteps)) ) - - +! call WrScr( NewLine//'Running case '//trim(num2lstr(iCase))//' of '//trim(num2lstr(DvrData%NumCases))//'.' ) + ! Set the Initialization input data for AeroDyn based on the Driver input file data, and initialize AD ! (this also initializes inputs to AD for first time step) + dT_Dvr = DvrData%Cases(iCase)%dT call Init_AeroDyn(iCase, DvrData, AD, dT_Dvr, errStat, errMsg) call CheckError() AD_Initialized = .true. @@ -99,18 +88,19 @@ program AeroDyn_Driver call CheckError() end if + if (iCase.eq.1) then + call Dvr_InitializeOutputFile(DvrData%numBlades, iCase, DvrData%Cases(iCase), DvrData%OutFileData, errStat, errMsg) + call CheckError() + endif - call Dvr_InitializeOutputFile( iCase, DvrData%Cases(iCase), DvrData%OutFileData, errStat, errMsg) - call CheckError() - - - do nt = 1, numSteps + RotAzimuth = 0.0_ReKi + do nt = 1, DvrData%Cases(iCase)%numSteps !............................... ! set AD inputs for nt (and keep values at nt-1 as well) !............................... - call Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) + call Set_AD_Inputs(iCase,nt,RotAzimuth,DvrData,AD,errStat,errMsg) ! u(1) is at nt+1, u(2) is at nt call CheckError() time = AD%InputTime(2) @@ -119,9 +109,14 @@ program AeroDyn_Driver call AD_CalcOutput( time, AD%u(2), AD%p, AD%x, AD%xd, AD%z, AD%OtherState, AD%y, AD%m, errStat, errMsg ) call CheckError() - - call Dvr_WriteOutputLine(DvrData%OutFileData, time, AD%y%WriteOutput, errStat, errMsg) + + + + + call Dvr_WriteOutputLine(DvrData%OutFileData, nt, RotAzimuth, AD%y%WriteOutput, DvrData%Cases(iCase), iCase, errStat, errMsg) call CheckError() + + ! Get state variables at next step: INPUT at step nt - 1, OUTPUT at step nt @@ -132,19 +127,8 @@ program AeroDyn_Driver end do !nt=1,numSteps - call AD_End( AD%u(1), AD%p, AD%x, AD%xd, AD%z, AD%OtherState, AD%y, AD%m, errStat, errMsg ) - AD_Initialized = .false. - call CheckError() - close( DvrData%OutFileData%unOutFile ) - - do j = 2, numInp - call AD_DestroyInput (AD%u(j), errStat, errMsg) - call CheckError() - end do - end do !iCase = 1, DvrData%NumCases - call Dvr_End() contains @@ -193,4 +177,4 @@ subroutine Dvr_End() end subroutine Dvr_End !................................ end program AeroDyn_Driver - \ No newline at end of file + diff --git a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt index 43a3c6f7d0..76f0f95c8e 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt @@ -15,28 +15,37 @@ usefrom AeroDyn_Registry.txt # # ..... Table of cases to run ....................................................................................................... -typedef AeroDyn_Driver/AD_Dvr Dvr_Case ReKi WndSpeed - - - "Wind Speed" "m/s" -typedef ^ ^ ReKi ShearExp - - - "Power Law Wind-Shear Exponent" "-" -typedef ^ ^ ReKi RotSpeed - - - "Rotor Speed" "rad/s" -typedef ^ ^ ReKi Pitch - - - "Pitch angle" "rad" -typedef ^ ^ ReKi Yaw - - - "Yaw angle" "rad" +typedef AeroDyn_Driver/AD_Dvr Dvr_Case ReKi WndSpeed {:} - - "Wind Speed" "m/s" +typedef ^ ^ ReKi ShearExp {:} - - "Power Law Wind-Shear Exponent" "-" +typedef ^ ^ ReKi RotSpeed {:} - - "Rotor Speed" "rad/s" +typedef ^ ^ ReKi Pitch {:} - - "Pitch angle" "rad" +typedef ^ ^ ReKi Yaw {:} - - "Yaw angle" "rad" +typedef ^ ^ DbKi time {:} - - "time increment" "s" typedef ^ ^ DbKi dT - - - "time increment" "s" -typedef ^ ^ DbKi Tmax - - - "length of this simulation" "s" +typedef ^ ^ IntKi numSteps - - - "number of steps in this case" "-" + + # # ..... Data for driver output file ....................................................................................................... typedef ^ Dvr_OutputFile ProgDesc AD_ver - - - "AeroDyn version information" - typedef ^ ^ IntKi unOutFile - - - "unit number for writing output file" "-" +typedef ^ ^ IntKi ActualChanLen - - - "Actual length of channels written to text file (less than or equal to ChanLen)" "-" +typedef ^ ^ character(20) Fmt_t - - - "Format specifier for time channel" "-" +typedef ^ ^ character(25) Fmt_a - - - "Format specifier for each column (including delimiter)" "-" +typedef ^ ^ character(20) Fmt_i - - - "Format specifier for integer column" "-" typedef ^ ^ character(1) delim - - - "column delimiter" "-" typedef ^ ^ character(20) outFmt - - - "Format specifier" "-" typedef ^ ^ character(1024) Root - - - "Output file rootname" "-" typedef ^ ^ character(1024) runTitle - - - "Description string from input file" "-" typedef ^ ^ character(ChanLen) WriteOutputHdr {:} - - "Channel headers" "-" typedef ^ ^ character(ChanLen) WriteOutputUnt {:} - - "Channel units" "-" +typedef ^ ^ logical AllFiles - - - "Output file for each case" "-" +typedef ^ ^ logical SumFile - - - "Output summary file for all cases with last timestep" "-" # # ..... AeroDyn data ....................................................................................................... -param ^ - INTEGER numInp - 2 - "Usually, order of interpolation for input-output extrap (not used in driver)" +param ^ - INTEGER numInp - 2 - "Determines order of interpolation for input-output extrap (2=linear;3=quadratic)" typedef ^ AeroDyn_Data AD_ContinuousStateType x - - - "Continuous states" typedef ^ ^ AD_DiscreteStateType xd - - - "Discrete states" typedef ^ ^ AD_ConstraintStateType z - - - "Constraint states" @@ -61,5 +70,5 @@ typedef ^ ^ IntKi NumCase typedef ^ ^ Dvr_Case Cases {:} - - "table of cases to run" "-" typedef ^ ^ Dvr_OutputFile OutFileData - - - "data for driver output file" "-" #typedef ^ ^ AeroDyn_Data AD - - - "data for the AeroDyn module" - +#typedef ^ ^ Dvr_RootInfo RootForceMom 3 - - "blade root forces and moments (blade coords)" "-" diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index c29920e573..86a0d94232 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -97,79 +97,93 @@ subroutine Init_AeroDyn(iCase, DvrData, AD, dt, errStat, errMsg) ! local data type(AD_InitInputType) :: InitInData ! Input data for initialization type(AD_InitOutputType) :: InitOutData ! Output data from initialization + real(ReKi) :: RotAzimuth ! Rotor azimuth -- aligned with blade 1 (deg) errStat = ErrID_None errMsg = '' - InitInData%InputFile = DvrData%AD_InputFile - InitInData%NumBlades = DvrData%numBlades - InitInData%RootName = DvrData%outFileData%Root - InitInData%Gravity = 9.80665_ReKi + if (iCase.EQ.1) then - ! set initialization data: - call AllocAry( InitInData%BladeRootPosition, 3, InitInData%NumBlades, 'BladeRootPosition', errStat2, ErrMsg2 ) - call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - call AllocAry( InitInData%BladeRootOrientation, 3, 3, InitInData%NumBlades, 'BladeRootOrientation', errStat2, ErrMsg2 ) - call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + InitInData%InputFile = DvrData%AD_InputFile + InitInData%NumBlades = DvrData%numBlades + InitInData%RootName = DvrData%outFileData%Root + InitInData%Gravity = 9.80665_ReKi + + + ! set initialization data: + call AllocAry( InitInData%BladeRootPosition, 3, InitInData%NumBlades, 'BladeRootPosition', errStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + call AllocAry( InitInData%BladeRootOrientation, 3, 3, InitInData%NumBlades, 'BladeRootOrientation', errStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if - InitInData%HubPosition = (/ DvrData%Overhang * cos(DvrData%shftTilt), 0.0_ReKi, DvrData%HubHt /) - theta(1) = 0.0_ReKi - theta(2) = -DvrData%shftTilt - theta(3) = 0.0_ReKi - InitInData%HubOrientation = EulerConstruct( theta ) + InitInData%HubPosition = (/ DvrData%Overhang * cos(DvrData%shftTilt), 0.0_ReKi, DvrData%HubHt /) + theta(1) = 0.0_ReKi + theta(2) = -DvrData%shftTilt + theta(3) = 0.0_ReKi + InitInData%HubOrientation = EulerConstruct( theta ) - do k=1,InitInData%numBlades + do k=1,InitInData%numBlades - theta(1) = (k-1)*TwoPi/real(InitInData%numBlades,ReKi) - theta(2) = DvrData%precone - theta(3) = 0.0_ReKi - InitInData%BladeRootOrientation(:,:,k) = matmul( EulerConstruct( theta ), InitInData%HubOrientation ) + theta(1) = (k-1)*TwoPi/real(InitInData%numBlades,ReKi) + theta(2) = DvrData%precone + theta(3) = 0.0_ReKi + InitInData%BladeRootOrientation(:,:,k) = matmul( EulerConstruct( theta ), InitInData%HubOrientation ) - InitInData%BladeRootPosition(:,k) = InitInData%HubPosition + DvrData%hubRad * InitInData%BladeRootOrientation(3,:,k) - - end do + InitInData%BladeRootPosition(:,k) = InitInData%HubPosition + DvrData%hubRad * InitInData%BladeRootOrientation(3,:,k) + end do - call AD_Init(InitInData, AD%u(1), AD%p, AD%x, AD%xd, AD%z, AD%OtherState, AD%y, AD%m, dt, InitOutData, ErrStat2, ErrMsg2 ) - call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + + call AD_Init(InitInData, AD%u(1), AD%p, AD%x, AD%xd, AD%z, AD%OtherState, AD%y, AD%m, dt, InitOutData, ErrStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if - do j = 2, numInp - call AD_CopyInput (AD%u(1), AD%u(j), MESH_NEWCOPY, errStat2, errMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - end do - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + do j = 2, numInp + call AD_CopyInput (AD%u(1), AD%u(j), MESH_NEWCOPY, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + + ! move AD initOut data to AD Driver + call move_alloc( InitOutData%WriteOutputHdr, DvrData%OutFileData%WriteOutputHdr ) + call move_alloc( InitOutData%WriteOutputUnt, DvrData%OutFileData%WriteOutputUnt ) + + DvrData%OutFileData%AD_ver = InitOutData%ver + + call cleanup() ! destroy init input/output data + + else + call AD_ReInit(AD%p, AD%x, AD%xd, AD%z, AD%OtherState, AD%m, dt, ErrStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + if (ErrStat >= AbortErrLev) return + + end if + + ! we know exact values, so we're going to initialize inputs this way (instead of using the input guesses from AD_Init) AD%InputTime = -999 + RotAzimuth = 0.0 DO j = 1-numInp, 0 - call Set_AD_Inputs(iCase,j,DvrData,AD,errStat2,errMsg2) + call Set_AD_Inputs(iCase,j,RotAzimuth,DvrData,AD,errStat2,errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) END DO - ! move AD initOut data to AD Driver - call move_alloc( InitOutData%WriteOutputHdr, DvrData%OutFileData%WriteOutputHdr ) - call move_alloc( InitOutData%WriteOutputUnt, DvrData%OutFileData%WriteOutputUnt ) - - DvrData%OutFileData%AD_ver = InitOutData%ver contains + subroutine cleanup() call AD_DestroyInitInput( InitInData, ErrStat2, ErrMsg2 ) call AD_DestroyInitOutput( InitOutData, ErrStat2, ErrMsg2 ) @@ -177,14 +191,15 @@ end subroutine cleanup end subroutine Init_AeroDyn !---------------------------------------------------------------------------------------------------------------------------------- -!> this routine returns time=(nt-1) * DvrData%Cases(iCase)%dT, and cycles values in the input array AD%InputTime and AD%u. +!> this routine cycles values in the input array AD%InputTime and AD%u. !! it then sets the inputs for nt * DvrData%Cases(iCase)%dT, which are index values 1 in the arrays. -subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) +subroutine Set_AD_Inputs(iCase,nt,RotAzimuth,DvrData,AD,errStat,errMsg) integer(IntKi) , intent(in ) :: iCase ! case number integer(IntKi) , intent(in ) :: nt ! time step number - - type(Dvr_SimData), intent(inout) :: DvrData ! Driver data + + real(ReKi) , intent(inout) :: RotAzimuth ! Rotor azimuth at time nt-1 -- aligned with blade 1 (deg) + type(Dvr_SimData), intent(in ) :: DvrData ! Driver data type(AeroDyn_Data), intent(inout) :: AD ! AeroDyn data integer(IntKi) , intent( out) :: errStat ! Status of error message character(*) , intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None @@ -196,6 +211,7 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) integer(intKi) :: j ! loop counter for nodes integer(intKi) :: k ! loop counter for blades + integer(intKi) :: timeIndex ! index for time real(ReKi) :: z ! height (m) !real(ReKi) :: angle @@ -211,6 +227,8 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) ! note that this initialization is a little different than the general algorithm in FAST because here ! we can get exact values, so we are going to ignore initial guesses and not extrapolate + timeIndex = min( max(1,nt+1), DvrData%Cases(iCase)%numSteps ) + !................ ! shift previous calculations: !................ @@ -220,7 +238,28 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) AD%InputTime(j+1) = AD%InputTime(j) end do - AD%inputTime(1) = nt * DvrData%Cases(iCase)%dT + + if (nt <= 0) then + ! save the azimuth at t (not t+dt) for output to file: + ! compare to theta(1) for calculate of HubMotion%Orientation below + RotAzimuth = MODULO( REAL( DvrData%Cases(iCase)%dT * (nt-1) * DvrData%Cases(iCase)%RotSpeed(1), ReKi) * R2D, 360.0_ReKi ) + + AD%inputTime(1) = DvrData%Cases(iCase)%time(1) + DvrData%Cases(iCase)%dT * nt ! time at nt+1 + else + + if (nt==1) then + RotAzimuth = 0.0_ReKi + else + RotAzimuth = MODULO( RotAzimuth + REAL(DvrData%Cases(iCase)%dt * DvrData%Cases(iCase)%RotSpeed(nt), ReKi) * R2D, 360.0_ReKi ) ! add a delta angle to the previous azimuth + end if + + if (nt == DvrData%Cases(iCase)%numSteps) then + AD%inputTime(1) = DvrData%Cases(iCase)%time(timeIndex) + DvrData%Cases(iCase)%dT + else + AD%inputTime(1) = DvrData%Cases(iCase)%time(timeIndex) + end if + + end if !................ ! calculate new values @@ -236,35 +275,34 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) ! Hub motions: theta(1) = 0.0_ReKi theta(2) = 0.0_ReKi - theta(3) = DvrData%Cases(iCase)%Yaw + theta(3) = DvrData%Cases(iCase)%Yaw(timeIndex) orientation = EulerConstruct(theta) AD%u(1)%HubMotion%TranslationDisp(:,1) = matmul( AD%u(1)%HubMotion%Position(:,1), orientation ) - AD%u(1)%HubMotion%Position(:,1) ! = matmul( transpose(orientation) - eye(3), AD%u(1)%HubMotion%Position(:,1) ) - - theta(1) = AD%inputTime(1) * DvrData%Cases(iCase)%RotSpeed + + theta(1) = RotAzimuth*D2R + DvrData%Cases(iCase)%dt * DvrData%Cases(iCase)%RotSpeed(timeIndex) ! AD%inputTime(1) * DvrData%Cases(iCase)%RotSpeed theta(2) = 0.0_ReKi theta(3) = 0.0_ReKi AD%u(1)%HubMotion%Orientation( :,:,1) = matmul( AD%u(1)%HubMotion%RefOrientation(:,:,1), orientation ) - orientation = EulerConstruct( theta ) + orientation = EulerConstruct( theta ) AD%u(1)%HubMotion%Orientation( :,:,1) = matmul( orientation, AD%u(1)%HubMotion%Orientation( :,:,1) ) - AD%u(1)%HubMotion%RotationVel( :,1) = AD%u(1)%HubMotion%Orientation(1,:,1) * DvrData%Cases(iCase)%RotSpeed + AD%u(1)%HubMotion%RotationVel( :,1) = AD%u(1)%HubMotion%Orientation(1,:,1) * DvrData%Cases(iCase)%RotSpeed(timeIndex) ! Blade motions: do k=1,DvrData%numBlades theta(1) = (k-1)*TwoPi/real(DvrData%numBlades,ReKi) theta(2) = DvrData%precone - theta(3) = -DvrData%Cases(iCase)%pitch + theta(3) = -DvrData%Cases(iCase)%pitch(timeIndex) orientation = EulerConstruct(theta) AD%u(1)%BladeRootMotion(k)%Orientation( :,:,1) = matmul( orientation, AD%u(1)%HubMotion%Orientation( :,:,1) ) - end do !k=numBlades ! Blade and blade root motions: do k=1,DvrData%numBlades rotateMat = transpose( AD%u(1)%BladeRootMotion(k)%Orientation( :,:,1) ) - rotateMat = matmul( rotateMat, AD%u(1)%BladeRootMotion(k)%RefOrientation( :,:,1) ) + rotateMat = matmul( rotateMat, AD%u(1)%BladeRootMotion(k)%RefOrientation( :,:,1) ) orientation = transpose(rotateMat) rotateMat(1,1) = rotateMat(1,1) - 1.0_ReKi @@ -289,7 +327,9 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) position = AD%u(1)%BladeMotion(k)%Position(:,j) + AD%u(1)%BladeMotion(k)%TranslationDisp(:,j) & - AD%u(1)%HubMotion%Position(:,1) - AD%u(1)%HubMotion%TranslationDisp(:,1) AD%u(1)%BladeMotion(k)%TranslationVel( :,j) = cross_product( AD%u(1)%HubMotion%RotationVel(:,1), position ) - + + AD%u(1)%BladeMotion(k)%RotationVel(:,j) = AD%u(1)%HubMotion%Orientation(1,:,1) * DvrData%Cases(iCase)%RotSpeed(timeIndex) ! simplification (without pitch rate) + AD%u(1)%BladeMotion(k)%TranslationAcc(:,j) = 0.0_ReKi ! simplification end do !j=nnodes end do !k=numBlades @@ -299,7 +339,7 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) do k=1,DvrData%numBlades do j=1,AD%u(1)%BladeMotion(k)%nnodes z = AD%u(1)%BladeMotion(k)%Position(3,j) + AD%u(1)%BladeMotion(k)%TranslationDisp(3,j) - AD%u(1)%InflowOnBlade(1,j,k) = GetU( DvrData%Cases(iCase)%WndSpeed, DvrData%HubHt, DvrData%Cases(iCase)%ShearExp, z ) + AD%u(1)%InflowOnBlade(1,j,k) = GetU( DvrData%Cases(iCase)%WndSpeed(timeIndex), DvrData%HubHt, DvrData%Cases(iCase)%ShearExp(timeIndex), z ) AD%u(1)%InflowOnBlade(2,j,k) = 0.0_ReKi !V AD%u(1)%InflowOnBlade(3,j,k) = 0.0_ReKi !W end do !j=nnodes @@ -308,7 +348,7 @@ subroutine Set_AD_Inputs(iCase,nt,DvrData,AD,errStat,errMsg) !InflowOnTower do j=1,AD%u(1)%TowerMotion%nnodes z = AD%u(1)%TowerMotion%Position(3,j) + AD%u(1)%TowerMotion%TranslationDisp(3,j) - AD%u(1)%InflowOnTower(1,j) = GetU( DvrData%Cases(iCase)%WndSpeed, DvrData%HubHt, DvrData%Cases(iCase)%ShearExp, z ) + AD%u(1)%InflowOnTower(1,j) = GetU( DvrData%Cases(iCase)%WndSpeed(timeIndex), DvrData%HubHt, DvrData%Cases(iCase)%ShearExp(timeIndex), z ) AD%u(1)%InflowOnTower(2,j) = 0.0_ReKi !V AD%u(1)%InflowOnTower(3,j) = 0.0_ReKi !W end do !j=nnodes @@ -338,9 +378,10 @@ subroutine Dvr_ReadInputFile(fileName, DvrData, errStat, errMsg ) ! Local variables character(1024) :: PriPath character(1024) :: inpVersion ! String containing the input-version information. - character(1024) :: line ! String containing a line of input. + character(1024) :: Line ! String containing a line of input. integer :: unIn, unEc integer :: ICase + integer :: nt, Ind integer :: Sttus character( 11) :: DateNow ! Date shortly after the start of execution. character( 8) :: TimeNow ! Time of day shortly after the start of execution. @@ -482,6 +523,7 @@ subroutine Dvr_ReadInputFile(fileName, DvrData, errStat, errMsg ) end if + ! Read the combined-case section. call ReadCom ( unIn, fileName, 'the combined-case subtitle', errStat2, errMsg2, UnEc ) @@ -513,18 +555,68 @@ subroutine Dvr_ReadInputFile(fileName, DvrData, errStat, errMsg ) do ICase=1,DvrData%NumCases - call ReadAry ( unIn, fileName, InpCase, NumCols, 'InpCase', 'parameters for Case #' & - //trim( Int2LStr( ICase ) )//'.', errStat2, errMsg2, UnEc ) - call setErrStat( errStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + CALL ReadStr( UnIn, fileName, line, 'line', 'Input data for case #'//trim( Int2LStr( ICase ) ), ErrStat2, ErrMsg2, UnEc ) + CALL setErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( errStat >= AbortErrLev ) then + call cleanup() + return + end if + + Line = ADJUSTL( Line ) ! remove leading spaces + + if (Line(1:1) == '@') then + Line = Line(2:) ! remove leading character + call ReadTimeHistoryFile(Line, PriPath, DvrData%Cases(iCase), ErrStat2, ErrMsg2, UnEc ) + call setErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( errStat >= AbortErrLev ) then + call cleanup() + return + end if + else + + READ (Line,*,IOSTAT=Sttus) InpCase ! read whole array (hopefully!) + + ! check errors + CALL CheckIOS ( Sttus, fileName, 'InpCase', NumType, ErrStat2, ErrMsg2 ) + call setErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + DO Ind=1,NumCols + CALL CheckRealVar( InpCase(Ind), 'InpCase', ErrStat2, ErrMsg2) + CALL setErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END DO - DvrData%Cases(iCase)%WndSpeed = InpCase( 1) - DvrData%Cases(ICase)%ShearExp = InpCase( 2) - DvrData%Cases(ICase)%RotSpeed = InpCase( 3)*RPM2RPS - DvrData%Cases(ICase)%Pitch = InpCase( 4)*D2R - DvrData%Cases(ICase)%Yaw = InpCase( 5)*D2R - DvrData%Cases(iCase)%dT = InpCase( 6) - DvrData%Cases(iCase)%Tmax = InpCase( 7) - + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + + IF ( UnEc > 0 ) THEN + WRITE( UnEc, Ec_ReAryFrmt ) TRIM( 'InpCase' ), 'Parameters for Case #'//trim( Int2LStr( ICase ) ), InpCase + END IF + + ! set data + DvrData%Cases(iCase)%numSteps = ceiling( InpCase( 7) / InpCase( 6) ) + call AllocateCase(DvrData%Cases(iCase), ErrStat2, ErrMsg2) ! needs %numSteps set prior to call + if (ErrStat2>=AbortErrLev) then + call SetErrStat( ErrStat2, ErrMsg2 , ErrStat, ErrMsg, RoutineName ) + call Cleanup() + return + end if + + DvrData%Cases(iCase)%WndSpeed = InpCase( 1) + DvrData%Cases(ICase)%ShearExp = InpCase( 2) + DvrData%Cases(ICase)%RotSpeed = InpCase( 3)*RPM2RPS + DvrData%Cases(ICase)%Pitch = InpCase( 4)*D2R + DvrData%Cases(ICase)%Yaw = InpCase( 5)*D2R + DvrData%Cases(iCase)%dT = InpCase( 6) + !DvrData%Cases(iCase)%Tmax = InpCase( 7) + + do nt = 1,DvrData%Cases(iCase)%numSteps + DvrData%Cases(iCase)%time(nt) = (nt-1) * DvrData%Cases(iCase)%dT + end do + + end if + end do ! ICase call cleanup ( ) @@ -538,9 +630,151 @@ subroutine cleanup() end subroutine cleanup end subroutine Dvr_ReadInputFile !---------------------------------------------------------------------------------------------------------------------------------- +subroutine ReadTimeHistoryFile(FileName, PriPath, CaseData, ErrStat, ErrMsg, UnEc ) + character(*), intent(inout) :: FileName + character(*), intent(in ) :: PriPath + type(Dvr_Case), intent(inout) :: CaseData + integer, intent( out) :: ErrStat ! returns a non-zero value when an error occurs + character(*), intent( out) :: ErrMsg ! Error message if errStat /= ErrID_None + integer, intent(in ) :: UnEc + + integer :: UnIn + integer :: i + integer, parameter :: NumHeaderLines = 2 + + character(*), parameter :: RoutineName = 'AllocateCase' + integer :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + integer, parameter :: NumCols = 6 ! number of columns to be read from the input file + real(DbKi) :: InpCase(NumCols) ! Temporary array to hold combined-case input parameters. (note that we store in double precision so the time is read correctly) + + + + ! Open the input file + IF ( PathIsRelative( FileName ) ) FileName = TRIM(PriPath)//TRIM(FileName) + + + call GetNewUnit( UnIn ) + call OpenFInpFile( UnIn, FileName, errStat2, ErrMsg2 ) + call setErrStat( errStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + if ( errStat >= AbortErrLev ) then + call cleanup() + return + end if + + + DO I=1,NumHeaderLines + call ReadCom(UnIn, FileName, 'Header', ErrStat2, ErrMsg2, UnEc) + call setErrStat( errStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + IF (ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + END DO + + + ! find out how many rows there are to the end of the file + CaseData%NumSteps = -1 + ErrStat2 = 0 + DO WHILE ( ErrStat2 == 0 ) + + CaseData%NumSteps = CaseData%NumSteps + 1 + READ(UnIn, *, IOSTAT=ErrStat2) InpCase(1) + + END DO + + CALL WrScr( ' Found '//TRIM(Num2LStr(CaseData%NumSteps))//' lines of time-series data.' ) + + IF (CaseData%NumSteps < 2) THEN + CALL SetErrStat(ErrID_Fatal, 'The user time-series input file must contain at least 2 rows of time data.', ErrStat, ErrMsg, RoutineName) + CALL Cleanup() + RETURN + END IF + + call AllocateCase(CaseData, ErrStat2, ErrMsg2) + call setErrStat( errStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + IF (ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + END IF + + ! now rewind and skip the first few lines. + REWIND( UnIn, IOSTAT=ErrStat2 ) + IF (ErrStat2 /= 0_IntKi ) THEN + CALL SetErrStat( ErrID_Fatal, 'Error rewinding file "'//TRIM(FileName)//'".', ErrStat, ErrMsg, RoutineName) + CALL Cleanup() + END IF + + !IMPORTANT: any changes to the number of lines in the header must be reflected in NumHeaderLines + DO I=1,NumHeaderLines + call ReadCom(UnIn, FileName, 'Header', ErrStat2, ErrMsg2, UnEc) ! I'm going to ignore this error because we should have caught any issues the first time we read the file. + END DO + + + DO i=1,CaseData%NumSteps + + call ReadAry ( unIn, fileName, InpCase, NumCols, 'InpCase', 'parameters for Case', errStat2, errMsg2, UnEc ) + call setErrStat( errStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + + if (ErrStat>=AbortErrLev) then + call Cleanup() + return + end if + + CaseData%time(i) = InpCase( 1) + CaseData%WndSpeed(i) = InpCase( 2) + CaseData%ShearExp(i) = InpCase( 3) + CaseData%RotSpeed(i) = InpCase( 4)*RPM2RPS + CaseData%Pitch(i) = InpCase( 5)*D2R + CaseData%Yaw(i) = InpCase( 6)*D2R + + END DO + + CaseData%dT = CaseData%time(2) - CaseData%time(1) + + do i=3,CaseData%NumSteps + if (.not. EqualRealNos( CaseData%time(i), CaseData%time(i-1) + CaseData%dT ) ) then + call SetErrStat(ErrID_Fatal,'Time history file must contain time constant deltas in the time channel.', ErrStat, ErrMsg, RoutineName) + call cleanup() + return + end if + end do + + call cleanup() + +contains + subroutine cleanup + close(UnIn) + end subroutine cleanup +end subroutine ReadTimeHistoryFile +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine AllocateCase(CaseData, ErrStat, ErrMsg) + type(Dvr_Case), intent(inout) :: CaseData + integer, intent( out) :: errStat ! returns a non-zero value when an error occurs + character(*), intent( out) :: errMsg ! Error message if errStat /= ErrID_None + + character(*), parameter :: routineName = 'AllocateCase' + integer :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat = ErrID_None + ErrMsg = "" + + CaseData%numSteps = max(1, CaseData%numSteps) + + call AllocAry( CaseData%time, CaseData%numSteps, 'time', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + call AllocAry( CaseData%WndSpeed, CaseData%numSteps, 'WndSpeed', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + call AllocAry( CaseData%ShearExp, CaseData%numSteps, 'ShearExp', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + call AllocAry( CaseData%RotSpeed, CaseData%numSteps, 'RotSpeed', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + call AllocAry( CaseData%Pitch, CaseData%numSteps, 'Pitch', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + call AllocAry( CaseData%Yaw, CaseData%numSteps, 'Yaw', ErrStat2,ErrMsg2); call setErrStat( ErrStat2, ErrMsg2 , errStat, ErrMsg , RoutineName ) + +end subroutine AllocateCase +!---------------------------------------------------------------------------------------------------------------------------------- subroutine ValidateInputs(DvrData, errStat, errMsg) - type(Dvr_SimData), intent(in) :: DvrData + type(Dvr_SimData), intent(inout) :: DvrData ! intent(out) only so that we can save FmtWidth in DvrData%OutFileData%ActualChanLen integer, intent( out) :: errStat ! returns a non-zero value when an error occurs character(*), intent( out) :: errMsg ! Error message if errStat /= ErrID_None @@ -559,7 +793,7 @@ subroutine ValidateInputs(DvrData, errStat, errMsg) ! Turbine Data: if ( DvrData%numBlades < 1 ) call SetErrStat( ErrID_Fatal, "There must be at least 1 blade (numBlades).", ErrStat, ErrMsg, RoutineName) - if ( DvrData%numBlades > 3 ) call SetErrStat( ErrID_Fatal, "There can be no more than 3 blades (numBlades).", ErrStat, ErrMsg, RoutineName) +! if ( DvrData%numBlades > 3 ) call SetErrStat( ErrID_Fatal, "There can be no more than 3 blades (numBlades).", ErrStat, ErrMsg, RoutineName) if ( DvrData%HubRad < 0.0_ReKi .or. EqualRealNos(DvrData%HubRad, 0.0_ReKi) ) call SetErrStat( ErrID_Fatal, "HubRad must be a positive number.", ErrStat, ErrMsg, RoutineName) if ( DvrData%HubHt < DvrData%HubRad ) call SetErrStat( ErrID_Fatal, "HubHt must be at least HubRad.", ErrStat, ErrMsg, RoutineName) @@ -569,14 +803,16 @@ subroutine ValidateInputs(DvrData, errStat, errMsg) call ChkRealFmtStr( DvrData%OutFileData%OutFmt, 'OutFmt', FmtWidth, ErrStat2, ErrMsg2 ) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if ( FmtWidth /= ChanLen ) call SetErrStat( ErrID_Warn, 'OutFmt produces a column width of '// & - TRIM(Num2LStr(FmtWidth))//' instead of '//TRIM(Num2LStr(ChanLen))//' characters.', ErrStat, ErrMsg, RoutineName ) - + !if ( FmtWidth /= ChanLen ) call SetErrStat( ErrID_Warn, 'OutFmt produces a column width of '// & + ! TRIM(Num2LStr(FmtWidth))//' instead of '//TRIM(Num2LStr(ChanLen))//' characters.', ErrStat, ErrMsg, RoutineName ) + 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 ) + DvrData%OutFileData%ActualChanLen = FmtWidth + ! Combined-Case Analysis: do i=1,DvrData%NumCases if (DvrData%Cases(i)%DT < epsilon(0.0_ReKi) ) call SetErrStat(ErrID_Fatal,'dT must be larger than 0 in case '//trim(num2lstr(i))//'.',ErrStat, ErrMsg,RoutineName) - if (DvrData%Cases(i)%TMax < DvrData%Cases(i)%DT ) call SetErrStat(ErrID_Fatal,'TMax must be larger than dT in case '//trim(num2lstr(i))//'.',ErrStat, ErrMsg,RoutineName) end do @@ -584,37 +820,40 @@ subroutine ValidateInputs(DvrData, errStat, errMsg) end subroutine ValidateInputs !---------------------------------------------------------------------------------------------------------------------------------- -subroutine Dvr_WriteOutputLine(OutFileData, t, output, errStat, errMsg) +subroutine Dvr_WriteOutputLine(OutFileData, nt, RotAzimuth, output, CaseData, iCase, errStat, errMsg) - real(DbKi) , intent(in ) :: t ! simulation time (s) + integer(IntKi) , intent(in ) :: nt ! simulation time step (-) + integer(IntKi) , intent(in ) :: iCase ! case # to write to file type(Dvr_OutputFile) , intent(in ) :: OutFileData - real(ReKi) , intent(in ) :: output(:) ! Rootname for the output file + type(Dvr_Case), intent(in ) :: CaseData + real(ReKi) , intent(in ) :: RotAzimuth ! Rotor azimuth -- aligned with blade 1 (deg) + real(ReKi) , intent(in ) :: output(:) ! array of requested outputs integer(IntKi) , intent(inout) :: errStat ! Status of error message character(*) , intent(inout) :: errMsg ! Error message if ErrStat /= ErrID_None ! Local variables. - character(200) :: frmt ! A string to hold a format specifier - character(15) :: tmpStr ! temporary string to print the time output as text - integer :: numOuts + character(ChanLen) :: tmpStr ! temporary string to print the time output as text errStat = ErrID_None errMsg = '' - numOuts = size(output,1) - frmt = '"'//OutFileData%delim//'"'//trim(OutFileData%outFmt) ! format for array elements from individual modules - + ! time - write( tmpStr, '(F15.4)' ) t - call WrFileNR( OutFileData%unOutFile, tmpStr ) - call WrNumAryFileNR ( OutFileData%unOutFile, output, frmt, errStat, errMsg ) - if ( errStat >= AbortErrLev ) return + write( tmpStr, OutFileData%Fmt_t ) CaseData%time(nt) ! '(F15.4)' + call WrFileNR( OutFileData%unOutFile, tmpStr(1:OutFileData%ActualChanLen) ) + call WrNumAryFileNR ( OutFileData%unOutFile, (/iCase/), OutFileData%Fmt_i, errStat, errMsg ) + call WrNumAryFileNR ( OutFileData%unOutFile, (/CaseData%WNDSPEED(nt), CaseData%SHEAREXP(nt), RotAzimuth, CaseData%Yaw(nt)*R2D/), OutFileData%Fmt_a, errStat, errMsg ) + call WrNumAryFileNR ( OutFileData%unOutFile, output, OutFileData%Fmt_a, errStat, errMsg ) + if ( errStat >= AbortErrLev ) return + ! write a new line (advance to the next line) write (OutFileData%unOutFile,'()') end subroutine Dvr_WriteOutputLine !---------------------------------------------------------------------------------------------------------------------------------- -subroutine Dvr_InitializeOutputFile( iCase, CaseData, OutFileData, errStat, errMsg) +subroutine Dvr_InitializeOutputFile(numBlades, iCase, CaseData, OutFileData, errStat, errMsg) !TODO:ADP -- how do we tell this routine that we are creating the summary file right now + integer(IntKi), intent(in ) :: numBlades ! driver data. neeeded for number of blades type(Dvr_OutputFile), intent(inout) :: OutFileData integer(IntKi) , intent(in ) :: iCase ! case number (to write in file description line and use for file name) @@ -625,7 +864,10 @@ subroutine Dvr_InitializeOutputFile( iCase, CaseData, OutFileData, errStat, errM ! locals integer(IntKi) :: i + integer(IntKi) :: numSpaces integer(IntKi) :: numOuts + character(ChanLen) :: colTxt + character(ChanLen) :: caseTxt @@ -635,35 +877,62 @@ subroutine Dvr_InitializeOutputFile( iCase, CaseData, OutFileData, errStat, errM return end if + numOuts = size(OutFileData%WriteOutputHdr) - call OpenFOutFile ( OutFileData%unOutFile, trim(outFileData%Root)//'.'//trim(num2lstr(iCase))//'.out', ErrStat, ErrMsg ) + ! compute the width of the column output + numSpaces = OutFileData%ActualChanLen ! the size of column produced by OutFmt + OutFileData%ActualChanLen = max( OutFileData%ActualChanLen, MinChanLen ) ! set this to at least MinChanLen , or the size of the column produced by OutFmt + do i=1,NumOuts + OutFileData%ActualChanLen = max(OutFileData%ActualChanLen, LEN_TRIM(OutFileData%WriteOutputHdr(i))) + OutFileData%ActualChanLen = max(OutFileData%ActualChanLen, LEN_TRIM(OutFileData%WriteOutputUnt(i))) + end do + + ! create format statements for time and the array outputs: + OutFileData%Fmt_t = '(F'//trim(num2lstr(OutFileData%ActualChanLen))//'.4)' + OutFileData%Fmt_i = '(I'//trim(num2lstr(OutFileData%ActualChanLen))//')' + OutFileData%Fmt_a = '"'//OutFileData%delim//'"'//trim(OutFileData%outFmt) ! format for array elements from individual modules + numSpaces = OutFileData%ActualChanLen - numSpaces ! the difference between the size of the headers and what is produced by OutFmt + if (numSpaces > 0) then + OutFileData%Fmt_a = trim(OutFileData%Fmt_a)//','//trim(num2lstr(numSpaces))//'x' + end if + + +! call OpenFOutFile ( OutFileData%unOutFile, trim(outFileData%Root)//'.'//trim(num2lstr(iCase))//'.out', ErrStat, ErrMsg ) + call OpenFOutFile ( OutFileData%unOutFile, trim(outFileData%Root)//'.out', ErrStat, ErrMsg ) if ( ErrStat >= AbortErrLev ) return write (OutFileData%unOutFile,'(/,A)') 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//trim( version%Name ) write (OutFileData%unOutFile,'(1X,A)') trim(GetNVD(OutFileData%AD_ver)) write (OutFileData%unOutFile,'()' ) !print a blank line - ! write (OutFileData%unOutFile,'(A,11(1x,A,"=",ES11.4e2,1x,A))' ) 'Case '//trim(num2lstr(iCase))//':' & - write (OutFileData%unOutFile,'(A,11(1x,A,"=",A,1x,A))' ) 'Case '//trim(num2lstr(iCase))//':' & - , 'WndSpeed', trim(num2lstr(CaseData%WndSpeed)), 'm/s;' & - , 'ShearExp', trim(num2lstr(CaseData%ShearExp)), ';' & - , 'RotSpeed', trim(num2lstr(CaseData%RotSpeed*RPS2RPM)),'rpm;' & - , 'Pitch', trim(num2lstr(CaseData%Pitch*R2D)), 'deg;' & - , 'Yaw', trim(num2lstr(CaseData%Yaw*R2D)), 'deg;' & - , 'dT', trim(num2lstr(CaseData%dT)), 's;' & - , 'Tmax', trim(num2lstr(CaseData%Tmax)),'s' + write (OutFileData%unOutFile,'()' ) !print a blank line write (OutFileData%unOutFile,'()' ) !print a blank line - numOuts = size(OutFileData%WriteOutputHdr) !...................................................... ! Write the names of the output parameters on one line: !...................................................... - call WrFileNR ( OutFileData%unOutFile, ' Time ' ) + colTxt = 'Time' + call WrFileNR ( OutFileData%unOutFile, colTxt(1:OutFileData%ActualChanLen)) + + colTxt = 'Case' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen)) + + colTxt = 'WindSpeed' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = 'ShearExp' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = 'RotAzimuth' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = 'Yaw' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) do i=1,NumOuts - call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//OutFileData%WriteOutputHdr(i) ) + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//OutFileData%WriteOutputHdr(i)(1:OutFileData%ActualChanLen) ) end do ! i write (OutFileData%unOutFile,'()') @@ -671,17 +940,30 @@ subroutine Dvr_InitializeOutputFile( iCase, CaseData, OutFileData, errStat, errM !...................................................... ! Write the units of the output parameters on one line: !...................................................... + colTxt = '(s)' + call WrFileNR ( OutFileData%unOutFile, colTxt(1:OutFileData%ActualChanLen)) + + colTxt = '(-)' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = '(m/s)' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = '(-)' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) - call WrFileNR ( OutFileData%unOutFile, ' (s) ' ) + colTxt = '(deg)' + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) + + colTxt = '(deg)' ! Yaw + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//colTxt(1:OutFileData%ActualChanLen) ) do i=1,NumOuts - call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//OutFileData%WriteOutputUnt(i) ) + call WrFileNR ( OutFileData%unOutFile, OutFileData%delim//OutFileData%WriteOutputUnt(i)(1:OutFileData%ActualChanLen) ) end do ! i - write (OutFileData%unOutFile,'()') - + write (OutFileData%unOutFile,'()') - end subroutine Dvr_InitializeOutputFile !---------------------------------------------------------------------------------------------------------------------------------- end module AeroDyn_Driver_Subs diff --git a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 index 6233a3ec5c..5d5a85517a 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 @@ -40,28 +40,35 @@ MODULE AeroDyn_Driver_Types USE AeroDyn_Types USE NWTC_Library IMPLICIT NONE - INTEGER(IntKi), PUBLIC, PARAMETER :: numInp = 2 ! Usually, order of interpolation for input-output extrap (not used in driver) [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: numInp = 2 ! Determines order of interpolation for input-output extrap (2=linear;3=quadratic) [-] ! ========= Dvr_Case ======= TYPE, PUBLIC :: Dvr_Case - REAL(ReKi) :: WndSpeed !< Wind Speed [m/s] - REAL(ReKi) :: ShearExp !< Power Law Wind-Shear Exponent [-] - REAL(ReKi) :: RotSpeed !< Rotor Speed [rad/s] - REAL(ReKi) :: Pitch !< Pitch angle [rad] - REAL(ReKi) :: Yaw !< Yaw angle [rad] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WndSpeed !< Wind Speed [m/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: ShearExp !< Power Law Wind-Shear Exponent [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RotSpeed !< Rotor Speed [rad/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Pitch angle [rad] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Yaw !< Yaw angle [rad] + REAL(DbKi) , DIMENSION(:), ALLOCATABLE :: time !< time increment [s] REAL(DbKi) :: dT !< time increment [s] - REAL(DbKi) :: Tmax !< length of this simulation [s] + INTEGER(IntKi) :: numSteps !< number of steps in this case [-] END TYPE Dvr_Case ! ======================= ! ========= Dvr_OutputFile ======= TYPE, PUBLIC :: Dvr_OutputFile TYPE(ProgDesc) :: AD_ver !< AeroDyn version information [-] INTEGER(IntKi) :: unOutFile !< unit number for writing output file [-] + INTEGER(IntKi) :: ActualChanLen !< Actual length of channels written to text file (less than or equal to ChanLen) [-] + character(20) :: Fmt_t !< Format specifier for time channel [-] + character(25) :: Fmt_a !< Format specifier for each column (including delimiter) [-] + character(20) :: Fmt_i !< Format specifier for integer column [-] character(1) :: delim !< column delimiter [-] character(20) :: outFmt !< Format specifier [-] character(1024) :: Root !< Output file rootname [-] character(1024) :: runTitle !< Description string from input file [-] character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Channel headers [-] character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Channel units [-] + LOGICAL :: AllFiles !< Output file for each case [-] + LOGICAL :: SumFile !< Output summary file for all cases with last timestep [-] END TYPE Dvr_OutputFile ! ======================= ! ========= AeroDyn_Data ======= @@ -107,13 +114,80 @@ SUBROUTINE AD_Dvr_CopyDvr_Case( SrcDvr_CaseData, DstDvr_CaseData, CtrlCode, ErrS ! ErrStat = ErrID_None ErrMsg = "" +IF (ALLOCATED(SrcDvr_CaseData%WndSpeed)) THEN + i1_l = LBOUND(SrcDvr_CaseData%WndSpeed,1) + i1_u = UBOUND(SrcDvr_CaseData%WndSpeed,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%WndSpeed)) THEN + ALLOCATE(DstDvr_CaseData%WndSpeed(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%WndSpeed.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstDvr_CaseData%WndSpeed = SrcDvr_CaseData%WndSpeed +ENDIF +IF (ALLOCATED(SrcDvr_CaseData%ShearExp)) THEN + i1_l = LBOUND(SrcDvr_CaseData%ShearExp,1) + i1_u = UBOUND(SrcDvr_CaseData%ShearExp,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%ShearExp)) THEN + ALLOCATE(DstDvr_CaseData%ShearExp(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%ShearExp.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstDvr_CaseData%ShearExp = SrcDvr_CaseData%ShearExp +ENDIF +IF (ALLOCATED(SrcDvr_CaseData%RotSpeed)) THEN + i1_l = LBOUND(SrcDvr_CaseData%RotSpeed,1) + i1_u = UBOUND(SrcDvr_CaseData%RotSpeed,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%RotSpeed)) THEN + ALLOCATE(DstDvr_CaseData%RotSpeed(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%RotSpeed.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstDvr_CaseData%RotSpeed = SrcDvr_CaseData%RotSpeed +ENDIF +IF (ALLOCATED(SrcDvr_CaseData%Pitch)) THEN + i1_l = LBOUND(SrcDvr_CaseData%Pitch,1) + i1_u = UBOUND(SrcDvr_CaseData%Pitch,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%Pitch)) THEN + ALLOCATE(DstDvr_CaseData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstDvr_CaseData%Pitch = SrcDvr_CaseData%Pitch +ENDIF +IF (ALLOCATED(SrcDvr_CaseData%Yaw)) THEN + i1_l = LBOUND(SrcDvr_CaseData%Yaw,1) + i1_u = UBOUND(SrcDvr_CaseData%Yaw,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%Yaw)) THEN + ALLOCATE(DstDvr_CaseData%Yaw(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%Yaw.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstDvr_CaseData%Yaw = SrcDvr_CaseData%Yaw +ENDIF +IF (ALLOCATED(SrcDvr_CaseData%time)) THEN + i1_l = LBOUND(SrcDvr_CaseData%time,1) + i1_u = UBOUND(SrcDvr_CaseData%time,1) + IF (.NOT. ALLOCATED(DstDvr_CaseData%time)) THEN + ALLOCATE(DstDvr_CaseData%time(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstDvr_CaseData%time.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstDvr_CaseData%time = SrcDvr_CaseData%time +ENDIF DstDvr_CaseData%dT = SrcDvr_CaseData%dT - DstDvr_CaseData%Tmax = SrcDvr_CaseData%Tmax + DstDvr_CaseData%numSteps = SrcDvr_CaseData%numSteps END SUBROUTINE AD_Dvr_CopyDvr_Case SUBROUTINE AD_Dvr_DestroyDvr_Case( Dvr_CaseData, ErrStat, ErrMsg ) @@ -125,6 +199,24 @@ SUBROUTINE AD_Dvr_DestroyDvr_Case( Dvr_CaseData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" +IF (ALLOCATED(Dvr_CaseData%WndSpeed)) THEN + DEALLOCATE(Dvr_CaseData%WndSpeed) +ENDIF +IF (ALLOCATED(Dvr_CaseData%ShearExp)) THEN + DEALLOCATE(Dvr_CaseData%ShearExp) +ENDIF +IF (ALLOCATED(Dvr_CaseData%RotSpeed)) THEN + DEALLOCATE(Dvr_CaseData%RotSpeed) +ENDIF +IF (ALLOCATED(Dvr_CaseData%Pitch)) THEN + DEALLOCATE(Dvr_CaseData%Pitch) +ENDIF +IF (ALLOCATED(Dvr_CaseData%Yaw)) THEN + DEALLOCATE(Dvr_CaseData%Yaw) +ENDIF +IF (ALLOCATED(Dvr_CaseData%time)) THEN + DEALLOCATE(Dvr_CaseData%time) +ENDIF END SUBROUTINE AD_Dvr_DestroyDvr_Case SUBROUTINE AD_Dvr_PackDvr_Case( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -162,13 +254,38 @@ SUBROUTINE AD_Dvr_PackDvr_Case( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! WndSpeed - Re_BufSz = Re_BufSz + 1 ! ShearExp - Re_BufSz = Re_BufSz + 1 ! RotSpeed - Re_BufSz = Re_BufSz + 1 ! Pitch - Re_BufSz = Re_BufSz + 1 ! Yaw + Int_BufSz = Int_BufSz + 1 ! WndSpeed allocated yes/no + IF ( ALLOCATED(InData%WndSpeed) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WndSpeed upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WndSpeed) ! WndSpeed + END IF + Int_BufSz = Int_BufSz + 1 ! ShearExp allocated yes/no + IF ( ALLOCATED(InData%ShearExp) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! ShearExp upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%ShearExp) ! ShearExp + END IF + Int_BufSz = Int_BufSz + 1 ! RotSpeed allocated yes/no + IF ( ALLOCATED(InData%RotSpeed) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! RotSpeed upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%RotSpeed) ! RotSpeed + END IF + Int_BufSz = Int_BufSz + 1 ! Pitch allocated yes/no + IF ( ALLOCATED(InData%Pitch) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Pitch upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Pitch) ! Pitch + END IF + Int_BufSz = Int_BufSz + 1 ! Yaw allocated yes/no + IF ( ALLOCATED(InData%Yaw) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Yaw upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Yaw) ! Yaw + END IF + Int_BufSz = Int_BufSz + 1 ! time allocated yes/no + IF ( ALLOCATED(InData%time) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! time upper/lower bounds for each dimension + Db_BufSz = Db_BufSz + SIZE(InData%time) ! time + END IF Db_BufSz = Db_BufSz + 1 ! dT - Db_BufSz = Db_BufSz + 1 ! Tmax + Int_BufSz = Int_BufSz + 1 ! numSteps IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -196,20 +313,100 @@ SUBROUTINE AD_Dvr_PackDvr_Case( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%WndSpeed - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%ShearExp - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%RotSpeed - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%Pitch - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%Yaw - Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%WndSpeed) ) 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%WndSpeed,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WndSpeed,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WndSpeed,1), UBOUND(InData%WndSpeed,1) + ReKiBuf(Re_Xferred) = InData%WndSpeed(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%ShearExp) ) 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%ShearExp,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%ShearExp,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%ShearExp,1), UBOUND(InData%ShearExp,1) + ReKiBuf(Re_Xferred) = InData%ShearExp(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%RotSpeed) ) 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%RotSpeed,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RotSpeed,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%RotSpeed,1), UBOUND(InData%RotSpeed,1) + ReKiBuf(Re_Xferred) = InData%RotSpeed(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Pitch) ) 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%Pitch,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Pitch,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Pitch,1), UBOUND(InData%Pitch,1) + ReKiBuf(Re_Xferred) = InData%Pitch(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Yaw) ) 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%Yaw,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Yaw,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Yaw,1), UBOUND(InData%Yaw,1) + ReKiBuf(Re_Xferred) = InData%Yaw(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%time) ) 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%time,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%time,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%time,1), UBOUND(InData%time,1) + DbKiBuf(Db_Xferred) = InData%time(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END IF DbKiBuf(Db_Xferred) = InData%dT Db_Xferred = Db_Xferred + 1 - DbKiBuf(Db_Xferred) = InData%Tmax - Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%numSteps + Int_Xferred = Int_Xferred + 1 END SUBROUTINE AD_Dvr_PackDvr_Case SUBROUTINE AD_Dvr_UnPackDvr_Case( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -239,20 +436,118 @@ SUBROUTINE AD_Dvr_UnPackDvr_Case( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%WndSpeed = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%ShearExp = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%RotSpeed = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%Pitch = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%Yaw = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WndSpeed 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%WndSpeed)) DEALLOCATE(OutData%WndSpeed) + ALLOCATE(OutData%WndSpeed(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WndSpeed.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WndSpeed,1), UBOUND(OutData%WndSpeed,1) + OutData%WndSpeed(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! ShearExp 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%ShearExp)) DEALLOCATE(OutData%ShearExp) + ALLOCATE(OutData%ShearExp(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%ShearExp.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%ShearExp,1), UBOUND(OutData%ShearExp,1) + OutData%ShearExp(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RotSpeed 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%RotSpeed)) DEALLOCATE(OutData%RotSpeed) + ALLOCATE(OutData%RotSpeed(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RotSpeed.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%RotSpeed,1), UBOUND(OutData%RotSpeed,1) + OutData%RotSpeed(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Pitch 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%Pitch)) DEALLOCATE(OutData%Pitch) + ALLOCATE(OutData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Pitch,1), UBOUND(OutData%Pitch,1) + OutData%Pitch(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Yaw 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%Yaw)) DEALLOCATE(OutData%Yaw) + ALLOCATE(OutData%Yaw(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Yaw.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Yaw,1), UBOUND(OutData%Yaw,1) + OutData%Yaw(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! time 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%time)) DEALLOCATE(OutData%time) + ALLOCATE(OutData%time(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%time.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%time,1), UBOUND(OutData%time,1) + OutData%time(i1) = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + END DO + END IF OutData%dT = DbKiBuf(Db_Xferred) Db_Xferred = Db_Xferred + 1 - OutData%Tmax = DbKiBuf(Db_Xferred) - Db_Xferred = Db_Xferred + 1 + OutData%numSteps = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE AD_Dvr_UnPackDvr_Case SUBROUTINE AD_Dvr_CopyDvr_OutputFile( SrcDvr_OutputFileData, DstDvr_OutputFileData, CtrlCode, ErrStat, ErrMsg ) @@ -274,6 +569,10 @@ SUBROUTINE AD_Dvr_CopyDvr_OutputFile( SrcDvr_OutputFileData, DstDvr_OutputFileDa CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN DstDvr_OutputFileData%unOutFile = SrcDvr_OutputFileData%unOutFile + DstDvr_OutputFileData%ActualChanLen = SrcDvr_OutputFileData%ActualChanLen + DstDvr_OutputFileData%Fmt_t = SrcDvr_OutputFileData%Fmt_t + DstDvr_OutputFileData%Fmt_a = SrcDvr_OutputFileData%Fmt_a + DstDvr_OutputFileData%Fmt_i = SrcDvr_OutputFileData%Fmt_i DstDvr_OutputFileData%delim = SrcDvr_OutputFileData%delim DstDvr_OutputFileData%outFmt = SrcDvr_OutputFileData%outFmt DstDvr_OutputFileData%Root = SrcDvr_OutputFileData%Root @@ -302,6 +601,8 @@ SUBROUTINE AD_Dvr_CopyDvr_OutputFile( SrcDvr_OutputFileData, DstDvr_OutputFileDa END IF DstDvr_OutputFileData%WriteOutputUnt = SrcDvr_OutputFileData%WriteOutputUnt ENDIF + DstDvr_OutputFileData%AllFiles = SrcDvr_OutputFileData%AllFiles + DstDvr_OutputFileData%SumFile = SrcDvr_OutputFileData%SumFile END SUBROUTINE AD_Dvr_CopyDvr_OutputFile SUBROUTINE AD_Dvr_DestroyDvr_OutputFile( Dvr_OutputFileData, ErrStat, ErrMsg ) @@ -376,6 +677,10 @@ SUBROUTINE AD_Dvr_PackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSta DEALLOCATE(Int_Buf) END IF Int_BufSz = Int_BufSz + 1 ! unOutFile + Int_BufSz = Int_BufSz + 1 ! ActualChanLen + Int_BufSz = Int_BufSz + 1*LEN(InData%Fmt_t) ! Fmt_t + Int_BufSz = Int_BufSz + 1*LEN(InData%Fmt_a) ! Fmt_a + Int_BufSz = Int_BufSz + 1*LEN(InData%Fmt_i) ! Fmt_i Int_BufSz = Int_BufSz + 1*LEN(InData%delim) ! delim Int_BufSz = Int_BufSz + 1*LEN(InData%outFmt) ! outFmt Int_BufSz = Int_BufSz + 1*LEN(InData%Root) ! Root @@ -390,6 +695,8 @@ SUBROUTINE AD_Dvr_PackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSta Int_BufSz = Int_BufSz + 2*1 ! WriteOutputUnt upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputUnt)*LEN(InData%WriteOutputUnt) ! WriteOutputUnt END IF + Int_BufSz = Int_BufSz + 1 ! AllFiles + Int_BufSz = Int_BufSz + 1 ! SumFile IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -447,6 +754,20 @@ SUBROUTINE AD_Dvr_PackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSta ENDIF IntKiBuf(Int_Xferred) = InData%unOutFile Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%ActualChanLen + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(InData%Fmt_t) + IntKiBuf(Int_Xferred) = ICHAR(InData%Fmt_t(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%Fmt_a) + IntKiBuf(Int_Xferred) = ICHAR(InData%Fmt_a(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%Fmt_i) + IntKiBuf(Int_Xferred) = ICHAR(InData%Fmt_i(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I DO I = 1, LEN(InData%delim) IntKiBuf(Int_Xferred) = ICHAR(InData%delim(I:I), IntKi) Int_Xferred = Int_Xferred + 1 @@ -497,6 +818,10 @@ SUBROUTINE AD_Dvr_PackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSta END DO ! I END DO END IF + IntKiBuf(Int_Xferred) = TRANSFER(InData%AllFiles, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%SumFile, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE AD_Dvr_PackDvr_OutputFile SUBROUTINE AD_Dvr_UnPackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -568,6 +893,20 @@ SUBROUTINE AD_Dvr_UnPackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, Err IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) OutData%unOutFile = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%ActualChanLen = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(OutData%Fmt_t) + OutData%Fmt_t(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%Fmt_a) + OutData%Fmt_a(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%Fmt_i) + OutData%Fmt_i(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I DO I = 1, LEN(OutData%delim) OutData%delim(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 @@ -624,6 +963,10 @@ SUBROUTINE AD_Dvr_UnPackDvr_OutputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, Err END DO ! I END DO END IF + OutData%AllFiles = TRANSFER(IntKiBuf(Int_Xferred), OutData%AllFiles) + Int_Xferred = Int_Xferred + 1 + OutData%SumFile = TRANSFER(IntKiBuf(Int_Xferred), OutData%SumFile) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE AD_Dvr_UnPackDvr_OutputFile SUBROUTINE AD_Dvr_CopyAeroDyn_Data( SrcAeroDyn_DataData, DstAeroDyn_DataData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index f6115fa23c..90465ed21e 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -36,10 +36,10 @@ MODULE AeroDyn_IO ! =================================================================================================== ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" -! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these -! lines should be modified in the Matlab script and/or Excel worksheet as necessary. +! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these +! lines should be modified in the Matlab script and/or Excel worksheet as necessary. ! =================================================================================================== -! This code was generated by Write_ChckOutLst.m at 05-May-2020 06:44:07. +! This code was generated by Write_ChckOutLst.m at 31-Aug-2020 13:14:21. ! Parameters related to output length (number of characters allowed in the output data headers): @@ -48,11 +48,11 @@ MODULE AeroDyn_IO ! Indices for computing output channels: - ! NOTES: + ! NOTES: ! (1) These parameters are in the order stored in "OutListParameters.xlsx" ! (2) Array AllOuts() must be dimensioned to the value of the largest output parameter - ! Time: + ! Time: INTEGER(IntKi), PARAMETER :: Time = 0 @@ -1278,10 +1278,11 @@ MODULE AeroDyn_IO INTEGER(IntKi), PARAMETER :: RtAeroCp = 1209 INTEGER(IntKi), PARAMETER :: RtAeroCq = 1210 INTEGER(IntKi), PARAMETER :: RtAeroCt = 1211 + INTEGER(IntKi), PARAMETER :: DBEMTau1 = 1212 ! The maximum number of output channels which can be output by the code. - INTEGER(IntKi), PARAMETER :: MaxOutPts = 1211 + INTEGER(IntKi), PARAMETER :: MaxOutPts = 1212 !End of code generated by Matlab script ! =================================================================================================== @@ -1634,24 +1635,22 @@ SUBROUTINE Calc_WriteOutput( p, u, m, y, OtherState, xd, indx, ErrStat, ErrMsg ) call Calc_WriteOutput_FVW endif - ! blade node tower clearance (requires tower influence calculation): if (p%TwrPotent /= TwrPotent_none .or. p%TwrShadow) then - do k=1,p%numBlades - do beta=1,p%NBlOuts + 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 - + end do + end if - !m%AllOuts( DBEMTau1 ) = OtherState%BEMT%DBEMT%tau1 CONTAINS + !.......................................................................................... subroutine Calc_WriteOutput_BEMT ! blade outputs do k=1,p%numBlades - m%AllOuts( BAzimuth(k) ) = m%BEMT_u(indx)%psi(k)*R2D + 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 @@ -1759,6 +1758,7 @@ subroutine Calc_WriteOutput_BEMT 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 @@ -1773,8 +1773,12 @@ subroutine Calc_WriteOutput_BEMT m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom end if + + m%AllOuts( DBEMTau1 ) = OtherState%BEMT%DBEMT%tau1 + end subroutine Calc_WriteOutput_BEMT + !.......................................................................................... !> Similar to Calc_WriteOutput_BEMT. TODO Merge me !! NOTE: relies on the prior calculation of m%V_dot_x, and m%V_diskAvg (done in DiskAvgValues) !! m%DisturbedInflow (done in SetInputs) @@ -2311,8 +2315,8 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE CALL ReadVar( UnIn, InputFile, InputFileData%FLookup, "FLookup", "Flag to indicate whether a lookup for f' will be calculated (TRUE) or whether best-fit exponential equations will be used (FALSE); if FALSE S1-S4 must be provided in airfoil input files [used only when AFAreoMod=2] (flag)", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! UACutout - Angle-of-attach beyond which unsteady aerodynamics are disabled (deg) -! CALL ReadVar( UnIn, InputFile, InputFileData%UACutout, "FLookup", "Angle-of-attach beyond which unsteady aerodynamics are disabled (deg)", ErrStat2, ErrMsg2, UnEc) + ! UACutout - Angle-of-attack beyond which unsteady aerodynamics are disabled (deg) +! CALL ReadVar( UnIn, InputFile, InputFileData%UACutout, "UACutout", "Angle-of-attack beyond which unsteady aerodynamics are disabled (deg)", ErrStat2, ErrMsg2, UnEc) ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! Return on error at end of section @@ -2397,7 +2401,7 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE ! IF ( ErrStat >= AbortErrLev ) RETURN ! ADBlFile - Names of files containing distributed aerodynamic properties for each blade (see AD_BladeInputFile type): - DO I = 1,MaxBl + DO I = 1,size(ADBlFile) CALL ReadVar ( UnIn, InputFile, ADBlFile(I), 'ADBlFile('//TRIM(Num2Lstr(I))//')', 'Name of file containing distributed aerodynamic properties for blade '//TRIM(Num2Lstr(I)), ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( PathIsRelative( ADBlFile(I) ) ) ADBlFile(I) = TRIM(PriPath)//TRIM(ADBlFile(I)) @@ -2826,7 +2830,7 @@ SUBROUTINE AD_PrintSum( InputFileData, p, u, y, ErrStat, ErrMsg ) WRITE (UnSu,Ec_LgFrmt) p%TwrAero, 'TwrAero', 'Calculate tower aerodynamic loads? '//TRIM(Msg) - if (p%WakeMod==WakeMod_BEMT .or. p%WakeMod==WakeMod_DBEMT) then + if (p%WakeMod/=WakeMod_none) then WRITE (UnSu,'(A)') '====== Blade-Element/Momentum Theory Options ======================================================' ! SkewMod @@ -2890,15 +2894,18 @@ SUBROUTINE AD_PrintSum( InputFileData, p, u, y, ErrStat, ErrMsg ) ! MaxIter - if (p%WakeMod==WakeMod_DBEMT) then + if (p%WakeMod == WakeMod_DBEMT) then select case (InputFileData%DBEMT_Mod) case (DBEMT_tauConst) Msg = 'constant tau1' case (DBEMT_tauVaries) Msg = 'time-dependent tau1' - case default - Msg = 'unknown' + case (DBEMT_cont_tauConst) + Msg = 'continuous formulation with constant tau1' + case default + Msg = 'unknown' end select + WRITE (UnSu,Ec_IntFrmt) InputFileData%DBEMT_Mod, 'DBEMT_Mod', 'Type of dynamic BEMT (DBEMT) model: '//TRIM(Msg) if (InputFileData%DBEMT_Mod==DBEMT_tauConst) & @@ -2947,7 +2954,7 @@ SUBROUTINE AD_PrintSum( InputFileData, p, u, y, ErrStat, ErrMsg ) WRITE (UnSu,"(15x,A)") 'Blade nodes selected for output: Output node Analysis node' WRITE (UnSu,"(15x,A)") ' ----------- -------------' - DO I = 1,size(p%BlOutNd) + DO I = 1,p%NBlOuts WRITE (UnSu,OutPFmt) I, p%BlOutNd(I) END DO end if @@ -2965,8 +2972,8 @@ SUBROUTINE AD_PrintSum( InputFileData, p, u, y, ErrStat, ErrMsg ) OutPFmt = '( 15x, I4, 2X, A '//TRIM(Num2LStr(ChanLen))//',1 X, A'//TRIM(Num2LStr(ChanLen))//' )' WRITE (UnSu,'(15x,A)') 'Requested Output Channels:' - WRITE (UnSu,'(15x,A)') 'Col Parameter Units' - WRITE (UnSu,'(15x,A)') '---- --------- -----' + WRITE (UnSu,'(15x,A)') 'Col Parameter Units' + WRITE (UnSu,'(15x,A)') '---- -------------- -----' DO I = 0,p%NumOuts WRITE (UnSu,OutPFmt) I, p%OutParam(I)%Name, p%OutParam(I)%Units @@ -2999,7 +3006,7 @@ END SUBROUTINE AD_PrintSum !! the sign is set to 0 if the channel is invalid. !! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here. !! -!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 05-May-2020 06:44:07. +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 31-Aug-2020 13:14:21. SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) !.................................................................................................................................. @@ -3024,528 +3031,465 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) CHARACTER(ChanLen) :: OutListTmp ! A string to temporarily hold OutList(I) CHARACTER(*), PARAMETER :: RoutineName = "SetOutParam" - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1211) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically - "B1AZIMUTH","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC","B1N1CM ", & - "B1N1CN ","B1N1CPMIN","B1N1CT ","B1N1CURVE","B1N1CX ","B1N1CY ","B1N1DYNP ", & - "B1N1FD ","B1N1FL ","B1N1FN ","B1N1FT ","B1N1FX ","B1N1FY ","B1N1GAM ", & - "B1N1M ","B1N1MM ","B1N1PHI ","B1N1RE ","B1N1SGCAV","B1N1SIGCR","B1N1STVX ", & - "B1N1STVY ","B1N1STVZ ","B1N1THETA","B1N1TNIND","B1N1VDISX","B1N1VDISY","B1N1VDISZ", & - "B1N1VINDX","B1N1VINDY","B1N1VREL ","B1N1VUNDX","B1N1VUNDY","B1N1VUNDZ","B1N2ALPHA", & - "B1N2AXIND","B1N2CD ","B1N2CL ","B1N2CLRNC","B1N2CM ","B1N2CN ","B1N2CPMIN", & - "B1N2CT ","B1N2CURVE","B1N2CX ","B1N2CY ","B1N2DYNP ","B1N2FD ","B1N2FL ", & - "B1N2FN ","B1N2FT ","B1N2FX ","B1N2FY ","B1N2GAM ","B1N2M ","B1N2MM ", & - "B1N2PHI ","B1N2RE ","B1N2SGCAV","B1N2SIGCR","B1N2STVX ","B1N2STVY ","B1N2STVZ ", & - "B1N2THETA","B1N2TNIND","B1N2VDISX","B1N2VDISY","B1N2VDISZ","B1N2VINDX","B1N2VINDY", & - "B1N2VREL ","B1N2VUNDX","B1N2VUNDY","B1N2VUNDZ","B1N3ALPHA","B1N3AXIND","B1N3CD ", & - "B1N3CL ","B1N3CLRNC","B1N3CM ","B1N3CN ","B1N3CPMIN","B1N3CT ","B1N3CURVE", & - "B1N3CX ","B1N3CY ","B1N3DYNP ","B1N3FD ","B1N3FL ","B1N3FN ","B1N3FT ", & - "B1N3FX ","B1N3FY ","B1N3GAM ","B1N3M ","B1N3MM ","B1N3PHI ","B1N3RE ", & - "B1N3SGCAV","B1N3SIGCR","B1N3STVX ","B1N3STVY ","B1N3STVZ ","B1N3THETA","B1N3TNIND", & - "B1N3VDISX","B1N3VDISY","B1N3VDISZ","B1N3VINDX","B1N3VINDY","B1N3VREL ","B1N3VUNDX", & - "B1N3VUNDY","B1N3VUNDZ","B1N4ALPHA","B1N4AXIND","B1N4CD ","B1N4CL ","B1N4CLRNC", & - "B1N4CM ","B1N4CN ","B1N4CPMIN","B1N4CT ","B1N4CURVE","B1N4CX ","B1N4CY ", & - "B1N4DYNP ","B1N4FD ","B1N4FL ","B1N4FN ","B1N4FT ","B1N4FX ","B1N4FY ", & - "B1N4GAM ","B1N4M ","B1N4MM ","B1N4PHI ","B1N4RE ","B1N4SGCAV","B1N4SIGCR", & - "B1N4STVX ","B1N4STVY ","B1N4STVZ ","B1N4THETA","B1N4TNIND","B1N4VDISX","B1N4VDISY", & - "B1N4VDISZ","B1N4VINDX","B1N4VINDY","B1N4VREL ","B1N4VUNDX","B1N4VUNDY","B1N4VUNDZ", & - "B1N5ALPHA","B1N5AXIND","B1N5CD ","B1N5CL ","B1N5CLRNC","B1N5CM ","B1N5CN ", & - "B1N5CPMIN","B1N5CT ","B1N5CURVE","B1N5CX ","B1N5CY ","B1N5DYNP ","B1N5FD ", & - "B1N5FL ","B1N5FN ","B1N5FT ","B1N5FX ","B1N5FY ","B1N5GAM ","B1N5M ", & - "B1N5MM ","B1N5PHI ","B1N5RE ","B1N5SGCAV","B1N5SIGCR","B1N5STVX ","B1N5STVY ", & - "B1N5STVZ ","B1N5THETA","B1N5TNIND","B1N5VDISX","B1N5VDISY","B1N5VDISZ","B1N5VINDX", & - "B1N5VINDY","B1N5VREL ","B1N5VUNDX","B1N5VUNDY","B1N5VUNDZ","B1N6ALPHA","B1N6AXIND", & - "B1N6CD ","B1N6CL ","B1N6CLRNC","B1N6CM ","B1N6CN ","B1N6CPMIN","B1N6CT ", & - "B1N6CURVE","B1N6CX ","B1N6CY ","B1N6DYNP ","B1N6FD ","B1N6FL ","B1N6FN ", & - "B1N6FT ","B1N6FX ","B1N6FY ","B1N6GAM ","B1N6M ","B1N6MM ","B1N6PHI ", & - "B1N6RE ","B1N6SGCAV","B1N6SIGCR","B1N6STVX ","B1N6STVY ","B1N6STVZ ","B1N6THETA", & - "B1N6TNIND","B1N6VDISX","B1N6VDISY","B1N6VDISZ","B1N6VINDX","B1N6VINDY","B1N6VREL ", & - "B1N6VUNDX","B1N6VUNDY","B1N6VUNDZ","B1N7ALPHA","B1N7AXIND","B1N7CD ","B1N7CL ", & - "B1N7CLRNC","B1N7CM ","B1N7CN ","B1N7CPMIN","B1N7CT ","B1N7CURVE","B1N7CX ", & - "B1N7CY ","B1N7DYNP ","B1N7FD ","B1N7FL ","B1N7FN ","B1N7FT ","B1N7FX ", & - "B1N7FY ","B1N7GAM ","B1N7M ","B1N7MM ","B1N7PHI ","B1N7RE ","B1N7SGCAV", & - "B1N7SIGCR","B1N7STVX ","B1N7STVY ","B1N7STVZ ","B1N7THETA","B1N7TNIND","B1N7VDISX", & - "B1N7VDISY","B1N7VDISZ","B1N7VINDX","B1N7VINDY","B1N7VREL ","B1N7VUNDX","B1N7VUNDY", & - "B1N7VUNDZ","B1N8ALPHA","B1N8AXIND","B1N8CD ","B1N8CL ","B1N8CLRNC","B1N8CM ", & - "B1N8CN ","B1N8CPMIN","B1N8CT ","B1N8CURVE","B1N8CX ","B1N8CY ","B1N8DYNP ", & - "B1N8FD ","B1N8FL ","B1N8FN ","B1N8FT ","B1N8FX ","B1N8FY ","B1N8GAM ", & - "B1N8M ","B1N8MM ","B1N8PHI ","B1N8RE ","B1N8SGCAV","B1N8SIGCR","B1N8STVX ", & - "B1N8STVY ","B1N8STVZ ","B1N8THETA","B1N8TNIND","B1N8VDISX","B1N8VDISY","B1N8VDISZ", & - "B1N8VINDX","B1N8VINDY","B1N8VREL ","B1N8VUNDX","B1N8VUNDY","B1N8VUNDZ","B1N9ALPHA", & - "B1N9AXIND","B1N9CD ","B1N9CL ","B1N9CLRNC","B1N9CM ","B1N9CN ","B1N9CPMIN", & - "B1N9CT ","B1N9CURVE","B1N9CX ","B1N9CY ","B1N9DYNP ","B1N9FD ","B1N9FL ", & - "B1N9FN ","B1N9FT ","B1N9FX ","B1N9FY ","B1N9GAM ","B1N9M ","B1N9MM ", & - "B1N9PHI ","B1N9RE ","B1N9SGCAV","B1N9SIGCR","B1N9STVX ","B1N9STVY ","B1N9STVZ ", & - "B1N9THETA","B1N9TNIND","B1N9VDISX","B1N9VDISY","B1N9VDISZ","B1N9VINDX","B1N9VINDY", & - "B1N9VREL ","B1N9VUNDX","B1N9VUNDY","B1N9VUNDZ","B1PITCH ","B2AZIMUTH","B2N1ALPHA", & - "B2N1AXIND","B2N1CD ","B2N1CL ","B2N1CLRNC","B2N1CM ","B2N1CN ","B2N1CPMIN", & - "B2N1CT ","B2N1CURVE","B2N1CX ","B2N1CY ","B2N1DYNP ","B2N1FD ","B2N1FL ", & - "B2N1FN ","B2N1FT ","B2N1FX ","B2N1FY ","B2N1GAM ","B2N1M ","B2N1MM ", & - "B2N1PHI ","B2N1RE ","B2N1SGCAV","B2N1SIGCR","B2N1STVX ","B2N1STVY ","B2N1STVZ ", & - "B2N1THETA","B2N1TNIND","B2N1VDISX","B2N1VDISY","B2N1VDISZ","B2N1VINDX","B2N1VINDY", & - "B2N1VREL ","B2N1VUNDX","B2N1VUNDY","B2N1VUNDZ","B2N2ALPHA","B2N2AXIND","B2N2CD ", & - "B2N2CL ","B2N2CLRNC","B2N2CM ","B2N2CN ","B2N2CPMIN","B2N2CT ","B2N2CURVE", & - "B2N2CX ","B2N2CY ","B2N2DYNP ","B2N2FD ","B2N2FL ","B2N2FN ","B2N2FT ", & - "B2N2FX ","B2N2FY ","B2N2GAM ","B2N2M ","B2N2MM ","B2N2PHI ","B2N2RE ", & - "B2N2SGCAV","B2N2SIGCR","B2N2STVX ","B2N2STVY ","B2N2STVZ ","B2N2THETA","B2N2TNIND", & - "B2N2VDISX","B2N2VDISY","B2N2VDISZ","B2N2VINDX","B2N2VINDY","B2N2VREL ","B2N2VUNDX", & - "B2N2VUNDY","B2N2VUNDZ","B2N3ALPHA","B2N3AXIND","B2N3CD ","B2N3CL ","B2N3CLRNC", & - "B2N3CM ","B2N3CN ","B2N3CPMIN","B2N3CT ","B2N3CURVE","B2N3CX ","B2N3CY ", & - "B2N3DYNP ","B2N3FD ","B2N3FL ","B2N3FN ","B2N3FT ","B2N3FX ","B2N3FY ", & - "B2N3GAM ","B2N3M ","B2N3MM ","B2N3PHI ","B2N3RE ","B2N3SGCAV","B2N3SIGCR", & - "B2N3STVX ","B2N3STVY ","B2N3STVZ ","B2N3THETA","B2N3TNIND","B2N3VDISX","B2N3VDISY", & - "B2N3VDISZ","B2N3VINDX","B2N3VINDY","B2N3VREL ","B2N3VUNDX","B2N3VUNDY","B2N3VUNDZ", & - "B2N4ALPHA","B2N4AXIND","B2N4CD ","B2N4CL ","B2N4CLRNC","B2N4CM ","B2N4CN ", & - "B2N4CPMIN","B2N4CT ","B2N4CURVE","B2N4CX ","B2N4CY ","B2N4DYNP ","B2N4FD ", & - "B2N4FL ","B2N4FN ","B2N4FT ","B2N4FX ","B2N4FY ","B2N4GAM ","B2N4M ", & - "B2N4MM ","B2N4PHI ","B2N4RE ","B2N4SGCAV","B2N4SIGCR","B2N4STVX ","B2N4STVY ", & - "B2N4STVZ ","B2N4THETA","B2N4TNIND","B2N4VDISX","B2N4VDISY","B2N4VDISZ","B2N4VINDX", & - "B2N4VINDY","B2N4VREL ","B2N4VUNDX","B2N4VUNDY","B2N4VUNDZ","B2N5ALPHA","B2N5AXIND", & - "B2N5CD ","B2N5CL ","B2N5CLRNC","B2N5CM ","B2N5CN ","B2N5CPMIN","B2N5CT ", & - "B2N5CURVE","B2N5CX ","B2N5CY ","B2N5DYNP ","B2N5FD ","B2N5FL ","B2N5FN ", & - "B2N5FT ","B2N5FX ","B2N5FY ","B2N5GAM ","B2N5M ","B2N5MM ","B2N5PHI ", & - "B2N5RE ","B2N5SGCAV","B2N5SIGCR","B2N5STVX ","B2N5STVY ","B2N5STVZ ","B2N5THETA", & - "B2N5TNIND","B2N5VDISX","B2N5VDISY","B2N5VDISZ","B2N5VINDX","B2N5VINDY","B2N5VREL ", & - "B2N5VUNDX","B2N5VUNDY","B2N5VUNDZ","B2N6ALPHA","B2N6AXIND","B2N6CD ","B2N6CL ", & - "B2N6CLRNC","B2N6CM ","B2N6CN ","B2N6CPMIN","B2N6CT ","B2N6CURVE","B2N6CX ", & - "B2N6CY ","B2N6DYNP ","B2N6FD ","B2N6FL ","B2N6FN ","B2N6FT ","B2N6FX ", & - "B2N6FY ","B2N6GAM ","B2N6M ","B2N6MM ","B2N6PHI ","B2N6RE ","B2N6SGCAV", & - "B2N6SIGCR","B2N6STVX ","B2N6STVY ","B2N6STVZ ","B2N6THETA","B2N6TNIND","B2N6VDISX", & - "B2N6VDISY","B2N6VDISZ","B2N6VINDX","B2N6VINDY","B2N6VREL ","B2N6VUNDX","B2N6VUNDY", & - "B2N6VUNDZ","B2N7ALPHA","B2N7AXIND","B2N7CD ","B2N7CL ","B2N7CLRNC","B2N7CM ", & - "B2N7CN ","B2N7CPMIN","B2N7CT ","B2N7CURVE","B2N7CX ","B2N7CY ","B2N7DYNP ", & - "B2N7FD ","B2N7FL ","B2N7FN ","B2N7FT ","B2N7FX ","B2N7FY ","B2N7GAM ", & - "B2N7M ","B2N7MM ","B2N7PHI ","B2N7RE ","B2N7SGCAV","B2N7SIGCR","B2N7STVX ", & - "B2N7STVY ","B2N7STVZ ","B2N7THETA","B2N7TNIND","B2N7VDISX","B2N7VDISY","B2N7VDISZ", & - "B2N7VINDX","B2N7VINDY","B2N7VREL ","B2N7VUNDX","B2N7VUNDY","B2N7VUNDZ","B2N8ALPHA", & - "B2N8AXIND","B2N8CD ","B2N8CL ","B2N8CLRNC","B2N8CM ","B2N8CN ","B2N8CPMIN", & - "B2N8CT ","B2N8CURVE","B2N8CX ","B2N8CY ","B2N8DYNP ","B2N8FD ","B2N8FL ", & - "B2N8FN ","B2N8FT ","B2N8FX ","B2N8FY ","B2N8GAM ","B2N8M ","B2N8MM ", & - "B2N8PHI ","B2N8RE ","B2N8SGCAV","B2N8SIGCR","B2N8STVX ","B2N8STVY ","B2N8STVZ ", & - "B2N8THETA","B2N8TNIND","B2N8VDISX","B2N8VDISY","B2N8VDISZ","B2N8VINDX","B2N8VINDY", & - "B2N8VREL ","B2N8VUNDX","B2N8VUNDY","B2N8VUNDZ","B2N9ALPHA","B2N9AXIND","B2N9CD ", & - "B2N9CL ","B2N9CLRNC","B2N9CM ","B2N9CN ","B2N9CPMIN","B2N9CT ","B2N9CURVE", & - "B2N9CX ","B2N9CY ","B2N9DYNP ","B2N9FD ","B2N9FL ","B2N9FN ","B2N9FT ", & - "B2N9FX ","B2N9FY ","B2N9GAM ","B2N9M ","B2N9MM ","B2N9PHI ","B2N9RE ", & - "B2N9SGCAV","B2N9SIGCR","B2N9STVX ","B2N9STVY ","B2N9STVZ ","B2N9THETA","B2N9TNIND", & - "B2N9VDISX","B2N9VDISY","B2N9VDISZ","B2N9VINDX","B2N9VINDY","B2N9VREL ","B2N9VUNDX", & - "B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AZIMUTH","B3N1ALPHA","B3N1AXIND","B3N1CD ", & - "B3N1CL ","B3N1CLRNC","B3N1CM ","B3N1CN ","B3N1CPMIN","B3N1CT ","B3N1CURVE", & - "B3N1CX ","B3N1CY ","B3N1DYNP ","B3N1FD ","B3N1FL ","B3N1FN ","B3N1FT ", & - "B3N1FX ","B3N1FY ","B3N1GAM ","B3N1M ","B3N1MM ","B3N1PHI ","B3N1RE ", & - "B3N1SGCAV","B3N1SIGCR","B3N1STVX ","B3N1STVY ","B3N1STVZ ","B3N1THETA","B3N1TNIND", & - "B3N1VDISX","B3N1VDISY","B3N1VDISZ","B3N1VINDX","B3N1VINDY","B3N1VREL ","B3N1VUNDX", & - "B3N1VUNDY","B3N1VUNDZ","B3N2ALPHA","B3N2AXIND","B3N2CD ","B3N2CL ","B3N2CLRNC", & - "B3N2CM ","B3N2CN ","B3N2CPMIN","B3N2CT ","B3N2CURVE","B3N2CX ","B3N2CY ", & - "B3N2DYNP ","B3N2FD ","B3N2FL ","B3N2FN ","B3N2FT ","B3N2FX ","B3N2FY ", & - "B3N2GAM ","B3N2M ","B3N2MM ","B3N2PHI ","B3N2RE ","B3N2SGCAV","B3N2SIGCR", & - "B3N2STVX ","B3N2STVY ","B3N2STVZ ","B3N2THETA","B3N2TNIND","B3N2VDISX","B3N2VDISY", & - "B3N2VDISZ","B3N2VINDX","B3N2VINDY","B3N2VREL ","B3N2VUNDX","B3N2VUNDY","B3N2VUNDZ", & - "B3N3ALPHA","B3N3AXIND","B3N3CD ","B3N3CL ","B3N3CLRNC","B3N3CM ","B3N3CN ", & - "B3N3CPMIN","B3N3CT ","B3N3CURVE","B3N3CX ","B3N3CY ","B3N3DYNP ","B3N3FD ", & - "B3N3FL ","B3N3FN ","B3N3FT ","B3N3FX ","B3N3FY ","B3N3GAM ","B3N3M ", & - "B3N3MM ","B3N3PHI ","B3N3RE ","B3N3SGCAV","B3N3SIGCR","B3N3STVX ","B3N3STVY ", & - "B3N3STVZ ","B3N3THETA","B3N3TNIND","B3N3VDISX","B3N3VDISY","B3N3VDISZ","B3N3VINDX", & - "B3N3VINDY","B3N3VREL ","B3N3VUNDX","B3N3VUNDY","B3N3VUNDZ","B3N4ALPHA","B3N4AXIND", & - "B3N4CD ","B3N4CL ","B3N4CLRNC","B3N4CM ","B3N4CN ","B3N4CPMIN","B3N4CT ", & - "B3N4CURVE","B3N4CX ","B3N4CY ","B3N4DYNP ","B3N4FD ","B3N4FL ","B3N4FN ", & - "B3N4FT ","B3N4FX ","B3N4FY ","B3N4GAM ","B3N4M ","B3N4MM ","B3N4PHI ", & - "B3N4RE ","B3N4SGCAV","B3N4SIGCR","B3N4STVX ","B3N4STVY ","B3N4STVZ ","B3N4THETA", & - "B3N4TNIND","B3N4VDISX","B3N4VDISY","B3N4VDISZ","B3N4VINDX","B3N4VINDY","B3N4VREL ", & - "B3N4VUNDX","B3N4VUNDY","B3N4VUNDZ","B3N5ALPHA","B3N5AXIND","B3N5CD ","B3N5CL ", & - "B3N5CLRNC","B3N5CM ","B3N5CN ","B3N5CPMIN","B3N5CT ","B3N5CURVE","B3N5CX ", & - "B3N5CY ","B3N5DYNP ","B3N5FD ","B3N5FL ","B3N5FN ","B3N5FT ","B3N5FX ", & - "B3N5FY ","B3N5GAM ","B3N5M ","B3N5MM ","B3N5PHI ","B3N5RE ","B3N5SGCAV", & - "B3N5SIGCR","B3N5STVX ","B3N5STVY ","B3N5STVZ ","B3N5THETA","B3N5TNIND","B3N5VDISX", & - "B3N5VDISY","B3N5VDISZ","B3N5VINDX","B3N5VINDY","B3N5VREL ","B3N5VUNDX","B3N5VUNDY", & - "B3N5VUNDZ","B3N6ALPHA","B3N6AXIND","B3N6CD ","B3N6CL ","B3N6CLRNC","B3N6CM ", & - "B3N6CN ","B3N6CPMIN","B3N6CT ","B3N6CURVE","B3N6CX ","B3N6CY ","B3N6DYNP ", & - "B3N6FD ","B3N6FL ","B3N6FN ","B3N6FT ","B3N6FX ","B3N6FY ","B3N6GAM ", & - "B3N6M ","B3N6MM ","B3N6PHI ","B3N6RE ","B3N6SGCAV","B3N6SIGCR","B3N6STVX ", & - "B3N6STVY ","B3N6STVZ ","B3N6THETA","B3N6TNIND","B3N6VDISX","B3N6VDISY","B3N6VDISZ", & - "B3N6VINDX","B3N6VINDY","B3N6VREL ","B3N6VUNDX","B3N6VUNDY","B3N6VUNDZ","B3N7ALPHA", & - "B3N7AXIND","B3N7CD ","B3N7CL ","B3N7CLRNC","B3N7CM ","B3N7CN ","B3N7CPMIN", & - "B3N7CT ","B3N7CURVE","B3N7CX ","B3N7CY ","B3N7DYNP ","B3N7FD ","B3N7FL ", & - "B3N7FN ","B3N7FT ","B3N7FX ","B3N7FY ","B3N7GAM ","B3N7M ","B3N7MM ", & - "B3N7PHI ","B3N7RE ","B3N7SGCAV","B3N7SIGCR","B3N7STVX ","B3N7STVY ","B3N7STVZ ", & - "B3N7THETA","B3N7TNIND","B3N7VDISX","B3N7VDISY","B3N7VDISZ","B3N7VINDX","B3N7VINDY", & - "B3N7VREL ","B3N7VUNDX","B3N7VUNDY","B3N7VUNDZ","B3N8ALPHA","B3N8AXIND","B3N8CD ", & - "B3N8CL ","B3N8CLRNC","B3N8CM ","B3N8CN ","B3N8CPMIN","B3N8CT ","B3N8CURVE", & - "B3N8CX ","B3N8CY ","B3N8DYNP ","B3N8FD ","B3N8FL ","B3N8FN ","B3N8FT ", & - "B3N8FX ","B3N8FY ","B3N8GAM ","B3N8M ","B3N8MM ","B3N8PHI ","B3N8RE ", & - "B3N8SGCAV","B3N8SIGCR","B3N8STVX ","B3N8STVY ","B3N8STVZ ","B3N8THETA","B3N8TNIND", & - "B3N8VDISX","B3N8VDISY","B3N8VDISZ","B3N8VINDX","B3N8VINDY","B3N8VREL ","B3N8VUNDX", & - "B3N8VUNDY","B3N8VUNDZ","B3N9ALPHA","B3N9AXIND","B3N9CD ","B3N9CL ","B3N9CLRNC", & - "B3N9CM ","B3N9CN ","B3N9CPMIN","B3N9CT ","B3N9CURVE","B3N9CX ","B3N9CY ", & - "B3N9DYNP ","B3N9FD ","B3N9FL ","B3N9FN ","B3N9FT ","B3N9FX ","B3N9FY ", & - "B3N9GAM ","B3N9M ","B3N9MM ","B3N9PHI ","B3N9RE ","B3N9SGCAV","B3N9SIGCR", & - "B3N9STVX ","B3N9STVY ","B3N9STVZ ","B3N9THETA","B3N9TNIND","B3N9VDISX","B3N9VDISY", & - "B3N9VDISZ","B3N9VINDX","B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ", & - "B3PITCH ","RTAEROCP ","RTAEROCQ ","RTAEROCT ","RTAEROFXH","RTAEROFYH","RTAEROFZH", & - "RTAEROMXH","RTAEROMYH","RTAEROMZH","RTAEROPWR","RTAREA ","RTSKEW ","RTSPEED ", & - "RTTSR ","RTVAVGXH ","RTVAVGYH ","RTVAVGZH ","TWN1DYNP ","TWN1FDX ","TWN1FDY ", & - "TWN1M ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ","TWN1VREL ","TWN1VUNDX", & - "TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FDX ","TWN2FDY ","TWN2M ","TWN2RE ", & - "TWN2STVX ","TWN2STVY ","TWN2STVZ ","TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ", & - "TWN3DYNP ","TWN3FDX ","TWN3FDY ","TWN3M ","TWN3RE ","TWN3STVX ","TWN3STVY ", & - "TWN3STVZ ","TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ","TWN4DYNP ","TWN4FDX ", & - "TWN4FDY ","TWN4M ","TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ", & - "TWN4VUNDX","TWN4VUNDY","TWN4VUNDZ","TWN5DYNP ","TWN5FDX ","TWN5FDY ","TWN5M ", & - "TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ","TWN5VREL ","TWN5VUNDX","TWN5VUNDY", & - "TWN5VUNDZ","TWN6DYNP ","TWN6FDX ","TWN6FDY ","TWN6M ","TWN6RE ","TWN6STVX ", & - "TWN6STVY ","TWN6STVZ ","TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ","TWN7DYNP ", & - "TWN7FDX ","TWN7FDY ","TWN7M ","TWN7RE ","TWN7STVX ","TWN7STVY ","TWN7STVZ ", & - "TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ","TWN8DYNP ","TWN8FDX ","TWN8FDY ", & - "TWN8M ","TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX", & - "TWN8VUNDY","TWN8VUNDZ","TWN9DYNP ","TWN9FDX ","TWN9FDY ","TWN9M ","TWN9RE ", & - "TWN9STVX ","TWN9STVY ","TWN9STVZ ","TWN9VREL ","TWN9VUNDX","TWN9VUNDY","TWN9VUNDZ"/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(1211) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) - B1Azimuth , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , B1N1Cm , & - B1N1Cn , B1N1Cpmin , B1N1Ct , B1N1Curve , B1N1Cx , B1N1Cy , B1N1DynP , & - B1N1Fd , B1N1Fl , B1N1Fn , B1N1Ft , B1N1Fx , B1N1Fy , B1N1Gam , & - B1N1M , B1N1Mm , B1N1Phi , B1N1Re , B1N1SgCav , B1N1SigCr , B1N1STVx , & - B1N1STVy , B1N1STVz , B1N1Theta , B1N1TnInd , B1N1VDisx , B1N1VDisy , B1N1VDisz , & - B1N1Vindx , B1N1Vindy , B1N1VRel , B1N1VUndx , B1N1VUndy , B1N1VUndz , B1N2Alpha , & - B1N2AxInd , B1N2Cd , B1N2Cl , B1N2Clrnc , B1N2Cm , B1N2Cn , B1N2Cpmin , & - B1N2Ct , B1N2Curve , B1N2Cx , B1N2Cy , B1N2DynP , B1N2Fd , B1N2Fl , & - B1N2Fn , B1N2Ft , B1N2Fx , B1N2Fy , B1N2Gam , B1N2M , B1N2Mm , & - B1N2Phi , B1N2Re , B1N2SgCav , B1N2SigCr , B1N2STVx , B1N2STVy , B1N2STVz , & - B1N2Theta , B1N2TnInd , B1N2VDisx , B1N2VDisy , B1N2VDisz , B1N2Vindx , B1N2Vindy , & - B1N2VRel , B1N2VUndx , B1N2VUndy , B1N2VUndz , B1N3Alpha , B1N3AxInd , B1N3Cd , & - B1N3Cl , B1N3Clrnc , B1N3Cm , B1N3Cn , B1N3Cpmin , B1N3Ct , B1N3Curve , & - B1N3Cx , B1N3Cy , B1N3DynP , B1N3Fd , B1N3Fl , B1N3Fn , B1N3Ft , & - B1N3Fx , B1N3Fy , B1N3Gam , B1N3M , B1N3Mm , B1N3Phi , B1N3Re , & - B1N3SgCav , B1N3SigCr , B1N3STVx , B1N3STVy , B1N3STVz , B1N3Theta , B1N3TnInd , & - B1N3VDisx , B1N3VDisy , B1N3VDisz , B1N3Vindx , B1N3Vindy , B1N3VRel , B1N3VUndx , & - B1N3VUndy , B1N3VUndz , B1N4Alpha , B1N4AxInd , B1N4Cd , B1N4Cl , B1N4Clrnc , & - B1N4Cm , B1N4Cn , B1N4Cpmin , B1N4Ct , B1N4Curve , B1N4Cx , B1N4Cy , & - B1N4DynP , B1N4Fd , B1N4Fl , B1N4Fn , B1N4Ft , B1N4Fx , B1N4Fy , & - B1N4Gam , B1N4M , B1N4Mm , B1N4Phi , B1N4Re , B1N4SgCav , B1N4SigCr , & - B1N4STVx , B1N4STVy , B1N4STVz , B1N4Theta , B1N4TnInd , B1N4VDisx , B1N4VDisy , & - B1N4VDisz , B1N4Vindx , B1N4Vindy , B1N4VRel , B1N4VUndx , B1N4VUndy , B1N4VUndz , & - B1N5Alpha , B1N5AxInd , B1N5Cd , B1N5Cl , B1N5Clrnc , B1N5Cm , B1N5Cn , & - B1N5Cpmin , B1N5Ct , B1N5Curve , B1N5Cx , B1N5Cy , B1N5DynP , B1N5Fd , & - B1N5Fl , B1N5Fn , B1N5Ft , B1N5Fx , B1N5Fy , B1N5Gam , B1N5M , & - B1N5Mm , B1N5Phi , B1N5Re , B1N5SgCav , B1N5SigCr , B1N5STVx , B1N5STVy , & - B1N5STVz , B1N5Theta , B1N5TnInd , B1N5VDisx , B1N5VDisy , B1N5VDisz , B1N5Vindx , & - B1N5Vindy , B1N5VRel , B1N5VUndx , B1N5VUndy , B1N5VUndz , B1N6Alpha , B1N6AxInd , & - B1N6Cd , B1N6Cl , B1N6Clrnc , B1N6Cm , B1N6Cn , B1N6Cpmin , B1N6Ct , & - B1N6Curve , B1N6Cx , B1N6Cy , B1N6DynP , B1N6Fd , B1N6Fl , B1N6Fn , & - B1N6Ft , B1N6Fx , B1N6Fy , B1N6Gam , B1N6M , B1N6Mm , B1N6Phi , & - B1N6Re , B1N6SgCav , B1N6SigCr , B1N6STVx , B1N6STVy , B1N6STVz , B1N6Theta , & - B1N6TnInd , B1N6VDisx , B1N6VDisy , B1N6VDisz , B1N6Vindx , B1N6Vindy , B1N6VRel , & - B1N6VUndx , B1N6VUndy , B1N6VUndz , B1N7Alpha , B1N7AxInd , B1N7Cd , B1N7Cl , & - B1N7Clrnc , B1N7Cm , B1N7Cn , B1N7Cpmin , B1N7Ct , B1N7Curve , B1N7Cx , & - B1N7Cy , B1N7DynP , B1N7Fd , B1N7Fl , B1N7Fn , B1N7Ft , B1N7Fx , & - B1N7Fy , B1N7Gam , B1N7M , B1N7Mm , B1N7Phi , B1N7Re , B1N7SgCav , & - B1N7SigCr , B1N7STVx , B1N7STVy , B1N7STVz , B1N7Theta , B1N7TnInd , B1N7VDisx , & - B1N7VDisy , B1N7VDisz , B1N7Vindx , B1N7Vindy , B1N7VRel , B1N7VUndx , B1N7VUndy , & - B1N7VUndz , B1N8Alpha , B1N8AxInd , B1N8Cd , B1N8Cl , B1N8Clrnc , B1N8Cm , & - B1N8Cn , B1N8Cpmin , B1N8Ct , B1N8Curve , B1N8Cx , B1N8Cy , B1N8DynP , & - B1N8Fd , B1N8Fl , B1N8Fn , B1N8Ft , B1N8Fx , B1N8Fy , B1N8Gam , & - B1N8M , B1N8Mm , B1N8Phi , B1N8Re , B1N8SgCav , B1N8SigCr , B1N8STVx , & - B1N8STVy , B1N8STVz , B1N8Theta , B1N8TnInd , B1N8VDisx , B1N8VDisy , B1N8VDisz , & - B1N8Vindx , B1N8Vindy , B1N8VRel , B1N8VUndx , B1N8VUndy , B1N8VUndz , B1N9Alpha , & - B1N9AxInd , B1N9Cd , B1N9Cl , B1N9Clrnc , B1N9Cm , B1N9Cn , B1N9Cpmin , & - B1N9Ct , B1N9Curve , B1N9Cx , B1N9Cy , B1N9DynP , B1N9Fd , B1N9Fl , & - B1N9Fn , B1N9Ft , B1N9Fx , B1N9Fy , B1N9Gam , B1N9M , B1N9Mm , & - B1N9Phi , B1N9Re , B1N9SgCav , B1N9SigCr , B1N9STVx , B1N9STVy , B1N9STVz , & - B1N9Theta , B1N9TnInd , B1N9VDisx , B1N9VDisy , B1N9VDisz , B1N9Vindx , B1N9Vindy , & - B1N9VRel , B1N9VUndx , B1N9VUndy , B1N9VUndz , B1Pitch , B2Azimuth , B2N1Alpha , & - B2N1AxInd , B2N1Cd , B2N1Cl , B2N1Clrnc , B2N1Cm , B2N1Cn , B2N1Cpmin , & - B2N1Ct , B2N1Curve , B2N1Cx , B2N1Cy , B2N1DynP , B2N1Fd , B2N1Fl , & - B2N1Fn , B2N1Ft , B2N1Fx , B2N1Fy , B2N1Gam , B2N1M , B2N1Mm , & - B2N1Phi , B2N1Re , B2N1SgCav , B2N1SigCr , B2N1STVx , B2N1STVy , B2N1STVz , & - B2N1Theta , B2N1TnInd , B2N1VDisx , B2N1VDisy , B2N1VDisz , B2N1Vindx , B2N1Vindy , & - B2N1VRel , B2N1VUndx , B2N1VUndy , B2N1VUndz , B2N2Alpha , B2N2AxInd , B2N2Cd , & - B2N2Cl , B2N2Clrnc , B2N2Cm , B2N2Cn , B2N2Cpmin , B2N2Ct , B2N2Curve , & - B2N2Cx , B2N2Cy , B2N2DynP , B2N2Fd , B2N2Fl , B2N2Fn , B2N2Ft , & - B2N2Fx , B2N2Fy , B2N2Gam , B2N2M , B2N2Mm , B2N2Phi , B2N2Re , & - B2N2SgCav , B2N2SigCr , B2N2STVx , B2N2STVy , B2N2STVz , B2N2Theta , B2N2TnInd , & - B2N2VDisx , B2N2VDisy , B2N2VDisz , B2N2Vindx , B2N2Vindy , B2N2VRel , B2N2VUndx , & - B2N2VUndy , B2N2VUndz , B2N3Alpha , B2N3AxInd , B2N3Cd , B2N3Cl , B2N3Clrnc , & - B2N3Cm , B2N3Cn , B2N3Cpmin , B2N3Ct , B2N3Curve , B2N3Cx , B2N3Cy , & - B2N3DynP , B2N3Fd , B2N3Fl , B2N3Fn , B2N3Ft , B2N3Fx , B2N3Fy , & - B2N3Gam , B2N3M , B2N3Mm , B2N3Phi , B2N3Re , B2N3SgCav , B2N3SigCr , & - B2N3STVx , B2N3STVy , B2N3STVz , B2N3Theta , B2N3TnInd , B2N3VDisx , B2N3VDisy , & - B2N3VDisz , B2N3Vindx , B2N3Vindy , B2N3VRel , B2N3VUndx , B2N3VUndy , B2N3VUndz , & - B2N4Alpha , B2N4AxInd , B2N4Cd , B2N4Cl , B2N4Clrnc , B2N4Cm , B2N4Cn , & - B2N4Cpmin , B2N4Ct , B2N4Curve , B2N4Cx , B2N4Cy , B2N4DynP , B2N4Fd , & - B2N4Fl , B2N4Fn , B2N4Ft , B2N4Fx , B2N4Fy , B2N4Gam , B2N4M , & - B2N4Mm , B2N4Phi , B2N4Re , B2N4SgCav , B2N4SigCr , B2N4STVx , B2N4STVy , & - B2N4STVz , B2N4Theta , B2N4TnInd , B2N4VDisx , B2N4VDisy , B2N4VDisz , B2N4Vindx , & - B2N4Vindy , B2N4VRel , B2N4VUndx , B2N4VUndy , B2N4VUndz , B2N5Alpha , B2N5AxInd , & - B2N5Cd , B2N5Cl , B2N5Clrnc , B2N5Cm , B2N5Cn , B2N5Cpmin , B2N5Ct , & - B2N5Curve , B2N5Cx , B2N5Cy , B2N5DynP , B2N5Fd , B2N5Fl , B2N5Fn , & - B2N5Ft , B2N5Fx , B2N5Fy , B2N5Gam , B2N5M , B2N5Mm , B2N5Phi , & - B2N5Re , B2N5SgCav , B2N5SigCr , B2N5STVx , B2N5STVy , B2N5STVz , B2N5Theta , & - B2N5TnInd , B2N5VDisx , B2N5VDisy , B2N5VDisz , B2N5Vindx , B2N5Vindy , B2N5VRel , & - B2N5VUndx , B2N5VUndy , B2N5VUndz , B2N6Alpha , B2N6AxInd , B2N6Cd , B2N6Cl , & - B2N6Clrnc , B2N6Cm , B2N6Cn , B2N6Cpmin , B2N6Ct , B2N6Curve , B2N6Cx , & - B2N6Cy , B2N6DynP , B2N6Fd , B2N6Fl , B2N6Fn , B2N6Ft , B2N6Fx , & - B2N6Fy , B2N6Gam , B2N6M , B2N6Mm , B2N6Phi , B2N6Re , B2N6SgCav , & - B2N6SigCr , B2N6STVx , B2N6STVy , B2N6STVz , B2N6Theta , B2N6TnInd , B2N6VDisx , & - B2N6VDisy , B2N6VDisz , B2N6Vindx , B2N6Vindy , B2N6VRel , B2N6VUndx , B2N6VUndy , & - B2N6VUndz , B2N7Alpha , B2N7AxInd , B2N7Cd , B2N7Cl , B2N7Clrnc , B2N7Cm , & - B2N7Cn , B2N7Cpmin , B2N7Ct , B2N7Curve , B2N7Cx , B2N7Cy , B2N7DynP , & - B2N7Fd , B2N7Fl , B2N7Fn , B2N7Ft , B2N7Fx , B2N7Fy , B2N7Gam , & - B2N7M , B2N7Mm , B2N7Phi , B2N7Re , B2N7SgCav , B2N7SigCr , B2N7STVx , & - B2N7STVy , B2N7STVz , B2N7Theta , B2N7TnInd , B2N7VDisx , B2N7VDisy , B2N7VDisz , & - B2N7Vindx , B2N7Vindy , B2N7VRel , B2N7VUndx , B2N7VUndy , B2N7VUndz , B2N8Alpha , & - B2N8AxInd , B2N8Cd , B2N8Cl , B2N8Clrnc , B2N8Cm , B2N8Cn , B2N8Cpmin , & - B2N8Ct , B2N8Curve , B2N8Cx , B2N8Cy , B2N8DynP , B2N8Fd , B2N8Fl , & - B2N8Fn , B2N8Ft , B2N8Fx , B2N8Fy , B2N8Gam , B2N8M , B2N8Mm , & - B2N8Phi , B2N8Re , B2N8SgCav , B2N8SigCr , B2N8STVx , B2N8STVy , B2N8STVz , & - B2N8Theta , B2N8TnInd , B2N8VDisx , B2N8VDisy , B2N8VDisz , B2N8Vindx , B2N8Vindy , & - B2N8VRel , B2N8VUndx , B2N8VUndy , B2N8VUndz , B2N9Alpha , B2N9AxInd , B2N9Cd , & - B2N9Cl , B2N9Clrnc , B2N9Cm , B2N9Cn , B2N9Cpmin , B2N9Ct , B2N9Curve , & - B2N9Cx , B2N9Cy , B2N9DynP , B2N9Fd , B2N9Fl , B2N9Fn , B2N9Ft , & - B2N9Fx , B2N9Fy , B2N9Gam , B2N9M , B2N9Mm , B2N9Phi , B2N9Re , & - B2N9SgCav , B2N9SigCr , B2N9STVx , B2N9STVy , B2N9STVz , B2N9Theta , B2N9TnInd , & - B2N9VDisx , B2N9VDisy , B2N9VDisz , B2N9Vindx , B2N9Vindy , B2N9VRel , B2N9VUndx , & - B2N9VUndy , B2N9VUndz , B2Pitch , B3Azimuth , B3N1Alpha , B3N1AxInd , B3N1Cd , & - B3N1Cl , B3N1Clrnc , B3N1Cm , B3N1Cn , B3N1Cpmin , B3N1Ct , B3N1Curve , & - B3N1Cx , B3N1Cy , B3N1DynP , B3N1Fd , B3N1Fl , B3N1Fn , B3N1Ft , & - B3N1Fx , B3N1Fy , B3N1Gam , B3N1M , B3N1Mm , B3N1Phi , B3N1Re , & - B3N1SgCav , B3N1SigCr , B3N1STVx , B3N1STVy , B3N1STVz , B3N1Theta , B3N1TnInd , & - B3N1VDisx , B3N1VDisy , B3N1VDisz , B3N1Vindx , B3N1Vindy , B3N1VRel , B3N1VUndx , & - B3N1VUndy , B3N1VUndz , B3N2Alpha , B3N2AxInd , B3N2Cd , B3N2Cl , B3N2Clrnc , & - B3N2Cm , B3N2Cn , B3N2Cpmin , B3N2Ct , B3N2Curve , B3N2Cx , B3N2Cy , & - B3N2DynP , B3N2Fd , B3N2Fl , B3N2Fn , B3N2Ft , B3N2Fx , B3N2Fy , & - B3N2Gam , B3N2M , B3N2Mm , B3N2Phi , B3N2Re , B3N2SgCav , B3N2SigCr , & - B3N2STVx , B3N2STVy , B3N2STVz , B3N2Theta , B3N2TnInd , B3N2VDisx , B3N2VDisy , & - B3N2VDisz , B3N2Vindx , B3N2Vindy , B3N2VRel , B3N2VUndx , B3N2VUndy , B3N2VUndz , & - B3N3Alpha , B3N3AxInd , B3N3Cd , B3N3Cl , B3N3Clrnc , B3N3Cm , B3N3Cn , & - B3N3Cpmin , B3N3Ct , B3N3Curve , B3N3Cx , B3N3Cy , B3N3DynP , B3N3Fd , & - B3N3Fl , B3N3Fn , B3N3Ft , B3N3Fx , B3N3Fy , B3N3Gam , B3N3M , & - B3N3Mm , B3N3Phi , B3N3Re , B3N3SgCav , B3N3SigCr , B3N3STVx , B3N3STVy , & - B3N3STVz , B3N3Theta , B3N3TnInd , B3N3VDisx , B3N3VDisy , B3N3VDisz , B3N3Vindx , & - B3N3Vindy , B3N3VRel , B3N3VUndx , B3N3VUndy , B3N3VUndz , B3N4Alpha , B3N4AxInd , & - B3N4Cd , B3N4Cl , B3N4Clrnc , B3N4Cm , B3N4Cn , B3N4Cpmin , B3N4Ct , & - B3N4Curve , B3N4Cx , B3N4Cy , B3N4DynP , B3N4Fd , B3N4Fl , B3N4Fn , & - B3N4Ft , B3N4Fx , B3N4Fy , B3N4Gam , B3N4M , B3N4Mm , B3N4Phi , & - B3N4Re , B3N4SgCav , B3N4SigCr , B3N4STVx , B3N4STVy , B3N4STVz , B3N4Theta , & - B3N4TnInd , B3N4VDisx , B3N4VDisy , B3N4VDisz , B3N4Vindx , B3N4Vindy , B3N4VRel , & - B3N4VUndx , B3N4VUndy , B3N4VUndz , B3N5Alpha , B3N5AxInd , B3N5Cd , B3N5Cl , & - B3N5Clrnc , B3N5Cm , B3N5Cn , B3N5Cpmin , B3N5Ct , B3N5Curve , B3N5Cx , & - B3N5Cy , B3N5DynP , B3N5Fd , B3N5Fl , B3N5Fn , B3N5Ft , B3N5Fx , & - B3N5Fy , B3N5Gam , B3N5M , B3N5Mm , B3N5Phi , B3N5Re , B3N5SgCav , & - B3N5SigCr , B3N5STVx , B3N5STVy , B3N5STVz , B3N5Theta , B3N5TnInd , B3N5VDisx , & - B3N5VDisy , B3N5VDisz , B3N5Vindx , B3N5Vindy , B3N5VRel , B3N5VUndx , B3N5VUndy , & - B3N5VUndz , B3N6Alpha , B3N6AxInd , B3N6Cd , B3N6Cl , B3N6Clrnc , B3N6Cm , & - B3N6Cn , B3N6Cpmin , B3N6Ct , B3N6Curve , B3N6Cx , B3N6Cy , B3N6DynP , & - B3N6Fd , B3N6Fl , B3N6Fn , B3N6Ft , B3N6Fx , B3N6Fy , B3N6Gam , & - B3N6M , B3N6Mm , B3N6Phi , B3N6Re , B3N6SgCav , B3N6SigCr , B3N6STVx , & - B3N6STVy , B3N6STVz , B3N6Theta , B3N6TnInd , B3N6VDisx , B3N6VDisy , B3N6VDisz , & - B3N6Vindx , B3N6Vindy , B3N6VRel , B3N6VUndx , B3N6VUndy , B3N6VUndz , B3N7Alpha , & - B3N7AxInd , B3N7Cd , B3N7Cl , B3N7Clrnc , B3N7Cm , B3N7Cn , B3N7Cpmin , & - B3N7Ct , B3N7Curve , B3N7Cx , B3N7Cy , B3N7DynP , B3N7Fd , B3N7Fl , & - B3N7Fn , B3N7Ft , B3N7Fx , B3N7Fy , B3N7Gam , B3N7M , B3N7Mm , & - B3N7Phi , B3N7Re , B3N7SgCav , B3N7SigCr , B3N7STVx , B3N7STVy , B3N7STVz , & - B3N7Theta , B3N7TnInd , B3N7VDisx , B3N7VDisy , B3N7VDisz , B3N7Vindx , B3N7Vindy , & - B3N7VRel , B3N7VUndx , B3N7VUndy , B3N7VUndz , B3N8Alpha , B3N8AxInd , B3N8Cd , & - B3N8Cl , B3N8Clrnc , B3N8Cm , B3N8Cn , B3N8Cpmin , B3N8Ct , B3N8Curve , & - B3N8Cx , B3N8Cy , B3N8DynP , B3N8Fd , B3N8Fl , B3N8Fn , B3N8Ft , & - B3N8Fx , B3N8Fy , B3N8Gam , B3N8M , B3N8Mm , B3N8Phi , B3N8Re , & - B3N8SgCav , B3N8SigCr , B3N8STVx , B3N8STVy , B3N8STVz , B3N8Theta , B3N8TnInd , & - B3N8VDisx , B3N8VDisy , B3N8VDisz , B3N8Vindx , B3N8Vindy , B3N8VRel , B3N8VUndx , & - B3N8VUndy , B3N8VUndz , B3N9Alpha , B3N9AxInd , B3N9Cd , B3N9Cl , B3N9Clrnc , & - B3N9Cm , B3N9Cn , B3N9Cpmin , B3N9Ct , B3N9Curve , B3N9Cx , B3N9Cy , & - B3N9DynP , B3N9Fd , B3N9Fl , B3N9Fn , B3N9Ft , B3N9Fx , B3N9Fy , & - B3N9Gam , B3N9M , B3N9Mm , B3N9Phi , B3N9Re , B3N9SgCav , B3N9SigCr , & - B3N9STVx , B3N9STVy , B3N9STVz , B3N9Theta , B3N9TnInd , B3N9VDisx , B3N9VDisy , & - B3N9VDisz , B3N9Vindx , B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , & - B3Pitch , RtAeroCp , RtAeroCq , RtAeroCt , RtAeroFxh , RtAeroFyh , RtAeroFzh , & - RtAeroMxh , RtAeroMyh , RtAeroMzh , RtAeroPwr , RtArea , RtSkew , RtSpeed , & - RtTSR , RtVAvgxh , RtVAvgyh , RtVAvgzh , TwN1DynP , TwN1Fdx , TwN1Fdy , & - TwN1M , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , TwN1Vrel , TwN1VUndx , & - TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fdx , TwN2Fdy , TwN2M , TwN2Re , & - TwN2STVx , TwN2STVy , TwN2STVz , TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , & - TwN3DynP , TwN3Fdx , TwN3Fdy , TwN3M , TwN3Re , TwN3STVx , TwN3STVy , & - TwN3STVz , TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , TwN4DynP , TwN4Fdx , & - TwN4Fdy , TwN4M , TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , & - TwN4VUndx , TwN4VUndy , TwN4VUndz , TwN5DynP , TwN5Fdx , TwN5Fdy , TwN5M , & - TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , TwN5Vrel , TwN5VUndx , TwN5VUndy , & - TwN5VUndz , TwN6DynP , TwN6Fdx , TwN6Fdy , TwN6M , TwN6Re , TwN6STVx , & - TwN6STVy , TwN6STVz , TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , TwN7DynP , & - TwN7Fdx , TwN7Fdy , TwN7M , TwN7Re , TwN7STVx , TwN7STVy , TwN7STVz , & - TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , TwN8DynP , TwN8Fdx , TwN8Fdy , & - TwN8M , TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , & - TwN8VUndy , TwN8VUndz , TwN9DynP , TwN9Fdx , TwN9Fdy , TwN9M , TwN9Re , & - TwN9STVx , TwN9STVy , TwN9STVz , TwN9Vrel , TwN9VUndx , TwN9VUndy , TwN9VUndz /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1211) = (/ & ! This lists the units corresponding to the allowed parameters - "(deg) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ", & - "(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(-) ","(-) ","(m) ","(-) ","(-) ","(-) ", & - "(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ", & - "(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & - "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ", & - "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & - "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ", & - "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & - "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ", & - "(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(-) ","(-) ","(m) ","(-) ","(-) ","(-) ","(-) ", & - "(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ", & - "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ", & - "(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & - "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ", & - "(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(-) ","(-) ","(m) ","(-) ","(-) ","(-) ", & - "(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ", & - "(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(deg) ","(deg) ", & - "(-) ","(-) ","(-) ","(m) ","(-) ","(-) ","(-) ", & - "(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ", & - "(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & - "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ", & - "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & - "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ", & - "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & - "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ", & - "(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(-) ","(-) ","(m) ","(-) ","(-) ","(-) ","(-) ", & - "(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ", & - "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ", & - "(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & - "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ", & - "(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(-) ","(-) ","(m) ","(-) ","(-) ","(-) ", & - "(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ", & - "(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & - "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ", & - "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(deg) ","(deg) ","(-) ","(-) ", & - "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ", & - "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & - "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ", & - "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & - "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ", & - "(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(-) ","(-) ","(m) ","(-) ","(-) ","(-) ","(-) ", & - "(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ", & - "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ", & - "(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & - "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ", & - "(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ", & - "(-) ","(-) ","(-) ","(m) ","(-) ","(-) ","(-) ", & - "(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ", & - "(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & - "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ", & - "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & - "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ", & - "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(m^2/s) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(deg) ","(-) ","(-) ","(-) ","(N) ","(N) ","(N) ", & - "(N-m) ","(N-m) ","(N-m) ","(W) ","(m^2) ","(deg) ","(rpm) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ", & - "(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ", & - "(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ", & - "(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) "/) + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1212) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "B1AZIMUTH","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC","B1N1CM ","B1N1CN ", & + "B1N1CPMIN","B1N1CT ","B1N1CURVE","B1N1CX ","B1N1CY ","B1N1DYNP ","B1N1FD ","B1N1FL ", & + "B1N1FN ","B1N1FT ","B1N1FX ","B1N1FY ","B1N1GAM ","B1N1M ","B1N1MM ","B1N1PHI ", & + "B1N1RE ","B1N1SGCAV","B1N1SIGCR","B1N1STVX ","B1N1STVY ","B1N1STVZ ","B1N1THETA","B1N1TNIND", & + "B1N1VDISX","B1N1VDISY","B1N1VDISZ","B1N1VINDX","B1N1VINDY","B1N1VREL ","B1N1VUNDX","B1N1VUNDY", & + "B1N1VUNDZ","B1N2ALPHA","B1N2AXIND","B1N2CD ","B1N2CL ","B1N2CLRNC","B1N2CM ","B1N2CN ", & + "B1N2CPMIN","B1N2CT ","B1N2CURVE","B1N2CX ","B1N2CY ","B1N2DYNP ","B1N2FD ","B1N2FL ", & + "B1N2FN ","B1N2FT ","B1N2FX ","B1N2FY ","B1N2GAM ","B1N2M ","B1N2MM ","B1N2PHI ", & + "B1N2RE ","B1N2SGCAV","B1N2SIGCR","B1N2STVX ","B1N2STVY ","B1N2STVZ ","B1N2THETA","B1N2TNIND", & + "B1N2VDISX","B1N2VDISY","B1N2VDISZ","B1N2VINDX","B1N2VINDY","B1N2VREL ","B1N2VUNDX","B1N2VUNDY", & + "B1N2VUNDZ","B1N3ALPHA","B1N3AXIND","B1N3CD ","B1N3CL ","B1N3CLRNC","B1N3CM ","B1N3CN ", & + "B1N3CPMIN","B1N3CT ","B1N3CURVE","B1N3CX ","B1N3CY ","B1N3DYNP ","B1N3FD ","B1N3FL ", & + "B1N3FN ","B1N3FT ","B1N3FX ","B1N3FY ","B1N3GAM ","B1N3M ","B1N3MM ","B1N3PHI ", & + "B1N3RE ","B1N3SGCAV","B1N3SIGCR","B1N3STVX ","B1N3STVY ","B1N3STVZ ","B1N3THETA","B1N3TNIND", & + "B1N3VDISX","B1N3VDISY","B1N3VDISZ","B1N3VINDX","B1N3VINDY","B1N3VREL ","B1N3VUNDX","B1N3VUNDY", & + "B1N3VUNDZ","B1N4ALPHA","B1N4AXIND","B1N4CD ","B1N4CL ","B1N4CLRNC","B1N4CM ","B1N4CN ", & + "B1N4CPMIN","B1N4CT ","B1N4CURVE","B1N4CX ","B1N4CY ","B1N4DYNP ","B1N4FD ","B1N4FL ", & + "B1N4FN ","B1N4FT ","B1N4FX ","B1N4FY ","B1N4GAM ","B1N4M ","B1N4MM ","B1N4PHI ", & + "B1N4RE ","B1N4SGCAV","B1N4SIGCR","B1N4STVX ","B1N4STVY ","B1N4STVZ ","B1N4THETA","B1N4TNIND", & + "B1N4VDISX","B1N4VDISY","B1N4VDISZ","B1N4VINDX","B1N4VINDY","B1N4VREL ","B1N4VUNDX","B1N4VUNDY", & + "B1N4VUNDZ","B1N5ALPHA","B1N5AXIND","B1N5CD ","B1N5CL ","B1N5CLRNC","B1N5CM ","B1N5CN ", & + "B1N5CPMIN","B1N5CT ","B1N5CURVE","B1N5CX ","B1N5CY ","B1N5DYNP ","B1N5FD ","B1N5FL ", & + "B1N5FN ","B1N5FT ","B1N5FX ","B1N5FY ","B1N5GAM ","B1N5M ","B1N5MM ","B1N5PHI ", & + "B1N5RE ","B1N5SGCAV","B1N5SIGCR","B1N5STVX ","B1N5STVY ","B1N5STVZ ","B1N5THETA","B1N5TNIND", & + "B1N5VDISX","B1N5VDISY","B1N5VDISZ","B1N5VINDX","B1N5VINDY","B1N5VREL ","B1N5VUNDX","B1N5VUNDY", & + "B1N5VUNDZ","B1N6ALPHA","B1N6AXIND","B1N6CD ","B1N6CL ","B1N6CLRNC","B1N6CM ","B1N6CN ", & + "B1N6CPMIN","B1N6CT ","B1N6CURVE","B1N6CX ","B1N6CY ","B1N6DYNP ","B1N6FD ","B1N6FL ", & + "B1N6FN ","B1N6FT ","B1N6FX ","B1N6FY ","B1N6GAM ","B1N6M ","B1N6MM ","B1N6PHI ", & + "B1N6RE ","B1N6SGCAV","B1N6SIGCR","B1N6STVX ","B1N6STVY ","B1N6STVZ ","B1N6THETA","B1N6TNIND", & + "B1N6VDISX","B1N6VDISY","B1N6VDISZ","B1N6VINDX","B1N6VINDY","B1N6VREL ","B1N6VUNDX","B1N6VUNDY", & + "B1N6VUNDZ","B1N7ALPHA","B1N7AXIND","B1N7CD ","B1N7CL ","B1N7CLRNC","B1N7CM ","B1N7CN ", & + "B1N7CPMIN","B1N7CT ","B1N7CURVE","B1N7CX ","B1N7CY ","B1N7DYNP ","B1N7FD ","B1N7FL ", & + "B1N7FN ","B1N7FT ","B1N7FX ","B1N7FY ","B1N7GAM ","B1N7M ","B1N7MM ","B1N7PHI ", & + "B1N7RE ","B1N7SGCAV","B1N7SIGCR","B1N7STVX ","B1N7STVY ","B1N7STVZ ","B1N7THETA","B1N7TNIND", & + "B1N7VDISX","B1N7VDISY","B1N7VDISZ","B1N7VINDX","B1N7VINDY","B1N7VREL ","B1N7VUNDX","B1N7VUNDY", & + "B1N7VUNDZ","B1N8ALPHA","B1N8AXIND","B1N8CD ","B1N8CL ","B1N8CLRNC","B1N8CM ","B1N8CN ", & + "B1N8CPMIN","B1N8CT ","B1N8CURVE","B1N8CX ","B1N8CY ","B1N8DYNP ","B1N8FD ","B1N8FL ", & + "B1N8FN ","B1N8FT ","B1N8FX ","B1N8FY ","B1N8GAM ","B1N8M ","B1N8MM ","B1N8PHI ", & + "B1N8RE ","B1N8SGCAV","B1N8SIGCR","B1N8STVX ","B1N8STVY ","B1N8STVZ ","B1N8THETA","B1N8TNIND", & + "B1N8VDISX","B1N8VDISY","B1N8VDISZ","B1N8VINDX","B1N8VINDY","B1N8VREL ","B1N8VUNDX","B1N8VUNDY", & + "B1N8VUNDZ","B1N9ALPHA","B1N9AXIND","B1N9CD ","B1N9CL ","B1N9CLRNC","B1N9CM ","B1N9CN ", & + "B1N9CPMIN","B1N9CT ","B1N9CURVE","B1N9CX ","B1N9CY ","B1N9DYNP ","B1N9FD ","B1N9FL ", & + "B1N9FN ","B1N9FT ","B1N9FX ","B1N9FY ","B1N9GAM ","B1N9M ","B1N9MM ","B1N9PHI ", & + "B1N9RE ","B1N9SGCAV","B1N9SIGCR","B1N9STVX ","B1N9STVY ","B1N9STVZ ","B1N9THETA","B1N9TNIND", & + "B1N9VDISX","B1N9VDISY","B1N9VDISZ","B1N9VINDX","B1N9VINDY","B1N9VREL ","B1N9VUNDX","B1N9VUNDY", & + "B1N9VUNDZ","B1PITCH ","B2AZIMUTH","B2N1ALPHA","B2N1AXIND","B2N1CD ","B2N1CL ","B2N1CLRNC", & + "B2N1CM ","B2N1CN ","B2N1CPMIN","B2N1CT ","B2N1CURVE","B2N1CX ","B2N1CY ","B2N1DYNP ", & + "B2N1FD ","B2N1FL ","B2N1FN ","B2N1FT ","B2N1FX ","B2N1FY ","B2N1GAM ","B2N1M ", & + "B2N1MM ","B2N1PHI ","B2N1RE ","B2N1SGCAV","B2N1SIGCR","B2N1STVX ","B2N1STVY ","B2N1STVZ ", & + "B2N1THETA","B2N1TNIND","B2N1VDISX","B2N1VDISY","B2N1VDISZ","B2N1VINDX","B2N1VINDY","B2N1VREL ", & + "B2N1VUNDX","B2N1VUNDY","B2N1VUNDZ","B2N2ALPHA","B2N2AXIND","B2N2CD ","B2N2CL ","B2N2CLRNC", & + "B2N2CM ","B2N2CN ","B2N2CPMIN","B2N2CT ","B2N2CURVE","B2N2CX ","B2N2CY ","B2N2DYNP ", & + "B2N2FD ","B2N2FL ","B2N2FN ","B2N2FT ","B2N2FX ","B2N2FY ","B2N2GAM ","B2N2M ", & + "B2N2MM ","B2N2PHI ","B2N2RE ","B2N2SGCAV","B2N2SIGCR","B2N2STVX ","B2N2STVY ","B2N2STVZ ", & + "B2N2THETA","B2N2TNIND","B2N2VDISX","B2N2VDISY","B2N2VDISZ","B2N2VINDX","B2N2VINDY","B2N2VREL ", & + "B2N2VUNDX","B2N2VUNDY","B2N2VUNDZ","B2N3ALPHA","B2N3AXIND","B2N3CD ","B2N3CL ","B2N3CLRNC", & + "B2N3CM ","B2N3CN ","B2N3CPMIN","B2N3CT ","B2N3CURVE","B2N3CX ","B2N3CY ","B2N3DYNP ", & + "B2N3FD ","B2N3FL ","B2N3FN ","B2N3FT ","B2N3FX ","B2N3FY ","B2N3GAM ","B2N3M ", & + "B2N3MM ","B2N3PHI ","B2N3RE ","B2N3SGCAV","B2N3SIGCR","B2N3STVX ","B2N3STVY ","B2N3STVZ ", & + "B2N3THETA","B2N3TNIND","B2N3VDISX","B2N3VDISY","B2N3VDISZ","B2N3VINDX","B2N3VINDY","B2N3VREL ", & + "B2N3VUNDX","B2N3VUNDY","B2N3VUNDZ","B2N4ALPHA","B2N4AXIND","B2N4CD ","B2N4CL ","B2N4CLRNC", & + "B2N4CM ","B2N4CN ","B2N4CPMIN","B2N4CT ","B2N4CURVE","B2N4CX ","B2N4CY ","B2N4DYNP ", & + "B2N4FD ","B2N4FL ","B2N4FN ","B2N4FT ","B2N4FX ","B2N4FY ","B2N4GAM ","B2N4M ", & + "B2N4MM ","B2N4PHI ","B2N4RE ","B2N4SGCAV","B2N4SIGCR","B2N4STVX ","B2N4STVY ","B2N4STVZ ", & + "B2N4THETA","B2N4TNIND","B2N4VDISX","B2N4VDISY","B2N4VDISZ","B2N4VINDX","B2N4VINDY","B2N4VREL ", & + "B2N4VUNDX","B2N4VUNDY","B2N4VUNDZ","B2N5ALPHA","B2N5AXIND","B2N5CD ","B2N5CL ","B2N5CLRNC", & + "B2N5CM ","B2N5CN ","B2N5CPMIN","B2N5CT ","B2N5CURVE","B2N5CX ","B2N5CY ","B2N5DYNP ", & + "B2N5FD ","B2N5FL ","B2N5FN ","B2N5FT ","B2N5FX ","B2N5FY ","B2N5GAM ","B2N5M ", & + "B2N5MM ","B2N5PHI ","B2N5RE ","B2N5SGCAV","B2N5SIGCR","B2N5STVX ","B2N5STVY ","B2N5STVZ ", & + "B2N5THETA","B2N5TNIND","B2N5VDISX","B2N5VDISY","B2N5VDISZ","B2N5VINDX","B2N5VINDY","B2N5VREL ", & + "B2N5VUNDX","B2N5VUNDY","B2N5VUNDZ","B2N6ALPHA","B2N6AXIND","B2N6CD ","B2N6CL ","B2N6CLRNC", & + "B2N6CM ","B2N6CN ","B2N6CPMIN","B2N6CT ","B2N6CURVE","B2N6CX ","B2N6CY ","B2N6DYNP ", & + "B2N6FD ","B2N6FL ","B2N6FN ","B2N6FT ","B2N6FX ","B2N6FY ","B2N6GAM ","B2N6M ", & + "B2N6MM ","B2N6PHI ","B2N6RE ","B2N6SGCAV","B2N6SIGCR","B2N6STVX ","B2N6STVY ","B2N6STVZ ", & + "B2N6THETA","B2N6TNIND","B2N6VDISX","B2N6VDISY","B2N6VDISZ","B2N6VINDX","B2N6VINDY","B2N6VREL ", & + "B2N6VUNDX","B2N6VUNDY","B2N6VUNDZ","B2N7ALPHA","B2N7AXIND","B2N7CD ","B2N7CL ","B2N7CLRNC", & + "B2N7CM ","B2N7CN ","B2N7CPMIN","B2N7CT ","B2N7CURVE","B2N7CX ","B2N7CY ","B2N7DYNP ", & + "B2N7FD ","B2N7FL ","B2N7FN ","B2N7FT ","B2N7FX ","B2N7FY ","B2N7GAM ","B2N7M ", & + "B2N7MM ","B2N7PHI ","B2N7RE ","B2N7SGCAV","B2N7SIGCR","B2N7STVX ","B2N7STVY ","B2N7STVZ ", & + "B2N7THETA","B2N7TNIND","B2N7VDISX","B2N7VDISY","B2N7VDISZ","B2N7VINDX","B2N7VINDY","B2N7VREL ", & + "B2N7VUNDX","B2N7VUNDY","B2N7VUNDZ","B2N8ALPHA","B2N8AXIND","B2N8CD ","B2N8CL ","B2N8CLRNC", & + "B2N8CM ","B2N8CN ","B2N8CPMIN","B2N8CT ","B2N8CURVE","B2N8CX ","B2N8CY ","B2N8DYNP ", & + "B2N8FD ","B2N8FL ","B2N8FN ","B2N8FT ","B2N8FX ","B2N8FY ","B2N8GAM ","B2N8M ", & + "B2N8MM ","B2N8PHI ","B2N8RE ","B2N8SGCAV","B2N8SIGCR","B2N8STVX ","B2N8STVY ","B2N8STVZ ", & + "B2N8THETA","B2N8TNIND","B2N8VDISX","B2N8VDISY","B2N8VDISZ","B2N8VINDX","B2N8VINDY","B2N8VREL ", & + "B2N8VUNDX","B2N8VUNDY","B2N8VUNDZ","B2N9ALPHA","B2N9AXIND","B2N9CD ","B2N9CL ","B2N9CLRNC", & + "B2N9CM ","B2N9CN ","B2N9CPMIN","B2N9CT ","B2N9CURVE","B2N9CX ","B2N9CY ","B2N9DYNP ", & + "B2N9FD ","B2N9FL ","B2N9FN ","B2N9FT ","B2N9FX ","B2N9FY ","B2N9GAM ","B2N9M ", & + "B2N9MM ","B2N9PHI ","B2N9RE ","B2N9SGCAV","B2N9SIGCR","B2N9STVX ","B2N9STVY ","B2N9STVZ ", & + "B2N9THETA","B2N9TNIND","B2N9VDISX","B2N9VDISY","B2N9VDISZ","B2N9VINDX","B2N9VINDY","B2N9VREL ", & + "B2N9VUNDX","B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AZIMUTH","B3N1ALPHA","B3N1AXIND","B3N1CD ", & + "B3N1CL ","B3N1CLRNC","B3N1CM ","B3N1CN ","B3N1CPMIN","B3N1CT ","B3N1CURVE","B3N1CX ", & + "B3N1CY ","B3N1DYNP ","B3N1FD ","B3N1FL ","B3N1FN ","B3N1FT ","B3N1FX ","B3N1FY ", & + "B3N1GAM ","B3N1M ","B3N1MM ","B3N1PHI ","B3N1RE ","B3N1SGCAV","B3N1SIGCR","B3N1STVX ", & + "B3N1STVY ","B3N1STVZ ","B3N1THETA","B3N1TNIND","B3N1VDISX","B3N1VDISY","B3N1VDISZ","B3N1VINDX", & + "B3N1VINDY","B3N1VREL ","B3N1VUNDX","B3N1VUNDY","B3N1VUNDZ","B3N2ALPHA","B3N2AXIND","B3N2CD ", & + "B3N2CL ","B3N2CLRNC","B3N2CM ","B3N2CN ","B3N2CPMIN","B3N2CT ","B3N2CURVE","B3N2CX ", & + "B3N2CY ","B3N2DYNP ","B3N2FD ","B3N2FL ","B3N2FN ","B3N2FT ","B3N2FX ","B3N2FY ", & + "B3N2GAM ","B3N2M ","B3N2MM ","B3N2PHI ","B3N2RE ","B3N2SGCAV","B3N2SIGCR","B3N2STVX ", & + "B3N2STVY ","B3N2STVZ ","B3N2THETA","B3N2TNIND","B3N2VDISX","B3N2VDISY","B3N2VDISZ","B3N2VINDX", & + "B3N2VINDY","B3N2VREL ","B3N2VUNDX","B3N2VUNDY","B3N2VUNDZ","B3N3ALPHA","B3N3AXIND","B3N3CD ", & + "B3N3CL ","B3N3CLRNC","B3N3CM ","B3N3CN ","B3N3CPMIN","B3N3CT ","B3N3CURVE","B3N3CX ", & + "B3N3CY ","B3N3DYNP ","B3N3FD ","B3N3FL ","B3N3FN ","B3N3FT ","B3N3FX ","B3N3FY ", & + "B3N3GAM ","B3N3M ","B3N3MM ","B3N3PHI ","B3N3RE ","B3N3SGCAV","B3N3SIGCR","B3N3STVX ", & + "B3N3STVY ","B3N3STVZ ","B3N3THETA","B3N3TNIND","B3N3VDISX","B3N3VDISY","B3N3VDISZ","B3N3VINDX", & + "B3N3VINDY","B3N3VREL ","B3N3VUNDX","B3N3VUNDY","B3N3VUNDZ","B3N4ALPHA","B3N4AXIND","B3N4CD ", & + "B3N4CL ","B3N4CLRNC","B3N4CM ","B3N4CN ","B3N4CPMIN","B3N4CT ","B3N4CURVE","B3N4CX ", & + "B3N4CY ","B3N4DYNP ","B3N4FD ","B3N4FL ","B3N4FN ","B3N4FT ","B3N4FX ","B3N4FY ", & + "B3N4GAM ","B3N4M ","B3N4MM ","B3N4PHI ","B3N4RE ","B3N4SGCAV","B3N4SIGCR","B3N4STVX ", & + "B3N4STVY ","B3N4STVZ ","B3N4THETA","B3N4TNIND","B3N4VDISX","B3N4VDISY","B3N4VDISZ","B3N4VINDX", & + "B3N4VINDY","B3N4VREL ","B3N4VUNDX","B3N4VUNDY","B3N4VUNDZ","B3N5ALPHA","B3N5AXIND","B3N5CD ", & + "B3N5CL ","B3N5CLRNC","B3N5CM ","B3N5CN ","B3N5CPMIN","B3N5CT ","B3N5CURVE","B3N5CX ", & + "B3N5CY ","B3N5DYNP ","B3N5FD ","B3N5FL ","B3N5FN ","B3N5FT ","B3N5FX ","B3N5FY ", & + "B3N5GAM ","B3N5M ","B3N5MM ","B3N5PHI ","B3N5RE ","B3N5SGCAV","B3N5SIGCR","B3N5STVX ", & + "B3N5STVY ","B3N5STVZ ","B3N5THETA","B3N5TNIND","B3N5VDISX","B3N5VDISY","B3N5VDISZ","B3N5VINDX", & + "B3N5VINDY","B3N5VREL ","B3N5VUNDX","B3N5VUNDY","B3N5VUNDZ","B3N6ALPHA","B3N6AXIND","B3N6CD ", & + "B3N6CL ","B3N6CLRNC","B3N6CM ","B3N6CN ","B3N6CPMIN","B3N6CT ","B3N6CURVE","B3N6CX ", & + "B3N6CY ","B3N6DYNP ","B3N6FD ","B3N6FL ","B3N6FN ","B3N6FT ","B3N6FX ","B3N6FY ", & + "B3N6GAM ","B3N6M ","B3N6MM ","B3N6PHI ","B3N6RE ","B3N6SGCAV","B3N6SIGCR","B3N6STVX ", & + "B3N6STVY ","B3N6STVZ ","B3N6THETA","B3N6TNIND","B3N6VDISX","B3N6VDISY","B3N6VDISZ","B3N6VINDX", & + "B3N6VINDY","B3N6VREL ","B3N6VUNDX","B3N6VUNDY","B3N6VUNDZ","B3N7ALPHA","B3N7AXIND","B3N7CD ", & + "B3N7CL ","B3N7CLRNC","B3N7CM ","B3N7CN ","B3N7CPMIN","B3N7CT ","B3N7CURVE","B3N7CX ", & + "B3N7CY ","B3N7DYNP ","B3N7FD ","B3N7FL ","B3N7FN ","B3N7FT ","B3N7FX ","B3N7FY ", & + "B3N7GAM ","B3N7M ","B3N7MM ","B3N7PHI ","B3N7RE ","B3N7SGCAV","B3N7SIGCR","B3N7STVX ", & + "B3N7STVY ","B3N7STVZ ","B3N7THETA","B3N7TNIND","B3N7VDISX","B3N7VDISY","B3N7VDISZ","B3N7VINDX", & + "B3N7VINDY","B3N7VREL ","B3N7VUNDX","B3N7VUNDY","B3N7VUNDZ","B3N8ALPHA","B3N8AXIND","B3N8CD ", & + "B3N8CL ","B3N8CLRNC","B3N8CM ","B3N8CN ","B3N8CPMIN","B3N8CT ","B3N8CURVE","B3N8CX ", & + "B3N8CY ","B3N8DYNP ","B3N8FD ","B3N8FL ","B3N8FN ","B3N8FT ","B3N8FX ","B3N8FY ", & + "B3N8GAM ","B3N8M ","B3N8MM ","B3N8PHI ","B3N8RE ","B3N8SGCAV","B3N8SIGCR","B3N8STVX ", & + "B3N8STVY ","B3N8STVZ ","B3N8THETA","B3N8TNIND","B3N8VDISX","B3N8VDISY","B3N8VDISZ","B3N8VINDX", & + "B3N8VINDY","B3N8VREL ","B3N8VUNDX","B3N8VUNDY","B3N8VUNDZ","B3N9ALPHA","B3N9AXIND","B3N9CD ", & + "B3N9CL ","B3N9CLRNC","B3N9CM ","B3N9CN ","B3N9CPMIN","B3N9CT ","B3N9CURVE","B3N9CX ", & + "B3N9CY ","B3N9DYNP ","B3N9FD ","B3N9FL ","B3N9FN ","B3N9FT ","B3N9FX ","B3N9FY ", & + "B3N9GAM ","B3N9M ","B3N9MM ","B3N9PHI ","B3N9RE ","B3N9SGCAV","B3N9SIGCR","B3N9STVX ", & + "B3N9STVY ","B3N9STVZ ","B3N9THETA","B3N9TNIND","B3N9VDISX","B3N9VDISY","B3N9VDISZ","B3N9VINDX", & + "B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ","B3PITCH ","DBEMTAU1 ","RTAEROCP ", & + "RTAEROCQ ","RTAEROCT ","RTAEROFXH","RTAEROFYH","RTAEROFZH","RTAEROMXH","RTAEROMYH","RTAEROMZH", & + "RTAEROPWR","RTAREA ","RTSKEW ","RTSPEED ","RTTSR ","RTVAVGXH ","RTVAVGYH ","RTVAVGZH ", & + "TWN1DYNP ","TWN1FDX ","TWN1FDY ","TWN1M ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ", & + "TWN1VREL ","TWN1VUNDX","TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FDX ","TWN2FDY ","TWN2M ", & + "TWN2RE ","TWN2STVX ","TWN2STVY ","TWN2STVZ ","TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ", & + "TWN3DYNP ","TWN3FDX ","TWN3FDY ","TWN3M ","TWN3RE ","TWN3STVX ","TWN3STVY ","TWN3STVZ ", & + "TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ","TWN4DYNP ","TWN4FDX ","TWN4FDY ","TWN4M ", & + "TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ","TWN4VUNDX","TWN4VUNDY","TWN4VUNDZ", & + "TWN5DYNP ","TWN5FDX ","TWN5FDY ","TWN5M ","TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ", & + "TWN5VREL ","TWN5VUNDX","TWN5VUNDY","TWN5VUNDZ","TWN6DYNP ","TWN6FDX ","TWN6FDY ","TWN6M ", & + "TWN6RE ","TWN6STVX ","TWN6STVY ","TWN6STVZ ","TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ", & + "TWN7DYNP ","TWN7FDX ","TWN7FDY ","TWN7M ","TWN7RE ","TWN7STVX ","TWN7STVY ","TWN7STVZ ", & + "TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ","TWN8DYNP ","TWN8FDX ","TWN8FDY ","TWN8M ", & + "TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX","TWN8VUNDY","TWN8VUNDZ", & + "TWN9DYNP ","TWN9FDX ","TWN9FDY ","TWN9M ","TWN9RE ","TWN9STVX ","TWN9STVY ","TWN9STVZ ", & + "TWN9VREL ","TWN9VUNDX","TWN9VUNDY","TWN9VUNDZ"/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(1212) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + B1Azimuth , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , B1N1Cm , B1N1Cn , & + B1N1Cpmin , B1N1Ct , B1N1Curve , B1N1Cx , B1N1Cy , B1N1DynP , B1N1Fd , B1N1Fl , & + B1N1Fn , B1N1Ft , B1N1Fx , B1N1Fy , B1N1Gam , B1N1M , B1N1Mm , B1N1Phi , & + B1N1Re , B1N1SgCav , B1N1SigCr , B1N1STVx , B1N1STVy , B1N1STVz , B1N1Theta , B1N1TnInd , & + B1N1VDisx , B1N1VDisy , B1N1VDisz , B1N1Vindx , B1N1Vindy , B1N1VRel , B1N1VUndx , B1N1VUndy , & + B1N1VUndz , B1N2Alpha , B1N2AxInd , B1N2Cd , B1N2Cl , B1N2Clrnc , B1N2Cm , B1N2Cn , & + B1N2Cpmin , B1N2Ct , B1N2Curve , B1N2Cx , B1N2Cy , B1N2DynP , B1N2Fd , B1N2Fl , & + B1N2Fn , B1N2Ft , B1N2Fx , B1N2Fy , B1N2Gam , B1N2M , B1N2Mm , B1N2Phi , & + B1N2Re , B1N2SgCav , B1N2SigCr , B1N2STVx , B1N2STVy , B1N2STVz , B1N2Theta , B1N2TnInd , & + B1N2VDisx , B1N2VDisy , B1N2VDisz , B1N2Vindx , B1N2Vindy , B1N2VRel , B1N2VUndx , B1N2VUndy , & + B1N2VUndz , B1N3Alpha , B1N3AxInd , B1N3Cd , B1N3Cl , B1N3Clrnc , B1N3Cm , B1N3Cn , & + B1N3Cpmin , B1N3Ct , B1N3Curve , B1N3Cx , B1N3Cy , B1N3DynP , B1N3Fd , B1N3Fl , & + B1N3Fn , B1N3Ft , B1N3Fx , B1N3Fy , B1N3Gam , B1N3M , B1N3Mm , B1N3Phi , & + B1N3Re , B1N3SgCav , B1N3SigCr , B1N3STVx , B1N3STVy , B1N3STVz , B1N3Theta , B1N3TnInd , & + B1N3VDisx , B1N3VDisy , B1N3VDisz , B1N3Vindx , B1N3Vindy , B1N3VRel , B1N3VUndx , B1N3VUndy , & + B1N3VUndz , B1N4Alpha , B1N4AxInd , B1N4Cd , B1N4Cl , B1N4Clrnc , B1N4Cm , B1N4Cn , & + B1N4Cpmin , B1N4Ct , B1N4Curve , B1N4Cx , B1N4Cy , B1N4DynP , B1N4Fd , B1N4Fl , & + B1N4Fn , B1N4Ft , B1N4Fx , B1N4Fy , B1N4Gam , B1N4M , B1N4Mm , B1N4Phi , & + B1N4Re , B1N4SgCav , B1N4SigCr , B1N4STVx , B1N4STVy , B1N4STVz , B1N4Theta , B1N4TnInd , & + B1N4VDisx , B1N4VDisy , B1N4VDisz , B1N4Vindx , B1N4Vindy , B1N4VRel , B1N4VUndx , B1N4VUndy , & + B1N4VUndz , B1N5Alpha , B1N5AxInd , B1N5Cd , B1N5Cl , B1N5Clrnc , B1N5Cm , B1N5Cn , & + B1N5Cpmin , B1N5Ct , B1N5Curve , B1N5Cx , B1N5Cy , B1N5DynP , B1N5Fd , B1N5Fl , & + B1N5Fn , B1N5Ft , B1N5Fx , B1N5Fy , B1N5Gam , B1N5M , B1N5Mm , B1N5Phi , & + B1N5Re , B1N5SgCav , B1N5SigCr , B1N5STVx , B1N5STVy , B1N5STVz , B1N5Theta , B1N5TnInd , & + B1N5VDisx , B1N5VDisy , B1N5VDisz , B1N5Vindx , B1N5Vindy , B1N5VRel , B1N5VUndx , B1N5VUndy , & + B1N5VUndz , B1N6Alpha , B1N6AxInd , B1N6Cd , B1N6Cl , B1N6Clrnc , B1N6Cm , B1N6Cn , & + B1N6Cpmin , B1N6Ct , B1N6Curve , B1N6Cx , B1N6Cy , B1N6DynP , B1N6Fd , B1N6Fl , & + B1N6Fn , B1N6Ft , B1N6Fx , B1N6Fy , B1N6Gam , B1N6M , B1N6Mm , B1N6Phi , & + B1N6Re , B1N6SgCav , B1N6SigCr , B1N6STVx , B1N6STVy , B1N6STVz , B1N6Theta , B1N6TnInd , & + B1N6VDisx , B1N6VDisy , B1N6VDisz , B1N6Vindx , B1N6Vindy , B1N6VRel , B1N6VUndx , B1N6VUndy , & + B1N6VUndz , B1N7Alpha , B1N7AxInd , B1N7Cd , B1N7Cl , B1N7Clrnc , B1N7Cm , B1N7Cn , & + B1N7Cpmin , B1N7Ct , B1N7Curve , B1N7Cx , B1N7Cy , B1N7DynP , B1N7Fd , B1N7Fl , & + B1N7Fn , B1N7Ft , B1N7Fx , B1N7Fy , B1N7Gam , B1N7M , B1N7Mm , B1N7Phi , & + B1N7Re , B1N7SgCav , B1N7SigCr , B1N7STVx , B1N7STVy , B1N7STVz , B1N7Theta , B1N7TnInd , & + B1N7VDisx , B1N7VDisy , B1N7VDisz , B1N7Vindx , B1N7Vindy , B1N7VRel , B1N7VUndx , B1N7VUndy , & + B1N7VUndz , B1N8Alpha , B1N8AxInd , B1N8Cd , B1N8Cl , B1N8Clrnc , B1N8Cm , B1N8Cn , & + B1N8Cpmin , B1N8Ct , B1N8Curve , B1N8Cx , B1N8Cy , B1N8DynP , B1N8Fd , B1N8Fl , & + B1N8Fn , B1N8Ft , B1N8Fx , B1N8Fy , B1N8Gam , B1N8M , B1N8Mm , B1N8Phi , & + B1N8Re , B1N8SgCav , B1N8SigCr , B1N8STVx , B1N8STVy , B1N8STVz , B1N8Theta , B1N8TnInd , & + B1N8VDisx , B1N8VDisy , B1N8VDisz , B1N8Vindx , B1N8Vindy , B1N8VRel , B1N8VUndx , B1N8VUndy , & + B1N8VUndz , B1N9Alpha , B1N9AxInd , B1N9Cd , B1N9Cl , B1N9Clrnc , B1N9Cm , B1N9Cn , & + B1N9Cpmin , B1N9Ct , B1N9Curve , B1N9Cx , B1N9Cy , B1N9DynP , B1N9Fd , B1N9Fl , & + B1N9Fn , B1N9Ft , B1N9Fx , B1N9Fy , B1N9Gam , B1N9M , B1N9Mm , B1N9Phi , & + B1N9Re , B1N9SgCav , B1N9SigCr , B1N9STVx , B1N9STVy , B1N9STVz , B1N9Theta , B1N9TnInd , & + B1N9VDisx , B1N9VDisy , B1N9VDisz , B1N9Vindx , B1N9Vindy , B1N9VRel , B1N9VUndx , B1N9VUndy , & + B1N9VUndz , B1Pitch , B2Azimuth , B2N1Alpha , B2N1AxInd , B2N1Cd , B2N1Cl , B2N1Clrnc , & + B2N1Cm , B2N1Cn , B2N1Cpmin , B2N1Ct , B2N1Curve , B2N1Cx , B2N1Cy , B2N1DynP , & + B2N1Fd , B2N1Fl , B2N1Fn , B2N1Ft , B2N1Fx , B2N1Fy , B2N1Gam , B2N1M , & + B2N1Mm , B2N1Phi , B2N1Re , B2N1SgCav , B2N1SigCr , B2N1STVx , B2N1STVy , B2N1STVz , & + B2N1Theta , B2N1TnInd , B2N1VDisx , B2N1VDisy , B2N1VDisz , B2N1Vindx , B2N1Vindy , B2N1VRel , & + B2N1VUndx , B2N1VUndy , B2N1VUndz , B2N2Alpha , B2N2AxInd , B2N2Cd , B2N2Cl , B2N2Clrnc , & + B2N2Cm , B2N2Cn , B2N2Cpmin , B2N2Ct , B2N2Curve , B2N2Cx , B2N2Cy , B2N2DynP , & + B2N2Fd , B2N2Fl , B2N2Fn , B2N2Ft , B2N2Fx , B2N2Fy , B2N2Gam , B2N2M , & + B2N2Mm , B2N2Phi , B2N2Re , B2N2SgCav , B2N2SigCr , B2N2STVx , B2N2STVy , B2N2STVz , & + B2N2Theta , B2N2TnInd , B2N2VDisx , B2N2VDisy , B2N2VDisz , B2N2Vindx , B2N2Vindy , B2N2VRel , & + B2N2VUndx , B2N2VUndy , B2N2VUndz , B2N3Alpha , B2N3AxInd , B2N3Cd , B2N3Cl , B2N3Clrnc , & + B2N3Cm , B2N3Cn , B2N3Cpmin , B2N3Ct , B2N3Curve , B2N3Cx , B2N3Cy , B2N3DynP , & + B2N3Fd , B2N3Fl , B2N3Fn , B2N3Ft , B2N3Fx , B2N3Fy , B2N3Gam , B2N3M , & + B2N3Mm , B2N3Phi , B2N3Re , B2N3SgCav , B2N3SigCr , B2N3STVx , B2N3STVy , B2N3STVz , & + B2N3Theta , B2N3TnInd , B2N3VDisx , B2N3VDisy , B2N3VDisz , B2N3Vindx , B2N3Vindy , B2N3VRel , & + B2N3VUndx , B2N3VUndy , B2N3VUndz , B2N4Alpha , B2N4AxInd , B2N4Cd , B2N4Cl , B2N4Clrnc , & + B2N4Cm , B2N4Cn , B2N4Cpmin , B2N4Ct , B2N4Curve , B2N4Cx , B2N4Cy , B2N4DynP , & + B2N4Fd , B2N4Fl , B2N4Fn , B2N4Ft , B2N4Fx , B2N4Fy , B2N4Gam , B2N4M , & + B2N4Mm , B2N4Phi , B2N4Re , B2N4SgCav , B2N4SigCr , B2N4STVx , B2N4STVy , B2N4STVz , & + B2N4Theta , B2N4TnInd , B2N4VDisx , B2N4VDisy , B2N4VDisz , B2N4Vindx , B2N4Vindy , B2N4VRel , & + B2N4VUndx , B2N4VUndy , B2N4VUndz , B2N5Alpha , B2N5AxInd , B2N5Cd , B2N5Cl , B2N5Clrnc , & + B2N5Cm , B2N5Cn , B2N5Cpmin , B2N5Ct , B2N5Curve , B2N5Cx , B2N5Cy , B2N5DynP , & + B2N5Fd , B2N5Fl , B2N5Fn , B2N5Ft , B2N5Fx , B2N5Fy , B2N5Gam , B2N5M , & + B2N5Mm , B2N5Phi , B2N5Re , B2N5SgCav , B2N5SigCr , B2N5STVx , B2N5STVy , B2N5STVz , & + B2N5Theta , B2N5TnInd , B2N5VDisx , B2N5VDisy , B2N5VDisz , B2N5Vindx , B2N5Vindy , B2N5VRel , & + B2N5VUndx , B2N5VUndy , B2N5VUndz , B2N6Alpha , B2N6AxInd , B2N6Cd , B2N6Cl , B2N6Clrnc , & + B2N6Cm , B2N6Cn , B2N6Cpmin , B2N6Ct , B2N6Curve , B2N6Cx , B2N6Cy , B2N6DynP , & + B2N6Fd , B2N6Fl , B2N6Fn , B2N6Ft , B2N6Fx , B2N6Fy , B2N6Gam , B2N6M , & + B2N6Mm , B2N6Phi , B2N6Re , B2N6SgCav , B2N6SigCr , B2N6STVx , B2N6STVy , B2N6STVz , & + B2N6Theta , B2N6TnInd , B2N6VDisx , B2N6VDisy , B2N6VDisz , B2N6Vindx , B2N6Vindy , B2N6VRel , & + B2N6VUndx , B2N6VUndy , B2N6VUndz , B2N7Alpha , B2N7AxInd , B2N7Cd , B2N7Cl , B2N7Clrnc , & + B2N7Cm , B2N7Cn , B2N7Cpmin , B2N7Ct , B2N7Curve , B2N7Cx , B2N7Cy , B2N7DynP , & + B2N7Fd , B2N7Fl , B2N7Fn , B2N7Ft , B2N7Fx , B2N7Fy , B2N7Gam , B2N7M , & + B2N7Mm , B2N7Phi , B2N7Re , B2N7SgCav , B2N7SigCr , B2N7STVx , B2N7STVy , B2N7STVz , & + B2N7Theta , B2N7TnInd , B2N7VDisx , B2N7VDisy , B2N7VDisz , B2N7Vindx , B2N7Vindy , B2N7VRel , & + B2N7VUndx , B2N7VUndy , B2N7VUndz , B2N8Alpha , B2N8AxInd , B2N8Cd , B2N8Cl , B2N8Clrnc , & + B2N8Cm , B2N8Cn , B2N8Cpmin , B2N8Ct , B2N8Curve , B2N8Cx , B2N8Cy , B2N8DynP , & + B2N8Fd , B2N8Fl , B2N8Fn , B2N8Ft , B2N8Fx , B2N8Fy , B2N8Gam , B2N8M , & + B2N8Mm , B2N8Phi , B2N8Re , B2N8SgCav , B2N8SigCr , B2N8STVx , B2N8STVy , B2N8STVz , & + B2N8Theta , B2N8TnInd , B2N8VDisx , B2N8VDisy , B2N8VDisz , B2N8Vindx , B2N8Vindy , B2N8VRel , & + B2N8VUndx , B2N8VUndy , B2N8VUndz , B2N9Alpha , B2N9AxInd , B2N9Cd , B2N9Cl , B2N9Clrnc , & + B2N9Cm , B2N9Cn , B2N9Cpmin , B2N9Ct , B2N9Curve , B2N9Cx , B2N9Cy , B2N9DynP , & + B2N9Fd , B2N9Fl , B2N9Fn , B2N9Ft , B2N9Fx , B2N9Fy , B2N9Gam , B2N9M , & + B2N9Mm , B2N9Phi , B2N9Re , B2N9SgCav , B2N9SigCr , B2N9STVx , B2N9STVy , B2N9STVz , & + B2N9Theta , B2N9TnInd , B2N9VDisx , B2N9VDisy , B2N9VDisz , B2N9Vindx , B2N9Vindy , B2N9VRel , & + B2N9VUndx , B2N9VUndy , B2N9VUndz , B2Pitch , B3Azimuth , B3N1Alpha , B3N1AxInd , B3N1Cd , & + B3N1Cl , B3N1Clrnc , B3N1Cm , B3N1Cn , B3N1Cpmin , B3N1Ct , B3N1Curve , B3N1Cx , & + B3N1Cy , B3N1DynP , B3N1Fd , B3N1Fl , B3N1Fn , B3N1Ft , B3N1Fx , B3N1Fy , & + B3N1Gam , B3N1M , B3N1Mm , B3N1Phi , B3N1Re , B3N1SgCav , B3N1SigCr , B3N1STVx , & + B3N1STVy , B3N1STVz , B3N1Theta , B3N1TnInd , B3N1VDisx , B3N1VDisy , B3N1VDisz , B3N1Vindx , & + B3N1Vindy , B3N1VRel , B3N1VUndx , B3N1VUndy , B3N1VUndz , B3N2Alpha , B3N2AxInd , B3N2Cd , & + B3N2Cl , B3N2Clrnc , B3N2Cm , B3N2Cn , B3N2Cpmin , B3N2Ct , B3N2Curve , B3N2Cx , & + B3N2Cy , B3N2DynP , B3N2Fd , B3N2Fl , B3N2Fn , B3N2Ft , B3N2Fx , B3N2Fy , & + B3N2Gam , B3N2M , B3N2Mm , B3N2Phi , B3N2Re , B3N2SgCav , B3N2SigCr , B3N2STVx , & + B3N2STVy , B3N2STVz , B3N2Theta , B3N2TnInd , B3N2VDisx , B3N2VDisy , B3N2VDisz , B3N2Vindx , & + B3N2Vindy , B3N2VRel , B3N2VUndx , B3N2VUndy , B3N2VUndz , B3N3Alpha , B3N3AxInd , B3N3Cd , & + B3N3Cl , B3N3Clrnc , B3N3Cm , B3N3Cn , B3N3Cpmin , B3N3Ct , B3N3Curve , B3N3Cx , & + B3N3Cy , B3N3DynP , B3N3Fd , B3N3Fl , B3N3Fn , B3N3Ft , B3N3Fx , B3N3Fy , & + B3N3Gam , B3N3M , B3N3Mm , B3N3Phi , B3N3Re , B3N3SgCav , B3N3SigCr , B3N3STVx , & + B3N3STVy , B3N3STVz , B3N3Theta , B3N3TnInd , B3N3VDisx , B3N3VDisy , B3N3VDisz , B3N3Vindx , & + B3N3Vindy , B3N3VRel , B3N3VUndx , B3N3VUndy , B3N3VUndz , B3N4Alpha , B3N4AxInd , B3N4Cd , & + B3N4Cl , B3N4Clrnc , B3N4Cm , B3N4Cn , B3N4Cpmin , B3N4Ct , B3N4Curve , B3N4Cx , & + B3N4Cy , B3N4DynP , B3N4Fd , B3N4Fl , B3N4Fn , B3N4Ft , B3N4Fx , B3N4Fy , & + B3N4Gam , B3N4M , B3N4Mm , B3N4Phi , B3N4Re , B3N4SgCav , B3N4SigCr , B3N4STVx , & + B3N4STVy , B3N4STVz , B3N4Theta , B3N4TnInd , B3N4VDisx , B3N4VDisy , B3N4VDisz , B3N4Vindx , & + B3N4Vindy , B3N4VRel , B3N4VUndx , B3N4VUndy , B3N4VUndz , B3N5Alpha , B3N5AxInd , B3N5Cd , & + B3N5Cl , B3N5Clrnc , B3N5Cm , B3N5Cn , B3N5Cpmin , B3N5Ct , B3N5Curve , B3N5Cx , & + B3N5Cy , B3N5DynP , B3N5Fd , B3N5Fl , B3N5Fn , B3N5Ft , B3N5Fx , B3N5Fy , & + B3N5Gam , B3N5M , B3N5Mm , B3N5Phi , B3N5Re , B3N5SgCav , B3N5SigCr , B3N5STVx , & + B3N5STVy , B3N5STVz , B3N5Theta , B3N5TnInd , B3N5VDisx , B3N5VDisy , B3N5VDisz , B3N5Vindx , & + B3N5Vindy , B3N5VRel , B3N5VUndx , B3N5VUndy , B3N5VUndz , B3N6Alpha , B3N6AxInd , B3N6Cd , & + B3N6Cl , B3N6Clrnc , B3N6Cm , B3N6Cn , B3N6Cpmin , B3N6Ct , B3N6Curve , B3N6Cx , & + B3N6Cy , B3N6DynP , B3N6Fd , B3N6Fl , B3N6Fn , B3N6Ft , B3N6Fx , B3N6Fy , & + B3N6Gam , B3N6M , B3N6Mm , B3N6Phi , B3N6Re , B3N6SgCav , B3N6SigCr , B3N6STVx , & + B3N6STVy , B3N6STVz , B3N6Theta , B3N6TnInd , B3N6VDisx , B3N6VDisy , B3N6VDisz , B3N6Vindx , & + B3N6Vindy , B3N6VRel , B3N6VUndx , B3N6VUndy , B3N6VUndz , B3N7Alpha , B3N7AxInd , B3N7Cd , & + B3N7Cl , B3N7Clrnc , B3N7Cm , B3N7Cn , B3N7Cpmin , B3N7Ct , B3N7Curve , B3N7Cx , & + B3N7Cy , B3N7DynP , B3N7Fd , B3N7Fl , B3N7Fn , B3N7Ft , B3N7Fx , B3N7Fy , & + B3N7Gam , B3N7M , B3N7Mm , B3N7Phi , B3N7Re , B3N7SgCav , B3N7SigCr , B3N7STVx , & + B3N7STVy , B3N7STVz , B3N7Theta , B3N7TnInd , B3N7VDisx , B3N7VDisy , B3N7VDisz , B3N7Vindx , & + B3N7Vindy , B3N7VRel , B3N7VUndx , B3N7VUndy , B3N7VUndz , B3N8Alpha , B3N8AxInd , B3N8Cd , & + B3N8Cl , B3N8Clrnc , B3N8Cm , B3N8Cn , B3N8Cpmin , B3N8Ct , B3N8Curve , B3N8Cx , & + B3N8Cy , B3N8DynP , B3N8Fd , B3N8Fl , B3N8Fn , B3N8Ft , B3N8Fx , B3N8Fy , & + B3N8Gam , B3N8M , B3N8Mm , B3N8Phi , B3N8Re , B3N8SgCav , B3N8SigCr , B3N8STVx , & + B3N8STVy , B3N8STVz , B3N8Theta , B3N8TnInd , B3N8VDisx , B3N8VDisy , B3N8VDisz , B3N8Vindx , & + B3N8Vindy , B3N8VRel , B3N8VUndx , B3N8VUndy , B3N8VUndz , B3N9Alpha , B3N9AxInd , B3N9Cd , & + B3N9Cl , B3N9Clrnc , B3N9Cm , B3N9Cn , B3N9Cpmin , B3N9Ct , B3N9Curve , B3N9Cx , & + B3N9Cy , B3N9DynP , B3N9Fd , B3N9Fl , B3N9Fn , B3N9Ft , B3N9Fx , B3N9Fy , & + B3N9Gam , B3N9M , B3N9Mm , B3N9Phi , B3N9Re , B3N9SgCav , B3N9SigCr , B3N9STVx , & + B3N9STVy , B3N9STVz , B3N9Theta , B3N9TnInd , B3N9VDisx , B3N9VDisy , B3N9VDisz , B3N9Vindx , & + B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , B3Pitch , DBEMTau1 , RtAeroCp , & + RtAeroCq , RtAeroCt , RtAeroFxh , RtAeroFyh , RtAeroFzh , RtAeroMxh , RtAeroMyh , RtAeroMzh , & + RtAeroPwr , RtArea , RtSkew , RtSpeed , RtTSR , RtVAvgxh , RtVAvgyh , RtVAvgzh , & + TwN1DynP , TwN1Fdx , TwN1Fdy , TwN1M , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , & + TwN1Vrel , TwN1VUndx , TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fdx , TwN2Fdy , TwN2M , & + TwN2Re , TwN2STVx , TwN2STVy , TwN2STVz , TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , & + TwN3DynP , TwN3Fdx , TwN3Fdy , TwN3M , TwN3Re , TwN3STVx , TwN3STVy , TwN3STVz , & + TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , TwN4DynP , TwN4Fdx , TwN4Fdy , TwN4M , & + TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , TwN4VUndx , TwN4VUndy , TwN4VUndz , & + TwN5DynP , TwN5Fdx , TwN5Fdy , TwN5M , TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , & + TwN5Vrel , TwN5VUndx , TwN5VUndy , TwN5VUndz , TwN6DynP , TwN6Fdx , TwN6Fdy , TwN6M , & + TwN6Re , TwN6STVx , TwN6STVy , TwN6STVz , TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , & + TwN7DynP , TwN7Fdx , TwN7Fdy , TwN7M , TwN7Re , TwN7STVx , TwN7STVy , TwN7STVz , & + TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , TwN8DynP , TwN8Fdx , TwN8Fdy , TwN8M , & + TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , TwN8VUndy , TwN8VUndz , & + TwN9DynP , TwN9Fdx , TwN9Fdy , TwN9M , TwN9Re , TwN9STVx , TwN9STVy , TwN9STVz , & + TwN9Vrel , TwN9VUndx , TwN9VUndy , TwN9VUndz /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1212) = (/ & ! This lists the units corresponding to the allowed parameters + "(deg) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & + "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ","(N-m/m)","(deg) ", & + "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(deg) ","(deg) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(-) ","(m) ", & + "(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(-) ", & + "(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(deg) ","(deg) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ", & + "(-) ","(m) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ", & + "(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(m^2/s)","(-) ","(N-m/m)","(deg) ","(-) ","(-) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(s) ","(-) ", & + "(-) ","(-) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ", & + "(W) ","(m^2) ","(deg) ","(rpm) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ", & + "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ", & + "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ", & + "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(-) ", & + "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) "/) ! Initialize values @@ -3560,15 +3504,15 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) if ( p%TwrPotent == TwrPotent_none .and. .not. p%TwrShadow ) then ! BNClrnc is set only when we're computing the tower influence - do I = 1,MaxBl ! all blades (need to do this in a loop because we need the index of InvalidOutput to be an array of rank one) + do i = 1,size(BNClrnc,2) ! all blades (need to do this in a loop because we need the index of InvalidOutput to be an array of rank one) InvalidOutput( BNClrnc(:,i) ) = .true. end do end if - !if (p%WakeMod /= WakeMod_DBEMT) then - ! InvalidOutput( DBEMTau1 ) = .true. - !end if + if (p%WakeMod /= WakeMod_DBEMT) then + InvalidOutput( DBEMTau1 ) = .true. + end if DO i = p%NTwOuts+1,9 ! Invalid tower nodes @@ -3583,7 +3527,7 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) END DO - DO I = p%NumBlades+1,MaxBl ! Invalid blades + DO I = p%NumBlades+1,size(BAzimuth,1) ! Invalid blades InvalidOutput( BAzimuth( i) ) = .true. InvalidOutput( BPitch( i) ) = .true. @@ -3738,15 +3682,16 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) IF ( Indx > 0 ) THEN ! we found the channel name - p%OutParam(I)%Indx = ParamIndxAry(Indx) IF ( InvalidOutput( ParamIndxAry(Indx) ) ) THEN ! but, it isn't valid for these settings + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) p%OutParam(I)%Units = "INVALID" p%OutParam(I)%SignM = 0 ELSE + p%OutParam(I)%Indx = ParamIndxAry(Indx) p%OutParam(I)%Units = ParamUnitsAry(Indx) ! it's a valid output END IF ELSE ! this channel isn't valid - p%OutParam(I)%Indx = Time ! pick any valid channel (I just picked "Time" here because it's universal) + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) p%OutParam(I)%Units = "INVALID" p%OutParam(I)%SignM = 0 ! multiply all results by zero diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 3d4b03171b..563b6cf202 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -22,8 +22,10 @@ param ^ - IntKi WakeMod_none - 0 - "Wake model param ^ - IntKi WakeMod_BEMT - 1 - "Wake model - BEMT (blade elememnt momentum theory)" - param ^ - IntKi WakeMod_DBEMT - 2 - "Wake model - DBEMT (dynamic elememnt momentum theory)" - param ^ - IntKi WakeMod_FVW - 3 - "Wake model - FVW (free vortex wake, OLAF)" - + param ^ - IntKi AFAeroMod_steady - 1 - "steady model" - param ^ - IntKi AFAeroMod_BL_unsteady - 2 - "Beddoes-Leishman unsteady model" - + param ^ - IntKi TwrPotent_none - 0 - "no tower potential flow" - param ^ - IntKi TwrPotent_baseline - 1 - "baseline tower potential flow" - param ^ - IntKi TwrPotent_Bak - 2 - "tower potential flow with Bak correction" - @@ -61,13 +63,14 @@ typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and da typedef ^ InitOutputType ReKi AirDens - - - "Air density" kg/m^3 typedef ^ InitOutputType AD_BladeShape BladeShape {:} - - "airfoil coordinates for each blade" m typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_y {:} - - "Names of the outputs used in linearization" - -typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_z {:} - - "Names of the constraint states used in linearization" - +typedef ^ InitOutputType CHARACTER(LinChanLen) LinNames_x {:} - - "Names of the continuous 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_z {:} - - "Flag that tells FAST/MBC3 if the constraint states used in linearization are in the rotating frame (not used for glue)" - +typedef ^ InitOutputType LOGICAL RotFrame_x {:} - - "Flag that tells FAST/MBC3 if the continuous states used in linearization are in the rotating frame (not used for glue)" - 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 AD_BladePropsType BladeProps {:} - - "blade property information from blade input files" - +typedef ^ InitOutputType IntKi DerivOrder_x {:} - - "Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization" - typedef ^ InitOutputType ReKi TwrElev {:} - - "Elevation at tower node" m typedef ^ InitOutputType ReKi TwrDiam {:} - - "Diameter of tower at node" m @@ -124,7 +127,7 @@ typedef ^ AD_InputFile IntKi NTwOuts - - - "Number of tower node outputs [0 - 9] typedef ^ AD_InputFile IntKi TwOutNd {9} - - "Tower nodes whose values will be output" - typedef ^ AD_InputFile IntKi NumOuts - - - "Number of parameters in the output list (number of outputs requested)" - typedef ^ AD_InputFile CHARACTER(ChanLen) OutList {:} - - "List of user-requested output channels" - -typedef ^ AD_InputFile ReKi tau1_const - - - "time constant for DBEMT [used only when WakeMod=2 and DBEMT_Mod=1]" s +typedef ^ AD_InputFile ReKi tau1_const - - - "time constant for DBEMT [used only when WakeMod=2 and DBEMT_Mod/=2]" s typedef ^ AD_InputFile IntKi DBEMT_Mod - - - "Type of dynamic BEMT (DBEMT) model {1=constant tau1, 2=time-dependent tau1}" - typedef ^ AD_InputFile IntKi BldNd_NumOuts - - - "Number of requested output channels per blade node (AD_AllBldNdOuts)" - typedef ^ AD_InputFile CHARACTER(ChanLen) BldNd_OutList {:} - - "List of user-requested output channels (AD_AllBldNdOuts)" - @@ -231,6 +234,7 @@ typedef ^ ParameterType IntKi BldNd_BladesOut - - - "The blades to output (AD typedef ^ ParameterType Integer Jac_u_indx {:}{:} - - "matrix to help fill/pack the u vector in computing the jacobian" - typedef ^ ParameterType ReKi 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_ny - - - "number of outputs in jacobian matrix" - # ..... Inputs .................................................................................................................... diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index a080196219..28487fc89c 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -87,13 +87,14 @@ MODULE AeroDyn_Types REAL(ReKi) :: AirDens !< Air density [kg/m^3] TYPE(AD_BladeShape) , DIMENSION(:), ALLOCATABLE :: BladeShape !< airfoil coordinates for each blade [m] CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_y !< Names of the outputs used in linearization [-] - CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_z !< Names of the constraint states used in linearization [-] + CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_x !< Names of the continuous states used in linearization [-] CHARACTER(LinChanLen) , DIMENSION(:), ALLOCATABLE :: LinNames_u !< Names of the inputs used in linearization [-] LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_y !< Flag that tells FAST/MBC3 if the outputs used in linearization are in the rotating frame [-] - LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_z !< Flag that tells FAST/MBC3 if the constraint states used in linearization are in the rotating frame (not used for glue) [-] + LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_x !< Flag that tells FAST/MBC3 if the continuous states used in linearization are in the rotating frame (not used for glue) [-] 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) [-] TYPE(AD_BladePropsType) , DIMENSION(:), ALLOCATABLE :: BladeProps !< blade property information from blade input files [-] + INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: DerivOrder_x !< Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrElev !< Elevation at tower node [m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrDiam !< Diameter of tower at node [m] END TYPE AD_InitOutputType @@ -149,7 +150,7 @@ MODULE AeroDyn_Types INTEGER(IntKi) , DIMENSION(1:9) :: TwOutNd !< Tower nodes whose values will be output [-] INTEGER(IntKi) :: NumOuts !< Number of parameters in the output list (number of outputs requested) [-] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< List of user-requested output channels [-] - REAL(ReKi) :: tau1_const !< time constant for DBEMT [used only when WakeMod=2 and DBEMT_Mod=1] [s] + REAL(ReKi) :: tau1_const !< time constant for DBEMT [used only when WakeMod=2 and DBEMT_Mod/=2] [s] INTEGER(IntKi) :: DBEMT_Mod !< Type of dynamic BEMT (DBEMT) model {1=constant tau1, 2=time-dependent tau1} [-] INTEGER(IntKi) :: BldNd_NumOuts !< Number of requested output channels per blade node (AD_AllBldNdOuts) [-] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: BldNd_OutList !< List of user-requested output channels (AD_AllBldNdOuts) [-] @@ -258,6 +259,7 @@ MODULE AeroDyn_Types INTEGER(IntKi) :: BldNd_BladesOut !< The blades to output (AD_AllBldNdOuts) [-] INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: Jac_u_indx !< matrix to help fill/pack the u vector in computing the jacobian [-] REAL(ReKi) , 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_ny !< number of outputs in jacobian matrix [-] END TYPE AD_ParameterType ! ======================= @@ -1389,17 +1391,17 @@ SUBROUTINE AD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, Er END IF DstInitOutputData%LinNames_y = SrcInitOutputData%LinNames_y ENDIF -IF (ALLOCATED(SrcInitOutputData%LinNames_z)) THEN - i1_l = LBOUND(SrcInitOutputData%LinNames_z,1) - i1_u = UBOUND(SrcInitOutputData%LinNames_z,1) - IF (.NOT. ALLOCATED(DstInitOutputData%LinNames_z)) THEN - ALLOCATE(DstInitOutputData%LinNames_z(i1_l:i1_u),STAT=ErrStat2) +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_z.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%LinNames_x.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInitOutputData%LinNames_z = SrcInitOutputData%LinNames_z + DstInitOutputData%LinNames_x = SrcInitOutputData%LinNames_x ENDIF IF (ALLOCATED(SrcInitOutputData%LinNames_u)) THEN i1_l = LBOUND(SrcInitOutputData%LinNames_u,1) @@ -1425,17 +1427,17 @@ SUBROUTINE AD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, Er END IF DstInitOutputData%RotFrame_y = SrcInitOutputData%RotFrame_y ENDIF -IF (ALLOCATED(SrcInitOutputData%RotFrame_z)) THEN - i1_l = LBOUND(SrcInitOutputData%RotFrame_z,1) - i1_u = UBOUND(SrcInitOutputData%RotFrame_z,1) - IF (.NOT. ALLOCATED(DstInitOutputData%RotFrame_z)) THEN - ALLOCATE(DstInitOutputData%RotFrame_z(i1_l:i1_u),STAT=ErrStat2) +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_z.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%RotFrame_x.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInitOutputData%RotFrame_z = SrcInitOutputData%RotFrame_z + DstInitOutputData%RotFrame_x = SrcInitOutputData%RotFrame_x ENDIF IF (ALLOCATED(SrcInitOutputData%RotFrame_u)) THEN i1_l = LBOUND(SrcInitOutputData%RotFrame_u,1) @@ -1477,6 +1479,18 @@ SUBROUTINE AD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, Er IF (ErrStat>=AbortErrLev) RETURN ENDDO 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 IF (ALLOCATED(SrcInitOutputData%TwrElev)) THEN i1_l = LBOUND(SrcInitOutputData%TwrElev,1) i1_u = UBOUND(SrcInitOutputData%TwrElev,1) @@ -1528,8 +1542,8 @@ SUBROUTINE AD_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) IF (ALLOCATED(InitOutputData%LinNames_y)) THEN DEALLOCATE(InitOutputData%LinNames_y) ENDIF -IF (ALLOCATED(InitOutputData%LinNames_z)) THEN - DEALLOCATE(InitOutputData%LinNames_z) +IF (ALLOCATED(InitOutputData%LinNames_x)) THEN + DEALLOCATE(InitOutputData%LinNames_x) ENDIF IF (ALLOCATED(InitOutputData%LinNames_u)) THEN DEALLOCATE(InitOutputData%LinNames_u) @@ -1537,8 +1551,8 @@ SUBROUTINE AD_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) IF (ALLOCATED(InitOutputData%RotFrame_y)) THEN DEALLOCATE(InitOutputData%RotFrame_y) ENDIF -IF (ALLOCATED(InitOutputData%RotFrame_z)) THEN - DEALLOCATE(InitOutputData%RotFrame_z) +IF (ALLOCATED(InitOutputData%RotFrame_x)) THEN + DEALLOCATE(InitOutputData%RotFrame_x) ENDIF IF (ALLOCATED(InitOutputData%RotFrame_u)) THEN DEALLOCATE(InitOutputData%RotFrame_u) @@ -1552,6 +1566,9 @@ SUBROUTINE AD_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) ENDDO DEALLOCATE(InitOutputData%BladeProps) ENDIF +IF (ALLOCATED(InitOutputData%DerivOrder_x)) THEN + DEALLOCATE(InitOutputData%DerivOrder_x) +ENDIF IF (ALLOCATED(InitOutputData%TwrElev)) THEN DEALLOCATE(InitOutputData%TwrElev) ENDIF @@ -1652,10 +1669,10 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs 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_z allocated yes/no - IF ( ALLOCATED(InData%LinNames_z) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! LinNames_z upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%LinNames_z)*LEN(InData%LinNames_z) ! LinNames_z + 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 @@ -1667,10 +1684,10 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs 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_z allocated yes/no - IF ( ALLOCATED(InData%RotFrame_z) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! RotFrame_z upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%RotFrame_z) ! RotFrame_z + 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 @@ -1705,6 +1722,11 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs END IF END DO 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 Int_BufSz = Int_BufSz + 1 ! TwrElev allocated yes/no IF ( ALLOCATED(InData%TwrElev) ) THEN Int_BufSz = Int_BufSz + 2*1 ! TwrElev upper/lower bounds for each dimension @@ -1864,19 +1886,19 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs END DO ! I END DO END IF - IF ( .NOT. ALLOCATED(InData%LinNames_z) ) THEN + 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_z,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%LinNames_z,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_z,1), UBOUND(InData%LinNames_z,1) - DO I = 1, LEN(InData%LinNames_z) - IntKiBuf(Int_Xferred) = ICHAR(InData%LinNames_z(i1)(I:I), IntKi) + 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 @@ -1913,18 +1935,18 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_Xferred = Int_Xferred + 1 END DO END IF - IF ( .NOT. ALLOCATED(InData%RotFrame_z) ) THEN + 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_z,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RotFrame_z,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_z,1), UBOUND(InData%RotFrame_z,1) - IntKiBuf(Int_Xferred) = TRANSFER(InData%RotFrame_z(i1), IntKiBuf(1)) + 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 @@ -1999,6 +2021,21 @@ SUBROUTINE AD_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs ENDIF 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 IF ( .NOT. ALLOCATED(InData%TwrElev) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -2216,22 +2253,22 @@ SUBROUTINE AD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er END DO ! I END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! LinNames_z not allocated + 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_z)) DEALLOCATE(OutData%LinNames_z) - ALLOCATE(OutData%LinNames_z(i1_l:i1_u),STAT=ErrStat2) + 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_z.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%LinNames_x.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%LinNames_z,1), UBOUND(OutData%LinNames_z,1) - DO I = 1, LEN(OutData%LinNames_z) - OutData%LinNames_z(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + 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 @@ -2274,21 +2311,21 @@ SUBROUTINE AD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er Int_Xferred = Int_Xferred + 1 END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RotFrame_z not allocated + 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_z)) DEALLOCATE(OutData%RotFrame_z) - ALLOCATE(OutData%RotFrame_z(i1_l:i1_u),STAT=ErrStat2) + 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_z.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RotFrame_x.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%RotFrame_z,1), UBOUND(OutData%RotFrame_z,1) - OutData%RotFrame_z(i1) = TRANSFER(IntKiBuf(Int_Xferred), OutData%RotFrame_z(i1)) + 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 @@ -2384,6 +2421,24 @@ SUBROUTINE AD_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) 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 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TwrElev not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -7259,6 +7314,18 @@ SUBROUTINE AD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) 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_ny = SrcParamData%Jac_ny END SUBROUTINE AD_CopyParam @@ -7307,6 +7374,9 @@ SUBROUTINE AD_DestroyParam( ParamData, ErrStat, ErrMsg ) ENDIF IF (ALLOCATED(ParamData%du)) THEN DEALLOCATE(ParamData%du) +ENDIF +IF (ALLOCATED(ParamData%dx)) THEN + DEALLOCATE(ParamData%dx) ENDIF END SUBROUTINE AD_DestroyParam @@ -7517,6 +7587,11 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si IF ( ALLOCATED(InData%du) ) THEN Int_BufSz = Int_BufSz + 2*1 ! du upper/lower bounds for each dimension Re_BufSz = Re_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_ny IF ( Re_BufSz .GT. 0 ) THEN @@ -7892,6 +7967,21 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si ReKiBuf(Re_Xferred) = InData%du(i1) Re_Xferred = Re_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_ny Int_Xferred = Int_Xferred + 1 @@ -8371,6 +8461,24 @@ SUBROUTINE AD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg OutData%du(i1) = ReKiBuf(Re_Xferred) Re_Xferred = Re_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_ny = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 diff --git a/modules/aerodyn/src/AirfoilInfo.f90 b/modules/aerodyn/src/AirfoilInfo.f90 index 1859c63bdd..4b7cb26c4a 100644 --- a/modules/aerodyn/src/AirfoilInfo.f90 +++ b/modules/aerodyn/src/AirfoilInfo.f90 @@ -36,8 +36,9 @@ MODULE AirfoilInfo PUBLIC :: AFI_ComputeAirfoilCoefs ! routine to perform 1D (AOA) or 2D (AOA, Re) or (AOA, UserProp) lookup of the airfoil coefs TYPE(ProgDesc), PARAMETER :: AFI_Ver = ProgDesc( 'AirfoilInfo', '', '') ! The name, version, and date of AirfoilInfo. + integer, parameter :: MaxNumAFCoeffs = 6 !cl,cd,cm,cpMin, UA_HGM:f_st, UA_HGM:cl_fs - CONTAINS +CONTAINS function CheckValuesAreUniqueMonotonicIncreasing(secondVals) @@ -65,6 +66,8 @@ SUBROUTINE AFI_Init ( InitInput, p, ErrStat, ErrMsg, UnEcho ) ! This routine initializes AirfoilInfo by reading the airfoil files and generating the spline coefficients. + + ! Argument declarations. INTEGER(IntKi), INTENT(OUT) :: ErrStat ! Error status. @@ -112,6 +115,7 @@ SUBROUTINE AFI_Init ( InitInput, p, ErrStat, ErrMsg, UnEcho ) p%ColCd = 2 p%ColCm = 0 ! These may or may not be used; initialize to zero in case they aren't used p%ColCpmin = 0 ! These may or may not be used; initialize to zero in case they aren't used + p%ColUAf = 0 ! These may or may not be used; initialize to zero in case they aren't used IF ( InitInput%InCol_Cm > 0 ) THEN p%ColCm = 3 @@ -142,7 +146,6 @@ SUBROUTINE AFI_Init ( InitInput, p, ErrStat, ErrMsg, UnEcho ) ENDIF - ! Make sure that all the tables meet the current restrictions. IF ( p%NumTabs > 1 ) THEN @@ -239,6 +242,7 @@ SUBROUTINE AFI_Init ( InitInput, p, ErrStat, ErrMsg, UnEcho ) p%AFTabMod = AFITable_1 ENDIF ! ( p%NumTabs > 1 ) + ! We need to deal with constant data. @@ -375,7 +379,7 @@ SUBROUTINE ReadAFfile ( AFfile, NumCoefs, InCol_Alfa, InCol_Cl, InCol_Cd, InCol_ INTEGER(IntKi), INTENT(IN) :: InCol_Cm ! The airfoil-table input column for pitching-moment coefficient. INTEGER(IntKi), INTENT(IN) :: InCol_Cpmin ! The airfoil-table input column for minimum pressure coefficient. INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status. - INTEGER(IntKi), INTENT(IN) :: NumCoefs ! The number of aerodynamic coefficients to be stored. + INTEGER(IntKi), INTENT(INOUT) :: NumCoefs ! The number of aerodynamic coefficients to be stored. INTEGER, INTENT(IN) :: UnEc ! I/O unit for echo file. If present and > 0, write to UnEc. CHARACTER(*), INTENT(IN) :: AFfile ! The file to be read. @@ -572,6 +576,14 @@ SUBROUTINE ReadAFfile ( AFfile, NumCoefs, InCol_Alfa, InCol_Cl, InCol_Cd, InCol_ CALL ParseVar ( FileInfo, CurLine, 'C_nalpha', p%Table(iTable)%UA_BL%C_nalpha, ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) +!>>> add after this feature gets tested better: +! CALL ParseVar ( FileInfo, CurLine, 'C_lalpha', p%Table(iTable)%UA_BL%C_lalpha, ErrStat2, ErrMsg2, UnEc ) +! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) +!<<< +!>>> remove after this feature gets tested better: +p%Table(iTable)%UA_BL%C_lalpha = p%Table(iTable)%UA_BL%C_nalpha +!<<< + CALL ParseVarWDefault ( FileInfo, CurLine, 'T_f0', p%Table(iTable)%UA_BL%T_f0, 3.0_ReKi, ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -651,9 +663,12 @@ SUBROUTINE ReadAFfile ( AFfile, NumCoefs, InCol_Alfa, InCol_Cl, InCol_Cd, InCol_ CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) p%Table(iTable)%UA_BL%UACutout = p%Table(iTable)%UA_BL%UACutout*D2R - CALL ParseVarWDefault ( FileInfo, CurLine, 'filtCutOff', p%Table(iTable)%UA_BL%filtCutOff, 20.0_ReKi, ErrStat2, ErrMsg2, UnEc ) + CALL ParseVarWDefault ( FileInfo, CurLine, 'filtCutOff', p%Table(iTable)%UA_BL%filtCutOff, 0.5_ReKi, ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + p%ColUAf = NumCoefs + 1 ! column for f_st + NumCoefs = p%ColUAf + 1 ! precompute f_st and cl_fs for the HGM model + IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() RETURN @@ -713,20 +728,16 @@ SUBROUTINE ReadAFfile ( AFfile, NumCoefs, InCol_Alfa, InCol_Cl, InCol_Cd, InCol_ RETURN END IF - p%Table(iTable)%Alpha(Row ) = SiAry(InCol_Alfa)*D2R - !p%Table(iTable)%Alpha(Row ) = SiAry(InCol_Alfa) - p%Table(iTable)%Coefs(Row,1) = SiAry(InCol_Cl ) - p%Table(iTable)%Coefs(Row,2) = SiAry(InCol_Cd ) + p%Table(iTable)%Alpha(Row ) = SiAry(InCol_Alfa)*D2R + p%Table(iTable)%Coefs(Row,p%ColCl) = SiAry(InCol_Cl ) + p%Table(iTable)%Coefs(Row,p%ColCd) = SiAry(InCol_Cd ) - IF ( InCol_Cm > 0 ) THEN - p%Table(iTable)%Coefs(Row,3) = SiAry(InCol_Cm) - IF ( InCol_Cpmin > 0 ) p%Table(iTable)%Coefs(Row,4) = SiAry(InCol_Cpmin) - ELSE - IF ( InCol_Cpmin > 0 ) p%Table(iTable)%Coefs(Row,3) = SiAry(InCol_Cpmin) - ENDIF ! IF ( Col_Cm > 0 ) THEN + IF ( InCol_Cm > 0 ) p%Table(iTable)%Coefs(Row,p%ColCm ) = SiAry(InCol_Cm) + IF ( InCol_Cpmin > 0 ) p%Table(iTable)%Coefs(Row,p%ColCpmin) = SiAry(InCol_Cpmin) ENDDO ! Row + call CalculateUACoeffs(p%Table(iTable), p%ColCl, p%ColUAf) ! Let's make sure that the data go from -Pi to Pi and that the values are the same for both ! unless there is only one point. @@ -735,11 +746,9 @@ SUBROUTINE ReadAFfile ( AFfile, NumCoefs, InCol_Alfa, InCol_Cl, InCol_Cd, InCol_ NumAlf = p%Table(iTable)%NumAlf BadVals = .FALSE. IF ( .NOT. EqualRealNos( p%Table(iTable)%Alpha(1), -Pi ) ) THEN - !IF ( .NOT. EqualRealNos( p%Table(iTable)%Alpha(1), -180.0_ReKi ) ) THEN BadVals = .TRUE. ENDIF IF ( .NOT. EqualRealNos( p%Table(iTable)%Alpha(NumAlf), Pi ) ) THEN - !IF ( .NOT. EqualRealNos( p%Table(iTable)%Alpha(NumAlf), 180.0_ReKi ) ) THEN BadVals = .TRUE. ENDIF DO Coef=1,NumCoefs @@ -778,6 +787,100 @@ END SUBROUTINE Cleanup END SUBROUTINE ReadAFfile +!---------------------------------------------------------------------------------------------------------------------------------- + SUBROUTINE CalculateUACoeffs(p,ColCl,ColUAf) + TYPE (AFI_Table_Type), intent(inout) :: p ! This structure stores all the module parameters that are set by AirfoilInfo during the initialization phase. + integer(IntKi), intent(in ) :: ColCl ! column for cl + integer(IntKi), intent(in ) :: ColUAf ! column for UA f_st + + INTEGER(IntKi) :: Row ! The row of a table to be parsed in the FileInfo structure. + INTEGER(IntKi) :: col_clFs ! column for UA cl_fs + + REAL(ReKi) :: cl_ratio, cl_inv + REAL(ReKi) :: f_st, cl_fs + REAL(ReKi) :: f_iHigh, f_iLow + INTEGER(IntKi) :: iHigh, iLow + + col_clFs = ColUAf + 1 + + if ( p%InclUAdata ) then + + if (EqualRealNos(p%UA_BL%c_lalpha,0.0_ReKi)) then + p%Coefs(:,ColUAf) = 0.0_ReKi ! Eq. 59 + p%Coefs(:,col_clFs) = p%Coefs(:,ColCl) ! Eq. 61 + else + + f_iHigh = huge(f_iHigh) + f_iLow = f_iHigh + iHigh = 0 + iLow = 0 + + do Row=1,p%NumAlf + + if (EqualRealNos( p%alpha(Row), p%UA_BL%alpha0)) then + f_st = 1.0_ReKi ! Eq. 59 + p%Coefs(Row,col_clFs) = p%Coefs(Row,ColCl) / 2.0_ReKi ! Eq. 61 (which should be very close to 0 because definition of alpha0 says cl(alpha0) = 0 ) + else + + cl_ratio = p%Coefs(Row,ColCl) / ( p%UA_BL%c_lalpha*(p%alpha(Row) - p%UA_BL%alpha0)) + cl_ratio = max(0.0_ReKi, cl_ratio) + + f_st = ( 2.0_ReKi * sqrt(cl_ratio) - 1.0_ReKi )**2 + + if (f_st < 1.0_ReKi) then + ! Region where f_st<1, merge + f_st = max(0.0_ReKi, f_st) ! make sure it is not negative + cl_fs = (p%Coefs(Row,ColCl) - p%UA_BL%c_lalpha* (p%alpha(Row) - p%UA_BL%alpha0)*f_st) / (1.0_ReKi - f_st) ! Eq 61 + else + ! Initialize to linear region (in fact only at singularity, where f_st=1) + f_st = 1.0_ReKi + cl_fs = p%Coefs(Row,ColCl) / 2.0_ReKi ! Eq. 61 + end if + + if (p%alpha(Row) < p%UA_BL%alpha0) then + if (f_st <= f_iLow) then + f_iLow = f_st + iLow = Row + end if + else !p%alpha(Row) > p%UA_BL%alpha0 (note that they can't be equal) + if (f_st < f_iHigh) then + f_iHigh = f_st + iHigh = Row + end if + end if + end if + + p%Coefs(Row,ColUAf) = f_st + p%Coefs(Row,col_clFs) = cl_fs + end do + if (iLow >0) p%Coefs(1:iLow,col_clFs) = p%Coefs(1:iLow,ColCl) + if (iHigh>0) p%Coefs(iHigh:,col_clFs) = p%Coefs(iHigh:,ColCl) + + + ! Ensuring everything is in harmony + do Row=1,p%NumAlf + cl_fs = p%Coefs(Row,col_clFs) + + cl_inv = p%UA_BL%c_lalpha*(p%alpha(Row) - p%UA_BL%alpha0) ! Eq. 64 + if (.not. EqualRealNos(cl_inv, cl_fs)) then + f_st=(p%Coefs(Row,ColCl) - cl_fs) / (cl_inv-cl_fs); ! Eq. 60 + f_st = max(0.0_ReKi, f_st) + f_st = min(1.0_ReKi, f_st) + + p%Coefs(Row,ColUAf) = f_st + else + p%Coefs(Row,ColUAf) = 1.0_ReKi + end if + + end do + end if ! c_lalpha == 0 + + end if + + + + + END SUBROUTINE CalculateUACoeffs !---------------------------------------------------------------------------------------------------------------------------------- subroutine FindBoundingTables(p, secondaryDepVal, lowerTable, upperTable, xVals) @@ -918,7 +1021,7 @@ subroutine AFI_ComputeAirfoilCoefs1D( AOA, p, AFI_interp, errStat, errMsg, Table integer(IntKi), optional, intent(in ) :: TableNum - real :: IntAFCoefs(4) ! The interpolated airfoil coefficients. + real :: IntAFCoefs(MaxNumAFCoeffs) ! The interpolated airfoil coefficients. real(reki) :: Alpha integer :: s1 integer :: iTab @@ -933,7 +1036,7 @@ subroutine AFI_ComputeAirfoilCoefs1D( AOA, p, AFI_interp, errStat, errMsg, Table iTab = 1 end if - IntAFCoefs = 0.0_ReKi ! initialize in case we only don't have 4 columns in the airfoil data (i.e., so cm is zero if not in the file) + IntAFCoefs = 0.0_ReKi ! initialize in case we only don't have MaxNumAFCoeffs columns in the airfoil data (e.g., so cm is zero if not in the file) s1 = size(p%Table(iTab)%Coefs,2) @@ -965,6 +1068,13 @@ subroutine AFI_ComputeAirfoilCoefs1D( AOA, p, AFI_interp, errStat, errMsg, Table AFI_interp%Cpmin = 0.0_Reki end if + if ( p%ColUAf > 0 ) then + AFI_interp%f_st = IntAFCoefs(p%ColUAf) + AFI_interp%cl_fs = IntAFCoefs(p%ColUAf+1) + else + AFI_interp%f_st = 0.0_ReKi + AFI_interp%cl_fs = 0.0_ReKi + end if ! needed if using UnsteadyAero: if (p%Table(iTab)%InclUAdata) then @@ -1027,6 +1137,7 @@ subroutine AFI_ComputeUACoefs( p, Re, UserProp, UA_BL, errMsg, errStat ) if ( p%AFTabMod == AFITable_1 ) then call AFI_CopyUA_BL_Type( p%Table(1)%UA_BL, UA_BL, MESH_NEWCOPY, errStat, errMsg ) ! this doesn't have a mesh, so the control code is irrelevant + return elseif ( p%AFTabMod == AFITable_2Re ) then #ifndef AFI_USE_LINEAR_RE ReInterp = log( Re ) @@ -1038,6 +1149,10 @@ subroutine AFI_ComputeUACoefs( p, Re, UserProp, UA_BL, errMsg, errStat ) call AFI_ComputeUACoefs2D( UserProp, p, UA_BL, errStat, errMsg ) end if + call MPi2Pi( UA_BL%alpha0 ) + call MPi2Pi( UA_BL%alpha1 ) + call MPi2Pi( UA_BL%alpha2 ) + ! Cn1=1.9 Tp=1.7 Tf=3., Tv=6 Tvl=11, Cd0=0.012 end subroutine AFI_ComputeUACoefs diff --git a/modules/aerodyn/src/AirfoilInfo_Registry.txt b/modules/aerodyn/src/AirfoilInfo_Registry.txt index 7e2501002e..be71570d7b 100644 --- a/modules/aerodyn/src/AirfoilInfo_Registry.txt +++ b/modules/aerodyn/src/AirfoilInfo_Registry.txt @@ -23,29 +23,30 @@ param AirfoilInfo/AFI - INTEGER AFITable_2Use # ..... Airfoil data ............................................................................................................... # The following derived type stores Beddoes-Leishman unsteady-aero data for an airfoil at a single combination of Re and control setting. The data can be computed internally of not read from the input file. -typedef AirfoilInfo/AFI AFI_UA_BL_Type ReKi alpha0 - - - "Angle of attack for zero lift (used for Beddoes-Leishman unsteady aero)" "input in degrees; stored as radians" -typedef ^ ^ ReKi alpha1 - - - "angle of attack at f = 0.7, approximately the stall angle; for alpha >= alpha0" "input in degrees; stored as radians" -typedef ^ ^ ReKi alpha2 - - - "angle of attack at f = 0.7, approximately the stall angle; for alpha < alpha0" "input in degrees; stored as radians" +typedef AirfoilInfo/AFI AFI_UA_BL_Type ReKi alpha0 - - 2pi "Angle of attack for zero lift (also used in HGM)" "input in degrees; stored as radians" +typedef ^ ^ ReKi alpha1 - - 2pi "angle of attack at f = 0.7, approximately the stall angle; for alpha >= alpha0" "input in degrees; stored as radians" +typedef ^ ^ ReKi alpha2 - - 2pi "angle of attack at f = 0.7, approximately the stall angle; for alpha < alpha0" "input in degrees; stored as radians" typedef ^ ^ ReKi eta_e - - - "Recovery factor in the range [0.85 - 0.95]" - typedef ^ ^ ReKi C_nalpha - - - "Cn slope for zero lift (used for Beddoes-Leishman unsteady aero)" 1/rad -typedef ^ ^ ReKi T_f0 - - - "initial value of T_f, airfoil specific, used to compute D_f and fprimeprime" - +typedef ^ ^ ReKi C_lalpha - - - "Cl slope for zero lift (used for HGM unsteady aero only) -> calculated" 1/rad +typedef ^ ^ ReKi T_f0 - - - "initial value of T_f, airfoil specific, used to compute D_f and fprimeprime (also used in HGM)" - typedef ^ ^ ReKi T_V0 - - - "initial value of T_V, airfoil specific, time parameter associated with the vortex lift decay process, used in Cn_v" - -typedef ^ ^ ReKi T_p - - - "boundary-layer, leading edge pressure gradient time parameter; used in D_p; airfoil specific" - +typedef ^ ^ ReKi T_p - - - "boundary-layer, leading edge pressure gradient time parameter; used in D_p; airfoil specific (also used in HGM)" - typedef ^ ^ ReKi T_VL - - - "Initial value of the time constant associated with the vortex advection process; it represents the non-dimensional time in semi-chords, needed for a vortex to travel from LE to trailing edge (TE); it is used in the expression of Cvn. It depends on Re, M (weakly), and airfoil. [valid range = 6 - 13]" - -typedef ^ ^ ReKi b1 - - - "airfoil constant derived from experimental results, usually 0.14" - -typedef ^ ^ ReKi b2 - - - "airfoil constant derived from experimental results, usually 0.53" - +typedef ^ ^ ReKi b1 - - - "airfoil constant derived from experimental results (also used in HGM), usually 0.14" - +typedef ^ ^ ReKi b2 - - - "airfoil constant derived from experimental results (also used in HGM), usually 0.53" - typedef ^ ^ ReKi b5 - - - "airfoil constant derived from experimental results, usually 5.0" - -typedef ^ ^ ReKi A1 - - - "airfoil constant derived from experimental results, usually 0.3" - -typedef ^ ^ ReKi A2 - - - "airfoil constant derived from experimental results, usually 0.7" - +typedef ^ ^ ReKi A1 - - - "airfoil constant derived from experimental results (also used in HGM), usually 0.3" - +typedef ^ ^ ReKi A2 - - - "airfoil constant derived from experimental results (also used in HGM), usually 0.7" - typedef ^ ^ ReKi A5 - - - "airfoil constant derived from experimental results, usually 1.0" - typedef ^ ^ ReKi S1 - - - "Constant in the f curve best-fit for alpha0<=AOA<=alpha1" - typedef ^ ^ ReKi S2 - - - "Constant in the f curve best-fit for AOA> alpha1" - typedef ^ ^ ReKi S3 - - - "Constant in the f curve best-fit for alpha2<=AOA< alpha0" - typedef ^ ^ ReKi S4 - - - "Constant in the f curve best-fit for AOA< alpha2" - -typedef ^ ^ ReKi Cn1 - - - "Cn at stall value for positive angle of attack (used for Beddoes-Leishman unsteady aero) [or critical value of Cn_prime at LE separation for alpha >= alpha0]" - -typedef ^ ^ ReKi Cn2 - - - "Cn at stall value for negative angle (used for Beddoes-Leishman unsteady aero) or [critical value of Cn_prime at LE separation for alpha < alpha0]" - +typedef ^ ^ ReKi Cn1 - - - "Cn at stall value for positive angle of attack [or critical value of Cn_prime at LE separation for alpha >= alpha0]" - +typedef ^ ^ ReKi Cn2 - - - "Cn at stall value for negative angle of attack [or critical value of Cn_prime at LE separation for alpha < alpha0]" - typedef ^ ^ ReKi St_sh - - - "Strouhal's shedding frequency constant." - -typedef ^ ^ ReKi Cd0 - - - "Minimum Cd value (used for Beddoes-Leishman unsteady aero)" - +typedef ^ ^ ReKi Cd0 - - - "Minimum Cd value" - typedef ^ ^ ReKi Cm0 - - - "2D pitching moment coefficient at zero lift, positive if nose is up" - typedef ^ ^ ReKi k0 - - - "airfoil parameter in the x_cp_hat curve best-fit [ignored if UAMod<>1]" - typedef ^ ^ ReKi k1 - - - "airfoil parameter in the x_cp_hat curve best-fit [ignored if UAMod<>1]" - @@ -54,7 +55,7 @@ typedef ^ ^ ReKi k3 typedef ^ ^ ReKi k1_hat - - - "Constant in the expression of Cc due to leading edge vortex effects. [ignored if UAMod<>1]" - typedef ^ ^ ReKi x_cp_bar - - - "Constant in the expression of \hat(x)_cp^v [ignored if UAMod<>1, default = 0.2]" - typedef ^ ^ ReKi UACutout - - - "Angle of attack above which unsteady aerodynamics are disabled" "input in degrees; stored as radians" -typedef ^ ^ ReKi filtCutOff - - - "low pass filter cut-off frequency for the pitching rate and accelerations" Hz +typedef ^ ^ ReKi filtCutOff - - - "Reduced frequency cutoff used to calculate the dynamic low pass filter cut-off frequency for the pitching rate and accelerations [default = 0.5]" - # The following derived type stores data for an airfoil at a single combination of Re and control setting. typedef ^ AFI_Table_Type ReKi Alpha {:} - - "Angle-of-attack vector that matches the Coefs matrix" rad @@ -87,6 +88,7 @@ typedef ^ ParameterType INTEGER ColCd typedef ^ ^ INTEGER ColCl - - - "The column in the p%Coefs arrays that contains Cl data" - typedef ^ ^ INTEGER ColCm - - - "The column in the p%Coefs arrays that contains Cm data" - typedef ^ ^ INTEGER ColCpmin - - - "The column in the p%Coefs arrays that contains Cpmin data" - +typedef ^ ^ INTEGER ColUAf - - - "The column in the p%Coefs arrays that contains f_st data for UA" - typedef ^ ^ INTEGER AFTabMod - - - "Interpolation method for multiple airfoil tables {1 = 1D on AoA (only first table is used); 2 = 2D on AoA and Re; 3 = 2D on AoA and UserProp}" - typedef ^ ^ ReKi secondVals {:} - - "The values of the 2nd dependent variable when using multiple airfoil tables (Re or UserProp, saved in an array so that the logic in the interpolation scheme is cleaner)" - typedef ^ ^ IntKi InterpOrd - - - "Interpolation order" - @@ -100,7 +102,7 @@ typedef ^ ^ CHARACTER(1024) BL_file # ..... Inputs .................................................................................................................... # Define inputs that are not on this mesh here: -typedef ^ InputType ReKi AoA - - - "The angle of attack" radians +typedef ^ InputType ReKi AoA - - 2pi "The angle of attack" radians typedef ^ ^ ReKi UserProp - - - "The user-defined control setting" - typedef ^ ^ ReKi Re - - - "Reynolds number" - @@ -112,5 +114,7 @@ typedef ^ ^ ReKi Cm typedef ^ ^ ReKi Cpmin - 0. - "Dimensionless coefficient of minimum pressure" - typedef ^ ^ ReKi Cd0 - 0. - "Minimum Cd value (used for Beddoes-Leishman unsteady aero)" - typedef ^ ^ ReKi Cm0 - 0. - "2D pitching moment coefficient at zero lift, positive if nose is up" - +typedef ^ ^ ReKi f_st - 0. - "separation function (used for UA HGM model)" - +typedef ^ ^ ReKi cl_fs - 0. - "fully separated polar function (used for UA HGM model)" - diff --git a/modules/aerodyn/src/AirfoilInfo_Types.f90 b/modules/aerodyn/src/AirfoilInfo_Types.f90 index 4c9b15d311..aa3fb2a01b 100644 --- a/modules/aerodyn/src/AirfoilInfo_Types.f90 +++ b/modules/aerodyn/src/AirfoilInfo_Types.f90 @@ -38,29 +38,30 @@ MODULE AirfoilInfo_Types INTEGER(IntKi), PUBLIC, PARAMETER :: AFITable_2User = 3 ! 2D interpolation on AoA and UserProp [-] ! ========= AFI_UA_BL_Type ======= TYPE, PUBLIC :: AFI_UA_BL_Type - REAL(ReKi) :: alpha0 !< Angle of attack for zero lift (used for Beddoes-Leishman unsteady aero) [input in degrees; stored as radians] + REAL(ReKi) :: alpha0 !< Angle of attack for zero lift (also used in HGM) [input in degrees; stored as radians] REAL(ReKi) :: alpha1 !< angle of attack at f = 0.7, approximately the stall angle; for alpha >= alpha0 [input in degrees; stored as radians] REAL(ReKi) :: alpha2 !< angle of attack at f = 0.7, approximately the stall angle; for alpha < alpha0 [input in degrees; stored as radians] REAL(ReKi) :: eta_e !< Recovery factor in the range [0.85 - 0.95] [-] REAL(ReKi) :: C_nalpha !< Cn slope for zero lift (used for Beddoes-Leishman unsteady aero) [1/rad] - REAL(ReKi) :: T_f0 !< initial value of T_f, airfoil specific, used to compute D_f and fprimeprime [-] + REAL(ReKi) :: C_lalpha !< Cl slope for zero lift (used for HGM unsteady aero only) -> calculated [1/rad] + REAL(ReKi) :: T_f0 !< initial value of T_f, airfoil specific, used to compute D_f and fprimeprime (also used in HGM) [-] REAL(ReKi) :: T_V0 !< initial value of T_V, airfoil specific, time parameter associated with the vortex lift decay process, used in Cn_v [-] - REAL(ReKi) :: T_p !< boundary-layer, leading edge pressure gradient time parameter; used in D_p; airfoil specific [-] + REAL(ReKi) :: T_p !< boundary-layer, leading edge pressure gradient time parameter; used in D_p; airfoil specific (also used in HGM) [-] REAL(ReKi) :: T_VL !< Initial value of the time constant associated with the vortex advection process; it represents the non-dimensional time in semi-chords, needed for a vortex to travel from LE to trailing edge (TE); it is used in the expression of Cvn. It depends on Re, M (weakly), and airfoil. [valid range = 6 - 13] [-] - REAL(ReKi) :: b1 !< airfoil constant derived from experimental results, usually 0.14 [-] - REAL(ReKi) :: b2 !< airfoil constant derived from experimental results, usually 0.53 [-] + REAL(ReKi) :: b1 !< airfoil constant derived from experimental results (also used in HGM), usually 0.14 [-] + REAL(ReKi) :: b2 !< airfoil constant derived from experimental results (also used in HGM), usually 0.53 [-] REAL(ReKi) :: b5 !< airfoil constant derived from experimental results, usually 5.0 [-] - REAL(ReKi) :: A1 !< airfoil constant derived from experimental results, usually 0.3 [-] - REAL(ReKi) :: A2 !< airfoil constant derived from experimental results, usually 0.7 [-] + REAL(ReKi) :: A1 !< airfoil constant derived from experimental results (also used in HGM), usually 0.3 [-] + REAL(ReKi) :: A2 !< airfoil constant derived from experimental results (also used in HGM), usually 0.7 [-] REAL(ReKi) :: A5 !< airfoil constant derived from experimental results, usually 1.0 [-] REAL(ReKi) :: S1 !< Constant in the f curve best-fit for alpha0<=AOA<=alpha1 [-] REAL(ReKi) :: S2 !< Constant in the f curve best-fit for AOA> alpha1 [-] REAL(ReKi) :: S3 !< Constant in the f curve best-fit for alpha2<=AOA< alpha0 [-] REAL(ReKi) :: S4 !< Constant in the f curve best-fit for AOA< alpha2 [-] - REAL(ReKi) :: Cn1 !< Cn at stall value for positive angle of attack (used for Beddoes-Leishman unsteady aero) [or critical value of Cn_prime at LE separation for alpha >= alpha0] [-] - REAL(ReKi) :: Cn2 !< Cn at stall value for negative angle (used for Beddoes-Leishman unsteady aero) or [critical value of Cn_prime at LE separation for alpha < alpha0] [-] + REAL(ReKi) :: Cn1 !< Cn at stall value for positive angle of attack [or critical value of Cn_prime at LE separation for alpha >= alpha0] [-] + REAL(ReKi) :: Cn2 !< Cn at stall value for negative angle of attack [or critical value of Cn_prime at LE separation for alpha < alpha0] [-] REAL(ReKi) :: St_sh !< Strouhal's shedding frequency constant. [-] - REAL(ReKi) :: Cd0 !< Minimum Cd value (used for Beddoes-Leishman unsteady aero) [-] + REAL(ReKi) :: Cd0 !< Minimum Cd value [-] REAL(ReKi) :: Cm0 !< 2D pitching moment coefficient at zero lift, positive if nose is up [-] REAL(ReKi) :: k0 !< airfoil parameter in the x_cp_hat curve best-fit [ignored if UAMod<>1] [-] REAL(ReKi) :: k1 !< airfoil parameter in the x_cp_hat curve best-fit [ignored if UAMod<>1] [-] @@ -69,7 +70,7 @@ MODULE AirfoilInfo_Types REAL(ReKi) :: k1_hat !< Constant in the expression of Cc due to leading edge vortex effects. [ignored if UAMod<>1] [-] REAL(ReKi) :: x_cp_bar !< Constant in the expression of \hat(x)_cp^v [ignored if UAMod<>1, default = 0.2] [-] REAL(ReKi) :: UACutout !< Angle of attack above which unsteady aerodynamics are disabled [input in degrees; stored as radians] - REAL(ReKi) :: filtCutOff !< low pass filter cut-off frequency for the pitching rate and accelerations [Hz] + REAL(ReKi) :: filtCutOff !< Reduced frequency cutoff used to calculate the dynamic low pass filter cut-off frequency for the pitching rate and accelerations [default = 0.5] [-] END TYPE AFI_UA_BL_Type ! ======================= ! ========= AFI_Table_Type ======= @@ -107,6 +108,7 @@ MODULE AirfoilInfo_Types INTEGER(IntKi) :: ColCl !< The column in the p%Coefs arrays that contains Cl data [-] INTEGER(IntKi) :: ColCm !< The column in the p%Coefs arrays that contains Cm data [-] INTEGER(IntKi) :: ColCpmin !< The column in the p%Coefs arrays that contains Cpmin data [-] + INTEGER(IntKi) :: ColUAf !< The column in the p%Coefs arrays that contains f_st data for UA [-] INTEGER(IntKi) :: AFTabMod !< Interpolation method for multiple airfoil tables {1 = 1D on AoA (only first table is used); 2 = 2D on AoA and Re; 3 = 2D on AoA and UserProp} [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: secondVals !< The values of the 2nd dependent variable when using multiple airfoil tables (Re or UserProp, saved in an array so that the logic in the interpolation scheme is cleaner) [-] INTEGER(IntKi) :: InterpOrd !< Interpolation order [-] @@ -134,6 +136,8 @@ MODULE AirfoilInfo_Types REAL(ReKi) :: Cpmin = 0. !< Dimensionless coefficient of minimum pressure [-] REAL(ReKi) :: Cd0 = 0. !< Minimum Cd value (used for Beddoes-Leishman unsteady aero) [-] REAL(ReKi) :: Cm0 = 0. !< 2D pitching moment coefficient at zero lift, positive if nose is up [-] + REAL(ReKi) :: f_st = 0. !< separation function (used for UA HGM model) [-] + REAL(ReKi) :: cl_fs = 0. !< fully separated polar function (used for UA HGM model) [-] END TYPE AFI_OutputType ! ======================= CONTAINS @@ -159,6 +163,7 @@ SUBROUTINE AFI_CopyUA_BL_Type( SrcUA_BL_TypeData, DstUA_BL_TypeData, CtrlCode, E DstUA_BL_TypeData%alpha2 = SrcUA_BL_TypeData%alpha2 DstUA_BL_TypeData%eta_e = SrcUA_BL_TypeData%eta_e DstUA_BL_TypeData%C_nalpha = SrcUA_BL_TypeData%C_nalpha + DstUA_BL_TypeData%C_lalpha = SrcUA_BL_TypeData%C_lalpha DstUA_BL_TypeData%T_f0 = SrcUA_BL_TypeData%T_f0 DstUA_BL_TypeData%T_V0 = SrcUA_BL_TypeData%T_V0 DstUA_BL_TypeData%T_p = SrcUA_BL_TypeData%T_p @@ -239,6 +244,7 @@ SUBROUTINE AFI_PackUA_BL_Type( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = Re_BufSz + 1 ! alpha2 Re_BufSz = Re_BufSz + 1 ! eta_e Re_BufSz = Re_BufSz + 1 ! C_nalpha + Re_BufSz = Re_BufSz + 1 ! C_lalpha Re_BufSz = Re_BufSz + 1 ! T_f0 Re_BufSz = Re_BufSz + 1 ! T_V0 Re_BufSz = Re_BufSz + 1 ! T_p @@ -303,6 +309,8 @@ SUBROUTINE AFI_PackUA_BL_Type( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%C_nalpha Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%C_lalpha + Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%T_f0 Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%T_V0 @@ -398,6 +406,8 @@ SUBROUTINE AFI_UnPackUA_BL_Type( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Re_Xferred = Re_Xferred + 1 OutData%C_nalpha = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%C_lalpha = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 OutData%T_f0 = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%T_V0 = ReKiBuf(Re_Xferred) @@ -1287,6 +1297,7 @@ SUBROUTINE AFI_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg DstParamData%ColCl = SrcParamData%ColCl DstParamData%ColCm = SrcParamData%ColCm DstParamData%ColCpmin = SrcParamData%ColCpmin + DstParamData%ColUAf = SrcParamData%ColUAf DstParamData%AFTabMod = SrcParamData%AFTabMod IF (ALLOCATED(SrcParamData%secondVals)) THEN i1_l = LBOUND(SrcParamData%secondVals,1) @@ -1412,6 +1423,7 @@ SUBROUTINE AFI_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_BufSz = Int_BufSz + 1 ! ColCl Int_BufSz = Int_BufSz + 1 ! ColCm Int_BufSz = Int_BufSz + 1 ! ColCpmin + Int_BufSz = Int_BufSz + 1 ! ColUAf Int_BufSz = Int_BufSz + 1 ! AFTabMod Int_BufSz = Int_BufSz + 1 ! secondVals allocated yes/no IF ( ALLOCATED(InData%secondVals) ) THEN @@ -1492,6 +1504,8 @@ SUBROUTINE AFI_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%ColCpmin Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%ColUAf + Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%AFTabMod Int_Xferred = Int_Xferred + 1 IF ( .NOT. ALLOCATED(InData%secondVals) ) THEN @@ -1629,6 +1643,8 @@ SUBROUTINE AFI_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Int_Xferred = Int_Xferred + 1 OutData%ColCpmin = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%ColUAf = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 OutData%AFTabMod = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! secondVals not allocated @@ -1912,6 +1928,8 @@ SUBROUTINE AFI_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrM DstOutputData%Cpmin = SrcOutputData%Cpmin DstOutputData%Cd0 = SrcOutputData%Cd0 DstOutputData%Cm0 = SrcOutputData%Cm0 + DstOutputData%f_st = SrcOutputData%f_st + DstOutputData%cl_fs = SrcOutputData%cl_fs END SUBROUTINE AFI_CopyOutput SUBROUTINE AFI_DestroyOutput( OutputData, ErrStat, ErrMsg ) @@ -1966,6 +1984,8 @@ SUBROUTINE AFI_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = Re_BufSz + 1 ! Cpmin Re_BufSz = Re_BufSz + 1 ! Cd0 Re_BufSz = Re_BufSz + 1 ! Cm0 + Re_BufSz = Re_BufSz + 1 ! f_st + Re_BufSz = Re_BufSz + 1 ! cl_fs IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2005,6 +2025,10 @@ SUBROUTINE AFI_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%Cm0 Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%f_st + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%cl_fs + Re_Xferred = Re_Xferred + 1 END SUBROUTINE AFI_PackOutput SUBROUTINE AFI_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -2045,6 +2069,10 @@ SUBROUTINE AFI_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Re_Xferred = Re_Xferred + 1 OutData%Cm0 = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%f_st = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%cl_fs = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 END SUBROUTINE AFI_UnPackOutput @@ -2152,6 +2180,10 @@ SUBROUTINE AFI_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg y_out%Cd0 = y1%Cd0 + b * ScaleFactor b = -(y1%Cm0 - y2%Cm0) y_out%Cm0 = y1%Cm0 + b * ScaleFactor + b = -(y1%f_st - y2%f_st) + y_out%f_st = y1%f_st + b * ScaleFactor + b = -(y1%cl_fs - y2%cl_fs) + y_out%cl_fs = y1%cl_fs + b * ScaleFactor END SUBROUTINE AFI_Output_ExtrapInterp1 @@ -2225,6 +2257,12 @@ SUBROUTINE AFI_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, Er b = (t(3)**2*(y1%Cm0 - y2%Cm0) + t(2)**2*(-y1%Cm0 + y3%Cm0))* scaleFactor c = ( (t(2)-t(3))*y1%Cm0 + t(3)*y2%Cm0 - t(2)*y3%Cm0 ) * scaleFactor y_out%Cm0 = y1%Cm0 + b + c * t_out + b = (t(3)**2*(y1%f_st - y2%f_st) + t(2)**2*(-y1%f_st + y3%f_st))* scaleFactor + c = ( (t(2)-t(3))*y1%f_st + t(3)*y2%f_st - t(2)*y3%f_st ) * scaleFactor + y_out%f_st = y1%f_st + b + c * t_out + b = (t(3)**2*(y1%cl_fs - y2%cl_fs) + t(2)**2*(-y1%cl_fs + y3%cl_fs))* scaleFactor + c = ( (t(2)-t(3))*y1%cl_fs + t(3)*y2%cl_fs - t(2)*y3%cl_fs ) * scaleFactor + y_out%cl_fs = y1%cl_fs + b + c * t_out END SUBROUTINE AFI_Output_ExtrapInterp2 @@ -2320,16 +2358,15 @@ SUBROUTINE AFI_UA_BL_Type_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, Er END IF ScaleFactor = t_out / t(2) - b = -(u1%alpha0 - u2%alpha0) - u_out%alpha0 = u1%alpha0 + b * ScaleFactor - b = -(u1%alpha1 - u2%alpha1) - u_out%alpha1 = u1%alpha1 + b * ScaleFactor - b = -(u1%alpha2 - u2%alpha2) - u_out%alpha2 = u1%alpha2 + b * ScaleFactor + CALL Angles_ExtrapInterp( u1%alpha0, u2%alpha0, tin, u_out%alpha0, tin_out ) + CALL Angles_ExtrapInterp( u1%alpha1, u2%alpha1, tin, u_out%alpha1, tin_out ) + CALL Angles_ExtrapInterp( u1%alpha2, u2%alpha2, tin, u_out%alpha2, tin_out ) b = -(u1%eta_e - u2%eta_e) u_out%eta_e = u1%eta_e + b * ScaleFactor b = -(u1%C_nalpha - u2%C_nalpha) u_out%C_nalpha = u1%C_nalpha + b * ScaleFactor + b = -(u1%C_lalpha - u2%C_lalpha) + u_out%C_lalpha = u1%C_lalpha + b * ScaleFactor b = -(u1%T_f0 - u2%T_f0) u_out%T_f0 = u1%T_f0 + b * ScaleFactor b = -(u1%T_V0 - u2%T_V0) @@ -2439,21 +2476,18 @@ SUBROUTINE AFI_UA_BL_Type_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat END IF ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) - b = (t(3)**2*(u1%alpha0 - u2%alpha0) + t(2)**2*(-u1%alpha0 + u3%alpha0))* scaleFactor - c = ( (t(2)-t(3))*u1%alpha0 + t(3)*u2%alpha0 - t(2)*u3%alpha0 ) * scaleFactor - u_out%alpha0 = u1%alpha0 + b + c * t_out - b = (t(3)**2*(u1%alpha1 - u2%alpha1) + t(2)**2*(-u1%alpha1 + u3%alpha1))* scaleFactor - c = ( (t(2)-t(3))*u1%alpha1 + t(3)*u2%alpha1 - t(2)*u3%alpha1 ) * scaleFactor - u_out%alpha1 = u1%alpha1 + b + c * t_out - b = (t(3)**2*(u1%alpha2 - u2%alpha2) + t(2)**2*(-u1%alpha2 + u3%alpha2))* scaleFactor - c = ( (t(2)-t(3))*u1%alpha2 + t(3)*u2%alpha2 - t(2)*u3%alpha2 ) * scaleFactor - u_out%alpha2 = u1%alpha2 + b + c * t_out + CALL Angles_ExtrapInterp( u1%alpha0, u2%alpha0, u3%alpha0, tin, u_out%alpha0, tin_out ) + CALL Angles_ExtrapInterp( u1%alpha1, u2%alpha1, u3%alpha1, tin, u_out%alpha1, tin_out ) + CALL Angles_ExtrapInterp( u1%alpha2, u2%alpha2, u3%alpha2, tin, u_out%alpha2, tin_out ) b = (t(3)**2*(u1%eta_e - u2%eta_e) + t(2)**2*(-u1%eta_e + u3%eta_e))* scaleFactor c = ( (t(2)-t(3))*u1%eta_e + t(3)*u2%eta_e - t(2)*u3%eta_e ) * scaleFactor u_out%eta_e = u1%eta_e + b + c * t_out b = (t(3)**2*(u1%C_nalpha - u2%C_nalpha) + t(2)**2*(-u1%C_nalpha + u3%C_nalpha))* scaleFactor c = ( (t(2)-t(3))*u1%C_nalpha + t(3)*u2%C_nalpha - t(2)*u3%C_nalpha ) * scaleFactor u_out%C_nalpha = u1%C_nalpha + b + c * t_out + b = (t(3)**2*(u1%C_lalpha - u2%C_lalpha) + t(2)**2*(-u1%C_lalpha + u3%C_lalpha))* scaleFactor + c = ( (t(2)-t(3))*u1%C_lalpha + t(3)*u2%C_lalpha - t(2)*u3%C_lalpha ) * scaleFactor + u_out%C_lalpha = u1%C_lalpha + b + c * t_out b = (t(3)**2*(u1%T_f0 - u2%T_f0) + t(2)**2*(-u1%T_f0 + u3%T_f0))* scaleFactor c = ( (t(2)-t(3))*u1%T_f0 + t(3)*u2%T_f0 - t(2)*u3%T_f0 ) * scaleFactor u_out%T_f0 = u1%T_f0 + b + c * t_out diff --git a/modules/aerodyn/src/BEMT.f90 b/modules/aerodyn/src/BEMT.f90 index 8f9efbd62c..2e44dacc91 100644 --- a/modules/aerodyn/src/BEMT.f90 +++ b/modules/aerodyn/src/BEMT.f90 @@ -55,9 +55,11 @@ module BEMT public :: BEMT_ReInit ! routines for linearization - public :: Get_phi_perturbations + public :: Get_phi_perturbations public :: ComputeFrozenWake public :: CheckLinearizationInput + public :: UpdatePhi + public :: BEMT_InitStates contains @@ -75,8 +77,8 @@ real(ReKi) function ComputePhiWithInduction( Vx, Vy, a, aprime ) real(ReKi) :: x real(ReKi) :: y - x = Vx*(1-a) - y = Vy*(1+aprime) + x = Vx*(1.0_ReKi-a) + y = Vy*(1.0_ReKi + aprime) if ( EqualRealNos(y, 0.0_ReKi) .AND. EqualRealNos(x, 0.0_ReKi) ) then ComputePhiWithInduction = 0.0_ReKi @@ -162,7 +164,6 @@ subroutine BEMT_SetParameters( InitInp, p, errStat, errMsg ) p%UA_Flag = InitInp%UA_Flag p%DBEMT_Mod = InitInp%DBEMT_Mod - allocate ( p%chord(p%numBladeNodes, p%numBlades), STAT = errStat2 ) if ( errStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, 'Error allocating memory for p%chord.', errStat, errMsg, RoutineName ) @@ -193,6 +194,12 @@ subroutine BEMT_SetParameters( InitInp, p, errStat, errMsg ) return end if + allocate ( p%FixedInductions(p%numBladeNodes, p%numBlades), STAT = errStat2 ) + if ( errStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error allocating memory for p%numBladeNodes.', errStat, errMsg, RoutineName ) + return + end if + p%AFindx = InitInp%AFindx ! Compute the tip and hub loss constants using the distances along the blade (provided as input for now) @@ -221,6 +228,14 @@ subroutine BEMT_SetParameters( InitInp, p, errStat, errMsg ) p%maxIndIterations = InitInp%maxIndIterations p%aTol = InitInp%aTol + + ! setting this condition here so we don't have to do some many EqualRealNos() checks later in the code. + do j=1,p%numBlades + do i=1,p%numBladeNodes + p%FixedInductions(i,j) = ( p%useTiploss .and. EqualRealNos(p%tipLossConst(i,j),0.0_ReKi) ) .or. ( p%useHubloss .and. EqualRealNos(p%hubLossConst(i,j),0.0_ReKi) ) + end do + end do + end subroutine BEMT_SetParameters !---------------------------------------------------------------------------------------------------------------------------------- @@ -249,8 +264,6 @@ subroutine BEMT_InitContraintStates( z, p, errStat, errMsg ) call SetErrStat( ErrID_Fatal, 'Error allocating memory for z%phi.', errStat, errMsg, RoutineName ) return end if - z%phi = 0.0_ReKi - end subroutine BEMT_InitContraintStates @@ -290,14 +303,11 @@ subroutine BEMT_InitOtherStates( OtherState, p, errStat, errMsg ) if ( errStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, 'Error allocating memory for OtherState%ValidPhi.', errStat, errMsg, RoutineName ) return - end if - OtherState%ValidPhi = .true. + end if end if - OtherState%UA_Flag = p%UA_Flag - OtherState%nodesInitialized = .false. ! z%phi hasn't been initialized properly, so make sure we compute a value for phi until we've updated them in the first call to BEMT_UpdateStates() - + ! values of the OtherStates are initialized in BEMT_ReInit() end subroutine BEMT_InitOtherStates @@ -351,6 +361,28 @@ subroutine BEMT_AllocInput( u, p, errStat, errMsg ) end if u%Vy = 0.0_ReKi + if (p%DBEMT_Mod==DBEMT_cont_tauConst) then + allocate ( u%Vx_elast_dot( p%numBladeNodes, p%numBlades ), STAT = errStat2 ) + if ( errStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error allocating memory for u%Vx_dot.', errStat, errMsg, RoutineName ) + return + end if + u%Vx_elast_dot = 0.0_ReKi + + allocate ( u%Vy_elast_dot( p%numBladeNodes, p%numBlades ), STAT = errStat2 ) + if ( errStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error allocating memory for u%Vy_dot.', errStat, errMsg, RoutineName ) + return + end if + u%Vy_elast_dot = 0.0_ReKi + end if + + allocate ( u%omega_z( p%numBladeNodes, p%numBlades ), STAT = errStat2 ) + if ( errStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error allocating memory for u%omega_z.', errStat, errMsg, RoutineName ) + return + end if + u%omega_z = 0.0_ReKi allocate ( u%rLocal( p%numBladeNodes, p%numBlades ), STAT = errStat2 ) if ( errStat2 /= 0 ) then @@ -464,13 +496,11 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None integer(IntKi) :: errStat2 ! temporary Error status of the operation character(*), parameter :: RoutineName = 'BEMT_Init' - type(UA_InputType) :: u_UA type(UA_InitInputType) :: Init_UA_Data type(UA_InitOutputType) :: InitOutData_UA type(DBEMT_InitInputType) :: InitInp_DBEMT type(DBEMT_InitOutputType) :: InitOut_DBEMT - type(DBEMT_InputType) :: u_DBEMT #ifdef UA_OUTS integer(IntKi) :: i @@ -485,10 +515,8 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte call NWTC_Init( EchoLibVer=.FALSE. ) ! Display the module information - call DispNVD( BEMT_Ver ) +! call DispNVD( BEMT_Ver ) - - !............................................................................................ ! Define parameters here @@ -507,10 +535,7 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return - ! initialize the continuous states - x%DummyContState = 0.0_SiKi - ! Now that we have DBEMT continuous states, let DBEMT_Init initialize these - + ! initialize the continuous states in DBEMT and/or UA ! Initialize other states call BEMT_InitOtherStates( OtherState, p, errStat, errMsg ) ! initialize the other states @@ -522,22 +547,41 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte InitInp_DBEMT%numNodes = p%numBladeNodes InitInp_DBEMT%tau1_const = InitInp%tau1_const + allocate(misc%u_DBEMT(2),stat=errStat2) + if (errStat2 /= 0) then + call SetErrStat(ErrID_Fatal,"Error allocating u_DBEMT",errStat,errMsg,RoutineName) + return + end if + if (allocated(InitInp%rlocal)) then call MOVE_ALLOC( InitInp%rlocal, InitInp_DBEMT%rlocal ) else ! If not allocated we have a problem! Issue an error and return call SetErrStat( ErrID_FATAL, " An InitInp%rlocal array has not been allocated and is required for DBEMT_Mod /= 0.", errStat, errMsg, RoutineName ) end if - - call DBEMT_Init(InitInp_DBEMT, u_DBEMT, p%DBEMT, x%DBEMT, OtherState%DBEMT, misc%DBEMT, interval, InitOut_DBEMT, errStat2, errMsg2) + if (errStat>=AbortErrLev) return + + call DBEMT_Init(InitInp_DBEMT, misc%u_DBEMT(1), p%DBEMT, x%DBEMT, OtherState%DBEMT, misc%DBEMT, interval, InitOut_DBEMT, errStat2, errMsg2) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return call MOVE_ALLOC( InitInp_DBEMT%rlocal, InitInp%rlocal ) + + call DBEMT_CopyInput(misc%u_DBEMT(1),misc%u_DBEMT(2), MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) else - OtherState%DBEMT%tau1 = 0.0_ReKi !we're going to output this value, so let's initialize it + p%DBEMT%lin_nx = 0 end if + + ! in calcOutput, we will use the UA inputs for output calculations, so we must allocate them regardless of UA_Flag: + allocate(misc%u_UA( p%numBladeNodes, p%numBlades, 2), stat=errStat2) + if (errStat2 /= 0) then + call SetErrStat(ErrID_Fatal,"Error allocating u_UA",errStat,errMsg,RoutineName) + call cleanup() + return + end if + if ( p%UA_Flag ) then call BEMT_Set_UA_InitData( InitInp, interval, Init_UA_Data, errStat2, errMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) @@ -546,8 +590,7 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte return end if - - call UA_Init( Init_UA_Data, u_UA, p%UA, xd%UA, OtherState%UA, misc%y_UA, misc%UA, interval, InitOutData_UA, errStat2, errMsg2 ) + call UA_Init( Init_UA_Data, misc%u_UA(1,1,1), p%UA, x%UA, xd%UA, OtherState%UA, misc%y_UA, misc%UA, interval, InitOutData_UA, errStat2, errMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) then call cleanup() @@ -556,40 +599,36 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte p%UA%ShedEffect=.True. ! This should be true when coupled to BEM. True in registry as default. - call BEMT_CheckInitUA(p, OtherState, AFInfo, ErrStat2, ErrMsg2) - call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - if (errStat >= AbortErrLev) then - call cleanup() - return - end if - -#ifdef UA_OUTS - !CALL GetNewUnit( UnUAOuts, ErrStat, ErrMsg ) - !IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( 69, 'Debug.UA.out', errStat, errMsg ) - IF (ErrStat >= AbortErrLev) RETURN - - - ! Heading: - WRITE (69,'(/,A)') 'This output information was generated by '//TRIM( GetNVD(BEMT_Ver) )// & - ' on '//CurDate()//' at '//CurTime()//'.' - WRITE (69,'(:,A20)', ADVANCE='no' ) 'Time' - do i=1,size(InitOutData_UA%WriteOutputHdr) - WRITE (69,'(:,A20)', ADVANCE='no' ) trim(InitOutData_UA%WriteOutputHdr(i)) - end do - write (69,'(A)') ' ' - - WRITE (69,'(:,A20)', ADVANCE='no' ) '(s)' - do i=1,size(InitOutData_UA%WriteOutputUnt) - WRITE (69,'(:,A20)', ADVANCE='no' ) trim(InitOutData_UA%WriteOutputUnt(i)) - end do - write (69,'(A)') ' ' -#endif - - + ! note: we check the validity of using UA in BEMT_ReInit() + +# ifdef UA_OUTS + !CALL GetNewUnit( UnUAOuts, ErrStat, ErrMsg ) + !IF ( ErrStat /= ErrID_None ) RETURN + + CALL OpenFOutFile ( 69, 'Debug.UA.out', errStat, errMsg ) + IF (ErrStat >= AbortErrLev) RETURN + + + ! Heading: + WRITE (69,'(/,A)') 'This output information was generated by '//TRIM( GetNVD(BEMT_Ver) )// & + ' on '//CurDate()//' at '//CurTime()//'.' + WRITE (69,'(:,A20)', ADVANCE='no' ) 'Time' + do i=1,size(InitOutData_UA%WriteOutputHdr) + WRITE (69,'(:,A20)', ADVANCE='no' ) trim(InitOutData_UA%WriteOutputHdr(i)) + end do + write (69,'(A)') ' ' + + WRITE (69,'(:,A20)', ADVANCE='no' ) '(s)' + do i=1,size(InitOutData_UA%WriteOutputUnt) + WRITE (69,'(:,A20)', ADVANCE='no' ) trim(InitOutData_UA%WriteOutputUnt(i)) + end do + write (69,'(A)') ' ' +# endif + else + p%UA%lin_nx = 0 end if ! unsteady aero is used + !............................................................................................ ! Define initial guess for the system inputs here: !............................................................................................ @@ -599,48 +638,46 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) then call cleanup() - return + return end if - - - - !............................................................................................ - ! Define system output initializations (set up meshes) here: - !............................................................................................ - !............................................................................................ - ! Define initialization-routine output here: - !............................................................................................ - - !call BEMT_InitOut(p, InitOut, errStat2, errMsg2) - !call CheckError( errStat2, errMsg2 ) - + call BEMT_AllocOutput(y, p, errStat2, errMsg2) !u is sent so we can create sibling meshes call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) then call cleanup() - return + return end if - - misc%useFrozenWake = .FALSE. - misc%FirstWarn_Skew = .true. - misc%FirstWarn_Phi = .true. - InitOut%Version = BEMT_Ver + InitOut%Version = BEMT_Ver - call AllocAry(misc%AxInduction,p%numBladeNodes,p%numBlades,'misc%AxInduction', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) + call AllocAry(misc%AxInduction, p%numBladeNodes,p%numBlades,'misc%AxInduction', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) call AllocAry(misc%TanInduction,p%numBladeNodes,p%numBlades,'misc%TanInduction', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) call AllocAry(misc%Rtip,p%numBlades,'misc%Rtip', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) + call AllocAry(misc%phi,p%numBladeNodes,p%numBlades,'misc%phi', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) + call AllocAry(misc%chi,p%numBladeNodes,p%numBlades,'misc%chi', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) + call AllocAry(misc%ValidPhi,p%numBladeNodes,p%numBlades,'misc%ValidPhi', errStat2,errMsg2); call SetErrStat(errStat2,errMsg2,errStat,errMsg,RoutineName) + + if (errStat >= AbortErrLev) then + call cleanup() + return + end if + + ! set initial values for states and misc vars + call BEMT_ReInit(p,x,xd,z,OtherState,misc,AFinfo,ErrStat2,ErrMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + call Cleanup() + CONTAINS !............................................................................................................................... SUBROUTINE Cleanup() ! This subroutine cleans up local variables that may have allocatable arrays !............................................................................................................................... - call UA_DestroyInput( u_UA, ErrStat2, ErrMsg2 ) call UA_DestroyInitInput( Init_UA_Data, ErrStat2, ErrMsg2 ) call UA_DestroyInitOutput( InitOutData_UA, ErrStat2, ErrMsg2 ) @@ -650,7 +687,7 @@ END SUBROUTINE BEMT_Init !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine reinitializes BEMT and UA, assuming that we will start the simulation over again, with only the inputs being different. !! This allows us to bypass reading input files and allocating arrays. -subroutine BEMT_ReInit(p,x,xd,z,OtherState,misc,AFinfo) +subroutine BEMT_ReInit(p,x,xd,z,OtherState,misc,AFinfo,ErrStat,ErrMsg) type(BEMT_ParameterType), intent(in ) :: p ! Parameters type(BEMT_ContinuousStateType), intent(inout) :: x ! Initial continuous states @@ -659,29 +696,49 @@ subroutine BEMT_ReInit(p,x,xd,z,OtherState,misc,AFinfo) type(BEMT_OtherStateType), intent(inout) :: OtherState ! Initial other states type(BEMT_MiscVarType), intent(inout) :: misc ! Initial misc/optimization variables type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + character(*), parameter :: RoutineName = 'BEMT_ReInit' - integer(intki) :: ErrStat2 - character(ErrMsgLen) :: errmsg2 + ErrStat = ErrID_None + ErrMsg = "" + misc%useFrozenWake = .FALSE. misc%FirstWarn_Skew = .true. misc%FirstWarn_Phi = .true. + misc%FirstWarn_BEMoff = .true. + misc%BEM_weight = 0.0_ReKi + + OtherState%DBEMT%tau1 = 0.0_ReKi !we're going to output this value, so let's initialize it if (p%UseInduction) then OtherState%ValidPhi = .true. if (p%DBEMT_Mod /= DBEMT_none ) then - call DBEMT_ReInit(x%DBEMT, OtherState%DBEMT, misc%DBEMT) + call DBEMT_ReInit(p%DBEMT, x%DBEMT, OtherState%DBEMT, misc%DBEMT) end if + else + misc%AxInduction = 0.0_ReKi + misc%TanInduction = 0.0_ReKi end if - OtherState%UA_Flag = p%UA_Flag + z%phi = 0.0_ReKi OtherState%nodesInitialized = .false. ! z%phi hasn't been initialized properly, so make sure we compute a value for phi until we've updated them in the first call to BEMT_UpdateStates() + OtherState%UA_Flag = p%UA_Flag if (p%UA_Flag) then - call UA_ReInit( p%UA, xd%UA, OtherState%UA, misc%UA ) - call BEMT_CheckInitUA(p, OtherState, AFInfo, errstat2, errmsg2) + call UA_ReInit( p%UA, x%UA, xd%UA, OtherState%UA, misc%UA, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call BEMT_CheckInitUA(p, OtherState, AFInfo, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if + + end subroutine BEMT_ReInit !---------------------------------------------------------------------------------------------------------------------------------- @@ -706,9 +763,9 @@ subroutine BEMT_CheckInitUA(p, OtherState, AFInfo, ErrStat, ErrMsg) do j = 1,p%numBlades do i = 1,p%numBladeNodes ! Loop over blades and nodes - call UA_TurnOff_param(AFInfo(p%AFindx(i,j)), ErrStat2, ErrMsg2) + call UA_TurnOff_param(p%UA, AFInfo(p%AFindx(i,j)), ErrStat2, ErrMsg2) if (ErrStat2 /= ErrID_None) then - call WrScr( 'Warning: Turning off Unsteady Aerodynamics because '//trim(ErrMsg2)//' BladeNode = '//trim(num2lstr(i))//', Blade = '//trim(num2lstr(j)) ) + call WrScr( 'Warning: Turning off Unsteady Aerodynamics because '//trim(ErrMsg2)//" "//trim(NodeText(i,j)) ) OtherState%UA_Flag(i,j) = .false. end if @@ -804,316 +861,369 @@ subroutine BEMT_UpdateStates( t, n, u1, u2, p, x, xd, z, OtherState, AFInfo, m, integer(IntKi) :: i,j - type(UA_InputType) :: u_UA - real(ReKi) :: chi ! BEMT outputs - real(ReKi) :: phitemp - - type(DBEMT_InputType) :: DBEMT_u(2) character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None integer(IntKi) :: errStat2 ! temporary Error status of the operation character(*), parameter :: RoutineName = 'BEMT_UpdateStates' + real(DbKi) :: uTimes(2) ErrStat = ErrID_None ErrMsg = "" - + + uTimes(1) = t + uTimes(2) = t+p%dt + !............................................................................................................................... ! if we haven't initialized z%phi, we want to get a better guess as to what the actual values of phi at t are: !............................................................................................................................... if (.not. OtherState%nodesInitialized) then - if (p%useInduction) then - - do j = 1,p%numBlades ! Loop through all blades - do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - - call BEMT_UnCoupledSolve(z%phi(i,j), p%numBlades, p%kinVisc, AFInfo(p%AFIndx(i,j)), u1%rlocal(i,j), p%chord(i,j), u1%theta(i,j), & - u1%Vx(i,j), u1%Vy(i,j), u1%UserProp(i,j), p%useTanInd, p%useAIDrag, p%useTIDrag, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & - p%maxIndIterations, p%aTol, OtherState%ValidPhi(i,j), m%FirstWarn_Phi, errStat2, errMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - end do - end do - else - ! We'll simply compute a geometrical phi based on both induction factors being 0.0 - do j = 1,p%numBlades ! Loop through all blades - do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - z%phi(i,j) = ComputePhiWithInduction(u1%Vx(i,j), u1%Vy(i,j), 0.0_ReKi, 0.0_ReKi) - end do - end do - - end if - OtherState%nodesInitialized = .true. ! state at t+1 + call UpdatePhi( u1, p, z%phi, AFInfo, m, OtherState%ValidPhi, errStat2, errMsg2 ) + OtherState%nodesInitialized = .true. ! otherState updated to t+dt (i.e., n+1) end if !............................................................................................................................... - ! compute inputs to DBEMT + ! compute inputs to DBEMT at step n (also setting inductions--including DBEMT and skewed wake corrections--at time n) + !............................................................................................................................... + call BEMT_CalcOutput_Inductions( 1, t, .true., .true., z%phi, u1, p, x, xd, z, OtherState, AFInfo, m%axInduction, m%tanInduction, m%chi, m, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + +#ifdef DEBUG_BEMT_RESIDUAL + if (p%useInduction) call WriteDEBUGValuesToFile(t, u1, p, x, xd, z, OtherState, m, AFInfo) +#endif !............................................................................................................................... + ! compute inputs to UA at step n + !............................................................................................................................... + if (p%UA_Flag) then + call CalculateInputsAndOtherStatesForUA(1, u1, p, x, xd, z, OtherState, AFInfo, m) + end if - if ( p%useInduction ) then + !............................................................................................................................... + ! update BEMT states to step n+1 + !............................................................................................................................... + call UpdatePhi( u2, p, z%phi, AFInfo, m, OtherState%ValidPhi, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (errStat >= AbortErrLev) return + + + !............................................................................................................................... + ! compute inputs to DBEMT at step n+1 (also setting inductions--WITHOUT DBEMT or skewed wake corrections--at step n+1) + !............................................................................................................................... + call BEMT_CalcOutput_Inductions( 2, t, .true., .false., z%phi, u2, p, x, xd, z, OtherState, AFInfo, m%axInduction, m%tanInduction, m%chi, m, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return - do j = 1,p%numBlades + !............................................................................................................................... + ! update DBEMT states to step n+1 + !............................................................................................................................... + if (p%DBEMT_Mod /= DBEMT_none) then - ! Locate the maximum rlocal value for this time step and this blade. This is passed to the solve as Rtip. - m%Rtip(j) = u1%rlocal(1,j) - do i = 2,p%numBladeNodes - m%Rtip(j) = max( m%Rtip(j), u1%rlocal(i,j) ) + !........................ + ! update DBEMT states to t+dt + !........................ + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + call DBEMT_UpdateStates(i, j, t, n, m%u_DBEMT, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, errStat2, errMsg2) + if (ErrStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) + if (errStat >= AbortErrLev) return + end if end do - end do - if (p%DBEMT_Mod /= DBEMT_none ) then - - ! Locate the maximum rlocal value for all blades. - DBEMT_u(1)%R_disk = m%Rtip(1) - do j = 2,p%numBlades - DBEMT_u(1)%R_disk = max( DBEMT_u(1)%R_disk , m%Rtip(j) ) - end do - - ! We are going to generate all the axial and tangential inductions for each blade element so that we can - ! use them later when calling get_inductions_from_DBEMT(). If tau varies, we need to compute a disk-averaged - ! axial induction, so we do the work here to avoid duplicating these calculations in the next set of do loops - ! over the blade elements. - do j = 1,p%numBlades - do i = 1,p%numBladeNodes - - call calculate_Inductions_from_BEMT(i, j, p, z%phi(i,j), u1, OtherState, AFInfo, m%axInduction(i,j), m%tanInduction(i,j), ErrStat2,ErrMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - - end do - end do - - if (p%DBEMT_Mod == DBEMT_tauVaries ) then - - ! We need to generate a disk-averaged axial induction for this timestep - DBEMT_u(1)%AxInd_disk = 0.0_ReKi - do j = 1,p%numBlades - do i = 1,p%numBladeNodes - DBEMT_u(1)%AxInd_disk = DBEMT_u(1)%AxInd_disk + m%axInduction(i,j) - end do - end do - DBEMT_u(1)%AxInd_disk = DBEMT_u(1)%AxInd_disk / (p%numBladeNodes*p%numBlades) - - DBEMT_u(1)%Un_disk = u1%Un_disk - end if - !DBEMT_u(2)%R_disk = DBEMT_u(1)%R_disk ! note that we don't use this - - end if end if + !............................................................................................................................... - ! compute states at t+dt + ! compute inputs to UA at time n+1 (also applying corrections to inductions--including DBEMT and skewed wake corrections) !............................................................................................................................... - - do j = 1,p%numBlades - - do i = 1,p%numBladeNodes - - !............................. - ! Update UA states: - !............................. + if (p%UA_Flag) then + ! after updating DBEMT states, we can now apply the corrections we omitted on the last call to BEMT_CalcOutput_Inductions() + if ( p%useInduction .and. .not. m%UseFrozenWake) then + !............................................ + ! apply DBEMT correction to axInduction and tanInduction: + !............................................ + if (p%DBEMT_Mod /= DBEMT_none) then + call calculate_Inductions_from_DBEMT_AllNodes(2, uTimes(2), u2, p, x, OtherState, m, m%axInduction, m%tanInduction) + end if - ! We only update the UnsteadyAero states if we have unsteady aero turned on for this node - if (OtherState%UA_Flag(i,j) .and. n > 0) then - - !............ Get inputs to UA, then call UA_UpdateStates if u_ua%alpha is valid ............... - - ! Set the active blade element for UnsteadyAero - m%UA%iBladeNode = i - m%UA%iBlade = j + call ApplySkewedWakeCorrection_AllNodes(p, u2, m, m%axInduction, m%chi) - if ( p%useInduction ) then - - if ( ( p%useTiploss .and. EqualRealNos(p%tipLossConst(i,j),0.0_ReKi) ) .or. ( p%useHubloss .and. EqualRealNos(p%hubLossConst(i,j),0.0_ReKi) ) ) then - m%axInduction(i,j) = 1.0_ReKi - m%tanInduction(i,j) = 0.0_ReKi - else + !............................................ + ! If TSR is too low, (start to) turn off induction + !............................................ + call check_turnOffBEMT(p, u2, m%BEM_weight, m%axInduction, m%tanInduction, m%FirstWarn_BEMoff) + + end if + + call CalculateInputsAndOtherStatesForUA(2, u2, p, x, xd, z, OtherState, AFInfo, m) + + !............................................................................................................................... + ! compute UA states at t+dt + !............................................................................................................................... + do j = 1,p%numBlades + do i = 1,p%numBladeNodes - if (p%DBEMT_Mod == DBEMT_none ) then - - call calculate_Inductions_from_BEMT(i,j,p,z%phi(i,j),u1,OtherState,AFInfo,m%axInduction(i,j), m%tanInduction(i,j), ErrStat2,ErrMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if + ! We only update the UnsteadyAero states if we have unsteady aero turned on for this node + if (OtherState%UA_Flag(i,j)) then + ! COMPUTE: x%UA and/or xd%UA, OtherState%UA + call UA_UpdateStates( i, j, t, n, m%u_UA(i,j,:), uTimes, p%UA, x%UA, xd%UA, OtherState%UA, AFInfo(p%AFIndx(i,j)), m%UA, errStat2, errMsg2 ) + if (ErrStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) + if (errStat >= AbortErrLev) return + end if - else ! use DBEMT - - ! NOTE: Since we are using DBEMT, we already computed the unfiltered m%axInduction(i,j), and m%tanInduction(i,j) quantities in the - ! "compute inputs to DBEMT" section above. + end if - ! If we are using DBEMT, then we will obtain the time-filtered versions of axInduction, tanInduction - call calculate_Inductions_from_DBEMT(i, j, u1%Vx(i,j), u1%Vy(i,j), t, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, m%axInduction(i,j), m%tanInduction(i,j)) - - end if !BEMT/DBEMT - - ! Apply the skewed wake correction to the axial induction - if ( p%skewWakeMod == SkewMod_PittPeters ) then - ! Correct for skewed wake, by recomputing axInduction - call ApplySkewedWakeCorrection( p%yawCorrFactor, u1%psi(j), u1%chi0, u1%rlocal(i,j)/m%Rtip(j), m%axInduction(i,j), chi, m%FirstWarn_Skew ) - end if ! p%skewWakeMod == SkewMod_PittPeters - + end do + end do - end if ! hub/tip loss constants - - ! recompute phi and alpha - - ! we're recomputing alpha and phi because we may have modified axInduction or tanInduction in BEMTU_InductionWithResidual and/or ApplySkewedWakeCorrection - ! but, we don't want to update the BEMT state here, so we are using a temp variable - phitemp = ComputePhiWithInduction( u1%Vx(i,j), u1%Vy(i,j), m%axInduction(i,j), m%tanInduction(i,j) ) + end if ! is UA used? + +end subroutine BEMT_UpdateStates +!.................................................................................................................................. +subroutine SetInputs_For_DBEMT(u_DBEMT, u, p, axInduction, tanInduction, Rtip) + ! note that this subroutine inherits all data from BEMT_UpdateStates + type(BEMT_InputType), intent(in ) :: u ! BEMT Input + type(BEMT_ParameterType), intent(in ) :: p ! BEMT parameters + type(DBEMT_InputType), intent(inout) :: u_DBEMT ! DBEMT Input + real(ReKi), intent(in ) :: axInduction(:,:) + real(ReKi), intent(in ) :: tanInduction(:,:) + real(ReKi), intent(in ) :: Rtip(:) + + integer :: i, j + + + ! Locate the maximum rlocal value for all blades. + u_DBEMT%R_disk = Rtip(1) + do j = 2,p%numBlades + u_DBEMT%R_disk = max( u_DBEMT%R_disk , Rtip(j) ) + end do - else - m%axInduction(i,j) = 0.0_ReKi - m%tanInduction(i,j) = 0.0_ReKi - phitemp = z%phi(i,j) - end if !p%useInduction + if (p%DBEMT_Mod == DBEMT_tauVaries ) then - ! ....... compute inputs to UA ........... - u_UA%alpha = phitemp - u1%theta(i,j) ! angle of attack - u_UA%UserProp = u1%UserProp(i,j) + ! We need to generate a disk-averaged axial induction for this timestep + u_DBEMT%AxInd_disk = 0.0_ReKi + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + u_DBEMT%AxInd_disk = u_DBEMT%AxInd_disk + axInduction(i,j) - ! Need to compute local velocity including both axial and tangential induction - ! COMPUTE: u_UA%U, u_UA%Re - call BEMTU_Wind( m%axInduction(i,j), m%tanInduction(i,j), u1%Vx(i,j), u1%Vy(i,j), p%chord(i,j), p%kinVisc, u_UA%Re, u_UA%U) + u_DBEMT%element(i,j)%spanRatio = u%rlocal(i,j)/u_DBEMT%R_disk + end do + end do + u_DBEMT%AxInd_disk = u_DBEMT%AxInd_disk / (p%numBladeNodes*p%numBlades) + + u_DBEMT%Un_disk = u%Un_disk + end if + + + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + u_DBEMT%element(i,j)%vind_s(1) = -axInduction( i,j)*u%Vx(i,j) ! Eq. 38 + u_DBEMT%element(i,j)%vind_s(2) = tanInduction(i,j)*u%Vy(i,j) ! Eq. 38 + end do + end do + + if( allocated(u%Vx_elast_dot)) then ! only for DBEMT_Mod=DBEMT_cont_tauConst + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + u_DBEMT%element(i,j)%vind_s_dot(1) = axInduction( i,j)*u%Vx_elast_dot(i,j) - u%omega_z(i,j)*tanInduction(i,j)*u%Vy(i,j) ! Eq. 41 + u_DBEMT%element(i,j)%vind_s_dot(2) = -tanInduction(i,j)*u%Vy_elast_dot(i,j) - u%omega_z(i,j)*axInduction( i,j)*u%Vx(i,j) ! Eq. 41 + end do + end do + end if + - +end subroutine SetInputs_For_DBEMT +!.................................................................................................................................. +subroutine CalculateInputsAndOtherStatesForUA(InputIndex, u, p, x, xd, z, OtherState, AFInfo, m) + integer(IntKi), intent(in ) :: InputIndex ! InputIndex= 1 or 2, depending on time step we are calculating inputs for + type(BEMT_InputType), intent(in ) :: u ! Input + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_ContinuousStateType), intent(in ) :: x ! Input: Continuous states at t; + ! Output: Continuous states at t + Interval + type(BEMT_DiscreteStateType), intent(in ) :: xd ! Input: Discrete states at t; + ! Output: Discrete states at t + Interval + type(BEMT_ConstraintStateType), intent(in ) :: z ! Input: Constraint states at t; + ! Output: Constraint states at t + Interval + type(BEMT_OtherStateType), intent(inout) :: OtherState ! Input: Other states at t; + ! Output: Other states at t + Interval + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + + + integer(IntKi) :: i,j + + character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + + + + !............................................................................................................................... + ! compute inputs to UA at time n (also setting inductions--including DBEMT and skewed wake corrections--at time n) + !............................................................................................................................... + m%phi = z%phi + call SetInputs_for_UA_AllNodes(u, p, m%phi, m%axInduction, m%tanInduction, m%u_UA(:,:,InputIndex)) + + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + + ! We only update the UnsteadyAero states if we have unsteady aero turned on for this node + if (OtherState%UA_Flag(i,j)) then ! ....... check inputs to UA ........... - call UA_TurnOff_input(AFInfo(p%AFIndx(i,j)), u_UA, ErrStat2, ErrMsg2) - + call UA_TurnOff_input(p%UA, AFInfo(p%AFIndx(i,j)), m%u_UA(i,j,InputIndex), ErrStat2, ErrMsg2) if (ErrStat2 /= ErrID_None) then OtherState%UA_Flag(i,j) = .FALSE. - call WrScr( 'Warning: Turning off Unsteady Aerodynamics due to '//trim(ErrMsg2)//' BladeNode = '//trim(num2lstr(i))//', Blade = '//trim(num2lstr(j)) ) - else - ! COMPUTE: xd%UA, OtherState%UA - call UA_UpdateStates( i, j, u_UA, p%UA, xd%UA, OtherState%UA, AFInfo(p%AFIndx(i,j)), m%UA, errStat2, errMsg2 ) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if + call WrScr( 'Warning: Turning off Unsteady Aerodynamics due to '//trim(ErrMsg2)//" "//trim(NodeText(i,j)) ) end if - end if ! if (OtherState%UA_Flag(i,j)) then - - - ! Now we need to update the inflow angle state, z%phi, independent of UnsteadyAero - if ( p%useInduction ) then - - !before updating z%phi to values at n+1, we should compute the input to DBEMT at n - if ( p%DBEMT_Mod /= DBEMT_none ) then - call get_DBEMT_inputs(1,u1) ! DBEMT inputs at t (u1) - end if - - !............................. - ! Update BEMT states to t+dt: - !............................. - - ! Solve this without any skewed wake correction and without UA - ! call BEMT_UnCoupledSolve2(i, j, u, p, z, Rtip, AFInfo, phiOut, axIndOut, tanIndOut, errStat, errMsg) - ! COMPUTE: z%phi(i,j) - call BEMT_UnCoupledSolve(z%phi(i,j), p%numBlades, p%kinVisc, AFInfo(p%AFIndx(i,j)), u2%rlocal(i,j), p%chord(i,j), u2%theta(i,j), & - u2%Vx(i,j), u2%Vy(i,j), u2%UserProp(i,j), p%useTanInd, p%useAIDrag, p%useTIDrag, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & - p%maxIndIterations, p%aTol, OtherState%ValidPhi(i,j), m%FirstWarn_Phi, errStat2, errMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - - if ( p%DBEMT_Mod /= DBEMT_none ) then - ! Generate DBEMT inputs - - !........................ - ! update DBEMT states to t+dt - !........................ - !call get_DBEMT_inputs(1,u1) ! DBEMT inputs at t (u1) - call get_DBEMT_inputs(2,u2) ! DBEMT inputs at t+dt (u2) - if (errStat >= AbortErrLev) return - - call DBEMT_UpdateStates(i, j, t, DBEMT_u, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, errStat2, errMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - end if - - else - ! We'll simply compute a geometrical phi based on both induction factors being 0.0 - z%phi(i,j) = ComputePhiWithInduction(u2%Vx(i,j), u2%Vy(i,j), 0.0_ReKi, 0.0_ReKi) end if - + end do end do -contains +end subroutine CalculateInputsAndOtherStatesForUA + +!.................................................................................................................................. +subroutine UpdatePhi( u, p, phi, AFInfo, m, ValidPhi, errStat, errMsg ) !.................................................................................................................................. - subroutine get_DBEMT_inputs(indx,u) - ! note that this subroutine inherits all data from BEMT_UpdateStates - integer , intent(in ) :: Indx ! index into DBEMT input array - type(BEMT_InputType), intent(in ) :: u ! BEMT Input at t or t + dt - call calculate_Inductions_from_BEMT(i, j, p, z%phi(i,j), u, OtherState, AFInfo, m%axInduction(i,j), m%tanInduction(i,j), ErrStat2,ErrMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - - - DBEMT_u(Indx)%vind_s(1) = -u%Vx(i,j)*m%axInduction(i,j) - DBEMT_u(Indx)%vind_s(2) = u%Vy(i,j)*m%tanInduction(i,j) - DBEMT_u(Indx)%spanRatio = u%rlocal(i,j)/DBEMT_u(1)%R_disk !DBEMT doesn't use this input for u2, so we're cheating a little + type(BEMT_InputType), intent(in ) :: u ! Input at t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + real(ReKi), intent(inout) :: phi(:,:) + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + logical, intent(inout) :: ValidPhi(:,:) ! if this is a valid BEM solution of phi + type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + integer(IntKi), intent( out) :: errStat ! Error status of the operation + character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None - end subroutine get_DBEMT_inputs + + integer(IntKi) :: i,j + character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + character(*), parameter :: RoutineName = 'UpdatePhi' + + ErrStat = ErrID_None + ErrMsg = "" + + !............................................................................................................................... + ! take the current guess of z%phi and update it using inputs + ! [called if we haven't initialized z%phi, we want to get a better guess as to what the actual values of phi at t are + ! *or* if we are updating the BEMT states] + !............................................................................................................................... -end subroutine BEMT_UpdateStates + if (p%useInduction) then + + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + + call BEMT_UnCoupledSolve(p, u, i, j, phi(i,j), AFInfo(p%AFIndx(i,j)), & + ValidPhi(i,j), m%FirstWarn_Phi,errStat2, errMsg2) + + if (errStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) + if (errStat >= AbortErrLev) return + end if + end do + end do + else + ! We'll simply compute a geometrical phi based on both induction factors being 0.0 + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + phi(i,j) = ComputePhiWithInduction(u%Vx(i,j), u%Vy(i,j), 0.0_ReKi, 0.0_ReKi) + end do + end do + + end if + + return + +end subroutine UpdatePhi +!.................................................................................................................................. +subroutine GetRTip( u, p, RTip ) !.................................................................................................................................. -subroutine calculate_Inductions_from_BEMT(i,j,p,phi,u,OtherState,AFInfo,axInduction,tanInduction, ErrStat,ErrMsg) - integer(IntKi), intent(in ) :: i !< blade node counter - integer(IntKi), intent(in ) :: j !< blade counter - type(BEMT_ParameterType), intent(in ) :: p !< Parameters - real(ReKi), intent(in ) :: phi !< phi - type(BEMT_InputType), intent(in ) :: u !< Inputs at t - type(BEMT_OtherStateType), intent(in ) :: OtherState !< Other/logical states at t - type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data - real(ReKi), intent(inout) :: axInduction !< axial induction - real(ReKi), intent(inout) :: tanInduction !< tangential induction - integer(IntKi), intent( out) :: errStat !< Error status of the operation - character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None - - real(ReKi) :: fzero ! residual from induction equation (not used here) - Real(ReKi) :: Re ! Reynold's number - logical :: IsValidSolution !< this indicates BEMT found a geometric solution because a BEMT solution could not be found - integer(IntKi) :: errStat2 !< Error status of the operation - character(ErrMsgLen) :: errMsg2 !< Error message if ErrStat /= ErrID_None + type(BEMT_InputType), intent(in ) :: u ! Input at t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + real(ReKi), intent( out) :: Rtip(:) + + integer(IntKi) :: i,j + + do j = 1,p%numBlades + + ! Locate the maximum rlocal value for this time step and this blade. This is passed to the solve as Rtip. + Rtip(j) = u%rlocal(1,j) + do i = 2,p%numBladeNodes + Rtip(j) = max( Rtip(j), u%rlocal(i,j) ) + end do + + end do + + return + +end subroutine GetRTip +!.................................................................................................................................. +subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction,tanInduction, ErrStat,ErrMsg) + + type(BEMT_ParameterType), intent(in ) :: p !< Parameters + real(ReKi), intent(in ) :: phi(:,:) !< phi + type(BEMT_InputType), intent(in ) :: u !< Inputs at t + type(BEMT_OtherStateType), intent(in ) :: OtherState !< Other/logical states at t + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data + real(ReKi), intent(inout) :: axInduction(:,:) !< axial induction + real(ReKi), intent(inout) :: tanInduction(:,:) !< tangential induction + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + + integer(IntKi) :: i !< blade node counter + integer(IntKi) :: j !< blade counter + + real(ReKi) :: fzero !< residual from induction equation (not used here) + logical :: IsValidSolution !< this indicates BEMT found a geometric solution because a BEMT solution could not be found + integer(IntKi) :: errStat2 !< Error status of the operation + character(ErrMsgLen) :: errMsg2 !< Error message if ErrStat /= ErrID_None character(*), parameter :: RoutineName = 'calculate_Inductions_from_BEMT' ErrStat = ErrID_None ErrMsg = "" - if (OtherState%ValidPhi(i,j)) then + + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + + if (OtherState%ValidPhi(i,j)) then - ! Need to get the induction factors for these conditions without skewed wake correction and without UA - ! COMPUTE: axInduction, tanInduction - fzero = BEMTU_InductionWithResidual(phi, u%theta(i,j), p%kinVisc, u%UserProp(i,j), p%numBlades, u%rlocal(i,j), p%chord(i,j), AFInfo(p%AFIndx(i,j)), & - u%Vx(i,j), u%Vy(i,j), p%useTanInd, p%useAIDrag, p%useTIDrag, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & - IsValidSolution, ErrStat2, ErrMsg2, a=axInduction, ap=tanInduction) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg, RoutineName) + ! Need to get the induction factors for these conditions without skewed wake correction and without UA + ! COMPUTE: axInduction, tanInduction + fzero = BEMTU_InductionWithResidual(p, u, i, j, phi(i,j), AFInfo(p%AFIndx(i,j)), IsValidSolution, ErrStat2, ErrMsg2, a=axInduction(i,j), ap=tanInduction(i,j)) - else + if (ErrStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) + if (errStat >= AbortErrLev) return + end if + + ! modify inductions based on max/min allowed values (note that we do this before calling DBEMT so that its disk-averaged induction input isn't dominated by very large values here + if (.not. IsValidSolution) then + axInduction(i,j) = 0.0_ReKi + tanInduction(i,j) = 0.0_ReKi + else + call limitInductionFactors(axInduction(i,j), tanInduction(i,j)) + end if + + else - axInduction = 0.0_ReKi - tanInduction = 0.0_ReKi + axInduction(i,j) = 0.0_ReKi + tanInduction(i,j) = 0.0_ReKi - end if - + end if + + end do + end do end subroutine calculate_Inductions_from_BEMT !.................................................................................................................................. -subroutine calculate_Inductions_from_DBEMT(i, j, Vx, Vy, t, p, x, OtherState, m, axInduction, tanInduction) +subroutine calculate_Inductions_from_DBEMT(i, j, Vx, Vy, t, p, u, x, OtherState, m, axInduction, tanInduction) integer(IntKi), intent(in ) :: i !< blade node counter integer(IntKi), intent(in ) :: j !< blade counter @@ -1121,6 +1231,7 @@ subroutine calculate_Inductions_from_DBEMT(i, j, Vx, Vy, t, p, x, OtherState, m, real(ReKi), intent(in ) :: Vy !< Velocity real(DbKi), intent(in ) :: t !< Current simulation time in seconds type(DBEMT_ParameterType), intent(in ) :: p !< Parameters + type(DBEMT_InputType), intent(in ) :: u !< Inputs for DBEMT module (note that there aren't any allocatable arrays or pointers); CalcOutput needs only vind_s to be set, and only at initialization type(DBEMT_ContinuousStateType), intent(in ) :: x !< Continuous states at t type(DBEMT_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables type(DBEMT_OtherStateType), intent(in ) :: OtherState !< Other/logical states at t @@ -1132,44 +1243,246 @@ subroutine calculate_Inductions_from_DBEMT(i, j, Vx, Vy, t, p, x, OtherState, m, ! DBEMT doesn't set ErrStat/ErrMsg to anything but ErrStat=ErrID_None so these are local variables integer(IntKi) :: errStat !< Error status of the operation character(ErrMsgLen) :: errMsg !< Error message if ErrStat /= ErrID_None - type(DBEMT_InputType) :: u !< Inputs for DBEMT module (note that there aren't any allocatable arrays or pointers); CalcOutput needs only vind_s to be set, and only at initialization - ! Note that the outputs of DBEMT are the state variables x%vind; we set the inputs only - ! in case the states have not yet been initialized. - - u%vind_s(1) = -Vx*axInduction - u%vind_s(2) = Vy*tanInduction + ! Note that the outputs of DBEMT are the state variables x%vind, except on the first call when they uninitialized and use the inputs in place of the states - call DBEMT_CalcOutput( i, j, t, u, dbemt_vind, p, x, OtherState, m, errStat, errMsg ) if ( EqualRealnos(Vx, 0.0_ReKi) ) then axInduction = 0.0_ReKi else axInduction = -dbemt_vind(1)/Vx + end if + + if ( EqualRealnos(Vy, 0.0_ReKi) ) then + tanInduction = 0.0_ReKi + else + tanInduction = dbemt_vind(2)/Vy + end if + + call limitInductionFactors(axInduction, tanInduction) + +end subroutine calculate_Inductions_from_DBEMT +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine check_turnOffBEMT(p, u, Weight, axInduction, tanInduction, FirstWarn) + + type(BEMT_ParameterType), intent(in ) :: p !< Parameters + type(BEMT_InputType), intent(in ) :: u !< Inputs at t + real(ReKi), intent( out) :: Weight !< scaling value from BEM-to-non_BEM solution (blends inductions from BEMT and non-BEMT[zeros]) + real(ReKi), intent(inout) :: axInduction(:,:) !< axial induction + real(ReKi), intent(inout) :: tanInduction(:,:) !< tangential induction + logical, intent(inout) :: FirstWarn !< Whether BEM had a warning about being shut off + + integer(IntKi) :: i !< blade node counter + integer(IntKi) :: j !< blade counter + + if( u%TSR < BEMT_upperBoundTSR ) then + + Weight = BlendCosine( u%TSR, BEMT_lowerBoundTSR, BEMT_upperBoundTSR ) + + if (FirstWarn) then + if (Weight < 1.0_ReKi) then + call WrScr( 'The BEM solution is being turned off due to low TSR. (TSR = ' & + //TRIM(Num2Lstr(u%TSR))//'). This warning will not be repeated though the condition may persist. (See GeomPhi output channel.)' ) + FirstWarn = .false. + end if + end if + + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + ! weighted average with BEM turned off (if TSR falls in certain range): + axInduction( i,j) = axInduction( i,j)*Weight + tanInduction(i,j) = tanInduction(i,j)*Weight + end do + end do + + else + Weight = 1.0_ReKi + end if + +end subroutine check_turnOffBEMT +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine BEMT_CalcOutput( t, u, p, x, xd, z, OtherState, AFInfo, y, m, errStat, errMsg ) +! Routine for computing outputs, used in both loose and tight coupling. +!.................................................................................................................................. + + + real(DbKi), intent(in ) :: t ! Current simulation time in seconds + type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_ContinuousStateType), intent(in ) :: x ! Continuous states at t + type(BEMT_DiscreteStateType), intent(in ) :: xd ! Discrete states at t + type(BEMT_ConstraintStateType), intent(in ) :: z ! Constraint states at t + type(BEMT_OtherStateType), intent(in ) :: OtherState ! Other states at t + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + type(BEMT_OutputType), intent(inout) :: y ! Outputs computed at t (Input only so that mesh con- + ! nectivity information does not have to be recalculated) + integer(IntKi), intent( out) :: errStat ! Error status of the operation + character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None + + + ! Local variables: + + integer(IntKi) :: i ! Generic index + integer(IntKi) :: j ! Loops through nodes / elements + integer(IntKi), parameter :: InputIndex=1 ! we will always use values at t in this routine + + character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat2 ! temporary Error status of the operation + character(*), parameter :: RoutineName = 'BEMT_CalcOutput' + + type(AFI_OutputType) :: AFI_interp + + +#ifdef UA_OUTS + integer(IntKi) :: k +#endif + + ! Initialize some output values + errStat = ErrID_None + errMsg = "" + + +#ifdef UA_OUTS + ! if ( mod(REAL(t,ReKi),.1) < p%dt) then + if (allocated(m%y_UA%WriteOutput)) m%y_UA%WriteOutput = 0.0 !reset to zero in case UA shuts off mid-simulation +#endif + +!!#ifdef DEBUG_BEMT_RESIDUAL +!! call WriteDEBUGValuesToFile(t, u, p, x, xd, z, OtherState, m, AFInfo) +!!#endif + + y%phi = z%phi ! set this before possibly calling UpdatePhi() because phi is intent(inout) in the solve + + !............................................................................................................................... + ! if we haven't initialized z%phi, we want to get a better guess as to what the actual values of phi are: + !............................................................................................................................... + if (.not. OtherState%nodesInitialized) then + call UpdatePhi( u, p, y%phi, AFInfo, m, m%ValidPhi, errStat2, errMsg2 ) + end if + + !............................................ + ! calculate inductions using BEMT, applying the DBEMT, and/or skewed wake corrections as applicable: + !............................................ + call BEMT_CalcOutput_Inductions( InputIndex, t, .false., .true., y%phi, u, p, x, xd, z, OtherState, AFInfo, y%axInduction, y%tanInduction, y%chi, m, errStat, errMsg ) + + !............................................ + ! update phi if necessary (consistent with inductions) and calculate inputs to UA: + !............................................ + call SetInputs_for_UA_AllNodes(u, p, y%phi, y%axInduction, y%tanInduction, m%u_UA(:,:,InputIndex)) + + !............................................ + ! unsteady aero and related outputs (cl, cd, cm, AoA, Vrel, Re) + !............................................ + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + + ! set output values: + y%AOA( i,j) = m%u_UA(i,j,InputIndex)%alpha + y%Vrel(i,j) = m%u_UA(i,j,InputIndex)%U + y%Re( i,j) = m%u_UA(i,j,InputIndex)%Re + + ! Now depending on the option for UA get the airfoil coefs, Cl, Cd, Cm for unsteady or steady implementation + if (OtherState%UA_Flag(i,j) ) then + call UA_CalcOutput(i, j, m%u_UA(i,j,InputIndex), p%UA, x%UA, xd%UA, OtherState%UA, AFInfo(p%AFindx(i,j)), m%y_UA, m%UA, errStat2, errMsg2 ) + y%Cl(i,j) = m%y_UA%Cl + y%Cd(i,j) = m%y_UA%Cd + y%Cm(i,j) = m%y_UA%Cm + else + ! compute steady Airfoil Coefs + call AFI_ComputeAirfoilCoefs( y%AOA(i,j), y%Re(i,j), u%UserProp(i,j), AFInfo(p%AFindx(i,j)), AFI_interp, errStat2, errMsg2 ) + y%Cl(i,j) = AFI_interp%Cl + y%Cd(i,j) = AFI_interp%Cd + y%Cm(i,j) = AFI_interp%Cm + y%Cpmin(i,j) = AFI_interp%Cpmin + end if + if (ErrStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) + if (errStat >= AbortErrLev) return + end if + + enddo ! I - Blade nodes / elements + enddo ! J - All blades + + + !............................................ + ! Compute Cx, Cy given Cl, Cd and phi + !............................................ + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + ! NOTE: For these calculations we force the useAIDrag and useTIDrag flags to .TRUE. + call Transform_ClCd_to_CxCy( y%phi(i,j), .TRUE., .TRUE., y%Cl(i,j), y%Cd(i,j),y%Cx(i,j), y%Cy(i,j) ) + + enddo ! I - Blade nodes / elements + enddo ! J - All blades + +#ifdef UA_OUTS + ! if ( mod(REAL(t,ReKi),.1) < p%dt) then + if (allocated(m%y_UA%WriteOutput)) & + WRITE (69, '(F20.6,'//trim(num2lstr(size(m%y_UA%WriteOutput)))//'(:,1x,ES19.5E3))') t, ( m%y_UA%WriteOutput(k), k=1,size(m%y_UA%WriteOutput)) + ! end if +#endif + + return + + +end subroutine BEMT_CalcOutput + +!---------------------------------------------------------------------------------------------------------------------------------- +!> Routine used in linearization to get the states initialized properly at t=0 (before perturbing things) +subroutine BEMT_InitStates(t, u, p, x, xd, z, OtherState, m, AFInfo, ErrStat, ErrMsg ) + REAL(DbKi), intent(in ) :: t ! current simulation time + type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_ContinuousStateType), intent(inout) :: x ! Continuous states at t + type(BEMT_DiscreteStateType), intent(in ) :: xd ! Discrete states at t + type(BEMT_ConstraintStateType), intent(in ) :: z ! Constraint states at t + type(BEMT_OtherStateType), intent(inout) :: OtherState ! Other states at t + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + integer(IntKi), intent( out) :: errStat ! Error status of the operation + character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None - axInduction = min( axInduction, BEMT_MaxInduction(1)) - axInduction = max( axInduction, BEMT_MinInduction(1)) - end if + INTEGER(IntKi) :: i, j + INTEGER(IntKi), parameter :: InputIndex = 1 + LOGICAL, parameter :: CalculateDBEMTInputs = .true. + LOGICAL, parameter :: ApplyCorrections = .true. - if ( EqualRealnos(Vy, 0.0_ReKi) ) then - tanInduction = 0.0_ReKi - else - tanInduction = dbemt_vind(2)/Vy + integer(IntKi) :: errStat2 ! Error status of the operation + character(ErrMsgLen) :: errMsg2 ! Error message if ErrStat /= ErrID_None + character(*), parameter :: RoutineName = 'BEMT_InitStates' + + + ErrStat = ErrID_None + ErrMsg = "" + + if (OtherState%nodesInitialized) return + + m%phi = z%phi + call BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, ApplyCorrections, m%phi, u, p, x, xd, z, OtherState, AFInfo, m%axInduction, m%tanInduction, m%chi, m, errStat, errMsg ) - tanInduction = min( tanInduction, BEMT_MaxInduction(2)) - tanInduction = max( tanInduction, BEMT_MinInduction(2)) + if (p%DBEMT_Mod /= DBEMT_none) then + call DBEMT_InitStates_AllNodes( m%u_DBEMT(InputIndex), p%DBEMT, x%DBEMT, OtherState%DBEMT ) end if - -end subroutine calculate_Inductions_from_DBEMT - + + if (p%UA_Flag) then + call CalculateInputsAndOtherStatesForUA(InputIndex, u, p, x, xd, z, OtherState, AFInfo, m) + call UA_InitStates_AllNodes( m%u_UA(i,j,InputIndex), p%UA, x%UA, OtherState%UA, OtherState%UA_Flag, AFInfo, p%AFIndx ) + end if ! is UA used? + + +end subroutine BEMT_InitStates !---------------------------------------------------------------------------------------------------------------------------------- -subroutine BEMT_CalcOutput( t, u, p, x, xd, z, OtherState, AFInfo, y, m, errStat, errMsg ) -! Routine for computing outputs, used in both loose and tight coupling. +!> Routine for computing inductions outputs, used in both loose and tight coupling. +subroutine BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, ApplyCorrections, phi, u, p, x, xd, z, OtherState, AFInfo, axInduction, tanInduction, chi, m, errStat, errMsg ) !.................................................................................................................................. - - real(DbKi), intent(in ) :: t ! Current simulation time in seconds + REAL(DbKi), intent(in ) :: t ! current simulation time + INTEGER(IntKi), intent(in ) :: InputIndex ! index into m%u_DEBMT (1 or 2) + LOGICAL, intent(in ) :: CalculateDBEMTInputs ! if called from UpdateStates, we'd want the DBEMT inputs calculated. Otherwise it saves time not to calculate them + LOGICAL, intent(in ) :: ApplyCorrections ! if called from UpdateStates and we haven't updated DBEMT states, we'd want to avoid applying DBEMT and the skewed wake corrections + REAL(ReKi), intent(in ) :: phi(:,:) type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t type(BEMT_ParameterType), intent(in ) :: p ! Parameters type(BEMT_ContinuousStateType), intent(in ) :: x ! Continuous states at t @@ -1178,212 +1491,158 @@ subroutine BEMT_CalcOutput( t, u, p, x, xd, z, OtherState, AFInfo, y, m, errStat type(BEMT_OtherStateType), intent(in ) :: OtherState ! Other states at t type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data - type(BEMT_OutputType), intent(inout) :: y ! Outputs computed at t (Input only so that mesh con- - ! nectivity information does not have to be recalculated) + REAL(ReKi), intent(inout) :: axInduction(:,:) + REAL(ReKi), intent(inout) :: tanInduction(:,:) + REAL(ReKi), intent(inout) :: chi(:,:) ! value used in skewed wake correction integer(IntKi), intent( out) :: errStat ! Error status of the operation character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None ! Local variables: - - real(ReKi) :: Rtip ! maximum rlocal value for node j for a given blade - integer(IntKi) :: i ! Generic index integer(IntKi) :: j ! Loops through nodes / elements character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None integer(IntKi) :: errStat2 ! temporary Error status of the operation - character(*), parameter :: RoutineName = 'BEMT_CalcOutput' - - type(AFI_OutputType) :: AFI_interp - + character(*), parameter :: RoutineName = 'BEMT_CalcOutput_Inductions' + -#ifdef UA_OUTS - integer(IntKi) :: k -#endif - - logical :: IsValidSolution !< this is set to false if k<=1 in propeller brake region or k<-1 in momentum region, indicating an invalid solution ! Initialize some output values errStat = ErrID_None errMsg = "" - -#ifdef UA_OUTS - ! if ( mod(REAL(t,ReKi),.1) < p%dt) then - if (allocated(m%y_UA%WriteOutput)) m%y_UA%WriteOutput = 0.0 !reset to zero in case UA shuts off mid-simulation -#endif - !............................................................................................................................... - ! if we haven't initialized z%phi, we want to get a better guess as to what the actual values of phi are: - !............................................................................................................................... - - if (OtherState%nodesInitialized) then - y%phi = z%phi - else - if (p%useInduction) then - + chi = u%chi0 ! with no induction, chi = chi0 at all nodes (overwritten in ApplySkewedWakeCorrection) + + if ( p%useInduction ) then + + if (m%UseFrozenWake) then ! note that this is used only when DBEMT_Mod==DBEMT_none + do j = 1,p%numBlades ! Loop through all blades do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - - y%phi(i,j) = z%phi(i,j) - call BEMT_UnCoupledSolve(y%phi(i,j), p%numBlades, p%kinVisc, AFInfo(p%AFIndx(i,j)), u%rlocal(i,j), p%chord(i,j), u%theta(i,j), & - u%Vx(i,j), u%Vy(i,j), u%UserProp(i,j), p%useTanInd, p%useAIDrag, p%useTIDrag, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & - p%maxIndIterations, p%aTol, IsValidSolution, m%FirstWarn_Phi, errStat2, errMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - end do - end do - - !bjj: IsValidSolution may cause inconsistent values for DBEMT here at initialization. Probably not a big deal. + ! note that we've already checked if these velocities are zero before calling this routine in linearization + !BJJ: THIS ISN'T NECESSARIALLY TRUE ANYMORE + if (EqualRealNos(u%Vx(i,j),0.0_ReKi)) then + axInduction(i,j) = 0.0_ReKi ! does this violate the frozen wake requirements???? + else + axInduction(i,j) = -m%AxInd_op(i,j) / u%Vx(i,j) + end if + if (EqualRealNos(u%Vy(i,j),0.0_ReKi)) then + tanInduction(i,j) = 0.0_ReKi ! does this violate the frozen wake requirements???? + else + tanInduction(i,j) = m%TnInd_op(i,j) / u%Vy(i,j) + end if + enddo ! I - Blade nodes / elements + enddo ! J - All blades - ! we need to initialize the inductions for the first time calling DBEMT + else + + ! Locate the maximum rlocal value for this time step and this blade. This is passed to the solve as Rtip. + call GetRTip( u, p, m%Rtip ) + + !............................................ + ! get BEMT inductions (axInduction and tanInduction): + !............................................ + call calculate_Inductions_from_BEMT(p, phi, u, OtherState, AFInfo, axInduction, tanInduction, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (errStat >= AbortErrLev) return + + !............................................ + ! apply DBEMT correction to axInduction and tanInduction: + !............................................ if (p%DBEMT_Mod /= DBEMT_none) then - do j = 1,p%numBlades ! Loop through all blades - do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - - call calculate_Inductions_from_BEMT(i, j, p, y%phi(i,j), u, OtherState, AFInfo, y%axInduction(i,j), y%tanInduction(i,j), ErrStat2, ErrMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - - end do - end do - end if ! DBEMT + ! If we are using DBEMT, then we will obtain the time-filtered versions of axInduction(i,j), tanInduction(i,j) - else + ! Note that the outputs of DBEMT are the state variables x%vind, so we don't NEED to set the inputs except on initialization step (when we output the inputs instead of the states) + ! If calling from UpdateStates, we'd want to have a copy of the DBEMT inputs for updating its states later + if (CalculateDBEMTInputs .or. .not. OtherState%nodesInitialized) then + call SetInputs_For_DBEMT(m%u_DBEMT(InputIndex), u, p, axInduction, tanInduction, m%Rtip) ! DBEMT inputs at InputIndex time (1=n; 2=n+1) + end if - ! We'll simply compute a geometrical phi based on both induction factors being 0.0 - do j = 1,p%numBlades ! Loop through all blades - do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - y%phi(i,j) = ComputePhiWithInduction(u%Vx(i,j), u%Vy(i,j), 0.0_ReKi, 0.0_ReKi) - end do - end do + if (ApplyCorrections) then ! avoid updating inductions when called before updating DBEMT states + call calculate_Inductions_from_DBEMT_AllNodes(InputIndex, t, u, p, x, OtherState, m, axInduction, tanInduction) + end if + end if ! DBEMT - end if - end if - - do j = 1,p%numBlades ! Loop through all blades - - ! Locate the maximum rlocal value for this time step and this blade. This is passed to the solve as Rtip - Rtip = 0.0_ReKi - do i = 1,p%numBladeNodes - Rtip = max( Rtip, u%rlocal(i,j) ) - end do - - do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements - - ! Set the active blade element for UnsteadyAero - m%UA%iBladeNode = i - m%UA%iBlade = j - - !y%phi(i,j) = z%phi(i,j) ! this was done above (to take possible initializion into account) - y%chi(i,j) = u%chi0 ! with no induction, chi = chi0 (overwritten in ApplySkewedWakeCorrection) - - if ( p%useInduction ) then + if (ApplyCorrections) then ! avoid updating inductions when called before updating DBEMT states + !............................................ + ! Apply skewed wake correction to the axial induction (axInduction) + !............................................ + call ApplySkewedWakeCorrection_AllNodes(p, u, m, axInduction, chi) - if (m%UseFrozenWake) then - ! note that we've already checked if these velocities are zero before calling this routine in linearization - y%axInduction(i,j) = -m%AxInd_op(i,j) / u%Vx(i,j) - y%tanInduction(i,j) = m%TnInd_op(i,j) / u%Vy(i,j) - else - - if ( ( p%useTiploss .and. EqualRealNos(p%tipLossConst(i,j),0.0_ReKi) ) .or. ( p%useHubloss .and. EqualRealNos(p%hubLossConst(i,j),0.0_ReKi) ) ) then - y%axInduction(i,j) = 1.0_ReKi - y%tanInduction(i,j) = 0.0_ReKi - else - - if (p%DBEMT_Mod == DBEMT_none) then + !............................................ + ! If TSR is too low, (start to) turn off induction + !............................................ + call check_turnOffBEMT(p, u, m%BEM_weight, axInduction, tanInduction, m%FirstWarn_BEMoff) + end if - call calculate_Inductions_from_BEMT(i, j, p, y%phi(i,j), u, OtherState, AFInfo, y%axInduction(i,j), y%tanInduction(i,j), ErrStat2,ErrMsg2) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if + end if ! UseFrozenWake - else ! if (p%DBEMT_Mod /= DBEMT_none) then - - ! If we are using DBEMT, then we will obtain the time-filtered versions of y%axInduction(i,j), y%tanInduction(i,j) - ! Note that the outputs of DBEMT are the state variables x%vind, so we don't need to set the inputs except on initialization step - call calculate_Inductions_from_DBEMT(i, j, u%Vx(i,j), u%Vy(i,j), t, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, y%axInduction(i,j), y%tanInduction(i,j)) + else ! no induction: + axInduction = 0.0_ReKi ! all nodes + tanInduction = 0.0_ReKi ! all nodes + end if ! UseInduction - end if ! BEMT/DBEMT - - ! Apply the skewed wake correction to the axial induction (y%axInduction) - if ( p%skewWakeMod == SkewMod_PittPeters ) then - call ApplySkewedWakeCorrection( p%yawCorrFactor, u%psi(j), u%chi0, u%rlocal(i,j)/Rtip, y%axInduction(i,j), y%chi(i,j), m%FirstWarn_Skew ) - end if - - end if ! special case for tip and/or hub loss - - end if ! UseFrozenWake - - ! recompute y%phi, y%AOA: - ! we're recomputing phi because it may not be consistent with the computed axInduction or tanInduction values (note this doesn't get modified with ValidPhi=false) - y%phi(i,j) = ComputePhiWithInduction( u%Vx(i,j), u%Vy(i,j), y%axInduction(i,j), y%tanInduction(i,j) ) + return +end subroutine BEMT_CalcOutput_Inductions +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine calculate_Inductions_from_DBEMT_AllNodes(InputIndex, t, u, p, x, OtherState, m, axInduction, tanInduction) + INTEGER(IntKi), intent(in ) :: InputIndex ! index into m%u_DEBMT (1 or 2) + REAL(DbKi), intent(in ) :: t ! current simulation time + type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_ContinuousStateType), intent(in ) :: x ! Continuous states at t + type(BEMT_OtherStateType), intent(in ) :: OtherState ! Other states at t + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + REAL(ReKi), intent(inout) :: axInduction(:,:) + REAL(ReKi), intent(inout) :: tanInduction(:,:) - else - ! initialize other outputs assuming no induction or skewed wake corrections - y%axInduction(i,j) = 0.0_ReKi - y%tanInduction(i,j) = 0.0_ReKi - end if ! UseInduction - - ! angle of attack - y%AOA(i,j) = y%phi(i,j) - u%theta(i,j) - - ! Compute Re, Vrel based on current values of axInduction, tanInduction - call BEMTU_Wind( y%axInduction(i,j), y%tanInduction(i,j), u%Vx(i,j), u%Vy(i,j), p%chord(i,j), p%kinVisc, y%Re(i,j), y%Vrel(I,J) ) - - ! Now depending on the option for UA get the airfoil coefs, Cl, Cd, Cm for unsteady or steady implementation - if (OtherState%UA_Flag(i,j) .and. ( .not. EqualRealNos(y%Vrel(I,J),0.0_ReKi) ) ) then - call Compute_UA_AirfoilCoefs( y%AOA(i,j), y%Vrel(I,J), y%Re(i,j), u%UserProp(i,j), AFInfo(p%AFindx(i,j)), p%UA, xd%UA, OtherState%UA, m%y_UA, m%UA, & - y%Cl(i,j), y%Cd(i,j), y%Cm(i,j), errStat2, errMsg2 ) - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - else - ! compute steady Airfoil Coefs - call AFI_ComputeAirfoilCoefs( y%AOA(i,j), y%Re(i,j), u%UserProp(i,j), AFInfo(p%AFindx(i,j)), AFI_interp, errStat2, errMsg2 ) - y%Cl(i,j) = AFI_interp%Cl - y%Cd(i,j) = AFI_interp%Cd - y%Cm(i,j) = AFI_interp%Cm - y%Cpmin(i,j) = AFI_interp%Cpmin - if (ErrStat2 /= ErrID_None) then - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) - if (errStat >= AbortErrLev) return - end if - end if + ! Local variables: - - ! Compute Cx, Cy given Cl, Cd and phi - ! NOTE: For these calculations we force the useAIDrag and useTIDrag flags to .TRUE. - call Transform_ClCd_to_CxCy( y%phi(i,j), .TRUE., .TRUE., y%Cl(i,j), y%Cd(i,j),y%Cx(i,j), y%Cy(i,j) ) - + integer(IntKi) :: i ! Generic index + integer(IntKi) :: j ! Loops through nodes / elements + + + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + if ( .not. p%FixedInductions(i,j) ) then + call calculate_Inductions_from_DBEMT(i, j, u%Vx(i,j), u%Vy(i,j), t, p%DBEMT, m%u_DBEMT(InputIndex), x%DBEMT, OtherState%DBEMT, m%DBEMT, axInduction(i,j), tanInduction(i,j)) + end if ! .not. p%FixedInductions (special case for tip and/or hub loss) enddo ! I - Blade nodes / elements - enddo ! J - All blades -#ifdef UA_OUTS - ! if ( mod(REAL(t,ReKi),.1) < p%dt) then - if (allocated(m%y_UA%WriteOutput)) & - WRITE (69, '(F20.6,'//trim(num2lstr(size(m%y_UA%WriteOutput)))//'(:,1x,ES19.5E3))') t, ( m%y_UA%WriteOutput(k), k=1,size(m%y_UA%WriteOutput)) - ! end if -#endif - - - return - -end subroutine BEMT_CalcOutput +end subroutine calculate_Inductions_from_DBEMT_AllNodes +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine ApplySkewedWakeCorrection_AllNodes(p, u, m, axInduction, chi) + type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + REAL(ReKi), intent(inout) :: axInduction(:,:) + REAL(ReKi), intent(inout) :: chi(:,:) ! value used in skewed wake correction + + integer(IntKi) :: i ! Generic index + integer(IntKi) :: j ! Loops through nodes / elements + + !............................................ + ! Apply skewed wake correction to the axial induction (y%axInduction) + !............................................ + if ( p%skewWakeMod == SkewMod_PittPeters ) then + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + if ( .not. p%FixedInductions(i,j) ) then + call ApplySkewedWakeCorrection( p%yawCorrFactor, u%psi(j), u%chi0, u%rlocal(i,j)/m%Rtip(j), axInduction(i,j), chi(i,j), m%FirstWarn_Skew ) + end if ! .not. p%FixedInductions (special case for tip and/or hub loss) + enddo ! I - Blade nodes / elements + enddo ! J - All blades + end if +end subroutine ApplySkewedWakeCorrection_AllNodes !---------------------------------------------------------------------------------------------------------------------------------- -subroutine BEMT_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) +subroutine BEMT_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, AFInfo, ErrStat, ErrMsg ) ! Tight coupling routine for computing derivatives of continuous states !.................................................................................................................................. @@ -1394,20 +1653,90 @@ subroutine BEMT_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrS TYPE(BEMT_DiscreteStateType), INTENT(IN ) :: xd ! Discrete states at t TYPE(BEMT_ConstraintStateType), INTENT(IN ) :: z ! Constraint states at t TYPE(BEMT_OtherStateType), INTENT(IN ) :: OtherState ! Other states at t - type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables - TYPE(BEMT_ContinuousStateType), INTENT( OUT) :: dxdt ! Continuous state derivatives at t + TYPE(BEMT_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization variables + TYPE(BEMT_ContinuousStateType), INTENT(INOUT) :: dxdt ! Continuous state derivatives at t + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo(:) ! The airfoil parameter data INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None - + ! local variables + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(*), PARAMETER :: RoutineName = 'BEMT_CalcContStateDeriv' + + INTEGER(IntKi), parameter :: InputIndex = 1 + INTEGER(IntKi) :: i, j ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" - dxdt%DummyContState = 0.0_ReKi + + + m%phi = z%phi ! set this before possibly calling InitPhi() because phi is intent(inout) in the solve + + !............................................................................................................................... + ! THIS IS CALLED ONLY DURING LINEARIZATION, where we want to treat z%phi as an implied input, thus we need to recalculate phi + ! consistent with the inputs: + !............................................................................................................................... + call UpdatePhi( u, p, m%phi, AFInfo, m, m%ValidPhi, errStat2, errMsg2 ) + + !............................................................................................................................... + ! compute inputs to DBEMT (also setting inductions needed for UA inputs--including DBEMT and skewed wake corrections) + !............................................................................................................................... + call BEMT_CalcOutput_Inductions( InputIndex, t, .true., .true., m%phi, u, p, x, xd, z, OtherState, AFInfo, m%axInduction, m%tanInduction, m%chi, m, errStat2, errMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + !............................................................................................................................... + ! compute derivatives for DBEMT continuous states: + !............................................................................................................................... + if (p%DBEMT_Mod /= DBEMT_none) then + if (.not. allocated(dxdt%DBEMT%element)) then + call DBEMT_CopyContState( x%DBEMT, dxdt%DBEMT, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + end if + + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + call DBEMT_CalcContStateDeriv( i, j, t, m%u_DBEMT(InputIndex)%element(i,j), p%DBEMT, x%DBEMT%element(i,j), OtherState%DBEMT, m%DBEMT, dxdt%DBEMT%element(i,j), ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + enddo ! I - Blade nodes / elements + enddo ! J - All blades + end if + + + + !............................................................................................................................... + ! compute inputs to UA + !............................................................................................................................... + if (p%UA_Flag) then + call SetInputs_for_UA_AllNodes(u, p, m%phi, m%axInduction, m%tanInduction, m%u_UA(:,:,InputIndex)) + + !............................................................................................................................... + ! compute derivatives for UA continuous states: + !............................................................................................................................... + if (.not. allocated(dxdt%UA%element)) then + call UA_CopyContState( x%UA, dxdt%UA, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + end if + do j = 1,p%numBlades + do i = 1,p%numBladeNodes + ! We only update the UnsteadyAero states if we have unsteady aero turned on for this node + if (OtherState%UA_Flag(i,j)) then + call UA_CalcContStateDeriv( i, j, t, m%u_UA(i,j,InputIndex), p%UA, x%UA%element(i,j), OtherState%UA, AFInfo(p%AFIndx(i,j)), m%UA, dxdt%UA%element(i,j), ErrStat2, ErrMsg2 ) + else + dxdt%UA%element(i,j)%x = 0.0_R8Ki + end if + end do + end do + + end if END SUBROUTINE BEMT_CalcContStateDeriv !---------------------------------------------------------------------------------------------------------------------------------- @@ -1490,9 +1819,7 @@ subroutine BEMT_CalcConstrStateResidual( Time, u, p, x, xd, z, OtherState, m, z_ do i = 1,p%numBladeNodes ! Solve for the constraint states here: - Z_residual%phi(i,j) = BEMTU_InductionWithResidual(z%phi(i,j), u%theta(i,j), p%kinVisc, u%UserProp(i,j), p%numBlades, u%rlocal(i,j), p%chord(i,j), AFInfo(p%AFindx(i,j)), & - u%Vx(i,j), u%Vy(i,j), p%useTanInd, p%useAIDrag, p%useTIDrag, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & - IsValidSolution, ErrStat2, ErrMsg2) + Z_residual%phi(i,j) = BEMTU_InductionWithResidual(p, u, i, j, z%phi(i,j), AFInfo(p%AFindx(i,j)), IsValidSolution, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return @@ -1530,10 +1857,9 @@ SUBROUTINE computeFrozenWake( u, p, y, m ) !type(BEMT_DiscreteStateType), intent(in ) :: xd ! Discrete states at t !type(BEMT_ConstraintStateType), intent(in ) :: z ! Constraint states at t !type(BEMT_OtherStateType), intent(in ) :: OtherState ! Other states at t - type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables + type(BEMT_MiscVarType), intent(inout) :: m ! Misc/optimization variables !type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data - type(BEMT_OutputType), intent(inout) :: y ! Outputs computed at t (Input only so that mesh con- - ! nectivity information does not have to be recalculated) + type(BEMT_OutputType), intent(inout) :: y ! Outputs computed at t !integer(IntKi), intent( out) :: errStat ! Error status of the operation !character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None @@ -1582,7 +1908,7 @@ SUBROUTINE CheckLinearizationInput(p, u, z, m, OtherState, ErrStat, ErrMsg) do k = 1,p%numBlades do j = 1,p%numBladeNodes if (.not. OtherState%ValidPhi(j,k)) then - call SetErrSTat(ErrID_Fatal,"Blade"//trim(num2lstr(k))//', node '//trim(num2lstr(j))//& + call SetErrStat(ErrID_Fatal,"Blade"//trim(num2lstr(k))//', node '//trim(num2lstr(j))//& ": Current operating point does not contain a valid value of phi.",ErrStat,ErrMsg,RoutineName) return end if @@ -1764,31 +2090,17 @@ subroutine GetSolveRegionOrdering(Vx, phiIn, test_lower, test_upper) end subroutine GetSolveRegionOrdering -integer function FindTestRegion(phiLower, phiUpper, numBlades, rlocal, chord, theta, AFInfo, & - Vx, Vy, kinVisc, UserProp, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, atol, & - phiIn_IsValidSolution, phiIn, f_phiIn, & - f1, f2, errStat, errMsg) result(TestRegion) +integer function FindTestRegion(p, u, iBladeNode, jBlade, phiLower, phiUpper, AFInfo, & + phiIn_IsValidSolution, phiIn, f_phiIn, f1, f2, errStat, errMsg) result(TestRegion) + type(BEMT_ParameterType),intent(in ) :: p + type(BEMT_InputType), intent(in ) :: u + integer(IntKi), intent(in ) :: iBladeNode !< index for blade node + integer(IntKi), intent(in ) :: jBlade !< index for blade real(ReKi), intent(inout) :: phiLower !intent "out" in case the previous solution can alter the test region bounds real(ReKi), intent(inout) :: phiUpper !intent "out" in case the previous solution can alter the test region bounds - integer, intent(in ) :: numBlades !integer, intent(in ) :: numBladeNodes type(AFI_ParameterType),intent(in ) :: AFInfo - real(ReKi), intent(in ) :: rlocal - real(ReKi), intent(in ) :: chord - real(ReKi), intent(in ) :: theta - real(ReKi), intent(in ) :: Vx - real(ReKi), intent(in ) :: Vy - real(ReKi), intent(in ) :: kinVisc - real(ReKi), intent(in ) :: UserProp - logical, intent(in ) :: useTanInd - logical, intent(in ) :: useAIDrag - logical, intent(in ) :: useTIDrag - logical, intent(in ) :: useHubLoss - logical, intent(in ) :: useTipLoss - real(ReKi), intent(in ) :: hubLossConst - real(ReKi), intent(in ) :: tipLossConst - real(ReKi), intent(in ) :: atol logical, intent(in ) :: phiIn_IsValidSolution real(ReKi), intent(in ) :: phiIn real(ReKi), intent(in ) :: f_phiIn @@ -1808,16 +2120,12 @@ integer function FindTestRegion(phiLower, phiUpper, numBlades, rlocal, chord, th ErrMsg = "" - f1 = BEMTU_InductionWithResidual(phiLower, theta, kinVisc, UserProp, numBlades, rlocal, chord, AFInfo, & - Vx, Vy, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & - IsValidSolution, errStat2, errMsg2) + f1 = BEMTU_InductionWithResidual(p, u, iBladeNode, jBlade, phiLower, AFInfo, IsValidSolution, errStat2, errMsg2) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return - f2 = BEMTU_InductionWithResidual(phiUpper, theta, kinVisc, UserProp, numBlades, rlocal, chord, AFInfo, & - Vx, Vy, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & - IsValidSolution2, errStat2, errMsg2) + f2 = BEMTU_InductionWithResidual(p, u, iBladeNode, jBlade, phiUpper, AFInfo, IsValidSolution2, errStat2, errMsg2) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return @@ -1827,7 +2135,7 @@ integer function FindTestRegion(phiLower, phiUpper, numBlades, rlocal, chord, th TestRegion = 0 ! all solutions yield zero -- special case return else - if ( abs(f1) < aTol ) then + if ( abs(f1) < p%aTol ) then if ( abs(f2) < abs(f1) .and. IsValidSolution2 ) then TestRegion = 4 ! special case: upper end point is a zero (and it's smaller than the solution at the lower end point) return @@ -1835,7 +2143,7 @@ integer function FindTestRegion(phiLower, phiUpper, numBlades, rlocal, chord, th TestRegion = 3 ! special case: lower end point is a zero return end if - elseif ( abs(f2) < aTol .and. IsValidSolution2 ) then + elseif ( abs(f2) < p%aTol .and. IsValidSolution2 ) then TestRegion = 4 ! special case: upper end point is a zero return end if @@ -1867,31 +2175,16 @@ integer function FindTestRegion(phiLower, phiUpper, numBlades, rlocal, chord, th end function FindTestRegion -subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, theta, & - Vx, Vy, UserProp, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & - maxIndIterations, aTol, ValidPhi, FirstWarn, ErrStat, ErrMsg) +subroutine BEMT_UnCoupledSolve(p, u, iBladeNode, jBlade, phi, AFInfo, ValidPhi, FirstWarn, ErrStat, ErrMsg) use mod_root1dim !use fminMod + type(BEMT_ParameterType),intent(in ) :: p + type(BEMT_InputType), intent(in ) :: u + integer(IntKi), intent(in ) :: iBladeNode !< index for blade node + integer(IntKi), intent(in ) :: jBlade !< index for blade real(ReKi), intent(inout) :: phi - integer, intent(in ) :: numBlades - real(ReKi), intent(in ) :: kinVisc TYPE(AFI_ParameterType),INTENT(IN ) :: AFInfo - real(ReKi), intent(in ) :: rlocal - real(ReKi), intent(in ) :: chord - real(ReKi), intent(in ) :: theta - real(ReKi), intent(in ) :: Vx - real(ReKi), intent(in ) :: Vy - real(ReKi), intent(in ) :: UserProp - logical, intent(in ) :: useTanInd - logical, intent(in ) :: useAIDrag - logical, intent(in ) :: useTIDrag - logical, intent(in ) :: useHubLoss - logical, intent(in ) :: useTipLoss - real(ReKi), intent(in ) :: hubLossConst - real(ReKi), intent(in ) :: tipLossConst - integer, intent(in ) :: maxIndIterations - real(ReKi), intent(in ) :: aTol logical, intent(inout) :: ValidPhi logical, intent(inout) :: FirstWarn integer(IntKi), intent( out) :: errStat ! Error status of the operation @@ -1900,8 +2193,6 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, ! Local variables - type(fmin_fcnArgs) :: fcnArgs - character(ErrMsgLen) :: errMsg2 ! temporary Error message if ErrStat /= ErrID_None integer(IntKi) :: errStat2 ! temporary Error status of the operation character(*), parameter :: RoutineName = 'BEMT_UnCoupledSolve' @@ -1916,12 +2207,12 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, ErrMsg = "" - if ( VelocityIsZero(Vx) ) then + if ( VelocityIsZero(u%Vx(iBladeNode,jBlade)) ) then phi = 0.0_ReKi ValidPhi = .true. return - else if ( VelocityIsZero(Vy) ) then - if (Vx>0.0_ReKi) then + else if ( VelocityIsZero(u%Vy(iBladeNode,jBlade)) ) then + if (u%Vx(iBladeNode,jBlade) > 0.0_ReKi) then phi = PiBy2 else phi = -PiBy2 @@ -1937,13 +2228,11 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, ! See if the previous value of phi still satisfies the residual equation. ! (If the previous phi wasn't a valid solution to BEMT equations, skip this check and just perform the solve) if (ValidPhi .and. .NOT. EqualRealNos(phi, 0.0_ReKi) .and. .not. EqualRealNos(abs(phi),PiBy2) ) then - f1 = BEMTU_InductionWithResidual(phi, theta, kinVisc, UserProp, numBlades, rlocal, chord, AFInfo, & - Vx, Vy, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & - IsValidSolution, errStat2, errMsg2) + f1 = BEMTU_InductionWithResidual(p, u, iBladeNode, jBlade, phi, AFInfo, IsValidSolution, errStat2, errMsg2) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return - if ( abs(f1) < aTol .and. IsValidSolution ) then + if ( abs(f1) < p%aTol .and. IsValidSolution ) then !phiStar = phiIn return end if @@ -1956,36 +2245,12 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, ! ValidPhi = .false. ! initialize to false while we try to find a new valid solution - !............ - ! - - ! Set up the fcn argument settings for Brent's method - - fcnArgs%nu = kinVisc - fcnArgs%numBlades = numBlades - fcnArgs%rlocal = rlocal - fcnArgs%chord = chord - fcnArgs%theta = theta - fcnArgs%Vx = Vx - fcnArgs%Vy = Vy - fcnArgs%UserProp = UserProp - fcnArgs%useTanInd = useTanInd - fcnArgs%useAIDrag = useAIDrag - fcnArgs%useTIDrag = useTIDrag - fcnArgs%useHubLoss = useHubLoss - fcnArgs%useTipLoss = useTipLoss - fcnArgs%hubLossConst = hubLossConst - fcnArgs%tipLossConst = tipLossConst - - - call GetSolveRegionOrdering(Vx, phi, phi_lower, phi_upper) + call GetSolveRegionOrdering(u%Vx(iBladeNode,jBlade), phi, phi_lower, phi_upper) phiIn = phi - do i = 1,size(phi_upper) ! Need to potentially test 3 regions - TestRegionResult = FindTestRegion(phi_lower(i), phi_upper(i), numBlades, rlocal, chord, theta, AFInfo, & - Vx, Vy, kinVisc, UserProp, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, atol, & - IsValidSolution, phiIn, f1, & - f_lower, f_upper, errStat2, errMsg2) + do i = 1,size(phi_upper) ! Need to potentially test 4 regions + TestRegionResult = FindTestRegion(p, u, iBladeNode, jBlade, phi_lower(i), phi_upper(i), AFInfo, & + IsValidSolution, phiIn, f1, f_lower, f_upper, errStat2, errMsg2) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if ( TestRegionResult == 1 ) then @@ -1993,10 +2258,10 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, ! There is a zero in the solution region [phi_lower(i), phi_upper(i)] because the endpoints have residuals with different signs (SolutionRegion=1) ! We use Brent's Method to find the zero-residual solution in this region - call sub_brent(phi,phi_lower(i),phi_upper(i), aTol, maxIndIterations, fcnArgs, AFInfo, f_lower, f_upper) - call SetErrStat(fcnArgs%ErrStat, fcnArgs%ErrMsg, ErrStat, ErrMsg, RoutineName) + call sub_brent(p, u, iBladeNode, jBlade, phi, phi_lower(i), phi_upper(i), AFInfo, IsValidSolution, ErrStat2, ErrMsg2, f_lower, f_upper) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (fcnArgs%IsValidSolution) then ! we have a valid BEMT solution + if (IsValidSolution) then ! we have a valid BEMT solution ValidPhi = .true. exit end if @@ -2024,12 +2289,12 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, if (.not. ValidPhi) then - phi = ComputePhiWithInduction(Vx, Vy, 0.0_ReKi, 0.0_ReKi) + phi = ComputePhiWithInduction(u%Vx(iBladeNode,jBlade), u%Vy(iBladeNode,jBlade), 0.0_ReKi, 0.0_ReKi) if (abs(phi)>MsgLimit .and. abs(abs(phi)-PiBy2) > MsgLimit ) then if (FirstWarn) then - call SetErrStat( ErrID_Info, 'There is no valid value of phi for these operating conditions: Vx = '//TRIM(Num2Lstr(Vx))//& - ', Vy = '//TRIM(Num2Lstr(Vy))//', rlocal = '//TRIM(Num2Lstr(rLocal))//', theta = '//TRIM(Num2Lstr(theta))//', geometric phi = '//TRIM(Num2Lstr(phi)) & + call SetErrStat( ErrID_Info, 'There is no valid value of phi for these operating conditions: Vx = '//TRIM(Num2Lstr(u%Vx(iBladeNode,jBlade)))//& + ', Vy = '//TRIM(Num2Lstr(u%Vy(iBladeNode,jBlade)))//', rlocal = '//TRIM(Num2Lstr(u%rLocal(iBladeNode,jBlade)))//', theta = '//TRIM(Num2Lstr(u%theta(iBladeNode,jBlade)))//', geometric phi = '//TRIM(Num2Lstr(phi)) & //'. This warning will not be repeated though the condition may persist. (See GeomPhi output channel.)', errStat, errMsg, RoutineName ) FirstWarn = .false. end if !FirstWarn @@ -2038,9 +2303,7 @@ subroutine BEMT_UnCoupledSolve( phi, numBlades, kinVisc, AFInfo, rlocal, chord, end subroutine BEMT_UnCoupledSolve - - - +!---------------------------------------------------------------------------------------------------------------------------------- function NodeText(i,j) integer(IntKi), intent(in) :: i ! node number integer(IntKi), intent(in) :: j ! blade number @@ -2048,6 +2311,178 @@ function NodeText(i,j) NodeText = '(node '//trim(num2lstr(i))//', blade '//trim(num2lstr(j))//')' end function NodeText +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine SetInputs_for_UA(phi, theta, axInduction, tanInduction, Vx, Vy, omega, chord, kinVisc, UserProp, u_UA) + real(ReKi), intent(in ) :: UserProp ! User property (for 2D Airfoil interp) + real(ReKi), intent(in ) :: phi + real(ReKi), intent(in ) :: theta + real(ReKi), intent(in ) :: axInduction + real(ReKi), intent(in ) :: tanInduction + real(ReKi), intent(in ) :: Vx + real(ReKi), intent(in ) :: Vy + real(ReKi), intent(in ) :: omega ! aka PitchRate + real(ReKi), intent(in ) :: chord + real(ReKi), intent(in ) :: kinVisc + type(UA_InputType), intent( out) :: u_UA + + + ! ....... compute inputs to UA ........... + u_UA%alpha = phi - theta ! angle of attack + u_UA%UserProp = UserProp + + ! Need to compute relative velocity at the aerodynamic center, including both axial and tangential induction + ! COMPUTE: u_UA%U, u_UA%Re, u_UA%v_ac + call GetRelativeVelocity( axInduction, tanInduction, Vx, Vy, u_UA%U, u_UA%v_ac ) + call GetReynoldsNumber( axInduction, tanInduction, Vx, Vy, chord, kinVisc, u_UA%Re) + + u_UA%v_ac(1) = sin(u_UA%alpha)*u_UA%U + u_UA%v_ac(2) = cos(u_UA%alpha)*u_UA%U + + u_UA%omega = omega + +end subroutine SetInputs_for_UA +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine SetInputs_for_UA_AllNodes(u, p, phi, axInduction, tanInduction, u_UA) + type(BEMT_InputType), intent(in ) :: u + type(BEMT_ParameterType), intent(in ) :: p + real(ReKi), intent(inout) :: phi(:,:) + real(ReKi), intent(in ) :: axInduction(:,:) + real(ReKi), intent(in ) :: tanInduction(:,:) + type(UA_InputType), intent( out) :: u_UA(:,:) + + INTEGER(IntKi) :: i, j + + if ( p%useInduction ) then + !............................................ + ! we're recomputing phi because it may not be consistent with the computed axInduction or tanInduction values + !............................................ + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + phi(i,j) = ComputePhiWithInduction( u%Vx(i,j), u%Vy(i,j), axInduction(i,j), tanInduction(i,j) ) + enddo ! I - Blade nodes / elements + enddo ! J - All blades + end if + + !............................................ + ! unsteady aero inputs (AoA, Vrel, Re) + !............................................ + do j = 1,p%numBlades ! Loop through all blades + do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements + + ! Compute AoA, Re, Vrel (inputs to UA) based on current values of axInduction, tanInduction: + call SetInputs_for_UA(phi(i,j), u%theta(i,j), axInduction(i,j), tanInduction(i,j), u%Vx(i,j), u%Vy(i,j), u%omega_z(i,j), p%chord(i,j), p%kinVisc, u%UserProp(i,j), u_UA(i,j)) + + end do + end do + +end subroutine SetInputs_for_UA_AllNodes +!---------------------------------------------------------------------------------------------------------------------------------- +#ifdef DEBUG_BEMT_RESIDUAL +subroutine WriteDEBUGValuesToFile(t, u, p, x, xd, z, OtherState, m, AFInfo) + real(DbKi), intent(in ) :: t ! Current simulation time in seconds + type(BEMT_InputType), intent(in ) :: u ! Inputs at Time t + type(BEMT_ParameterType), intent(in ) :: p ! Parameters + type(BEMT_ContinuousStateType), intent(in ) :: x ! Continuous states at t + type(BEMT_DiscreteStateType), intent(in ) :: xd ! Discrete states at t + type(BEMT_ConstraintStateType), intent(in ) :: z ! Constraint states at t + type(BEMT_OtherStateType), intent(in ) :: OtherState ! Other states at t + type(BEMT_MiscVarType), intent(in ) :: m ! Misc/optimization variables + type(AFI_ParameterType), intent(in ) :: AFInfo(:) ! The airfoil parameter data + + character(ErrMsgLen) :: errMsg ! temporary Error message if ErrStat /= ErrID_None + integer(IntKi) :: errStat ! temporary Error status of the operation + integer(IntKi) :: OutInt + integer(IntKi) :: UnOut + logical :: ValidPhi + integer(IntKi) :: ii + integer(IntKi), parameter :: numPhi = 3001 + real(ReKi) :: phi + real(ReKi) :: fzero + real(ReKi) :: delta_phi + real(ReKi) :: axInd, tnInd + + ! I'm using persistent data.... don't copy this code anywhere else :) + integer, save :: DEBUG_BLADE + integer, save :: DEBUG_BLADENODE + integer, save :: DEBUG_nStep = 1 + integer, save :: DEBUG_FILE_UNIT + +! character(*), parameter :: RoutineName = 'BEMT_UnCoupledSolve' + + DEBUG_BLADE = 1 !size(u%Vx,2) + DEBUG_BLADENODE = 23 !max(1, size(u%Vx,1) / 2 ) + + if (DEBUG_nStep == 1) then + call GetNewUnit(DEBUG_FILE_UNIT, ErrStat, ErrMsg ) + call OpenFOutFile ( DEBUG_FILE_UNIT, "CheckBEMT.inputs.out", ErrStat, ErrMsg ) + + WRITE(DEBUG_FILE_UNIT,'(A7,200(1x,A15))') "Step","IsGeomPhi","Time", "GeomPhi", "phi" & + , "chi0", "omega", "Un_disk", "TSR" & + , "theta" , "psi" & + , "Vx" , "Vy" & + , "omega_z" & + , "rLocal" , "UserProp" & + , "AxInd", "TanInd" +! , "Vx_elast_dot" , "Vy_elast_dot" & + + end if + + ! get geometric phi for these inputs: + phi = ComputePhiWithInduction(u%Vx(DEBUG_BLADENODE,DEBUG_BLADE), u%Vy(DEBUG_BLADENODE,DEBUG_BLADE), 0.0_ReKi, 0.0_ReKi) + + if (OtherState%ValidPhi(DEBUG_BLADENODE,DEBUG_BLADE)) then + OutInt = 0 + else + OutInt = 1 + end if + + WRITE(DEBUG_FILE_UNIT, '(I7,1x,I15,200(1x,ES15.6))') DEBUG_nStep, OutInt, t, phi*R2D & + , z%phi( DEBUG_BLADENODE,DEBUG_BLADE)*R2D & ! remember this does not have any corrections + , u%chi0, u%omega, u%Un_disk, u%TSR & + , u%theta( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%psi( DEBUG_BLADE) & + , u%Vx( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%Vy( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%Vz( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%omega_z( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%rLocal( DEBUG_BLADENODE,DEBUG_BLADE) & + , u%UserProp( DEBUG_BLADENODE,DEBUG_BLADE) & + , m%axInduction( DEBUG_BLADENODE,DEBUG_BLADE) & + , m%tanInduction(DEBUG_BLADENODE,DEBUG_BLADE) +! these are not always allocated +! , u%Vx_elast_dot(DEBUG_BLADENODE,DEBUG_BLADE) & +! , u%Vy_elast_dot(DEBUG_BLADENODE,DEBUG_BLADE) & + + ! now write the residual function to a separate file: + if ((DEBUG_nStep >= 0).AND.(DEBUG_nStep <= 450000).AND.(MOD(DEBUG_nStep,25) == 0)) then + + call GetNewUnit( UnOut, ErrStat, ErrMsg ) + call OpenFOutFile ( UnOut, "CheckBEMT.residual."//trim(num2lstr(DEBUG_nStep))//".out", ErrStat, ErrMsg ) + !WRITE(UnOut, '(2(A15,1x),A2,5(1x,A15))') 'phi', 'residual', 'OK', 'AxialInd', 'TangentialInd', 'k', 'kp' + + do ii = 1, numPhi + ! nonlinear mapping of ii --> phi + phi = smoothStep( real(ii,ReKi), 1.0, -pi+BEMT_epsilon2, real(numPhi,ReKi)/2.0, 0.0_ReKi ) + smoothStep( real(ii,ReKi), real(numPhi,ReKi)/2.0, 0.0_ReKi, real(numPhi,ReKi), pi-BEMT_epsilon2 ) + + fzero = BEMTU_InductionWithResidual(p, u, DEBUG_BLADENODE, DEBUG_BLADE, phi, AFInfo(p%AFIndx(DEBUG_BLADENODE,DEBUG_BLADE)), ValidPhi, errStat, errMsg, a=axInd, ap=tnInd ) + if (ValidPhi) then + OutInt = 0 + else + OutInt = 1 + end if + + WRITE(UnOut, '(2(ES15.6,1x),I2,8(1x,ES15.6))') phi, fzero, OutInt, axInd, tnInd + + end do + + CLOSE(UnOut) + end if + + DEBUG_nStep = DEBUG_nStep + 1 + +end subroutine WriteDEBUGValuesToFile +#endif +!---------------------------------------------------------------------------------------------------------------------------------- end module BEMT diff --git a/modules/aerodyn/src/BEMTUncoupled.f90 b/modules/aerodyn/src/BEMTUncoupled.f90 index 6a59122947..ea760fd74e 100644 --- a/modules/aerodyn/src/BEMTUncoupled.f90 +++ b/modules/aerodyn/src/BEMTUncoupled.f90 @@ -25,6 +25,7 @@ module BEMTUnCoupled use AirfoilInfo_Types use UnsteadyAero use UnsteadyAero_Types + use BEMT_Types implicit none @@ -36,6 +37,8 @@ module BEMTUnCoupled real(ReKi), public, parameter :: BEMT_MaxInduction(2) = (/1.5_ReKi, 1.0_ReKi /) ! largest magnitude of axial (1) and tangential (2) induction factors real(ReKi), public, parameter :: BEMT_MinInduction(2) = -1.0_ReKi + real(ReKi), public, parameter :: BEMT_lowerBoundTSR = 1.0_ReKi + real(ReKi), public, parameter :: BEMT_upperBoundTSR = 2.0_ReKi !1e-6 works for double precision, but not single precision real(ReKi), public, parameter :: BEMT_epsilon2 = 10.0_ReKi*sqrt(epsilon(1.0_ReKi)) !this is the tolerance in radians for values around singularities in phi (i.e., phi=0 and phi=pi/2); must be large enough so that EqualRealNos(BEMT_epsilon2, 0.0_ReKi) is false @@ -43,12 +46,14 @@ module BEMTUnCoupled private - public :: Compute_UA_AirfoilCoefs + public :: GetRelativeVelocity + public :: GetReynoldsNumber public :: BEMTU_InductionWithResidual public :: ApplySkewedWakeCorrection public :: Transform_ClCd_to_CxCy + public :: getHubTipLossCorrection + public :: limitInductionFactors - public :: BEMTU_Wind public :: VelocityIsZero contains @@ -68,41 +73,40 @@ function VelocityIsZero ( v ) end function VelocityIsZero !.................................................................................................................................. - subroutine BEMTU_Wind( axInduction, tanInduction, Vx, Vy, chord, nu, Re, Vrel ) + subroutine GetReynoldsNumber( axInduction, tanInduction, Vx, Vy, chord, nu, Re ) - ! in real(ReKi), intent(in) :: axInduction, tanInduction, Vx, Vy real(ReKi), intent(in) :: chord, nu ! out real(ReKi), intent(out) :: Re ! Reynolds number - real(ReKi), intent(out),optional :: Vrel ! relative velocity real(ReKi) :: W ! relative velocity - - - - ! avoid numerical errors when angle is close to 0 or 90 deg - ! and other induction factor is at some ridiculous value - ! this only occurs when iterating on Reynolds number - ! during the phi sweep where a solution has not been found yet - !if ( abs(axInduction) > 10 ) then - ! W = Vy*(1+tanInduction)/cos(phi) - !else if ( abs(tanInduction) > 10 ) then - ! W = Vx*(1-axInduction)/sin(phi) - !else - W = sqrt((Vx*(1-axInduction))**2 + (Vy*(1+tanInduction))**2) - !end if + W = sqrt((Vx*(1-axInduction))**2 + (Vy*(1+tanInduction))**2) Re = W * chord / nu if ( EqualRealNos(Re, 0.0_ReKi) ) Re = 0.001 ! Do this to avoid a singularity when we take log(Re) in the airfoil lookup. - if (present(Vrel)) Vrel = W - - end subroutine BEMTU_Wind + end subroutine GetReynoldsNumber +!.................................................................................................................................. + subroutine GetRelativeVelocity( axInduction, tanInduction, Vx, Vy, Vrel, v_ac ) + + ! in + real(ReKi), intent(in) :: axInduction, tanInduction, Vx, Vy + + ! out + real(ReKi), intent(out) :: Vrel ! relative velocity + real(ReKi), intent(out) :: v_ac(2) ! components of relative velocity + + v_ac(1) = Vx*(1-axInduction) + v_ac(2) = Vy*(1+tanInduction) + + Vrel = TwoNorm(v_ac) + end subroutine GetRelativeVelocity +!.................................................................................................................................. subroutine Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, Cl, Cd, Cx, Cy ) real(ReKi), intent(in ) :: phi logical, intent(in ) :: useAIDrag @@ -131,78 +135,20 @@ subroutine Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, Cl, Cd, Cx, Cy ) end if end subroutine Transform_ClCd_to_CxCy +!---------------------------------------------------------------------------------------------------------------------------------- -!---------------------------------------------------------------------------------------------------------------------------------- -!> Determine the Cl, Cd, Cm coeficients for a given angle of attack, Re, and UserProp -subroutine Compute_UA_AirfoilCoefs( AOA, U, Re, UserProp, AFInfo, & - p_UA, xd_UA, OtherState_UA, y_UA, m_UA, & - Cl, Cd, Cm, errStat, errMsg ) -!.................................................................................................................................. - real(ReKi), intent(in ) :: AOA !< angle of attack, radians - real(ReKi), intent(in ) :: U !< Vrel, m/s - real(ReKi), intent(in ) :: Re ! Reynolds Number (for 2D Airfoil interp) - real(ReKi), intent(in ) :: UserProp ! User property (for 2D Airfoil interp) - type(AFI_ParameterType), intent(in ) :: AFInfo - type(UA_ParameterType), intent(in ) :: p_UA ! Parameters - type(UA_DiscreteStateType), intent(in ) :: xd_UA ! Discrete states at Time - type(UA_OtherStateType), intent(in ) :: OtherState_UA ! Other states at Time - type(UA_OutputType), intent(inout) :: y_UA ! - type(UA_MiscVarType), intent(inout) :: m_UA ! misc/optimization variables - real(ReKi), intent( out) :: Cl, Cd, Cm - integer(IntKi), intent( out) :: errStat ! Error status of the operation - character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None - - integer(intKi) :: ErrStat2 ! temporary Error status - character(ErrMsgLen) :: ErrMsg2 ! temporary Error message - character(*), parameter :: RoutineName = 'Compute_UA_AirfoilCoefs' - - - type(UA_InputType) :: u_UA - - ErrStat = ErrID_None - ErrMsg = '' - - u_UA%alpha = AOA - u_UA%Re = Re - u_UA%U = U - u_UA%UserProp = UserProp - - - call UA_CalcOutput(u_UA, p_UA, xd_UA, OtherState_UA, AFInfo, y_UA, m_UA, errStat2, errMsg2 ) - call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - if (errStat >= AbortErrLev) return - - Cl = y_UA%Cl - Cd = y_UA%Cd - Cm = y_UA%Cm - - -end subroutine Compute_UA_AirfoilCoefs !---------------------------------------------------------------------------------------------------------------------------------- !>This is the residual calculation for the uncoupled BEM solve -real(ReKi) function BEMTU_InductionWithResidual(phi, theta, kinVisc, UserProp, numBlades, rlocal, chord, AFInfo, & - Vx, Vy, useTanInd, useAIDrag, useTIDrag, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & - IsValidSolution, ErrStat, ErrMsg, a, ap) result (ResidualVal) +real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValidSolution, ErrStat, ErrMsg, a, ap ) result (ResidualVal) - + type(BEMT_ParameterType),intent(in ) :: p !< parameters + type(BEMT_InputType), intent(in ) :: u !< Inputs at t + integer(IntKi), intent(in ) :: i !< index for blade node + integer(IntKi), intent(in ) :: j !< index for blade + real(ReKi), intent(in ) :: phi - real(ReKi), intent(in ) :: theta - real(ReKi), intent(in ) :: kinVisc - real(ReKi), intent(in ) :: UserProp - integer, intent(in ) :: numBlades - real(ReKi), intent(in ) :: rlocal - real(ReKi), intent(in ) :: chord type(AFI_ParameterType),intent(in ) :: AFInfo - real(ReKi), intent(in ) :: Vx - real(ReKi), intent(in ) :: Vy - logical, intent(in ) :: useTanInd - logical, intent(in ) :: useAIDrag - logical, intent(in ) :: useTIDrag - logical, intent(in ) :: useHubLoss - logical, intent(in ) :: useTipLoss - real(ReKi), intent(in ) :: hubLossConst - real(ReKi), intent(in ) :: tipLossConst logical, intent( out) :: IsValidSolution !< this is set to false if k<=1 in the propeller brake region or k<-1 in the momentum region, indicating an invalid solution integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -232,31 +178,31 @@ real(ReKi) function BEMTU_InductionWithResidual(phi, theta, kinVisc, UserProp, n ! make these return values consistent with what is returned in inductionFactors routine: ! Set the local version of the induction factors - if ( ( useTiploss .and. EqualRealNos(tipLossConst,0.0_ReKi) ) .or. ( useHubloss .and. EqualRealNos(hubLossConst,0.0_ReKi) ) ) then + if ( p%FixedInductions(i,j) ) then ! We are simply going to bail if we are using tiploss and tipLossConst = 0 or using hubloss and hubLossConst=0, regardless of phi! [do this before checking if Vx or Vy is zero or you'll get jumps in the induction and loads] axInduction = 1.0_ReKi tanInduction = 0.0_ReKi - elseif ( EqualRealNos(phi, 0.0_ReKi) .or. VelocityIsZero(Vx) .OR. VelocityIsZero(Vy) ) then + elseif ( EqualRealNos(phi, 0.0_ReKi) .or. VelocityIsZero(u%Vx(i,j)) .OR. VelocityIsZero(u%Vy(i,j)) ) then axInduction = 0.0_ReKi tanInduction = 0.0_ReKi else !if ( (.NOT. VelocityIsZero(Vx)) .AND. (.NOT. VelocityIsZero(Vy)) ) then - AOA = phi - theta + AOA = phi - u%theta(i,j) ! FIX ME: Note that the Re used here is computed assuming axInduction and tanInduction are 0. Is that a problem for 2D Re interpolation on airfoils? or should update solve method to take this into account? - call BEMTU_Wind( 0.0_ReKi, 0.0_ReKi, Vx, Vy, chord, kinVisc, Re ) + call GetReynoldsNumber( 0.0_ReKi, 0.0_ReKi, u%Vx(i,j), u%Vy(i,j), p%chord(i,j), p%kinVisc, Re) - call AFI_ComputeAirfoilCoefs( AOA, Re, UserProp, AFInfo, AFI_interp, errStat2, errMsg2 ) !bjj: would be nice if this could be done outside this routine (so we don't copy AFInfo so much) + call AFI_ComputeAirfoilCoefs( AOA, Re, u%UserProp(i,j), AFInfo, AFI_interp, errStat2, errMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (ErrStat >= AbortErrLev) return - ! Compute Cx, Cy given Cl, Cd and phi, we honor the useAIDrag and useTIDrag flag because Cx,Cy are only used for the solution of inductions - call Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, AFI_interp%Cl, AFI_interp%Cd, Cx, Cy ) + ! Compute Cx, Cy given Cl, Cd and phi, we honor the useAIDrag and useTIDrag flag because Cx,Cy are only used for the solution of inductions + call Transform_ClCd_to_CxCy( phi, p%useAIDrag, p%useTIDrag, AFI_interp%Cl, AFI_interp%Cd, Cx, Cy ) ! Determine axInduction, tanInduction for the current Cl, Cd, phi - call inductionFactors( rlocal, chord, phi, Cx, Cy, numBlades, & - Vx, Vy, useTanInd, useHubLoss, useTipLoss, hubLossConst, tipLossConst, & + call inductionFactors( u%rlocal(i,j), p%chord(i,j), phi, Cx, Cy, p%numBlades, & + u%Vx(i,j), u%Vy(i,j), p%useTanInd, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), & ResidualVal, axInduction, tanInduction, IsValidSolution) end if @@ -265,7 +211,7 @@ real(ReKi) function BEMTU_InductionWithResidual(phi, theta, kinVisc, UserProp, n if (present(ap)) ap = tanInduction end function BEMTU_InductionWithResidual - +!----------------------------------------------------------------------------------------- subroutine ApplySkewedWakeCorrection( yawCorrFactor, azimuth, chi0, tipRatio, a, chi, FirstWarn ) real(ReKi), intent(in ) :: yawCorrFactor ! set to 15*pi/32 previously; now allowed to be input (to better match data) @@ -292,7 +238,7 @@ subroutine ApplySkewedWakeCorrection( yawCorrFactor, azimuth, chi0, tipRatio, a, if (FirstWarn) then call WrScr( 'Warning: SkewedWakeCorrection encountered a large value of chi ('//trim(num2lstr(chi*R2D))// & ' deg), so the yaw correction will be limited. This warning will not be repeated though the condition may persist. See the AD15 chi output channels, and'// & - ' consider turning off the Pitt/Peters skew model (set SkewMod=1) if this condition persists.') + ' consider turning off the Pitt/Peters skew model (set SkewMod=1) if this condition persists.'//NewLine) FirstWarn = .false. end if @@ -345,11 +291,7 @@ subroutine inductionFactors(r, chord, phi, cn, ct, B, Vx, Vy, wakerotation, useH real(ReKi) :: g1, g2, g3 real(ReKi) :: temp ! temporary variable so we don't have to calculate 2.0_ReKi*F*k multiple times real(ReKi), parameter :: InductionLimit = 1000000.0_ReKi - real(ReKi), parameter :: MaxTnInd = BEMT_MaxInduction(2) - real(ReKi), parameter :: MaxAxInd = BEMT_MaxInduction(1) - real(ReKi), parameter :: MinTnInd = BEMT_MinInduction(2) - real(ReKi), parameter :: MinAxInd = BEMT_MinInduction(1) - + logical :: momentumRegion @@ -428,10 +370,7 @@ subroutine inductionFactors(r, chord, phi, cn, ct, B, Vx, Vy, wakerotation, useH if (k<=1.0_ReKi) then ! k <= 1 cannot be a solution in propeller brake region (this is equivalent to a<1.0) IsValidSolution = .false. - else if (a > MaxAxInd) then ! propeller brake region is for induction factors > 1, but not too large; - ! note that we use k in the residual equation instead of a in the propeller brake region, so we can put the limit here - a = MaxAxInd - end if + end if end if @@ -460,13 +399,8 @@ subroutine inductionFactors(r, chord, phi, cn, ct, B, Vx, Vy, wakerotation, useH else ap = kp/(1.0_ReKi-kp) end if - - ! bandaid so that this doesn't blow up. Note that we're not using ap in the residual calculation, so we can modify it here. - ap = min( ap, MaxTnInd) - ap = max( ap, MinTnInd) - - end if - + + endif else @@ -487,22 +421,29 @@ subroutine inductionFactors(r, chord, phi, cn, ct, B, Vx, Vy, wakerotation, useH fzero = - cphi/lambda_r*(1-kp) else fzero = sphi/(1-a) - cphi/lambda_r*(1-kp) - - ! bandaid so that axial induction doesn't blow up - a = max(a,MinAxInd) end if else ! propeller brake region fzero = sphi*(1-k) - cphi/lambda_r*(1-kp) end if - - if (.not. IsValidSolution) then - a = 0.0_ReKi - ap = 0.0_ReKi - end if + +end subroutine inductionFactors +!----------------------------------------------------------------------------------------- +subroutine limitInductionFactors(a,ap) + real(ReKi), intent(inout) :: a ! axial induction + real(ReKi), intent(inout), optional :: ap ! tangential induction + ! Impose limits on axial induction + a = max( a, BEMT_MinInduction(1) ) + a = min( a, BEMT_MaxInduction(1) ) + + if (present(ap)) then + ! Impose limits on tangential induction + ap = max( ap, BEMT_MinInduction(2) ) + ap = min( ap, BEMT_MaxInduction(2) ) + end if -end subroutine inductionFactors +end subroutine limitInductionFactors !----------------------------------------------------------------------------------------- !> This function computes \f$F\f$, the hub/tip loss correction real(reKi) function getHubTipLossCorrection(sphi, useHubLoss, useTipLoss, hubLossConst, tipLossConst) result(F) diff --git a/modules/aerodyn/src/BEMT_Registry.txt b/modules/aerodyn/src/BEMT_Registry.txt index d995711134..d0c1984977 100644 --- a/modules/aerodyn/src/BEMT_Registry.txt +++ b/modules/aerodyn/src/BEMT_Registry.txt @@ -64,8 +64,8 @@ typedef ^ InitOutputType ProgDesc # ..... States .................................................................................................................... # Define continuous (differentiable) states here: # -typedef ^ ContinuousStateType SiKi DummyContState - - - "Remove this variable if you have continuous states" - -typedef ^ ContinuousStateType DBEMT_ContinuousStateType DBEMT - - - "DBEMT module continuous states" - +typedef ^ ContinuousStateType UA_ContinuousStateType UA - - - "UA module continuous states" - +typedef ^ ContinuousStateType DBEMT_ContinuousStateType DBEMT - - - "DBEMT module continuous states" - # # # Define discrete (non-differentiable) states here: @@ -91,15 +91,23 @@ typedef ^ OtherStateType Logical # e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. typedef ^ MiscVarType Logical FirstWarn_Skew - - - "flag so invalid skew warning doesn't get repeated forever" - typedef ^ MiscVarType Logical FirstWarn_Phi - - - "flag so Invalid Phi warning doesn't get repeated forever" - +typedef ^ MiscVarType Logical FirstWarn_BEMoff - - - "flag to warn the BEM was turned off" - typedef ^ MiscVarType UA_MiscVarType UA - - - "misc vars for UnsteadyAero" - typedef ^ MiscVarType DBEMT_MiscVarType DBEMT - - - "misc vars for DBEMT" - typedef ^ MiscVarType UA_OutputType y_UA - - - "outputs from UnsteadyAero" - +typedef ^ MiscVarType UA_InputType u_UA {:}{:}{:} - - "inputs to UnsteadyAero at t and t+dt" - +typedef ^ MiscVarType DBEMT_InputType u_DBEMT {:} - - "inputs to DBEMT" - typedef ^ MiscVarType ReKi TnInd_op {:}{:} - - "tangential induction at the operating point (for linearization with frozen wake assumption)" typedef ^ MiscVarType ReKi AxInd_op {:}{:} - - "axial induction at the operating point (for linearization) with frozen wake assumption" typedef ^ MiscVarType ReKi AxInduction {:}{:} - - "axial induction used for code run-time optimization" - typedef ^ MiscVarType ReKi TanInduction {:}{:} - - "tangential induction used for code run-time optimization" - typedef ^ MiscVarType Logical UseFrozenWake - - - "flag set to determine if frozen values of TnInd_op and AxInd_op should be used for this calculation in the linearization process" typedef ^ MiscVarType ReKi Rtip {:} - - "maximum rlocal value for each blade (typically the value at the tip)" m +typedef ^ MiscVarType ReKi phi {:}{:} - - "temp variable used in update states for returning phi (to allow computing inputs and states at multiple times)" - +typedef ^ MiscVarType ReKi chi {:}{:} - - "temp variable used in update states for returning chi (to allow calling same routine from CalcOutput and UpdateStates)" - +typedef ^ MiscVarType Logical ValidPhi {:}{:} - - "temp variable used in calcOutput for ValidPhi (to allow calling same routine from CalcOutput and UpdateStates)" - +typedef ^ MiscVarType ReKi BEM_weight - - "temp variable used to turn off BEM for low TSR and/or large skew angles" - + # ..... Parameters ................................................................................................................ # Define parameters here: # Time step for integration of continuous states (if a fixed-step integrator is used) and update of discrete states: @@ -129,6 +137,7 @@ typedef ^ ^ DBEMT_Param typedef ^ ^ LOGICAL UA_Flag - - - "logical flag indicating whether to use UnsteadyAero" - typedef ^ ^ IntKi DBEMT_Mod - - - "DBEMT Model. 0 = constant tau1, 1 = time dependent tau1" - typedef ^ ^ ReKi yawCorrFactor - - - "constant used in Pitt/Peters skewed wake model (default is 15*pi/32)" - +typedef ^ ^ LOGICAL FixedInductions {:}{:} - - "flag to determine if BEM inductions should be fixed and not modified by dbemt or skewed wake" - # # @@ -139,8 +148,12 @@ typedef ^ InputType ReKi typedef ^ ^ ReKi chi0 - - - "Angle between the vector normal to the rotor plane and the wind vector (e.g., the yaw angle in the case of no tilt)" rad typedef ^ ^ ReKi psi {:} - - "Azimuth angle" rad typedef ^ ^ ReKi omega - - - "Angular velocity of rotor" rad/s +typedef ^ ^ ReKi TSR - - - "Tip-speed ratio (to check if BEM should be turned off)" - typedef ^ ^ ReKi Vx {:}{:} - - "Local axial velocity at node" m/s typedef ^ ^ ReKi Vy {:}{:} - - "Local tangential velocity at node" m/s +typedef ^ ^ ReKi Vx_elast_dot {:}{:} - - "Local relative axial acceleration at node (for CDBEMT)" "m/s^2" +typedef ^ ^ ReKi Vy_elast_dot {:}{:} - - "Local relative tangential acceleration at node (for CDBEMT)" "m/s^2" +typedef ^ ^ ReKi omega_z {:}{:} - - "rotation of no-sweep-pitch-twist coordinate system around z (for CDBEMT and CUA)" "rad/s" typedef ^ ^ ReKi rLocal {:}{:} - - "Radial distance from center-of-rotation to node" m typedef ^ InputType ReKi Un_disk - - - "disk-averaged velocity normal to the rotor disk (for input to DBEMT)" m/s typedef ^ ^ ReKi UserProp {:}{:} - - "Optional user property for interpolating airfoils (per element per blade)" - diff --git a/modules/aerodyn/src/BEMT_Types.f90 b/modules/aerodyn/src/BEMT_Types.f90 index a5450d6eb5..385866ddd7 100644 --- a/modules/aerodyn/src/BEMT_Types.f90 +++ b/modules/aerodyn/src/BEMT_Types.f90 @@ -74,7 +74,7 @@ MODULE BEMT_Types ! ======================= ! ========= BEMT_ContinuousStateType ======= TYPE, PUBLIC :: BEMT_ContinuousStateType - REAL(SiKi) :: DummyContState !< Remove this variable if you have continuous states [-] + TYPE(UA_ContinuousStateType) :: UA !< UA module continuous states [-] TYPE(DBEMT_ContinuousStateType) :: DBEMT !< DBEMT module continuous states [-] END TYPE BEMT_ContinuousStateType ! ======================= @@ -101,15 +101,22 @@ MODULE BEMT_Types TYPE, PUBLIC :: BEMT_MiscVarType LOGICAL :: FirstWarn_Skew !< flag so invalid skew warning doesn't get repeated forever [-] LOGICAL :: FirstWarn_Phi !< flag so Invalid Phi warning doesn't get repeated forever [-] + LOGICAL :: FirstWarn_BEMoff !< flag to warn the BEM was turned off [-] TYPE(UA_MiscVarType) :: UA !< misc vars for UnsteadyAero [-] TYPE(DBEMT_MiscVarType) :: DBEMT !< misc vars for DBEMT [-] TYPE(UA_OutputType) :: y_UA !< outputs from UnsteadyAero [-] + TYPE(UA_InputType) , DIMENSION(:,:,:), ALLOCATABLE :: u_UA !< inputs to UnsteadyAero at t and t+dt [-] + TYPE(DBEMT_InputType) , DIMENSION(:), ALLOCATABLE :: u_DBEMT !< inputs to DBEMT [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TnInd_op !< tangential induction at the operating point (for linearization with frozen wake assumption) [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AxInd_op !< axial induction at the operating point (for linearization) with frozen wake assumption [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AxInduction !< axial induction used for code run-time optimization [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TanInduction !< tangential induction used for code run-time optimization [-] LOGICAL :: UseFrozenWake !< flag set to determine if frozen values of TnInd_op and AxInd_op should be used for this calculation in the linearization process [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Rtip !< maximum rlocal value for each blade (typically the value at the tip) [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: phi !< temp variable used in update states for returning phi (to allow computing inputs and states at multiple times) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: chi !< temp variable used in update states for returning chi (to allow calling same routine from CalcOutput and UpdateStates) [-] + LOGICAL , DIMENSION(:,:), ALLOCATABLE :: ValidPhi !< temp variable used in calcOutput for ValidPhi (to allow calling same routine from CalcOutput and UpdateStates) [-] + REAL(ReKi) :: BEM_weight END TYPE BEMT_MiscVarType ! ======================= ! ========= BEMT_ParameterType ======= @@ -139,6 +146,7 @@ MODULE BEMT_Types LOGICAL :: UA_Flag !< logical flag indicating whether to use UnsteadyAero [-] INTEGER(IntKi) :: DBEMT_Mod !< DBEMT Model. 0 = constant tau1, 1 = time dependent tau1 [-] REAL(ReKi) :: yawCorrFactor !< constant used in Pitt/Peters skewed wake model (default is 15*pi/32) [-] + LOGICAL , DIMENSION(:,:), ALLOCATABLE :: FixedInductions !< flag to determine if BEM inductions should be fixed and not modified by dbemt or skewed wake [-] END TYPE BEMT_ParameterType ! ======================= ! ========= BEMT_InputType ======= @@ -147,8 +155,12 @@ MODULE BEMT_Types REAL(ReKi) :: chi0 !< Angle between the vector normal to the rotor plane and the wind vector (e.g., the yaw angle in the case of no tilt) [rad] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: psi !< Azimuth angle [rad] REAL(ReKi) :: omega !< Angular velocity of rotor [rad/s] + REAL(ReKi) :: TSR !< Tip-speed ratio (to check if BEM should be turned off) [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vx !< Local axial velocity at node [m/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vy !< Local tangential velocity at node [m/s] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vx_elast_dot !< Local relative axial acceleration at node (for CDBEMT) [m/s^2] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vy_elast_dot !< Local relative tangential acceleration at node (for CDBEMT) [m/s^2] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: omega_z !< rotation of no-sweep-pitch-twist coordinate system around z (for CDBEMT and CUA) [rad/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: rLocal !< Radial distance from center-of-rotation to node [m] REAL(ReKi) :: Un_disk !< disk-averaged velocity normal to the rotor disk (for input to DBEMT) [m/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: UserProp !< Optional user property for interpolating airfoils (per element per blade) [-] @@ -182,6 +194,7 @@ SUBROUTINE BEMT_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, Err 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 = 'BEMT_CopyInitInput' @@ -602,6 +615,7 @@ SUBROUTINE BEMT_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E 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 = 'BEMT_UnPackInitInput' @@ -1010,7 +1024,9 @@ SUBROUTINE BEMT_CopyContState( SrcContStateData, DstContStateData, CtrlCode, Err ! ErrStat = ErrID_None ErrMsg = "" - DstContStateData%DummyContState = SrcContStateData%DummyContState + CALL UA_CopyContState( SrcContStateData%UA, DstContStateData%UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN CALL DBEMT_CopyContState( SrcContStateData%DBEMT, DstContStateData%DBEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN @@ -1025,6 +1041,7 @@ SUBROUTINE BEMT_DestroyContState( ContStateData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" + CALL UA_DestroyContState( ContStateData%UA, ErrStat, ErrMsg ) CALL DBEMT_DestroyContState( ContStateData%DBEMT, ErrStat, ErrMsg ) END SUBROUTINE BEMT_DestroyContState @@ -1063,8 +1080,24 @@ SUBROUTINE BEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyContState ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! UA: size of buffers for each call to pack subtype + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, .TRUE. ) ! UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF Int_BufSz = Int_BufSz + 3 ! DBEMT: size of buffers for each call to pack subtype CALL DBEMT_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%DBEMT, ErrStat2, ErrMsg2, .TRUE. ) ! DBEMT CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1109,8 +1142,34 @@ SUBROUTINE BEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyContState - Re_Xferred = Re_Xferred + 1 + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, OnlySize ) ! UA + 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 DBEMT_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%DBEMT, ErrStat2, ErrMsg2, OnlySize ) ! DBEMT CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -1167,8 +1226,46 @@ SUBROUTINE BEMT_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyContState = REAL(ReKiBuf(Re_Xferred), SiKi) - Re_Xferred = Re_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL UA_UnpackContState( Re_Buf, Db_Buf, Int_Buf, OutData%UA, ErrStat2, ErrMsg2 ) ! UA + 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 @@ -2056,6 +2153,7 @@ SUBROUTINE BEMT_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) 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 = 'BEMT_CopyMisc' @@ -2064,6 +2162,7 @@ SUBROUTINE BEMT_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) ErrMsg = "" DstMiscData%FirstWarn_Skew = SrcMiscData%FirstWarn_Skew DstMiscData%FirstWarn_Phi = SrcMiscData%FirstWarn_Phi + DstMiscData%FirstWarn_BEMoff = SrcMiscData%FirstWarn_BEMoff CALL UA_CopyMisc( SrcMiscData%UA, DstMiscData%UA, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN @@ -2073,6 +2172,46 @@ SUBROUTINE BEMT_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) CALL UA_CopyOutput( SrcMiscData%y_UA, DstMiscData%y_UA, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcMiscData%u_UA)) THEN + i1_l = LBOUND(SrcMiscData%u_UA,1) + i1_u = UBOUND(SrcMiscData%u_UA,1) + i2_l = LBOUND(SrcMiscData%u_UA,2) + i2_u = UBOUND(SrcMiscData%u_UA,2) + i3_l = LBOUND(SrcMiscData%u_UA,3) + i3_u = UBOUND(SrcMiscData%u_UA,3) + IF (.NOT. ALLOCATED(DstMiscData%u_UA)) THEN + ALLOCATE(DstMiscData%u_UA(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%u_UA.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i3 = LBOUND(SrcMiscData%u_UA,3), UBOUND(SrcMiscData%u_UA,3) + DO i2 = LBOUND(SrcMiscData%u_UA,2), UBOUND(SrcMiscData%u_UA,2) + DO i1 = LBOUND(SrcMiscData%u_UA,1), UBOUND(SrcMiscData%u_UA,1) + CALL UA_CopyInput( SrcMiscData%u_UA(i1,i2,i3), DstMiscData%u_UA(i1,i2,i3), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO + ENDDO + ENDDO +ENDIF +IF (ALLOCATED(SrcMiscData%u_DBEMT)) THEN + i1_l = LBOUND(SrcMiscData%u_DBEMT,1) + i1_u = UBOUND(SrcMiscData%u_DBEMT,1) + IF (.NOT. ALLOCATED(DstMiscData%u_DBEMT)) THEN + ALLOCATE(DstMiscData%u_DBEMT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%u_DBEMT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcMiscData%u_DBEMT,1), UBOUND(SrcMiscData%u_DBEMT,1) + CALL DBEMT_CopyInput( SrcMiscData%u_DBEMT(i1), DstMiscData%u_DBEMT(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF IF (ALLOCATED(SrcMiscData%TnInd_op)) THEN i1_l = LBOUND(SrcMiscData%TnInd_op,1) i1_u = UBOUND(SrcMiscData%TnInd_op,1) @@ -2142,6 +2281,49 @@ SUBROUTINE BEMT_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) END IF DstMiscData%Rtip = SrcMiscData%Rtip ENDIF +IF (ALLOCATED(SrcMiscData%phi)) THEN + i1_l = LBOUND(SrcMiscData%phi,1) + i1_u = UBOUND(SrcMiscData%phi,1) + i2_l = LBOUND(SrcMiscData%phi,2) + i2_u = UBOUND(SrcMiscData%phi,2) + IF (.NOT. ALLOCATED(DstMiscData%phi)) THEN + ALLOCATE(DstMiscData%phi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%phi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%phi = SrcMiscData%phi +ENDIF +IF (ALLOCATED(SrcMiscData%chi)) THEN + i1_l = LBOUND(SrcMiscData%chi,1) + i1_u = UBOUND(SrcMiscData%chi,1) + i2_l = LBOUND(SrcMiscData%chi,2) + i2_u = UBOUND(SrcMiscData%chi,2) + IF (.NOT. ALLOCATED(DstMiscData%chi)) THEN + ALLOCATE(DstMiscData%chi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%chi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%chi = SrcMiscData%chi +ENDIF +IF (ALLOCATED(SrcMiscData%ValidPhi)) THEN + i1_l = LBOUND(SrcMiscData%ValidPhi,1) + i1_u = UBOUND(SrcMiscData%ValidPhi,1) + i2_l = LBOUND(SrcMiscData%ValidPhi,2) + i2_u = UBOUND(SrcMiscData%ValidPhi,2) + IF (.NOT. ALLOCATED(DstMiscData%ValidPhi)) THEN + ALLOCATE(DstMiscData%ValidPhi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%ValidPhi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%ValidPhi = SrcMiscData%ValidPhi +ENDIF + DstMiscData%BEM_weight = SrcMiscData%BEM_weight END SUBROUTINE BEMT_CopyMisc SUBROUTINE BEMT_DestroyMisc( MiscData, ErrStat, ErrMsg ) @@ -2156,6 +2338,22 @@ SUBROUTINE BEMT_DestroyMisc( MiscData, ErrStat, ErrMsg ) CALL UA_DestroyMisc( MiscData%UA, ErrStat, ErrMsg ) CALL DBEMT_DestroyMisc( MiscData%DBEMT, ErrStat, ErrMsg ) CALL UA_DestroyOutput( MiscData%y_UA, ErrStat, ErrMsg ) +IF (ALLOCATED(MiscData%u_UA)) THEN +DO i3 = LBOUND(MiscData%u_UA,3), UBOUND(MiscData%u_UA,3) +DO i2 = LBOUND(MiscData%u_UA,2), UBOUND(MiscData%u_UA,2) +DO i1 = LBOUND(MiscData%u_UA,1), UBOUND(MiscData%u_UA,1) + CALL UA_DestroyInput( MiscData%u_UA(i1,i2,i3), ErrStat, ErrMsg ) +ENDDO +ENDDO +ENDDO + DEALLOCATE(MiscData%u_UA) +ENDIF +IF (ALLOCATED(MiscData%u_DBEMT)) THEN +DO i1 = LBOUND(MiscData%u_DBEMT,1), UBOUND(MiscData%u_DBEMT,1) + CALL DBEMT_DestroyInput( MiscData%u_DBEMT(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(MiscData%u_DBEMT) +ENDIF IF (ALLOCATED(MiscData%TnInd_op)) THEN DEALLOCATE(MiscData%TnInd_op) ENDIF @@ -2170,6 +2368,15 @@ SUBROUTINE BEMT_DestroyMisc( MiscData, ErrStat, ErrMsg ) ENDIF IF (ALLOCATED(MiscData%Rtip)) THEN DEALLOCATE(MiscData%Rtip) +ENDIF +IF (ALLOCATED(MiscData%phi)) THEN + DEALLOCATE(MiscData%phi) +ENDIF +IF (ALLOCATED(MiscData%chi)) THEN + DEALLOCATE(MiscData%chi) +ENDIF +IF (ALLOCATED(MiscData%ValidPhi)) THEN + DEALLOCATE(MiscData%ValidPhi) ENDIF END SUBROUTINE BEMT_DestroyMisc @@ -2210,6 +2417,7 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_BufSz = 0 Int_BufSz = Int_BufSz + 1 ! FirstWarn_Skew Int_BufSz = Int_BufSz + 1 ! FirstWarn_Phi + Int_BufSz = Int_BufSz + 1 ! FirstWarn_BEMoff ! Allocate buffers for subtypes, if any (we'll get sizes from these) Int_BufSz = Int_BufSz + 3 ! UA: size of buffers for each call to pack subtype CALL UA_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, .TRUE. ) ! UA @@ -2262,6 +2470,56 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 1 ! u_UA allocated yes/no + IF ( ALLOCATED(InData%u_UA) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! u_UA upper/lower bounds for each dimension + DO i3 = LBOUND(InData%u_UA,3), UBOUND(InData%u_UA,3) + DO i2 = LBOUND(InData%u_UA,2), UBOUND(InData%u_UA,2) + DO i1 = LBOUND(InData%u_UA,1), UBOUND(InData%u_UA,1) + Int_BufSz = Int_BufSz + 3 ! u_UA: size of buffers for each call to pack subtype + CALL UA_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%u_UA(i1,i2,i3), ErrStat2, ErrMsg2, .TRUE. ) ! u_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! u_UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! u_UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! u_UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END DO + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! u_DBEMT allocated yes/no + IF ( ALLOCATED(InData%u_DBEMT) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! u_DBEMT upper/lower bounds for each dimension + DO i1 = LBOUND(InData%u_DBEMT,1), UBOUND(InData%u_DBEMT,1) + Int_BufSz = Int_BufSz + 3 ! u_DBEMT: size of buffers for each call to pack subtype + CALL DBEMT_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%u_DBEMT(i1), ErrStat2, ErrMsg2, .TRUE. ) ! u_DBEMT + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! u_DBEMT + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! u_DBEMT + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! u_DBEMT + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF Int_BufSz = Int_BufSz + 1 ! TnInd_op allocated yes/no IF ( ALLOCATED(InData%TnInd_op) ) THEN Int_BufSz = Int_BufSz + 2*2 ! TnInd_op upper/lower bounds for each dimension @@ -2288,6 +2546,22 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_BufSz = Int_BufSz + 2*1 ! Rtip upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%Rtip) ! Rtip END IF + Int_BufSz = Int_BufSz + 1 ! phi allocated yes/no + IF ( ALLOCATED(InData%phi) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! phi upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%phi) ! phi + END IF + Int_BufSz = Int_BufSz + 1 ! chi allocated yes/no + IF ( ALLOCATED(InData%chi) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! chi upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%chi) ! chi + END IF + Int_BufSz = Int_BufSz + 1 ! ValidPhi allocated yes/no + IF ( ALLOCATED(InData%ValidPhi) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! ValidPhi upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%ValidPhi) ! ValidPhi + END IF + Re_BufSz = Re_BufSz + 1 ! BEM_weight IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2318,6 +2592,8 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstWarn_Skew, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstWarn_Phi, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstWarn_BEMoff, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 CALL UA_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, OnlySize ) ! UA CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -2403,6 +2679,98 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + IF ( .NOT. ALLOCATED(InData%u_UA) ) 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%u_UA,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%u_UA,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%u_UA,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%u_UA,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%u_UA,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%u_UA,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%u_UA,3), UBOUND(InData%u_UA,3) + DO i2 = LBOUND(InData%u_UA,2), UBOUND(InData%u_UA,2) + DO i1 = LBOUND(InData%u_UA,1), UBOUND(InData%u_UA,1) + CALL UA_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%u_UA(i1,i2,i3), ErrStat2, ErrMsg2, OnlySize ) ! u_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%u_DBEMT) ) 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%u_DBEMT,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%u_DBEMT,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%u_DBEMT,1), UBOUND(InData%u_DBEMT,1) + CALL DBEMT_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%u_DBEMT(i1), ErrStat2, ErrMsg2, OnlySize ) ! u_DBEMT + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF IF ( .NOT. ALLOCATED(InData%TnInd_op) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -2500,6 +2868,68 @@ SUBROUTINE BEMT_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( .NOT. ALLOCATED(InData%phi) ) 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%phi,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%phi,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%phi,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%phi,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%phi,2), UBOUND(InData%phi,2) + DO i1 = LBOUND(InData%phi,1), UBOUND(InData%phi,1) + ReKiBuf(Re_Xferred) = InData%phi(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%chi) ) 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%chi,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chi,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%chi,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chi,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%chi,2), UBOUND(InData%chi,2) + DO i1 = LBOUND(InData%chi,1), UBOUND(InData%chi,1) + ReKiBuf(Re_Xferred) = InData%chi(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%ValidPhi) ) 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%ValidPhi,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%ValidPhi,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%ValidPhi,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%ValidPhi,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%ValidPhi,2), UBOUND(InData%ValidPhi,2) + DO i1 = LBOUND(InData%ValidPhi,1), UBOUND(InData%ValidPhi,1) + IntKiBuf(Int_Xferred) = TRANSFER(InData%ValidPhi(i1,i2), IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + ReKiBuf(Re_Xferred) = InData%BEM_weight + Re_Xferred = Re_Xferred + 1 END SUBROUTINE BEMT_PackMisc SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -2517,6 +2947,7 @@ SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg 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 = 'BEMT_UnPackMisc' @@ -2533,6 +2964,8 @@ SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg OutData%FirstWarn_Skew = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstWarn_Skew) Int_Xferred = Int_Xferred + 1 OutData%FirstWarn_Phi = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstWarn_Phi) + Int_Xferred = Int_Xferred + 1 + OutData%FirstWarn_BEMoff = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstWarn_BEMoff) Int_Xferred = Int_Xferred + 1 Buf_size=IntKiBuf( Int_Xferred ) Int_Xferred = Int_Xferred + 1 @@ -2607,13 +3040,133 @@ SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL DBEMT_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%DBEMT, ErrStat2, ErrMsg2 ) ! DBEMT + CALL DBEMT_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%DBEMT, ErrStat2, ErrMsg2 ) ! DBEMT + 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 UA_UnpackOutput( Re_Buf, Db_Buf, Int_Buf, OutData%y_UA, ErrStat2, ErrMsg2 ) ! y_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! u_UA 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%u_UA)) DEALLOCATE(OutData%u_UA) + ALLOCATE(OutData%u_UA(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%u_UA.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%u_UA,3), UBOUND(OutData%u_UA,3) + DO i2 = LBOUND(OutData%u_UA,2), UBOUND(OutData%u_UA,2) + DO i1 = LBOUND(OutData%u_UA,1), UBOUND(OutData%u_UA,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL UA_UnpackInput( Re_Buf, Db_Buf, Int_Buf, OutData%u_UA(i1,i2,i3), ErrStat2, ErrMsg2 ) ! u_UA CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! u_DBEMT 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%u_DBEMT)) DEALLOCATE(OutData%u_DBEMT) + ALLOCATE(OutData%u_DBEMT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%u_DBEMT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%u_DBEMT,1), UBOUND(OutData%u_DBEMT,1) Buf_size=IntKiBuf( Int_Xferred ) Int_Xferred = Int_Xferred + 1 IF(Buf_size > 0) THEN @@ -2647,13 +3200,15 @@ SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL UA_UnpackOutput( Re_Buf, Db_Buf, Int_Buf, OutData%y_UA, ErrStat2, ErrMsg2 ) ! y_UA + CALL DBEMT_UnpackInput( Re_Buf, Db_Buf, Int_Buf, OutData%u_DBEMT(i1), ErrStat2, ErrMsg2 ) ! u_DBEMT CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TnInd_op not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -2766,6 +3321,77 @@ SUBROUTINE BEMT_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! phi 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%phi)) DEALLOCATE(OutData%phi) + ALLOCATE(OutData%phi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%phi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%phi,2), UBOUND(OutData%phi,2) + DO i1 = LBOUND(OutData%phi,1), UBOUND(OutData%phi,1) + OutData%phi(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! chi 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%chi)) DEALLOCATE(OutData%chi) + ALLOCATE(OutData%chi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%chi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%chi,2), UBOUND(OutData%chi,2) + DO i1 = LBOUND(OutData%chi,1), UBOUND(OutData%chi,1) + OutData%chi(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! ValidPhi 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%ValidPhi)) DEALLOCATE(OutData%ValidPhi) + ALLOCATE(OutData%ValidPhi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%ValidPhi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%ValidPhi,2), UBOUND(OutData%ValidPhi,2) + DO i1 = LBOUND(OutData%ValidPhi,1), UBOUND(OutData%ValidPhi,1) + OutData%ValidPhi(i1,i2) = TRANSFER(IntKiBuf(Int_Xferred), OutData%ValidPhi(i1,i2)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + OutData%BEM_weight = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 END SUBROUTINE BEMT_UnPackMisc SUBROUTINE BEMT_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) @@ -2876,6 +3502,20 @@ SUBROUTINE BEMT_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg DstParamData%UA_Flag = SrcParamData%UA_Flag DstParamData%DBEMT_Mod = SrcParamData%DBEMT_Mod DstParamData%yawCorrFactor = SrcParamData%yawCorrFactor +IF (ALLOCATED(SrcParamData%FixedInductions)) THEN + i1_l = LBOUND(SrcParamData%FixedInductions,1) + i1_u = UBOUND(SrcParamData%FixedInductions,1) + i2_l = LBOUND(SrcParamData%FixedInductions,2) + i2_u = UBOUND(SrcParamData%FixedInductions,2) + IF (.NOT. ALLOCATED(DstParamData%FixedInductions)) THEN + ALLOCATE(DstParamData%FixedInductions(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%FixedInductions.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%FixedInductions = SrcParamData%FixedInductions +ENDIF END SUBROUTINE BEMT_CopyParam SUBROUTINE BEMT_DestroyParam( ParamData, ErrStat, ErrMsg ) @@ -2904,6 +3544,9 @@ SUBROUTINE BEMT_DestroyParam( ParamData, ErrStat, ErrMsg ) ENDIF CALL UA_DestroyParam( ParamData%UA, ErrStat, ErrMsg ) CALL DBEMT_DestroyParam( ParamData%DBEMT, ErrStat, ErrMsg ) +IF (ALLOCATED(ParamData%FixedInductions)) THEN + DEALLOCATE(ParamData%FixedInductions) +ENDIF END SUBROUTINE BEMT_DestroyParam SUBROUTINE BEMT_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3019,6 +3662,11 @@ SUBROUTINE BEMT_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + 1 ! UA_Flag Int_BufSz = Int_BufSz + 1 ! DBEMT_Mod Re_BufSz = Re_BufSz + 1 ! yawCorrFactor + Int_BufSz = Int_BufSz + 1 ! FixedInductions allocated yes/no + IF ( ALLOCATED(InData%FixedInductions) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! FixedInductions upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%FixedInductions) ! FixedInductions + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -3233,6 +3881,26 @@ SUBROUTINE BEMT_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_Xferred = Int_Xferred + 1 ReKiBuf(Re_Xferred) = InData%yawCorrFactor Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%FixedInductions) ) 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%FixedInductions,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%FixedInductions,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%FixedInductions,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%FixedInductions,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%FixedInductions,2), UBOUND(InData%FixedInductions,2) + DO i1 = LBOUND(InData%FixedInductions,1), UBOUND(InData%FixedInductions,1) + IntKiBuf(Int_Xferred) = TRANSFER(InData%FixedInductions(i1,i2), IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE BEMT_PackParam SUBROUTINE BEMT_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -3489,6 +4157,29 @@ SUBROUTINE BEMT_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Int_Xferred = Int_Xferred + 1 OutData%yawCorrFactor = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! FixedInductions 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%FixedInductions)) DEALLOCATE(OutData%FixedInductions) + ALLOCATE(OutData%FixedInductions(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%FixedInductions.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%FixedInductions,2), UBOUND(OutData%FixedInductions,2) + DO i1 = LBOUND(OutData%FixedInductions,1), UBOUND(OutData%FixedInductions,1) + OutData%FixedInductions(i1,i2) = TRANSFER(IntKiBuf(Int_Xferred), OutData%FixedInductions(i1,i2)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE BEMT_UnPackParam SUBROUTINE BEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) @@ -3535,6 +4226,7 @@ SUBROUTINE BEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg DstInputData%psi = SrcInputData%psi ENDIF DstInputData%omega = SrcInputData%omega + DstInputData%TSR = SrcInputData%TSR IF (ALLOCATED(SrcInputData%Vx)) THEN i1_l = LBOUND(SrcInputData%Vx,1) i1_u = UBOUND(SrcInputData%Vx,1) @@ -3563,6 +4255,48 @@ SUBROUTINE BEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg END IF DstInputData%Vy = SrcInputData%Vy ENDIF +IF (ALLOCATED(SrcInputData%Vx_elast_dot)) THEN + i1_l = LBOUND(SrcInputData%Vx_elast_dot,1) + i1_u = UBOUND(SrcInputData%Vx_elast_dot,1) + i2_l = LBOUND(SrcInputData%Vx_elast_dot,2) + i2_u = UBOUND(SrcInputData%Vx_elast_dot,2) + IF (.NOT. ALLOCATED(DstInputData%Vx_elast_dot)) THEN + ALLOCATE(DstInputData%Vx_elast_dot(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%Vx_elast_dot.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%Vx_elast_dot = SrcInputData%Vx_elast_dot +ENDIF +IF (ALLOCATED(SrcInputData%Vy_elast_dot)) THEN + i1_l = LBOUND(SrcInputData%Vy_elast_dot,1) + i1_u = UBOUND(SrcInputData%Vy_elast_dot,1) + i2_l = LBOUND(SrcInputData%Vy_elast_dot,2) + i2_u = UBOUND(SrcInputData%Vy_elast_dot,2) + IF (.NOT. ALLOCATED(DstInputData%Vy_elast_dot)) THEN + ALLOCATE(DstInputData%Vy_elast_dot(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%Vy_elast_dot.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%Vy_elast_dot = SrcInputData%Vy_elast_dot +ENDIF +IF (ALLOCATED(SrcInputData%omega_z)) THEN + i1_l = LBOUND(SrcInputData%omega_z,1) + i1_u = UBOUND(SrcInputData%omega_z,1) + i2_l = LBOUND(SrcInputData%omega_z,2) + i2_u = UBOUND(SrcInputData%omega_z,2) + IF (.NOT. ALLOCATED(DstInputData%omega_z)) THEN + ALLOCATE(DstInputData%omega_z(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%omega_z.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%omega_z = SrcInputData%omega_z +ENDIF IF (ALLOCATED(SrcInputData%rLocal)) THEN i1_l = LBOUND(SrcInputData%rLocal,1) i1_u = UBOUND(SrcInputData%rLocal,1) @@ -3615,6 +4349,15 @@ SUBROUTINE BEMT_DestroyInput( InputData, ErrStat, ErrMsg ) IF (ALLOCATED(InputData%Vy)) THEN DEALLOCATE(InputData%Vy) ENDIF +IF (ALLOCATED(InputData%Vx_elast_dot)) THEN + DEALLOCATE(InputData%Vx_elast_dot) +ENDIF +IF (ALLOCATED(InputData%Vy_elast_dot)) THEN + DEALLOCATE(InputData%Vy_elast_dot) +ENDIF +IF (ALLOCATED(InputData%omega_z)) THEN + DEALLOCATE(InputData%omega_z) +ENDIF IF (ALLOCATED(InputData%rLocal)) THEN DEALLOCATE(InputData%rLocal) ENDIF @@ -3670,6 +4413,7 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = Re_BufSz + SIZE(InData%psi) ! psi END IF Re_BufSz = Re_BufSz + 1 ! omega + Re_BufSz = Re_BufSz + 1 ! TSR Int_BufSz = Int_BufSz + 1 ! Vx allocated yes/no IF ( ALLOCATED(InData%Vx) ) THEN Int_BufSz = Int_BufSz + 2*2 ! Vx upper/lower bounds for each dimension @@ -3680,6 +4424,21 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + 2*2 ! Vy upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%Vy) ! Vy END IF + Int_BufSz = Int_BufSz + 1 ! Vx_elast_dot allocated yes/no + IF ( ALLOCATED(InData%Vx_elast_dot) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Vx_elast_dot upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vx_elast_dot) ! Vx_elast_dot + END IF + Int_BufSz = Int_BufSz + 1 ! Vy_elast_dot allocated yes/no + IF ( ALLOCATED(InData%Vy_elast_dot) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Vy_elast_dot upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vy_elast_dot) ! Vy_elast_dot + END IF + Int_BufSz = Int_BufSz + 1 ! omega_z allocated yes/no + IF ( ALLOCATED(InData%omega_z) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! omega_z upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%omega_z) ! omega_z + END IF Int_BufSz = Int_BufSz + 1 ! rLocal allocated yes/no IF ( ALLOCATED(InData%rLocal) ) THEN Int_BufSz = Int_BufSz + 2*2 ! rLocal upper/lower bounds for each dimension @@ -3757,6 +4516,8 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, END IF ReKiBuf(Re_Xferred) = InData%omega Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TSR + Re_Xferred = Re_Xferred + 1 IF ( .NOT. ALLOCATED(InData%Vx) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -3797,6 +4558,66 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, END DO END DO END IF + IF ( .NOT. ALLOCATED(InData%Vx_elast_dot) ) 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%Vx_elast_dot,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vx_elast_dot,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vx_elast_dot,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vx_elast_dot,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Vx_elast_dot,2), UBOUND(InData%Vx_elast_dot,2) + DO i1 = LBOUND(InData%Vx_elast_dot,1), UBOUND(InData%Vx_elast_dot,1) + ReKiBuf(Re_Xferred) = InData%Vx_elast_dot(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vy_elast_dot) ) 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%Vy_elast_dot,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vy_elast_dot,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vy_elast_dot,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vy_elast_dot,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Vy_elast_dot,2), UBOUND(InData%Vy_elast_dot,2) + DO i1 = LBOUND(InData%Vy_elast_dot,1), UBOUND(InData%Vy_elast_dot,1) + ReKiBuf(Re_Xferred) = InData%Vy_elast_dot(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%omega_z) ) 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%omega_z,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%omega_z,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%omega_z,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%omega_z,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%omega_z,2), UBOUND(InData%omega_z,2) + DO i1 = LBOUND(InData%omega_z,1), UBOUND(InData%omega_z,1) + ReKiBuf(Re_Xferred) = InData%omega_z(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF IF ( .NOT. ALLOCATED(InData%rLocal) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -3914,6 +4735,8 @@ SUBROUTINE BEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs END IF OutData%omega = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%TSR = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vx not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -3960,6 +4783,75 @@ SUBROUTINE BEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs END DO END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vx_elast_dot 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%Vx_elast_dot)) DEALLOCATE(OutData%Vx_elast_dot) + ALLOCATE(OutData%Vx_elast_dot(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vx_elast_dot.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Vx_elast_dot,2), UBOUND(OutData%Vx_elast_dot,2) + DO i1 = LBOUND(OutData%Vx_elast_dot,1), UBOUND(OutData%Vx_elast_dot,1) + OutData%Vx_elast_dot(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vy_elast_dot 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%Vy_elast_dot)) DEALLOCATE(OutData%Vy_elast_dot) + ALLOCATE(OutData%Vy_elast_dot(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vy_elast_dot.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Vy_elast_dot,2), UBOUND(OutData%Vy_elast_dot,2) + DO i1 = LBOUND(OutData%Vy_elast_dot,1), UBOUND(OutData%Vy_elast_dot,1) + OutData%Vy_elast_dot(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! omega_z 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%omega_z)) DEALLOCATE(OutData%omega_z) + ALLOCATE(OutData%omega_z(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%omega_z.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%omega_z,2), UBOUND(OutData%omega_z,2) + DO i1 = LBOUND(OutData%omega_z,1), UBOUND(OutData%omega_z,1) + OutData%omega_z(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! rLocal not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -5093,6 +5985,8 @@ SUBROUTINE BEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg END IF ! check if allocated b = -(u1%omega - u2%omega) u_out%omega = u1%omega + b * ScaleFactor + b = -(u1%TSR - u2%TSR) + u_out%TSR = u1%TSR + b * ScaleFactor IF (ALLOCATED(u_out%Vx) .AND. ALLOCATED(u1%Vx)) THEN DO i2 = LBOUND(u_out%Vx,2),UBOUND(u_out%Vx,2) DO i1 = LBOUND(u_out%Vx,1),UBOUND(u_out%Vx,1) @@ -5109,6 +6003,30 @@ SUBROUTINE BEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg END DO END DO END IF ! check if allocated +IF (ALLOCATED(u_out%Vx_elast_dot) .AND. ALLOCATED(u1%Vx_elast_dot)) THEN + DO i2 = LBOUND(u_out%Vx_elast_dot,2),UBOUND(u_out%Vx_elast_dot,2) + DO i1 = LBOUND(u_out%Vx_elast_dot,1),UBOUND(u_out%Vx_elast_dot,1) + b = -(u1%Vx_elast_dot(i1,i2) - u2%Vx_elast_dot(i1,i2)) + u_out%Vx_elast_dot(i1,i2) = u1%Vx_elast_dot(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%Vy_elast_dot) .AND. ALLOCATED(u1%Vy_elast_dot)) THEN + DO i2 = LBOUND(u_out%Vy_elast_dot,2),UBOUND(u_out%Vy_elast_dot,2) + DO i1 = LBOUND(u_out%Vy_elast_dot,1),UBOUND(u_out%Vy_elast_dot,1) + b = -(u1%Vy_elast_dot(i1,i2) - u2%Vy_elast_dot(i1,i2)) + u_out%Vy_elast_dot(i1,i2) = u1%Vy_elast_dot(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%omega_z) .AND. ALLOCATED(u1%omega_z)) THEN + DO i2 = LBOUND(u_out%omega_z,2),UBOUND(u_out%omega_z,2) + DO i1 = LBOUND(u_out%omega_z,1),UBOUND(u_out%omega_z,1) + b = -(u1%omega_z(i1,i2) - u2%omega_z(i1,i2)) + u_out%omega_z(i1,i2) = u1%omega_z(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated IF (ALLOCATED(u_out%rLocal) .AND. ALLOCATED(u1%rLocal)) THEN DO i2 = LBOUND(u_out%rLocal,2),UBOUND(u_out%rLocal,2) DO i1 = LBOUND(u_out%rLocal,1),UBOUND(u_out%rLocal,1) @@ -5208,6 +6126,9 @@ SUBROUTINE BEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er b = (t(3)**2*(u1%omega - u2%omega) + t(2)**2*(-u1%omega + u3%omega))* scaleFactor c = ( (t(2)-t(3))*u1%omega + t(3)*u2%omega - t(2)*u3%omega ) * scaleFactor u_out%omega = u1%omega + b + c * t_out + b = (t(3)**2*(u1%TSR - u2%TSR) + t(2)**2*(-u1%TSR + u3%TSR))* scaleFactor + c = ( (t(2)-t(3))*u1%TSR + t(3)*u2%TSR - t(2)*u3%TSR ) * scaleFactor + u_out%TSR = u1%TSR + b + c * t_out IF (ALLOCATED(u_out%Vx) .AND. ALLOCATED(u1%Vx)) THEN DO i2 = LBOUND(u_out%Vx,2),UBOUND(u_out%Vx,2) DO i1 = LBOUND(u_out%Vx,1),UBOUND(u_out%Vx,1) @@ -5226,6 +6147,33 @@ SUBROUTINE BEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er END DO END DO END IF ! check if allocated +IF (ALLOCATED(u_out%Vx_elast_dot) .AND. ALLOCATED(u1%Vx_elast_dot)) THEN + DO i2 = LBOUND(u_out%Vx_elast_dot,2),UBOUND(u_out%Vx_elast_dot,2) + DO i1 = LBOUND(u_out%Vx_elast_dot,1),UBOUND(u_out%Vx_elast_dot,1) + b = (t(3)**2*(u1%Vx_elast_dot(i1,i2) - u2%Vx_elast_dot(i1,i2)) + t(2)**2*(-u1%Vx_elast_dot(i1,i2) + u3%Vx_elast_dot(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%Vx_elast_dot(i1,i2) + t(3)*u2%Vx_elast_dot(i1,i2) - t(2)*u3%Vx_elast_dot(i1,i2) ) * scaleFactor + u_out%Vx_elast_dot(i1,i2) = u1%Vx_elast_dot(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%Vy_elast_dot) .AND. ALLOCATED(u1%Vy_elast_dot)) THEN + DO i2 = LBOUND(u_out%Vy_elast_dot,2),UBOUND(u_out%Vy_elast_dot,2) + DO i1 = LBOUND(u_out%Vy_elast_dot,1),UBOUND(u_out%Vy_elast_dot,1) + b = (t(3)**2*(u1%Vy_elast_dot(i1,i2) - u2%Vy_elast_dot(i1,i2)) + t(2)**2*(-u1%Vy_elast_dot(i1,i2) + u3%Vy_elast_dot(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%Vy_elast_dot(i1,i2) + t(3)*u2%Vy_elast_dot(i1,i2) - t(2)*u3%Vy_elast_dot(i1,i2) ) * scaleFactor + u_out%Vy_elast_dot(i1,i2) = u1%Vy_elast_dot(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%omega_z) .AND. ALLOCATED(u1%omega_z)) THEN + DO i2 = LBOUND(u_out%omega_z,2),UBOUND(u_out%omega_z,2) + DO i1 = LBOUND(u_out%omega_z,1),UBOUND(u_out%omega_z,1) + b = (t(3)**2*(u1%omega_z(i1,i2) - u2%omega_z(i1,i2)) + t(2)**2*(-u1%omega_z(i1,i2) + u3%omega_z(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%omega_z(i1,i2) + t(3)*u2%omega_z(i1,i2) - t(2)*u3%omega_z(i1,i2) ) * scaleFactor + u_out%omega_z(i1,i2) = u1%omega_z(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated IF (ALLOCATED(u_out%rLocal) .AND. ALLOCATED(u1%rLocal)) THEN DO i2 = LBOUND(u_out%rLocal,2),UBOUND(u_out%rLocal,2) DO i1 = LBOUND(u_out%rLocal,1),UBOUND(u_out%rLocal,1) diff --git a/modules/aerodyn/src/DBEMT.f90 b/modules/aerodyn/src/DBEMT.f90 index a9f63471bd..e01d334629 100644 --- a/modules/aerodyn/src/DBEMT.f90 +++ b/modules/aerodyn/src/DBEMT.f90 @@ -31,8 +31,11 @@ module DBEMT public :: DBEMT_UpdateStates public :: DBEMT_CalcOutput public :: DBEMT_End + PUBLIC :: DBEMT_CalcContStateDeriv ! Tight coupling routine for computing derivatives of continuous states + public :: DBEMT_ReInit + public :: DBEMT_InitStates_AllNodes contains @@ -52,12 +55,23 @@ subroutine DBEMT_ValidateInitInp(interval, InitInp, errStat, errMsg) errMsg = "" if ( interval <= sqrt(epsilon(1.0_ReKi)) ) call SetErrStat( ErrID_Fatal, " The timestep size for DBEMT (interval) must be larger than sqrt(epsilon).", ErrStat, ErrMsg, RoutineName) - if ( (InitInp%DBEMT_Mod .ne. DBEMT_tauConst) .and. (InitInp%DBEMT_Mod .ne. DBEMT_tauVaries) ) call SetErrStat( ErrID_Fatal, " DBEMT_Mod must be set to 1 or 2.", ErrStat, ErrMsg, RoutineName) + + !>>> remove after this feature gets tested better: + if (InitInp%DBEMT_Mod == DBEMT_cont_tauConst ) then + call SetErrStat( ErrID_Fatal, "DBEMT_Mod cannot be 3 in this version of OpenFAST.", ErrStat, ErrMsg, RoutineName ) + return + end if + !<<< + + if ( (InitInp%DBEMT_Mod .ne. DBEMT_tauConst) .and. (InitInp%DBEMT_Mod .ne. DBEMT_tauVaries) .and. (InitInp%DBEMT_Mod .ne. DBEMT_cont_tauConst)) then + call SetErrStat( ErrID_Fatal, " DBEMT_Mod must be set to 1, 2, or 3.", ErrStat, ErrMsg, RoutineName) + end if if (InitInp%numBlades < 1) call SetErrStat( ErrID_Fatal, " InitInp%numBlades must set to 1 or more.", ErrStat, ErrMsg, RoutineName) if (InitInp%numNodes < 2) call SetErrStat( ErrID_Fatal, " InitInp%numNodes must set to 2 or more.", ErrStat, ErrMsg, RoutineName) - - if ( (InitInp%DBEMT_Mod == DBEMT_tauConst) )then + + + if ( InitInp%DBEMT_Mod == DBEMT_tauConst .or. InitInp%DBEMT_Mod == DBEMT_cont_tauConst ) then if (InitInp%tau1_const <= 0.0_ReKi) call SetErrStat( ErrID_Fatal, " InitInp%tau1_const must be greater than zero.", ErrStat, ErrMsg, RoutineName) ! Default = 0.33_ReKi @@ -123,9 +137,8 @@ subroutine DBEMT_Init( InitInp, u, p, x, OtherState, m, Interval, InitOut, ErrSt errStat = ErrID_None errMsg = "" - ! initialize InitOut and u to avoid compiler warnings - InitOut%Ver = ProgDesc( 'DBEMT', 'v1.00.00', '28-Jul-2017' ) - u%spanRatio = 0.0_ReKi + ! initialize InitOut to avoid compiler warnings + InitOut%Ver = ProgDesc( 'DBEMT', '', '' ) !if (p%DBEMT_Mod == DBEMT_none) return ! DBEMT is turned off. @@ -153,8 +166,14 @@ subroutine DBEMT_Init( InitInp, u, p, x, OtherState, m, Interval, InitOut, ErrSt !<<<<<< p%tau1_const = InitInp%tau1_const ! Default = 0.33_ReKi - if (p%DBEMT_Mod == DBEMT_tauConst) then - ! DBEMT_Mod = 1 uses constant tau1 and tau2 + allocate(u%element(p%numNodes, p%numBlades), stat=ErrStat2) + if (ErrStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, " Error allocating u%element.", ErrStat, ErrMsg, RoutineName) + return + end if + + if (p%DBEMT_Mod == DBEMT_tauConst .or. p%DBEMT_Mod == DBEMT_cont_tauConst) then + ! DBEMT_Mod = 1 and 3 use constant tau1 and tau2 allocate( p%spanRatio(p%numNodes, p%numBlades), STAT=ErrStat2) if (ErrStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, " Error allocating p%spanRatio. ", ErrStat, ErrMsg, RoutineName) @@ -176,54 +195,147 @@ subroutine DBEMT_Init( InitInp, u, p, x, OtherState, m, Interval, InitOut, ErrSt end if ! Initialize the continuous states - allocate( x%vind(2,p%numNodes, p%numBlades), STAT=ErrStat2) ! This is the axial and tangential induced velocity at node i on blade j + allocate( x%element(p%numNodes, p%numBlades), STAT=ErrStat2) ! This is the axial and tangential induced velocity at node i on blade j if (ErrStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, " Error allocating x%vind. ", ErrStat, ErrMsg, RoutineName) + call SetErrStat( ErrID_Fatal, " Error allocating x%element. ", ErrStat, ErrMsg, RoutineName) return end if - allocate( x%vind_1(2,p%numNodes, p%numBlades), STAT=ErrStat2) ! This is the axial and tangential induced velocity at node i on blade j - if (ErrStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, " Error allocating x%vind_1. ", ErrStat, ErrMsg, RoutineName) - return - end if - + if (p%DBEMT_Mod == DBEMT_cont_tauConst) then + allocate( OtherState%n(p%numNodes, p%numBlades), STAT=ErrStat2) + if (ErrStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, " Error allocating OtherState%n.", ErrStat, ErrMsg, RoutineName) + return + end if + + do i=1,size(OtherState%xdot) + call DBEMT_CopyContState( x, OtherState%xdot(i), MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + if (ErrStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, " Error allocating OtherState%xdot.", ErrStat, ErrMsg, RoutineName) + return + end if + end do + + p%lin_nx = p%numNodes*p%numBlades*4 ! vind and vind_dot + else + p%lin_nx = 0 + end if + allocate( OtherState%areStatesInitialized(p%numNodes, p%numBlades), STAT=ErrStat2) if (ErrStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, " Error allocating OtherState%areStatesInitialized. ", ErrStat, ErrMsg, RoutineName) return end if - call DBEMT_ReInit(x,OtherState,m) + call DBEMT_ReInit(p, x,OtherState,m) end subroutine DBEMT_Init !.................................................................................................................................. -subroutine DBEMT_ReInit( x, OtherState, m ) +subroutine DBEMT_ReInit( p, x, OtherState, m ) + type(DBEMT_ParameterType), intent(in ) :: p !< parameters type(DBEMT_ContinuousStateType), intent(inout) :: x !< Initial continuous states type(DBEMT_OtherStateType), intent(inout) :: OtherState !< Initial other/logical states type(DBEMT_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer :: i + integer :: j + integer :: n + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + ! Initialize variables for this routine - x%vind = 0.0 ! This is the axial and tangential induced velocity - x%vind_1 = 0.0 ! This is the axial and tangential induced velocity + do j=1,size(x%element,2) + do i=1,size(x%element,1) + x%element(i,j)%vind = 0.0_ReKi + x%element(i,j)%vind_dot = 0.0_ReKi + x%element(i,j)%vind_1 = 0.0_ReKi + end do + end do + OtherState%areStatesInitialized = .false. - OtherState%tau1 = 0.0_ReKi + + if (p%DBEMT_Mod == DBEMT_tauConst .or. p%DBEMT_Mod == DBEMT_cont_tauConst) then + OtherState%tau1 = p%tau1_const + else + OtherState%tau1 = 0.0_ReKi + end if + + if (allocated(OtherState%n)) then + OtherState%n = -1 + + do n=1,size(OtherState%xdot) + do j=1,size(x%element,2) + do i=1,size(x%element,1) + call DBEMT_CopyElementContinuousStateType( x%element(i,j), OtherState%xdot(n)%element(i,j), MESH_UPDATECOPY, ErrStat2, ErrMsg2) + end do + end do + end do + end if + m%FirstWarn_tau1 = .true. end subroutine DBEMT_ReInit +!!---------------------------------------------------------------------------------------------------------------------------------- +!> routine to initialize the states based on inputs +subroutine DBEMT_InitStates_AllNodes( u, p, x, OtherState ) + type(DBEMT_InputType), intent(in ) :: u !< Inputs at t + type(DBEMT_ParameterType), intent(in ) :: p !< Parameters + type(DBEMT_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; + !! Output: Continuous states at t + Interval + type(DBEMT_OtherStateType), intent(inout) :: OtherState !< Other/logical states at t on input; at t+dt on output + + integer(IntKi) :: i !< blade node counter + integer(IntKi) :: j !< blade counter + + do j=1,size(x%element,2) + do i=1,size(x%element,1) + call DBEMT_InitStates( i, j, u, p, x, OtherState ) + end do + end do + +end subroutine DBEMT_InitStates_AllNodes +!!---------------------------------------------------------------------------------------------------------------------------------- +!> routine to initialize the states based on inputs +subroutine DBEMT_InitStates( i, j, u, p, x, OtherState ) + integer(IntKi), intent(in ) :: i !< blade node counter + integer(IntKi), intent(in ) :: j !< blade counter + type(DBEMT_InputType), intent(in ) :: u !< Inputs at t + type(DBEMT_ParameterType), intent(in ) :: p !< Parameters + type(DBEMT_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; + !! Output: Continuous states at t + Interval + type(DBEMT_OtherStateType), intent(inout) :: OtherState !< Other/logical states at t on input; at t+dt on output + + if ( .not. OtherState%areStatesInitialized(i,j) ) then + x%element(i,j)%vind(1) = u%element(i,j)%vind_s(1) + x%element(i,j)%vind(2) = u%element(i,j)%vind_s(2) + + if (p%DBEMT_Mod == DBEMT_cont_tauConst) then + x%element(i,j)%vind_dot(1) = u%element(i,j)%vind_s_dot(1) + x%element(i,j)%vind_dot(2) = u%element(i,j)%vind_s_dot(2) + else + x%element(i,j)%vind_1(1) = u%element(i,j)%vind_s(1) + x%element(i,j)%vind_1(2) = u%element(i,j)%vind_s(2) + end if + + OtherState%areStatesInitialized(i,j) = .true. + return + end if + +end subroutine DBEMT_InitStates !!---------------------------------------------------------------------------------------------------------------------------------- !> Loose coupling routine for solving for constraint states, integrating continuous states, and updating discrete and other states. !! Continuous, constraint, discrete, and other states are updated for t + Interval -subroutine DBEMT_UpdateStates( i, j, t, u, p, x, OtherState, m, errStat, errMsg ) +subroutine DBEMT_UpdateStates( i, j, t, n, u, p, x, OtherState, m, errStat, errMsg ) !.................................................................................................................................. integer(IntKi), intent(in ) :: i !< blade node counter integer(IntKi), intent(in ) :: j !< blade counter real(DbKi), intent(in ) :: t !< Current simulation time in seconds - type(DBEMT_InputType), intent(inout) :: u(2) !< Inputs at utimes (out only for mesh record-keeping in ExtrapInterp routine) + integer(IntKi), intent(in ) :: n !< Current simulation time step n = 0,1,... + type(DBEMT_InputType), intent(in ) :: u(2) !< Inputs at t and t+dt type(DBEMT_ParameterType), intent(in ) :: p !< Parameters type(DBEMT_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; !! Output: Continuous states at t + Interval @@ -233,11 +345,13 @@ subroutine DBEMT_UpdateStates( i, j, t, u, p, x, OtherState, m, errStat, errMsg character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None ! local variables - real(ReKi) :: spanRatio ! local version of r / R - real(ReKi) :: tau2 , A, B, C0, k_tau, C0_2 ! tau1_plus1, C_tau1, C, K1 - integer(IntKi) :: indx + real(ReKi) :: A, B, C0, k_tau, C0_2 ! tau1_plus1, C_tau1, C, K1 + integer(IntKi) :: indx + real(DbKi) :: utimes(2) - character(*), parameter :: RoutineName = 'DBEMT_UpdateStates' + TYPE(DBEMT_ElementInputType) :: u_elem(2) !< Inputs at utimes + + character(*), parameter :: RoutineName = 'DBEMT_UpdateStates' ErrStat = ErrID_None ErrMsg = "" @@ -246,61 +360,54 @@ subroutine DBEMT_UpdateStates( i, j, t, u, p, x, OtherState, m, errStat, errMsg call ComputeTau1(u(1), p, m, OtherState%tau1, errStat, errMsg) ! place this here for DBEMTau1 output reasons if (errStat >= AbortErrLev) return + call ComputeTau2(i, j, u(1)%element(i,j), p, OtherState%tau1, OtherState%tau2, k_tau) - if ( .not. OtherState%areStatesInitialized(i,j) ) then - x%vind_1(1,i,j) = u(1)%vind_s(1) - x%vind_1(2,i,j) = u(1)%vind_s(2) - x%vind(1,i,j) = u(1)%vind_s(1) - x%vind(2,i,j) = u(1)%vind_s(2) - OtherState%areStatesInitialized(i,j) = .true. - return - end if - - - if ( p%DBEMT_Mod == DBEMT_tauConst ) then - spanRatio = p%spanRatio(i,j) - else - spanRatio = u(1)%spanRatio - end if - + call DBEMT_InitStates( i, j, u(1), p, x, OtherState ) - do indx=1,2 !Axial and tangential components. jmj questions if this should be done for tangential induction. + if (p%DBEMT_Mod == DBEMT_cont_tauConst) then ! continuous formulation: + utimes(1) = t + utimes(2) = t + p%dt + u_elem(1) = u(1)%element(i,j) + u_elem(2) = u(2)%element(i,j) + call DBEMT_ABM4( i, j, t, n, u_elem, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) + + else ! finite difference formulation: + + do indx=1,2 !Axial and tangential components. jmj questions if this should be done for tangential induction. - ! TODO: Deal with initialization so that we avoid spikes??? + B = ( u(2)%element(i,j)%vind_s(indx) - u(1)%element(i,j)%vind_s(indx) ) / p%dt ! Eqn. 1.17c ! bjj: note that interpOrder will affect this numerical derivative + A = u(1)%element(i,j)%vind_s(indx) + B*p%k_0ye*OtherState%tau1 ! Eqn. 1.17b - B = ( u(2)%vind_s(indx) - u(1)%vind_s(indx) ) / p%dt ! Eqn. 1.17c ! bjj: note that interpOrder will affect this numerical derivative - A = u(1)%vind_s(indx) + B*p%k_0ye*OtherState%tau1 ! Eqn. 1.17b + C0 = x%element(i,j)%vind_1(indx) - A + B*OtherState%tau1 ! Eqn. 1.21b - C0 = x%vind_1(indx,i,j) - A + B*OtherState%tau1 ! Eqn. 1.21b + x%element(i,j)%vind_1(indx) = C0*exp(-p%dt/OtherState%tau1) + A + B*(p%dt-OtherState%tau1) ! Eqn. 1.21a, but this is using p%dt instead of t - x%vind_1(indx,i,j) = C0*exp(-p%dt/OtherState%tau1) + A + B*(p%dt-OtherState%tau1) ! Eqn. 1.21a, but this is using p%dt instead of t + C0_2 = x%element(i,j)%vind(indx) - C0/(1-k_tau) - A + B*(OtherState%tau1 + OtherState%tau2) ! Eqn. 1.24c + x%element(i,j)%vind(indx) = C0_2*exp(-p%dt/OtherState%tau2) + A + B*(p%dt-OtherState%tau1-OtherState%tau2) & + + (C0/(1-k_tau))*exp(-p%dt/OtherState%tau1) ! Eqn. 1.25 - k_tau = 0.39 - 0.26*spanRatio**2 ! Eqn. 1.23b - tau2 = k_tau*OtherState%tau1 ! Eqn. 1.7 or Eqn 1.23a - C0_2 = x%vind(indx,i,j) - C0/(1-k_tau) - A + B*(OtherState%tau1 + tau2) ! Eqn. 1.24c - x%vind(indx,i,j) = C0_2*exp(-p%dt/tau2) + A + B*(p%dt-OtherState%tau1-tau2) + (C0/(1-k_tau))*exp(-p%dt/OtherState%tau1) ! Eqn. 1.25 + !C = (u(2)%element(i,j)%vind_s(indx) - u(1)%element(i,j)%vind_s(indx))/p%dt ! v_ind_s_future could come from BEMT update states, but this seems to violate the framework !Eqn. 1.27C + !A = u(1)%element(i,j)%vind_s(indx) + C*p%k_0ye*tau1 ! + !B = C*(p%k_0ye*C_tau1+1) + !K1 = (A + A*C_tau1 - B*tau1) / (1+C_tau1) + !C0 = ( x%element(i,j)%vind_1(indx) - K1 )*tau1**(1.0/C_tau1) + !C0_2 = ( x%element(i,j)%vind(indx) - K1 - C0 / ((1-k_tau)**(1.0/C_tau1)) + B*k_tau*tau1/((1+C_tau1)*(1+k_tau*C_tau1)) ) * tau1**(1.0/(k_tau*C_tau1)) + !x%element(i,j)%vind(indx) = K1 + B*(p%dt-k_tau*tau1)/((1+C_tau1)*(1+k_tau*C_tau1)) + C0 / ((1-k_tau)*(tau1+C_tau1*p%dt)**(1.0/C_tau1)) + C0_2 / ((tau1 + C_tau1*p%dt)**(1.0/(k_tau*C_tau1))) + end do - !C = (u(2)%vind_s(indx) - u(1)%vind_s(indx))/p%dt ! v_ind_s_future could come from BEMT update states, but this seems to violate the framework !Eqn. 1.27C - !A = u(1)%vind_s(indx) + C*p%k_0ye*tau1 ! - !B = C*(p%k_0ye*C_tau1+1) - !K1 = (A + A*C_tau1 - B*tau1) / (1+C_tau1) - !C0 = ( x%vind_1(indx,i,j) - K1 )*tau1**(1.0/C_tau1) - !k_tau = 0.39 - 0.26*(spanRatio)**2 - !C0_2 = ( x%vind(indx,i,j) - K1 - C0 / ((1-k_tau)**(1.0/C_tau1)) + B*k_tau*tau1/((1+C_tau1)*(1+k_tau*C_tau1)) ) * tau1**(1.0/(k_tau*C_tau1)) - !x%vind(indx,i,j) = K1 + B*(p%dt-k_tau*tau1)/((1+C_tau1)*(1+k_tau*C_tau1)) + C0 / ((1-k_tau)*(tau1+C_tau1*p%dt)**(1.0/C_tau1)) + C0_2 / ((tau1 + C_tau1*p%dt)**(1.0/(k_tau*C_tau1))) - end do + end if end subroutine DBEMT_UpdateStates !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine computes the (rotor) value of tau1 for DBEMT !---------------------------------------------------------------------------------------------------------------------------------- subroutine ComputeTau1(u, p, m, tau1, errStat, errMsg) - type(DBEMT_InputType), intent(inout) :: u !< Inputs at u(1) + type(DBEMT_InputType), intent(in ) :: u !< Inputs at u(1) type(DBEMT_ParameterType), intent(in ) :: p !< Parameters type(DBEMT_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables - real(ReKi) , intent(inout) :: tau1 !< tau1 value used in DBEMT filter + real(ReKi) , intent( out) :: tau1 !< tau1 value used in DBEMT filter integer(IntKi), intent( out) :: errStat !< Error status of the operation character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None @@ -313,13 +420,13 @@ subroutine ComputeTau1(u, p, m, tau1, errStat, errMsg) real(ReKi) :: Un_disk real(ReKi), parameter :: min_Un = 0.1_ReKi - character(*), parameter :: RoutineName = 'ComputeTau1' + character(*), parameter :: RoutineName = 'ComputeTau' ErrStat = ErrID_None ErrMsg = "" - if ( p%DBEMT_Mod == DBEMT_tauConst ) then + if ( p%DBEMT_Mod == DBEMT_tauConst .or. p%DBEMT_Mod == DBEMT_cont_tauConst) then tau1 = p%tau1_const else @@ -345,7 +452,7 @@ subroutine ComputeTau1(u, p, m, tau1, errStat, errMsg) if ( u%Un_disk < min_Un ) then Un_disk = min_Un if (m%FirstWarn_tau1) then - call setErrStat( ErrID_Severe, 'Induced axial relative air speed, Un, is less than '//trim(num2lstr(min_Un)) & + call setErrStat( ErrID_Severe, 'Uninduced axial relative air speed, Un, is less than '//trim(num2lstr(min_Un)) & // ' m/s; limiting time-varying tau1. This message will not be repeated though the ' & //'condition may persist.', ErrStat, ErrMsg, RoutineName ) ! don't print this error more than one time m%FirstWarn_tau1 = .false. @@ -362,6 +469,35 @@ subroutine ComputeTau1(u, p, m, tau1, errStat, errMsg) end if end subroutine ComputeTau1 +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine computes the (rotor) value of tau1, tau2, and k_tau for DBEMT +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine ComputeTau2(i, j, u, p, tau1, tau2, k_tau_out) + integer(IntKi), intent(in ) :: i !< blade node counter + integer(IntKi), intent(in ) :: j !< blade counter + type(DBEMT_ElementInputType), intent(in ) :: u !< element inputs at u(1) + type(DBEMT_ParameterType), intent(in ) :: p !< Parameters + real(ReKi) , intent(in ) :: tau1 !< tau1 value used in DBEMT filter + real(ReKi) , intent( out) :: tau2 !< tau2 value used in DBEMT filter + real(ReKi), optional , intent( out) :: k_tau_out !< k_tau value used in DBEMT filter + + ! local variables + real(ReKi) :: spanRatio ! local version of r / R + real(ReKi) :: k_tau + + + if ( p%DBEMT_Mod == DBEMT_tauConst .or. p%DBEMT_Mod == DBEMT_cont_tauConst ) then + spanRatio = p%spanRatio(i,j) + else + spanRatio = u%spanRatio + end if + + k_tau = 0.39 - 0.26*spanRatio**2 ! Eqn. 1.23b + tau2 = k_tau*tau1 ! Eqn. 1.7 or Eqn 1.23a + + if (present(k_tau_out) ) k_tau_out = k_tau + +end subroutine ComputeTau2 !---------------------------------------------------------------------------------------------------------------------------------- !> Routine for computing outputs, used in both loose and tight coupling. @@ -396,14 +532,353 @@ subroutine DBEMT_CalcOutput( i, j, t, u, y_vind, p, x, OtherState, m, errStat, e ErrMsg = "" if ( .not. OtherState%areStatesInitialized(i,j) ) then - y_vind = u%vind_s + y_vind = u%element(i,j)%vind_s else - y_vind(:) = x%vind(:,i,j) + y_vind = x%element(i,j)%vind ! array copy end if end subroutine DBEMT_CalcOutput +!---------------------------------------------------------------------------------------------------------------------------------- +!> Tight coupling routine for computing derivatives of continuous states. +SUBROUTINE DBEMT_CalcContStateDeriv( i, j, t, u, p, x, OtherState, m, dxdt, ErrStat, ErrMsg ) +!.................................................................................................................................. + + INTEGER(IntKi), INTENT(IN ) :: i !< blade node counter + INTEGER(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + TYPE(DBEMT_ElementInputType), INTENT(IN ) :: u !< Inputs at t + TYPE(DBEMT_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(DBEMT_ElementContinuousStateType), INTENT(IN ) :: x !< Continuous states at t (and i and j) + TYPE(DBEMT_OtherStateType), INTENT(IN ) :: OtherState !< Other states + TYPE(DBEMT_MiscVarType), INTENT(INOUT) :: m !< Misc variables for optimization (not copied in glue code) + TYPE(DBEMT_ElementContinuousStateType), INTENT(OUT) :: dxdt !< Continuous state derivatives at t (note that since we are operating on only a portion of the continuous states, I have made a separate, smaller type to avoid excessive memory allocation/deallocation) + 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 = 'DBEMT_CalcContStateDeriv' + + REAL(ReKi) :: tauConst + REAL(ReKi) :: tau1 + REAL(ReKi) :: tau2 + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! Compute the first time derivatives of the continuous states here: + + if (p%DBEMT_Mod /= DBEMT_cont_tauConst) then + call SetErrStat(ErrID_Fatal,"Continuous state derivatives cannot be calculated unless DBEMT_Mod is 3.",ErrStat,ErrMsg,RoutineName) + return + end if + + tau1 = p%tau1_const + !call ComputeTau1( u, p, m, tau1, errStat, errMsg) + call ComputeTau2(i, j, u, p, tau1, tau2) + + ! Implement Equation 37 from E.Branlard 16-Dec-2019 doc: + + dxdt%vind = x%vind_dot + + tauConst = -1.0_ReKi/(tau1 * tau2) + + dxdt%vind_dot = tauConst * ( x%vind(:) + (tau1 + tau2)*x%vind_dot(:) & + - u%vind_s(:) - p%k_0ye*tau1*u%vind_s_dot(:) ) + +END SUBROUTINE DBEMT_CalcContStateDeriv +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Runge-Kutta Method (RK4) for numerically integrating ordinary differential equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! Define constants k1, k2, k3, and k4 as +!! k1 = dt * f(t , x_t ) +!! k2 = dt * f(t + dt/2 , x_t + k1/2 ) +!! k3 = dt * f(t + dt/2 , x_t + k2/2 ), and +!! k4 = dt * f(t + dt , x_t + k3 ). +!! Then the continuous states at t = t + dt are +!! x_(t+dt) = x_t + k1/6 + k2/3 + k3/3 + k4/6 + O(dt^5) +!! +!! For details, see: +!! Press, W. H.; Flannery, B. P.; Teukolsky, S. A.; and Vetterling, W. T. "Runge-Kutta Method" and "Adaptive Step Size Control for +!! Runge-Kutta." Sections 16.1 and 16.2 in Numerical Recipes in FORTRAN: The Art of Scientific Computing, 2nd ed. Cambridge, England: +!! Cambridge University Press, pp. 704-716, 1992. +SUBROUTINE DBEMT_RK4( i, j, t, n, u, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(DBEMT_ElementInputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(DBEMT_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(DBEMT_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(DBEMT_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + + TYPE(DBEMT_ElementContinuousStateType) :: k1 ! RK4 constant; see above + TYPE(DBEMT_ElementContinuousStateType) :: k2 ! RK4 constant; see above + TYPE(DBEMT_ElementContinuousStateType) :: k3 ! RK4 constant; see above + TYPE(DBEMT_ElementContinuousStateType) :: k4 ! RK4 constant; see above + TYPE(DBEMT_ElementContinuousStateType) :: x_tmp ! Holds temporary modification to x + TYPE(DBEMT_ElementInputType) :: u_interp ! interpolated value of inputs + + REAL(DbKi) :: TPlusHalfDt + REAL(DbKi) :: TPlusDt + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_RK4' + + + !NOTE: the error handling here assumes that we do not have any allocatable data in the inputs (u_interp) to be concerned with. + ! Also, We assume that if there is going to be an error in DBEMT_CalcContStateDeriv, it will happen only on the first call + ! to the routine. + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! interpolate u to find u_interp = u(t) + CALL DBEMT_ElementInputType_ExtrapInterp( u, utimes, u_interp, t, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + x_tmp = x%element(i,j) + + ! find xdot at t + CALL DBEMT_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, m, k1, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + k1%vind = p%dt * k1%vind + k1%vind_dot = p%dt * k1%vind_dot + + x_tmp%vind = x%element(i,j)%vind + 0.5 * k1%vind + x_tmp%vind_dot = x%element(i,j)%vind_dot + 0.5 * k1%vind_dot + + ! interpolate u to find u_interp = u(t + dt/2) + TPlusHalfDt = t+0.5_DbKi*p%dt + CALL DBEMT_ElementInputType_ExtrapInterp(u, utimes, u_interp, TPlusHalfDt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! find xdot at t + dt/2 + CALL DBEMT_CalcContStateDeriv( i, j, TPlusHalfDt, u_interp, p, x_tmp, OtherState, m, k2, ErrStat2, ErrMsg2 ) + + k2%vind = p%dt * k2%vind + k2%vind_dot = p%dt * k2%vind_dot + + x_tmp%vind = x%element(i,j)%vind + 0.5 * k2%vind + x_tmp%vind_dot = x%element(i,j)%vind_dot + 0.5 * k2%vind_dot + + ! find xdot at t + dt/2 (note x_tmp has changed) + CALL DBEMT_CalcContStateDeriv( i, j, TPlusHalfDt, u_interp, p, x_tmp, OtherState, m, k3, ErrStat2, ErrMsg2 ) + + k3%vind = p%dt * k3%vind + k3%vind_dot = p%dt * k3%vind_dot + + x_tmp%vind = x%element(i,j)%vind + k3%vind + x_tmp%vind_dot = x%element(i,j)%vind_dot + k3%vind_dot + + ! interpolate u to find u_interp = u(t + dt) + TPlusDt = t + p%dt + CALL DBEMT_ElementInputType_ExtrapInterp(u, utimes, u_interp, TPlusDt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! find xdot at t + dt + CALL DBEMT_CalcContStateDeriv( i, j, TPlusDt, u_interp, p, x_tmp, OtherState, m, k4, ErrStat2, ErrMsg2 ) + + k4%vind = p%dt * k4%vind + k4%vind_dot = p%dt * k4%vind_dot + + x%element(i,j)%vind = x%element(i,j)%vind + ( k1%vind + 2. * k2%vind + 2. * k3%vind + k4%vind ) / 6. + x%element(i,j)%vind_dot = x%element(i,j)%vind_dot + ( k1%vind_dot + 2. * k2%vind_dot + 2. * k3%vind_dot + k4%vind_dot ) / 6. + +END SUBROUTINE DBEMT_RK4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Adams-Bashforth Method (RK4) for numerically integrating ordinary differential +!! equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! +!! x(t+dt) = x(t) + (dt / 24.) * ( 55.*f(t,x) - 59.*f(t-dt,x) + 37.*f(t-2.*dt,x) - 9.*f(t-3.*dt,x) ) +!! +!! See, e.g., +!! http://en.wikipedia.org/wiki/Linear_multistep_method +!! +!! or +!! +!! K. E. Atkinson, "An Introduction to Numerical Analysis", 1989, John Wiley & Sons, Inc, Second Edition. +SUBROUTINE DBEMT_AB4( i, j, t, n, u, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(DBEMT_ElementInputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(DBEMT_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(DBEMT_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(DBEMT_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + + ! local variables + TYPE(DBEMT_ElementInputType) :: u_interp + TYPE(DBEMT_ElementContinuousStateType) :: x_tmp + + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_AB4' + + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + if (OtherState%n(i,j) < n) then + + OtherState%n(i,j) = n + ! these types don't contain pointers or allocatable arrays, so we can copy them directly here: + OtherState%xdot(4)%element(i,j) = OtherState%xdot(3)%element(i,j) + OtherState%xdot(3)%element(i,j) = OtherState%xdot(2)%element(i,j) + OtherState%xdot(2)%element(i,j) = OtherState%xdot(1)%element(i,j) + + elseif (OtherState%n(i,j) > n) then + + CALL SetErrStat(ErrID_Fatal,'Backing up in time is not supported with a multistep method.',ErrStat,ErrMsg,RoutineName) + RETURN + + endif + + ! need xdot at t, get inputs at t + CALL DBEMT_ElementInputType_ExtrapInterp(u, utimes, u_interp, t, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + x_tmp = x%element(i,j) + + ! calculate OtherState%xdot( 1 )%element(i,j) + CALL DBEMT_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, m, OtherState%xdot( 1 )%element(i,j), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + if (n <= 2) then + + CALL DBEMT_RK4(i, j, t, n, u, utimes, p, x, OtherState, m, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + else + + x%element(i,j)%vind = x%element(i,j)%vind + p%DT/24. * ( 55.*OtherState%xdot(1)%element(i,j)%vind - 59.*OtherState%xdot(2)%element(i,j)%vind & + + 37.*OtherState%xdot(3)%element(i,j)%vind - 9.*OtherState%xdot(4)%element(i,j)%vind ) + + x%element(i,j)%vind_dot = x%element(i,j)%vind_dot + p%DT/24. * ( 55.*OtherState%xdot(1)%element(i,j)%vind_dot - 59.*OtherState%xdot(2)%element(i,j)%vind_dot & + + 37.*OtherState%xdot(3)%element(i,j)%vind_dot - 9.*OtherState%xdot(4)%element(i,j)%vind_dot ) + + endif + + +END SUBROUTINE DBEMT_AB4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Adams-Bashforth-Moulton Method (RK4) for numerically integrating ordinary +!! differential equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! +!! Adams-Bashforth Predictor: \n +!! x^p(t+dt) = x(t) + (dt / 24.) * ( 55.*f(t,x) - 59.*f(t-dt,x) + 37.*f(t-2.*dt,x) - 9.*f(t-3.*dt,x) ) +!! +!! Adams-Moulton Corrector: \n +!! x(t+dt) = x(t) + (dt / 24.) * ( 9.*f(t+dt,x^p) + 19.*f(t,x) - 5.*f(t-dt,x) + 1.*f(t-2.*dt,x) ) +!! +!! See, e.g., +!! http://en.wikipedia.org/wiki/Linear_multistep_method +!! +!! or +!! +!! K. E. Atkinson, "An Introduction to Numerical Analysis", 1989, John Wiley & Sons, Inc, Second Edition. +SUBROUTINE DBEMT_ABM4( i, j, t, n, u, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(DBEMT_ElementInputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(DBEMT_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(DBEMT_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(DBEMT_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + + TYPE(DBEMT_ElementInputType) :: u_interp ! Inputs at t + TYPE(DBEMT_ElementContinuousStateType) :: x_in ! Continuous states at t + TYPE(DBEMT_ElementContinuousStateType) :: xdot_pred ! Derivative of continuous states at t + + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_ABM4' + + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! save copy of x(t): + x_in = x%element(i,j) + + + ! predict: (note that we are overwritting x%element(i,j)%vind and x%element(i,j)%vind_dot here): + CALL DBEMT_AB4( i, j, t, n, u, utimes, p, x, OtherState, m, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + if (n > 2_IntKi) then + + ! correct: + + CALL DBEMT_ElementInputType_ExtrapInterp(u, utimes, u_interp, t + p%dt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + CALL DBEMT_CalcContStateDeriv(i, j, t + p%dt, u_interp, p, x%element(i,j), OtherState, m, xdot_pred, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + x%element(i,j)%vind = x_in%vind + p%DT/24. * ( 9. * xdot_pred%vind + 19. * OtherState%xdot(1)%element(i,j)%vind & + - 5. * OtherState%xdot(2)%element(i,j)%vind & + + 1. * OtherState%xdot(3)%element(i,j)%vind ) + + x%element(i,j)%vind_dot = x_in%vind_dot + p%DT/24. * ( 9. * xdot_pred%vind_dot + 19. * OtherState%xdot(1)%element(i,j)%vind_dot & + - 5. * OtherState%xdot(2)%element(i,j)%vind_dot & + + 1. * OtherState%xdot(3)%element(i,j)%vind_dot ) + endif + +END SUBROUTINE DBEMT_ABM4 !---------------------------------------------------------------------------------------------------------------------------------- !> This routine is called at the end of the simulation. subroutine DBEMT_End( u, p, x, OtherState, m, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/src/DBEMT_Registry.txt b/modules/aerodyn/src/DBEMT_Registry.txt index 2f21637c7f..c5fa20f529 100644 --- a/modules/aerodyn/src/DBEMT_Registry.txt +++ b/modules/aerodyn/src/DBEMT_Registry.txt @@ -15,41 +15,39 @@ include Registry_NWTC_Library.txt param DBEMT/DBEMT - INTEGER DBEMT_none - 0 - "use BEMT instead (not DBEMT)" - param DBEMT/DBEMT - INTEGER DBEMT_tauConst - 1 - "use constant tau1" - param DBEMT/DBEMT - INTEGER DBEMT_tauVaries - 2 - "use time-dependent tau1" - - +param DBEMT/DBEMT - INTEGER DBEMT_cont_tauConst - 3 - "use continuous formulation with constant tau1" - + # ..... Initialization data ....................................................................................................... # Define inputs that the initialization routine may need here: typedef DBEMT/DBEMT InitInputType IntKi NumBlades - - - "Number of blades on the turbine" - typedef ^ InitInputType IntKi NumNodes - - - "Number of nodes on each blade" - -typedef ^ InitInputType ReKi k_0ye - - - "Filter dynamics constant [default = 0.6 ]" - -typedef ^ InitInputType ReKi c5 - - - "Filter dynamics constant [default = 1.1 ]" - -typedef ^ InitInputType ReKi c6 - - - "Filter dynamics constant [default = 1.0 ]" - -typedef ^ InitInputType ReKi c7 - - - "Filter dynamics constant [default = 1.3 ]" - -typedef ^ InitInputType ReKi c8 - - - "Filter dynamics constant [default = 0.39]" - -typedef ^ InitInputType ReKi c9 - - - "Filter dynamics constant [default = 0.26]" - typedef ^ InitInputType ReKi tau1_const - - - "delay value based on disk-averaged quantities" - -typedef ^ InitInputType ReKi spanRatio {:}{:} - - "static span ratio of each blade node" -typedef ^ InitInputType IntKi DBEMT_Mod - - - "DBEMT Model. 0 = constant tau1, 1 = time dependent tau1" - +typedef ^ InitInputType IntKi DBEMT_Mod - - - "DBEMT Model. 1 = constant tau1, 2 = time dependent tau1, 3=continuous form with constant tau1" - typedef ^ ^ ReKi rLocal {:}{:} - - "Radial distance to blade node from the center of rotation, measured in the rotor plane, needed for DBEMT" m # 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 ^ DBEMT_ElementContinuousStateType R8Ki vind {2} - - "The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a')" m/s +typedef ^ DBEMT_ElementContinuousStateType R8Ki vind_dot {2} - - "Time derivative of the filtered induced velocity, x%vind in CCSD" "m/s^2" +typedef ^ DBEMT_ElementContinuousStateType R8Ki vind_1 {2} - - "The filtered intermediate induced velocity" "m/s" + # ..... States .................................................................................................................... # Define continuous (differentiable) states here: -typedef ^ ContinuousStateType ReKi vind {:}{:}{:} - - "The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j" m/s -typedef ^ ContinuousStateType ReKi vind_1 {:}{:}{:} - - "The filtered intermediate induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j" m/s +typedef ^ ContinuousStateType DBEMT_ElementContinuousStateType element {:}{:} - - "The filtered induced velocity [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j" m/s # # Define discrete (nondifferentiable) states here: -typedef ^ DiscreteStateType SiKi DummyDiscreteState - - - "Remove this variable if you have continuous states" - +typedef ^ DiscreteStateType SiKi DummyState - - - "Remove this variable if you have continuous states" - # # Define constraint states here: -typedef ^ ConstraintStateType SiKi DummyContState - - - "Remove this variable if you have constraint states" - +typedef ^ ConstraintStateType SiKi DummyState - - - "Remove this variable if you have constraint states" - # # Define "other" states here: typedef ^ OtherStateType Logical areStatesInitialized {:}{:} - - "Flag indicating whether the module's states have been initialized properly" - typedef ^ OtherStateType ReKi tau1 - - - "value of tau1 used in updateStates (for output-to-file only)" - +typedef ^ OtherStateType ReKi tau2 - - - "value of tau2 used in updateStates (equal to k_tau * tau1, not used between time steps)" - +typedef ^ OtherStateType IntKi n {:}{:} - - "time step # value used for continuous state integrator" - +typedef ^ OtherStateType DBEMT_ContinuousStateType xdot {4} - - "derivative history for continuous state integrators" - # # Define misc/optimization variables (any data that are not considered actual states) here: @@ -59,6 +57,7 @@ typedef ^ MiscVarType Logical FirstWarn_tau1 - # Define parameters here: # Time step for integration of continuous states (if a fixed-step integrator is used) and update of discrete states: typedef ^ ParameterType DbKi DT - - - "Time step for continuous state integration & discrete state update" seconds +typedef ^ ParameterType IntKi lin_nx - 0 - "Number of continuous states for linearization" - typedef ^ ParameterType IntKi NumBlades - - - "Number of blades on the turbine" - typedef ^ ParameterType IntKi NumNodes - - - "Number of nodes on each blade" - typedef ^ ParameterType ReKi k_0ye - - - "Filter dynamics constant [default = 0.6 ]" - @@ -69,22 +68,22 @@ typedef ^ ParameterType ReKi k_0ye #typedef ^ ParameterType ReKi c9 - - - "Filter dynamics constant [default = 0.26]" - typedef ^ ParameterType ReKi tau1_const - - - "constant version of the delay value" - typedef ^ ParameterType ReKi spanRatio {:}{:} - - "static span ratio of each blade node" -typedef ^ ParameterType IntKi DBEMT_Mod - - - "DBEMT Model. 0 = constant tau1, 1 = time dependent tau1" - +typedef ^ ParameterType IntKi DBEMT_Mod - - - "DBEMT Model. 1 = constant tau1, 2 = time dependent tau1, 3=continuous form of constant tau1" - # ..... Inputs .................................................................................................................... +typedef ^ DBEMT_ElementInputType ReKi vind_s {2} - - "The unfiltered induced velocity, [1] is the axial induced velocity (-Vx*a) and [2] is the tangential induced velocity (Vy*a') at node i on blade j. Note that the inputs are used only operated on at a particular node and blade, so we don't store all elements" "m/s" +typedef ^ DBEMT_ElementInputType ReKi vind_s_dot {2} - - "The first time derivative of the unfiltered induced velocity, u%vind_s" "m/s^2" +typedef ^ DBEMT_ElementInputType ReKi spanRatio - - - "Normalized span location of blade node" - # Define inputs that are contained on the mesh here: # # Define inputs that are not on this mesh here: -#typedef ^ InputType ReKi tau1 - - - "delay value based on disk-averaged quantities" - -typedef ^ InputType ReKi AxInd_disk - - - "Disk-averaged axial induction (for time-varying tau)" - -typedef ^ InputType ReKi Un_disk - - - "Disk-averaged normal relative inflow velocity (for time-varying tau)" m/s -typedef ^ InputType ReKi R_disk - - - "Disk-averaged rotor radius (for time-varying tau)" m -typedef ^ InputType ReKi vind_s {2} - - "The unfiltered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j" m/s -typedef ^ InputType ReKi spanRatio - - - "Normalized span location of blade node" - +typedef ^ InputType ReKi AxInd_disk - - - "Disk-averaged axial induction (for time-varying tau)" - +typedef ^ InputType ReKi Un_disk - - - "Disk-averaged normal relative inflow velocity (for time-varying tau)" m/s +typedef ^ InputType ReKi R_disk - - - "Disk-averaged rotor radius (for time-varying tau)" m +typedef ^ InputType DBEMT_ElementInputType element {:}{:} - - "The element-level inputs at each blade node" - # ..... Outputs ................................................................................................................... # Define outputs that are contained on the mesh here: # # Define outputs that are not on this mesh here: -typedef ^ OutputType ReKi vind {:}{:}{:} - - "The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j" m/s -#typedef ^ OutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" +typedef ^ OutputType ReKi vind {:}{:}{:} - - "The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tangential induced velocity (Vy*a') at node i on blade j" m/s diff --git a/modules/aerodyn/src/DBEMT_Types.f90 b/modules/aerodyn/src/DBEMT_Types.f90 index 2f3fa7499c..04f0fb3af0 100644 --- a/modules/aerodyn/src/DBEMT_Types.f90 +++ b/modules/aerodyn/src/DBEMT_Types.f90 @@ -36,19 +36,13 @@ MODULE DBEMT_Types INTEGER(IntKi), PUBLIC, PARAMETER :: DBEMT_none = 0 ! use BEMT instead (not DBEMT) [-] INTEGER(IntKi), PUBLIC, PARAMETER :: DBEMT_tauConst = 1 ! use constant tau1 [-] INTEGER(IntKi), PUBLIC, PARAMETER :: DBEMT_tauVaries = 2 ! use time-dependent tau1 [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: DBEMT_cont_tauConst = 3 ! use continuous formulation with constant tau1 [-] ! ========= DBEMT_InitInputType ======= TYPE, PUBLIC :: DBEMT_InitInputType INTEGER(IntKi) :: NumBlades !< Number of blades on the turbine [-] INTEGER(IntKi) :: NumNodes !< Number of nodes on each blade [-] - REAL(ReKi) :: k_0ye !< Filter dynamics constant [default = 0.6 ] [-] - REAL(ReKi) :: c5 !< Filter dynamics constant [default = 1.1 ] [-] - REAL(ReKi) :: c6 !< Filter dynamics constant [default = 1.0 ] [-] - REAL(ReKi) :: c7 !< Filter dynamics constant [default = 1.3 ] [-] - REAL(ReKi) :: c8 !< Filter dynamics constant [default = 0.39] [-] - REAL(ReKi) :: c9 !< Filter dynamics constant [default = 0.26] [-] REAL(ReKi) :: tau1_const !< delay value based on disk-averaged quantities [-] - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: spanRatio !< static span ratio of each blade node [-] - INTEGER(IntKi) :: DBEMT_Mod !< DBEMT Model. 0 = constant tau1, 1 = time dependent tau1 [-] + INTEGER(IntKi) :: DBEMT_Mod !< DBEMT Model. 1 = constant tau1, 2 = time dependent tau1, 3=continuous form with constant tau1 [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: rLocal !< Radial distance to blade node from the center of rotation, measured in the rotor plane, needed for DBEMT [m] END TYPE DBEMT_InitInputType ! ======================= @@ -57,26 +51,35 @@ MODULE DBEMT_Types TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] END TYPE DBEMT_InitOutputType ! ======================= +! ========= DBEMT_ElementContinuousStateType ======= + TYPE, PUBLIC :: DBEMT_ElementContinuousStateType + REAL(R8Ki) , DIMENSION(1:2) :: vind !< The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') [m/s] + REAL(R8Ki) , DIMENSION(1:2) :: vind_dot !< Time derivative of the filtered induced velocity, x%vind in CCSD [m/s^2] + REAL(R8Ki) , DIMENSION(1:2) :: vind_1 !< The filtered intermediate induced velocity [m/s] + END TYPE DBEMT_ElementContinuousStateType +! ======================= ! ========= DBEMT_ContinuousStateType ======= TYPE, PUBLIC :: DBEMT_ContinuousStateType - REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: vind !< The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j [m/s] - REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: vind_1 !< The filtered intermediate induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j [m/s] + TYPE(DBEMT_ElementContinuousStateType) , DIMENSION(:,:), ALLOCATABLE :: element !< The filtered induced velocity [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j [m/s] END TYPE DBEMT_ContinuousStateType ! ======================= ! ========= DBEMT_DiscreteStateType ======= TYPE, PUBLIC :: DBEMT_DiscreteStateType - REAL(SiKi) :: DummyDiscreteState !< Remove this variable if you have continuous states [-] + REAL(SiKi) :: DummyState !< Remove this variable if you have continuous states [-] END TYPE DBEMT_DiscreteStateType ! ======================= ! ========= DBEMT_ConstraintStateType ======= TYPE, PUBLIC :: DBEMT_ConstraintStateType - REAL(SiKi) :: DummyContState !< Remove this variable if you have constraint states [-] + REAL(SiKi) :: DummyState !< Remove this variable if you have constraint states [-] END TYPE DBEMT_ConstraintStateType ! ======================= ! ========= DBEMT_OtherStateType ======= TYPE, PUBLIC :: DBEMT_OtherStateType LOGICAL , DIMENSION(:,:), ALLOCATABLE :: areStatesInitialized !< Flag indicating whether the module's states have been initialized properly [-] REAL(ReKi) :: tau1 !< value of tau1 used in updateStates (for output-to-file only) [-] + REAL(ReKi) :: tau2 !< value of tau2 used in updateStates (equal to k_tau * tau1, not used between time steps) [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: n !< time step value used for continuous state integrator [-] + TYPE(DBEMT_ContinuousStateType) , DIMENSION(1:4) :: xdot !< derivative history for continuous state integrators [-] END TYPE DBEMT_OtherStateType ! ======================= ! ========= DBEMT_MiscVarType ======= @@ -87,26 +90,33 @@ MODULE DBEMT_Types ! ========= DBEMT_ParameterType ======= TYPE, PUBLIC :: DBEMT_ParameterType REAL(DbKi) :: DT !< Time step for continuous state integration & discrete state update [seconds] + INTEGER(IntKi) :: lin_nx = 0 !< Number of continuous states for linearization [-] INTEGER(IntKi) :: NumBlades !< Number of blades on the turbine [-] INTEGER(IntKi) :: NumNodes !< Number of nodes on each blade [-] REAL(ReKi) :: k_0ye !< Filter dynamics constant [default = 0.6 ] [-] REAL(ReKi) :: tau1_const !< constant version of the delay value [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: spanRatio !< static span ratio of each blade node [-] - INTEGER(IntKi) :: DBEMT_Mod !< DBEMT Model. 0 = constant tau1, 1 = time dependent tau1 [-] + INTEGER(IntKi) :: DBEMT_Mod !< DBEMT Model. 1 = constant tau1, 2 = time dependent tau1, 3=continuous form of constant tau1 [-] END TYPE DBEMT_ParameterType ! ======================= +! ========= DBEMT_ElementInputType ======= + TYPE, PUBLIC :: DBEMT_ElementInputType + REAL(ReKi) , DIMENSION(1:2) :: vind_s !< The unfiltered induced velocity, [1] is the axial induced velocity (-Vx*a) and [2] is the tangential induced velocity (Vy*a') at node i on blade j. Note that the inputs are used only operated on at a particular node and blade, so we don't store all elements [m/s] + REAL(ReKi) , DIMENSION(1:2) :: vind_s_dot !< The first time derivative of the unfiltered induced velocity, u%vind_s [m/s^2] + REAL(ReKi) :: spanRatio !< Normalized span location of blade node [-] + END TYPE DBEMT_ElementInputType +! ======================= ! ========= DBEMT_InputType ======= TYPE, PUBLIC :: DBEMT_InputType REAL(ReKi) :: AxInd_disk !< Disk-averaged axial induction (for time-varying tau) [-] REAL(ReKi) :: Un_disk !< Disk-averaged normal relative inflow velocity (for time-varying tau) [m/s] REAL(ReKi) :: R_disk !< Disk-averaged rotor radius (for time-varying tau) [m] - REAL(ReKi) , DIMENSION(1:2) :: vind_s !< The unfiltered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j [m/s] - REAL(ReKi) :: spanRatio !< Normalized span location of blade node [-] + TYPE(DBEMT_ElementInputType) , DIMENSION(:,:), ALLOCATABLE :: element !< The element-level inputs at each blade node [-] END TYPE DBEMT_InputType ! ======================= ! ========= DBEMT_OutputType ======= TYPE, PUBLIC :: DBEMT_OutputType - REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: vind !< The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tantential induced velocity (Vy*a') at node i on blade j [m/s] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: vind !< The filtered induced velocity, [1,i,j] is the axial induced velocity (-Vx*a) at node i on blade j and [2,i,j] is the tangential induced velocity (Vy*a') at node i on blade j [m/s] END TYPE DBEMT_OutputType ! ======================= CONTAINS @@ -129,27 +139,7 @@ SUBROUTINE DBEMT_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, Er ErrMsg = "" DstInitInputData%NumBlades = SrcInitInputData%NumBlades DstInitInputData%NumNodes = SrcInitInputData%NumNodes - DstInitInputData%k_0ye = SrcInitInputData%k_0ye - DstInitInputData%c5 = SrcInitInputData%c5 - DstInitInputData%c6 = SrcInitInputData%c6 - DstInitInputData%c7 = SrcInitInputData%c7 - DstInitInputData%c8 = SrcInitInputData%c8 - DstInitInputData%c9 = SrcInitInputData%c9 DstInitInputData%tau1_const = SrcInitInputData%tau1_const -IF (ALLOCATED(SrcInitInputData%spanRatio)) THEN - i1_l = LBOUND(SrcInitInputData%spanRatio,1) - i1_u = UBOUND(SrcInitInputData%spanRatio,1) - i2_l = LBOUND(SrcInitInputData%spanRatio,2) - i2_u = UBOUND(SrcInitInputData%spanRatio,2) - IF (.NOT. ALLOCATED(DstInitInputData%spanRatio)) THEN - ALLOCATE(DstInitInputData%spanRatio(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%spanRatio.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstInitInputData%spanRatio = SrcInitInputData%spanRatio -ENDIF DstInitInputData%DBEMT_Mod = SrcInitInputData%DBEMT_Mod IF (ALLOCATED(SrcInitInputData%rLocal)) THEN i1_l = LBOUND(SrcInitInputData%rLocal,1) @@ -176,9 +166,6 @@ SUBROUTINE DBEMT_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(InitInputData%spanRatio)) THEN - DEALLOCATE(InitInputData%spanRatio) -ENDIF IF (ALLOCATED(InitInputData%rLocal)) THEN DEALLOCATE(InitInputData%rLocal) ENDIF @@ -221,18 +208,7 @@ SUBROUTINE DBEMT_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = 0 Int_BufSz = Int_BufSz + 1 ! NumBlades Int_BufSz = Int_BufSz + 1 ! NumNodes - Re_BufSz = Re_BufSz + 1 ! k_0ye - Re_BufSz = Re_BufSz + 1 ! c5 - Re_BufSz = Re_BufSz + 1 ! c6 - Re_BufSz = Re_BufSz + 1 ! c7 - Re_BufSz = Re_BufSz + 1 ! c8 - Re_BufSz = Re_BufSz + 1 ! c9 Re_BufSz = Re_BufSz + 1 ! tau1_const - Int_BufSz = Int_BufSz + 1 ! spanRatio allocated yes/no - IF ( ALLOCATED(InData%spanRatio) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! spanRatio upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%spanRatio) ! spanRatio - END IF Int_BufSz = Int_BufSz + 1 ! DBEMT_Mod Int_BufSz = Int_BufSz + 1 ! rLocal allocated yes/no IF ( ALLOCATED(InData%rLocal) ) THEN @@ -270,40 +246,8 @@ SUBROUTINE DBEMT_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%NumNodes Int_Xferred = Int_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%k_0ye - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%c5 - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%c6 - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%c7 - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%c8 - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%c9 - Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%tau1_const Re_Xferred = Re_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%spanRatio) ) 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%spanRatio,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%spanRatio,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%spanRatio,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%spanRatio,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%spanRatio,2), UBOUND(InData%spanRatio,2) - DO i1 = LBOUND(InData%spanRatio,1), UBOUND(InData%spanRatio,1) - ReKiBuf(Re_Xferred) = InData%spanRatio(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF IntKiBuf(Int_Xferred) = InData%DBEMT_Mod Int_Xferred = Int_Xferred + 1 IF ( .NOT. ALLOCATED(InData%rLocal) ) THEN @@ -361,43 +305,8 @@ SUBROUTINE DBEMT_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Xferred = Int_Xferred + 1 OutData%NumNodes = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 - OutData%k_0ye = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%c5 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%c6 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%c7 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%c8 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%c9 = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 OutData%tau1_const = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! spanRatio 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%spanRatio)) DEALLOCATE(OutData%spanRatio) - ALLOCATE(OutData%spanRatio(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%spanRatio.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i2 = LBOUND(OutData%spanRatio,2), UBOUND(OutData%spanRatio,2) - DO i1 = LBOUND(OutData%spanRatio,1), UBOUND(OutData%spanRatio,1) - OutData%spanRatio(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF OutData%DBEMT_Mod = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! rLocal not allocated @@ -634,79 +543,42 @@ SUBROUTINE DBEMT_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END SUBROUTINE DBEMT_UnPackInitOutput - SUBROUTINE DBEMT_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(DBEMT_ContinuousStateType), INTENT(IN) :: SrcContStateData - TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: DstContStateData + SUBROUTINE DBEMT_CopyElementContinuousStateType( SrcElementContinuousStateTypeData, DstElementContinuousStateTypeData, CtrlCode, ErrStat, ErrMsg ) + TYPE(DBEMT_ElementContinuousStateType), INTENT(IN) :: SrcElementContinuousStateTypeData + TYPE(DBEMT_ElementContinuousStateType), INTENT(INOUT) :: DstElementContinuousStateTypeData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: 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 = 'DBEMT_CopyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyElementContinuousStateType' ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(SrcContStateData%vind)) THEN - i1_l = LBOUND(SrcContStateData%vind,1) - i1_u = UBOUND(SrcContStateData%vind,1) - i2_l = LBOUND(SrcContStateData%vind,2) - i2_u = UBOUND(SrcContStateData%vind,2) - i3_l = LBOUND(SrcContStateData%vind,3) - i3_u = UBOUND(SrcContStateData%vind,3) - IF (.NOT. ALLOCATED(DstContStateData%vind)) THEN - ALLOCATE(DstContStateData%vind(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%vind.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstContStateData%vind = SrcContStateData%vind -ENDIF -IF (ALLOCATED(SrcContStateData%vind_1)) THEN - i1_l = LBOUND(SrcContStateData%vind_1,1) - i1_u = UBOUND(SrcContStateData%vind_1,1) - i2_l = LBOUND(SrcContStateData%vind_1,2) - i2_u = UBOUND(SrcContStateData%vind_1,2) - i3_l = LBOUND(SrcContStateData%vind_1,3) - i3_u = UBOUND(SrcContStateData%vind_1,3) - IF (.NOT. ALLOCATED(DstContStateData%vind_1)) THEN - ALLOCATE(DstContStateData%vind_1(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%vind_1.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstContStateData%vind_1 = SrcContStateData%vind_1 -ENDIF - END SUBROUTINE DBEMT_CopyContState + DstElementContinuousStateTypeData%vind = SrcElementContinuousStateTypeData%vind + DstElementContinuousStateTypeData%vind_dot = SrcElementContinuousStateTypeData%vind_dot + DstElementContinuousStateTypeData%vind_1 = SrcElementContinuousStateTypeData%vind_1 + END SUBROUTINE DBEMT_CopyElementContinuousStateType - SUBROUTINE DBEMT_DestroyContState( ContStateData, ErrStat, ErrMsg ) - TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: ContStateData + SUBROUTINE DBEMT_DestroyElementContinuousStateType( ElementContinuousStateTypeData, ErrStat, ErrMsg ) + TYPE(DBEMT_ElementContinuousStateType), INTENT(INOUT) :: ElementContinuousStateTypeData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyElementContinuousStateType' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(ContStateData%vind)) THEN - DEALLOCATE(ContStateData%vind) -ENDIF -IF (ALLOCATED(ContStateData%vind_1)) THEN - DEALLOCATE(ContStateData%vind_1) -ENDIF - END SUBROUTINE DBEMT_DestroyContState + END SUBROUTINE DBEMT_DestroyElementContinuousStateType - SUBROUTINE DBEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE DBEMT_PackElementContinuousStateType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(DBEMT_ContinuousStateType), INTENT(IN) :: InData + TYPE(DBEMT_ElementContinuousStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -721,7 +593,7 @@ SUBROUTINE DBEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackElementContinuousStateType' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -737,16 +609,9 @@ SUBROUTINE DBEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! vind allocated yes/no - IF ( ALLOCATED(InData%vind) ) THEN - Int_BufSz = Int_BufSz + 2*3 ! vind upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%vind) ! vind - END IF - Int_BufSz = Int_BufSz + 1 ! vind_1 allocated yes/no - IF ( ALLOCATED(InData%vind_1) ) THEN - Int_BufSz = Int_BufSz + 2*3 ! vind_1 upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%vind_1) ! vind_1 - END IF + Db_BufSz = Db_BufSz + SIZE(InData%vind) ! vind + Db_BufSz = Db_BufSz + SIZE(InData%vind_dot) ! vind_dot + Db_BufSz = Db_BufSz + SIZE(InData%vind_1) ! vind_1 IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -774,63 +639,25 @@ SUBROUTINE DBEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Db_Xferred = 1 Int_Xferred = 1 - IF ( .NOT. ALLOCATED(InData%vind) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind,3) - Int_Xferred = Int_Xferred + 2 - - DO i3 = LBOUND(InData%vind,3), UBOUND(InData%vind,3) - DO i2 = LBOUND(InData%vind,2), UBOUND(InData%vind,2) - DO i1 = LBOUND(InData%vind,1), UBOUND(InData%vind,1) - ReKiBuf(Re_Xferred) = InData%vind(i1,i2,i3) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%vind_1) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind_1,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind_1,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind_1,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind_1,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%vind_1,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%vind_1,3) - Int_Xferred = Int_Xferred + 2 - - DO i3 = LBOUND(InData%vind_1,3), UBOUND(InData%vind_1,3) - DO i2 = LBOUND(InData%vind_1,2), UBOUND(InData%vind_1,2) - DO i1 = LBOUND(InData%vind_1,1), UBOUND(InData%vind_1,1) - ReKiBuf(Re_Xferred) = InData%vind_1(i1,i2,i3) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - END SUBROUTINE DBEMT_PackContState + DO i1 = LBOUND(InData%vind,1), UBOUND(InData%vind,1) + DbKiBuf(Db_Xferred) = InData%vind(i1) + Db_Xferred = Db_Xferred + 1 + END DO + DO i1 = LBOUND(InData%vind_dot,1), UBOUND(InData%vind_dot,1) + DbKiBuf(Db_Xferred) = InData%vind_dot(i1) + Db_Xferred = Db_Xferred + 1 + END DO + DO i1 = LBOUND(InData%vind_1,1), UBOUND(InData%vind_1,1) + DbKiBuf(Db_Xferred) = InData%vind_1(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END SUBROUTINE DBEMT_PackElementContinuousStateType - SUBROUTINE DBEMT_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE DBEMT_UnPackElementContinuousStateType( 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(DBEMT_ContinuousStateType), INTENT(INOUT) :: OutData + TYPE(DBEMT_ElementContinuousStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -840,11 +667,9 @@ SUBROUTINE DBEMT_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, 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 = 'DBEMT_UnPackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_UnPackElementContinuousStateType' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -855,97 +680,88 @@ SUBROUTINE DBEMT_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! vind not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%vind)) DEALLOCATE(OutData%vind) - ALLOCATE(OutData%vind(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%vind.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i3 = LBOUND(OutData%vind,3), UBOUND(OutData%vind,3) - DO i2 = LBOUND(OutData%vind,2), UBOUND(OutData%vind,2) - DO i1 = LBOUND(OutData%vind,1), UBOUND(OutData%vind,1) - OutData%vind(i1,i2,i3) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! vind_1 not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%vind_1)) DEALLOCATE(OutData%vind_1) - ALLOCATE(OutData%vind_1(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%vind_1.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i3 = LBOUND(OutData%vind_1,3), UBOUND(OutData%vind_1,3) - DO i2 = LBOUND(OutData%vind_1,2), UBOUND(OutData%vind_1,2) - DO i1 = LBOUND(OutData%vind_1,1), UBOUND(OutData%vind_1,1) - OutData%vind_1(i1,i2,i3) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - END SUBROUTINE DBEMT_UnPackContState + i1_l = LBOUND(OutData%vind,1) + i1_u = UBOUND(OutData%vind,1) + DO i1 = LBOUND(OutData%vind,1), UBOUND(OutData%vind,1) + OutData%vind(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + i1_l = LBOUND(OutData%vind_dot,1) + i1_u = UBOUND(OutData%vind_dot,1) + DO i1 = LBOUND(OutData%vind_dot,1), UBOUND(OutData%vind_dot,1) + OutData%vind_dot(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + i1_l = LBOUND(OutData%vind_1,1) + i1_u = UBOUND(OutData%vind_1,1) + DO i1 = LBOUND(OutData%vind_1,1), UBOUND(OutData%vind_1,1) + OutData%vind_1(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END SUBROUTINE DBEMT_UnPackElementContinuousStateType - SUBROUTINE DBEMT_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(DBEMT_DiscreteStateType), INTENT(IN) :: SrcDiscStateData - TYPE(DBEMT_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + SUBROUTINE DBEMT_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(DBEMT_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: DstContStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyContState' ! ErrStat = ErrID_None ErrMsg = "" - DstDiscStateData%DummyDiscreteState = SrcDiscStateData%DummyDiscreteState - END SUBROUTINE DBEMT_CopyDiscState +IF (ALLOCATED(SrcContStateData%element)) THEN + i1_l = LBOUND(SrcContStateData%element,1) + i1_u = UBOUND(SrcContStateData%element,1) + i2_l = LBOUND(SrcContStateData%element,2) + i2_u = UBOUND(SrcContStateData%element,2) + IF (.NOT. ALLOCATED(DstContStateData%element)) THEN + ALLOCATE(DstContStateData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i2 = LBOUND(SrcContStateData%element,2), UBOUND(SrcContStateData%element,2) + DO i1 = LBOUND(SrcContStateData%element,1), UBOUND(SrcContStateData%element,1) + CALL DBEMT_Copyelementcontinuousstatetype( SrcContStateData%element(i1,i2), DstContStateData%element(i1,i2), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO + ENDDO +ENDIF + END SUBROUTINE DBEMT_CopyContState - SUBROUTINE DBEMT_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) - TYPE(DBEMT_DiscreteStateType), INTENT(INOUT) :: DiscStateData + SUBROUTINE DBEMT_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(DBEMT_ContinuousStateType), INTENT(INOUT) :: ContStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyContState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE DBEMT_DestroyDiscState +IF (ALLOCATED(ContStateData%element)) THEN +DO i2 = LBOUND(ContStateData%element,2), UBOUND(ContStateData%element,2) +DO i1 = LBOUND(ContStateData%element,1), UBOUND(ContStateData%element,1) + CALL DBEMT_Destroyelementcontinuousstatetype( ContStateData%element(i1,i2), ErrStat, ErrMsg ) +ENDDO +ENDDO + DEALLOCATE(ContStateData%element) +ENDIF + END SUBROUTINE DBEMT_DestroyContState - SUBROUTINE DBEMT_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE DBEMT_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(DBEMT_DiscreteStateType), INTENT(IN) :: InData + TYPE(DBEMT_ContinuousStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -960,7 +776,7 @@ SUBROUTINE DBEMT_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackContState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -976,22 +792,277 @@ SUBROUTINE DBEMT_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyDiscreteState - IF ( Re_BufSz .GT. 0 ) THEN - ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Db_BufSz .GT. 0 ) THEN - ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Int_BufSz .GT. 0 ) THEN + Int_BufSz = Int_BufSz + 1 ! element allocated yes/no + IF ( ALLOCATED(InData%element) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! element upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + Int_BufSz = Int_BufSz + 3 ! element: size of buffers for each call to pack subtype + CALL DBEMT_Packelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, .TRUE. ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! element + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! element + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! element + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END DO + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%element) ) 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%element,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%element,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + CALL DBEMT_Packelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, OnlySize ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END DO + END IF + END SUBROUTINE DBEMT_PackContState + + SUBROUTINE DBEMT_UnPackContState( 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(DBEMT_ContinuousStateType), 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) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_UnPackContState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! element 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%element)) DEALLOCATE(OutData%element) + ALLOCATE(OutData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%element,2), UBOUND(OutData%element,2) + DO i1 = LBOUND(OutData%element,1), UBOUND(OutData%element,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL DBEMT_Unpackelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, OutData%element(i1,i2), ErrStat2, ErrMsg2 ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END DO + END IF + END SUBROUTINE DBEMT_UnPackContState + + SUBROUTINE DBEMT_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(DBEMT_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(DBEMT_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyDiscState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstDiscStateData%DummyState = SrcDiscStateData%DummyState + END SUBROUTINE DBEMT_CopyDiscState + + SUBROUTINE DBEMT_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(DBEMT_DiscreteStateType), INTENT(INOUT) :: DiscStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyDiscState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE DBEMT_DestroyDiscState + + SUBROUTINE DBEMT_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(DBEMT_DiscreteStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackDiscState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) @@ -1004,7 +1075,7 @@ SUBROUTINE DBEMT_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyDiscreteState + ReKiBuf(Re_Xferred) = InData%DummyState Re_Xferred = Re_Xferred + 1 END SUBROUTINE DBEMT_PackDiscState @@ -1034,7 +1105,7 @@ SUBROUTINE DBEMT_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyDiscreteState = REAL(ReKiBuf(Re_Xferred), SiKi) + OutData%DummyState = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END SUBROUTINE DBEMT_UnPackDiscState @@ -1052,7 +1123,7 @@ SUBROUTINE DBEMT_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCo ! ErrStat = ErrID_None ErrMsg = "" - DstConstrStateData%DummyContState = SrcConstrStateData%DummyContState + DstConstrStateData%DummyState = SrcConstrStateData%DummyState END SUBROUTINE DBEMT_CopyConstrState SUBROUTINE DBEMT_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) @@ -1101,7 +1172,7 @@ SUBROUTINE DBEMT_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyContState + Re_BufSz = Re_BufSz + 1 ! DummyState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1129,7 +1200,7 @@ SUBROUTINE DBEMT_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyContState + ReKiBuf(Re_Xferred) = InData%DummyState Re_Xferred = Re_Xferred + 1 END SUBROUTINE DBEMT_PackConstrState @@ -1159,7 +1230,7 @@ SUBROUTINE DBEMT_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyContState = REAL(ReKiBuf(Re_Xferred), SiKi) + OutData%DummyState = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END SUBROUTINE DBEMT_UnPackConstrState @@ -1194,6 +1265,26 @@ SUBROUTINE DBEMT_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, DstOtherStateData%areStatesInitialized = SrcOtherStateData%areStatesInitialized ENDIF DstOtherStateData%tau1 = SrcOtherStateData%tau1 + DstOtherStateData%tau2 = SrcOtherStateData%tau2 +IF (ALLOCATED(SrcOtherStateData%n)) THEN + i1_l = LBOUND(SrcOtherStateData%n,1) + i1_u = UBOUND(SrcOtherStateData%n,1) + i2_l = LBOUND(SrcOtherStateData%n,2) + i2_u = UBOUND(SrcOtherStateData%n,2) + IF (.NOT. ALLOCATED(DstOtherStateData%n)) THEN + ALLOCATE(DstOtherStateData%n(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOtherStateData%n.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOtherStateData%n = SrcOtherStateData%n +ENDIF + DO i1 = LBOUND(SrcOtherStateData%xdot,1), UBOUND(SrcOtherStateData%xdot,1) + CALL DBEMT_CopyContState( SrcOtherStateData%xdot(i1), DstOtherStateData%xdot(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO END SUBROUTINE DBEMT_CopyOtherState SUBROUTINE DBEMT_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) @@ -1208,6 +1299,12 @@ SUBROUTINE DBEMT_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) IF (ALLOCATED(OtherStateData%areStatesInitialized)) THEN DEALLOCATE(OtherStateData%areStatesInitialized) ENDIF +IF (ALLOCATED(OtherStateData%n)) THEN + DEALLOCATE(OtherStateData%n) +ENDIF +DO i1 = LBOUND(OtherStateData%xdot,1), UBOUND(OtherStateData%xdot,1) + CALL DBEMT_DestroyContState( OtherStateData%xdot(i1), ErrStat, ErrMsg ) +ENDDO END SUBROUTINE DBEMT_DestroyOtherState SUBROUTINE DBEMT_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -1251,6 +1348,32 @@ SUBROUTINE DBEMT_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Int_BufSz = Int_BufSz + SIZE(InData%areStatesInitialized) ! areStatesInitialized END IF Re_BufSz = Re_BufSz + 1 ! tau1 + Re_BufSz = Re_BufSz + 1 ! tau2 + Int_BufSz = Int_BufSz + 1 ! n allocated yes/no + IF ( ALLOCATED(InData%n) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! n upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%n) ! n + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%xdot,1), UBOUND(InData%xdot,1) + Int_BufSz = Int_BufSz + 3 ! xdot: size of buffers for each call to pack subtype + CALL DBEMT_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%xdot(i1), ErrStat2, ErrMsg2, .TRUE. ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! xdot + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! xdot + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! xdot + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1284,22 +1407,74 @@ SUBROUTINE DBEMT_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%areStatesInitialized,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%areStatesInitialized,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%areStatesInitialized,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%areStatesInitialized,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%areStatesInitialized,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%areStatesInitialized,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%areStatesInitialized,2), UBOUND(InData%areStatesInitialized,2) + DO i1 = LBOUND(InData%areStatesInitialized,1), UBOUND(InData%areStatesInitialized,1) + IntKiBuf(Int_Xferred) = TRANSFER(InData%areStatesInitialized(i1,i2), IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + ReKiBuf(Re_Xferred) = InData%tau1 + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%tau2 + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%n) ) 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%n,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%n,1) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%areStatesInitialized,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%areStatesInitialized,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%n,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%n,2) Int_Xferred = Int_Xferred + 2 - DO i2 = LBOUND(InData%areStatesInitialized,2), UBOUND(InData%areStatesInitialized,2) - DO i1 = LBOUND(InData%areStatesInitialized,1), UBOUND(InData%areStatesInitialized,1) - IntKiBuf(Int_Xferred) = TRANSFER(InData%areStatesInitialized(i1,i2), IntKiBuf(1)) + DO i2 = LBOUND(InData%n,2), UBOUND(InData%n,2) + DO i1 = LBOUND(InData%n,1), UBOUND(InData%n,1) + IntKiBuf(Int_Xferred) = InData%n(i1,i2) Int_Xferred = Int_Xferred + 1 END DO END DO END IF - ReKiBuf(Re_Xferred) = InData%tau1 - Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%xdot,1), UBOUND(InData%xdot,1) + CALL DBEMT_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%xdot(i1), ErrStat2, ErrMsg2, OnlySize ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO END SUBROUTINE DBEMT_PackOtherState SUBROUTINE DBEMT_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -1355,6 +1530,75 @@ SUBROUTINE DBEMT_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, END IF OutData%tau1 = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%tau2 = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! n 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%n)) DEALLOCATE(OutData%n) + ALLOCATE(OutData%n(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%n.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%n,2), UBOUND(OutData%n,2) + DO i1 = LBOUND(OutData%n,1), UBOUND(OutData%n,1) + OutData%n(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + i1_l = LBOUND(OutData%xdot,1) + i1_u = UBOUND(OutData%xdot,1) + DO i1 = LBOUND(OutData%xdot,1), UBOUND(OutData%xdot,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL DBEMT_UnpackContState( Re_Buf, Db_Buf, Int_Buf, OutData%xdot(i1), ErrStat2, ErrMsg2 ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO END SUBROUTINE DBEMT_UnPackOtherState SUBROUTINE DBEMT_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) @@ -1499,6 +1743,7 @@ SUBROUTINE DBEMT_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMs ErrStat = ErrID_None ErrMsg = "" DstParamData%DT = SrcParamData%DT + DstParamData%lin_nx = SrcParamData%lin_nx DstParamData%NumBlades = SrcParamData%NumBlades DstParamData%NumNodes = SrcParamData%NumNodes DstParamData%k_0ye = SrcParamData%k_0ye @@ -1570,6 +1815,7 @@ SUBROUTINE DBEMT_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Db_BufSz = 0 Int_BufSz = 0 Db_BufSz = Db_BufSz + 1 ! DT + Int_BufSz = Int_BufSz + 1 ! lin_nx Int_BufSz = Int_BufSz + 1 ! NumBlades Int_BufSz = Int_BufSz + 1 ! NumNodes Re_BufSz = Re_BufSz + 1 ! k_0ye @@ -1609,6 +1855,8 @@ SUBROUTINE DBEMT_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, DbKiBuf(Db_Xferred) = InData%DT Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%lin_nx + Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%NumBlades Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%NumNodes @@ -1671,6 +1919,8 @@ SUBROUTINE DBEMT_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM Int_Xferred = 1 OutData%DT = DbKiBuf(Db_Xferred) Db_Xferred = Db_Xferred + 1 + OutData%lin_nx = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 OutData%NumBlades = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 OutData%NumNodes = IntKiBuf(Int_Xferred) @@ -1706,6 +1956,157 @@ SUBROUTINE DBEMT_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM Int_Xferred = Int_Xferred + 1 END SUBROUTINE DBEMT_UnPackParam + SUBROUTINE DBEMT_CopyElementInputType( SrcElementInputTypeData, DstElementInputTypeData, CtrlCode, ErrStat, ErrMsg ) + TYPE(DBEMT_ElementInputType), INTENT(IN) :: SrcElementInputTypeData + TYPE(DBEMT_ElementInputType), INTENT(INOUT) :: DstElementInputTypeData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyElementInputType' +! + ErrStat = ErrID_None + ErrMsg = "" + DstElementInputTypeData%vind_s = SrcElementInputTypeData%vind_s + DstElementInputTypeData%vind_s_dot = SrcElementInputTypeData%vind_s_dot + DstElementInputTypeData%spanRatio = SrcElementInputTypeData%spanRatio + END SUBROUTINE DBEMT_CopyElementInputType + + SUBROUTINE DBEMT_DestroyElementInputType( ElementInputTypeData, ErrStat, ErrMsg ) + TYPE(DBEMT_ElementInputType), INTENT(INOUT) :: ElementInputTypeData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_DestroyElementInputType' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE DBEMT_DestroyElementInputType + + SUBROUTINE DBEMT_PackElementInputType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(DBEMT_ElementInputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_PackElementInputType' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + SIZE(InData%vind_s) ! vind_s + Re_BufSz = Re_BufSz + SIZE(InData%vind_s_dot) ! vind_s_dot + Re_BufSz = Re_BufSz + 1 ! spanRatio + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DO i1 = LBOUND(InData%vind_s,1), UBOUND(InData%vind_s,1) + ReKiBuf(Re_Xferred) = InData%vind_s(i1) + Re_Xferred = Re_Xferred + 1 + END DO + DO i1 = LBOUND(InData%vind_s_dot,1), UBOUND(InData%vind_s_dot,1) + ReKiBuf(Re_Xferred) = InData%vind_s_dot(i1) + Re_Xferred = Re_Xferred + 1 + END DO + ReKiBuf(Re_Xferred) = InData%spanRatio + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE DBEMT_PackElementInputType + + SUBROUTINE DBEMT_UnPackElementInputType( 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(DBEMT_ElementInputType), 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 = 'DBEMT_UnPackElementInputType' + ! 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 + i1_l = LBOUND(OutData%vind_s,1) + i1_u = UBOUND(OutData%vind_s,1) + DO i1 = LBOUND(OutData%vind_s,1), UBOUND(OutData%vind_s,1) + OutData%vind_s(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + i1_l = LBOUND(OutData%vind_s_dot,1) + i1_u = UBOUND(OutData%vind_s_dot,1) + DO i1 = LBOUND(OutData%vind_s_dot,1), UBOUND(OutData%vind_s_dot,1) + OutData%vind_s_dot(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + OutData%spanRatio = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE DBEMT_UnPackElementInputType + SUBROUTINE DBEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) TYPE(DBEMT_InputType), INTENT(IN) :: SrcInputData TYPE(DBEMT_InputType), INTENT(INOUT) :: DstInputData @@ -1715,6 +2116,7 @@ SUBROUTINE DBEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMs ! 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) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_CopyInput' @@ -1724,8 +2126,26 @@ SUBROUTINE DBEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMs DstInputData%AxInd_disk = SrcInputData%AxInd_disk DstInputData%Un_disk = SrcInputData%Un_disk DstInputData%R_disk = SrcInputData%R_disk - DstInputData%vind_s = SrcInputData%vind_s - DstInputData%spanRatio = SrcInputData%spanRatio +IF (ALLOCATED(SrcInputData%element)) THEN + i1_l = LBOUND(SrcInputData%element,1) + i1_u = UBOUND(SrcInputData%element,1) + i2_l = LBOUND(SrcInputData%element,2) + i2_u = UBOUND(SrcInputData%element,2) + IF (.NOT. ALLOCATED(DstInputData%element)) THEN + ALLOCATE(DstInputData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i2 = LBOUND(SrcInputData%element,2), UBOUND(SrcInputData%element,2) + DO i1 = LBOUND(SrcInputData%element,1), UBOUND(SrcInputData%element,1) + CALL DBEMT_Copyelementinputtype( SrcInputData%element(i1,i2), DstInputData%element(i1,i2), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO + ENDDO +ENDIF END SUBROUTINE DBEMT_CopyInput SUBROUTINE DBEMT_DestroyInput( InputData, ErrStat, ErrMsg ) @@ -1737,6 +2157,14 @@ SUBROUTINE DBEMT_DestroyInput( InputData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" +IF (ALLOCATED(InputData%element)) THEN +DO i2 = LBOUND(InputData%element,2), UBOUND(InputData%element,2) +DO i1 = LBOUND(InputData%element,1), UBOUND(InputData%element,1) + CALL DBEMT_Destroyelementinputtype( InputData%element(i1,i2), ErrStat, ErrMsg ) +ENDDO +ENDDO + DEALLOCATE(InputData%element) +ENDIF END SUBROUTINE DBEMT_DestroyInput SUBROUTINE DBEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -1777,8 +2205,32 @@ SUBROUTINE DBEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = Re_BufSz + 1 ! AxInd_disk Re_BufSz = Re_BufSz + 1 ! Un_disk Re_BufSz = Re_BufSz + 1 ! R_disk - Re_BufSz = Re_BufSz + SIZE(InData%vind_s) ! vind_s - Re_BufSz = Re_BufSz + 1 ! spanRatio + Int_BufSz = Int_BufSz + 1 ! element allocated yes/no + IF ( ALLOCATED(InData%element) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! element upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + Int_BufSz = Int_BufSz + 3 ! element: size of buffers for each call to pack subtype + CALL DBEMT_Packelementinputtype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, .TRUE. ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! element + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! element + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! element + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END DO + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1812,12 +2264,52 @@ SUBROUTINE DBEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%R_disk Re_Xferred = Re_Xferred + 1 - DO i1 = LBOUND(InData%vind_s,1), UBOUND(InData%vind_s,1) - ReKiBuf(Re_Xferred) = InData%vind_s(i1) - Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%element) ) 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%element,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%element,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + CALL DBEMT_Packelementinputtype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, OnlySize ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF END DO - ReKiBuf(Re_Xferred) = InData%spanRatio - Re_Xferred = Re_Xferred + 1 + END DO + END IF END SUBROUTINE DBEMT_PackInput SUBROUTINE DBEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -1834,6 +2326,7 @@ SUBROUTINE DBEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM 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) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_UnPackInput' @@ -1853,14 +2346,67 @@ SUBROUTINE DBEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM Re_Xferred = Re_Xferred + 1 OutData%R_disk = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - i1_l = LBOUND(OutData%vind_s,1) - i1_u = UBOUND(OutData%vind_s,1) - DO i1 = LBOUND(OutData%vind_s,1), UBOUND(OutData%vind_s,1) - OutData%vind_s(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! element 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%element)) DEALLOCATE(OutData%element) + ALLOCATE(OutData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%element,2), UBOUND(OutData%element,2) + DO i1 = LBOUND(OutData%element,1), UBOUND(OutData%element,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL DBEMT_Unpackelementinputtype( Re_Buf, Db_Buf, Int_Buf, OutData%element(i1,i2), ErrStat2, ErrMsg2 ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END DO - OutData%spanRatio = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + END DO + END IF END SUBROUTINE DBEMT_UnPackInput SUBROUTINE DBEMT_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) @@ -2066,6 +2612,183 @@ SUBROUTINE DBEMT_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err END SUBROUTINE DBEMT_UnPackOutput + SUBROUTINE DBEMT_ElementInputType_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) ElementInputType u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u(:) ! ElementInputType at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the ElementInputTypes + TYPE(DBEMT_ElementInputType), INTENT(INOUT) :: u_out ! ElementInputType at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_ElementInputType_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(u)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(u)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(u) - 1 + IF ( order .eq. 0 ) THEN + CALL DBEMT_CopyElementInputType(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL DBEMT_ElementInputType_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL DBEMT_ElementInputType_ExtrapInterp2(u(1), u(2), u(3), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(u) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE DBEMT_ElementInputType_ExtrapInterp + + + SUBROUTINE DBEMT_ElementInputType_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) ElementInputType u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u1 ! ElementInputType at t1 > t2 + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u2 ! ElementInputType at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the ElementInputTypes + TYPE(DBEMT_ElementInputType), INTENT(INOUT) :: u_out ! ElementInputType at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the ElementInputTypes + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_ElementInputType_ExtrapInterp1' + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / t(2) + DO i1 = LBOUND(u_out%vind_s,1),UBOUND(u_out%vind_s,1) + b = -(u1%vind_s(i1) - u2%vind_s(i1)) + u_out%vind_s(i1) = u1%vind_s(i1) + b * ScaleFactor + END DO + DO i1 = LBOUND(u_out%vind_s_dot,1),UBOUND(u_out%vind_s_dot,1) + b = -(u1%vind_s_dot(i1) - u2%vind_s_dot(i1)) + u_out%vind_s_dot(i1) = u1%vind_s_dot(i1) + b * ScaleFactor + END DO + b = -(u1%spanRatio - u2%spanRatio) + u_out%spanRatio = u1%spanRatio + b * ScaleFactor + END SUBROUTINE DBEMT_ElementInputType_ExtrapInterp1 + + + SUBROUTINE DBEMT_ElementInputType_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) ElementInputType u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u1 ! ElementInputType at t1 > t2 > t3 + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u2 ! ElementInputType at t2 > t3 + TYPE(DBEMT_ElementInputType), INTENT(IN) :: u3 ! ElementInputType at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the ElementInputTypes + TYPE(DBEMT_ElementInputType), INTENT(INOUT) :: u_out ! ElementInputType at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the ElementInputTypes + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: c ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_ElementInputType_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) + DO i1 = LBOUND(u_out%vind_s,1),UBOUND(u_out%vind_s,1) + b = (t(3)**2*(u1%vind_s(i1) - u2%vind_s(i1)) + t(2)**2*(-u1%vind_s(i1) + u3%vind_s(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%vind_s(i1) + t(3)*u2%vind_s(i1) - t(2)*u3%vind_s(i1) ) * scaleFactor + u_out%vind_s(i1) = u1%vind_s(i1) + b + c * t_out + END DO + DO i1 = LBOUND(u_out%vind_s_dot,1),UBOUND(u_out%vind_s_dot,1) + b = (t(3)**2*(u1%vind_s_dot(i1) - u2%vind_s_dot(i1)) + t(2)**2*(-u1%vind_s_dot(i1) + u3%vind_s_dot(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%vind_s_dot(i1) + t(3)*u2%vind_s_dot(i1) - t(2)*u3%vind_s_dot(i1) ) * scaleFactor + u_out%vind_s_dot(i1) = u1%vind_s_dot(i1) + b + c * t_out + END DO + b = (t(3)**2*(u1%spanRatio - u2%spanRatio) + t(2)**2*(-u1%spanRatio + u3%spanRatio))* scaleFactor + c = ( (t(2)-t(3))*u1%spanRatio + t(3)*u2%spanRatio - t(2)*u3%spanRatio ) * scaleFactor + u_out%spanRatio = u1%spanRatio + b + c * t_out + END SUBROUTINE DBEMT_ElementInputType_ExtrapInterp2 + + SUBROUTINE DBEMT_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) ! ! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time @@ -2145,7 +2868,9 @@ SUBROUTINE DBEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMs INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i02 ! dim2 level 0 counter variable for arrays of ddts INTEGER :: i1 ! dim1 counter variable for arrays + INTEGER :: i2 ! dim2 counter variable for arrays ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" @@ -2166,12 +2891,30 @@ SUBROUTINE DBEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMs u_out%Un_disk = u1%Un_disk + b * ScaleFactor b = -(u1%R_disk - u2%R_disk) u_out%R_disk = u1%R_disk + b * ScaleFactor - DO i1 = LBOUND(u_out%vind_s,1),UBOUND(u_out%vind_s,1) - b = -(u1%vind_s(i1) - u2%vind_s(i1)) - u_out%vind_s(i1) = u1%vind_s(i1) + b * ScaleFactor +IF (ALLOCATED(u_out%element) .AND. ALLOCATED(u1%element)) THEN + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + DO i1 = LBOUND(u_out%element(i01,i02)%vind_s,1),UBOUND(u_out%element(i01,i02)%vind_s,1) + b = -(u1%element(i01,i02)%vind_s(i1) - u2%element(i01,i02)%vind_s(i1)) + u_out%element(i01,i02)%vind_s(i1) = u1%element(i01,i02)%vind_s(i1) + b * ScaleFactor END DO - b = -(u1%spanRatio - u2%spanRatio) - u_out%spanRatio = u1%spanRatio + b * ScaleFactor + ENDDO + ENDDO + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + DO i1 = LBOUND(u_out%element(i01,i02)%vind_s_dot,1),UBOUND(u_out%element(i01,i02)%vind_s_dot,1) + b = -(u1%element(i01,i02)%vind_s_dot(i1) - u2%element(i01,i02)%vind_s_dot(i1)) + u_out%element(i01,i02)%vind_s_dot(i1) = u1%element(i01,i02)%vind_s_dot(i1) + b * ScaleFactor + END DO + ENDDO + ENDDO + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + b = -(u1%element(i01,i02)%spanRatio - u2%element(i01,i02)%spanRatio) + u_out%element(i01,i02)%spanRatio = u1%element(i01,i02)%spanRatio + b * ScaleFactor + ENDDO + ENDDO +END IF ! check if allocated END SUBROUTINE DBEMT_Input_ExtrapInterp1 @@ -2208,7 +2951,9 @@ SUBROUTINE DBEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, E CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors CHARACTER(*), PARAMETER :: RoutineName = 'DBEMT_Input_ExtrapInterp2' INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i02 ! dim2 level 0 counter variable for arrays of ddts INTEGER :: i1 ! dim1 counter variable for arrays + INTEGER :: i2 ! dim2 counter variable for arrays ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" @@ -2238,14 +2983,33 @@ SUBROUTINE DBEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, E b = (t(3)**2*(u1%R_disk - u2%R_disk) + t(2)**2*(-u1%R_disk + u3%R_disk))* scaleFactor c = ( (t(2)-t(3))*u1%R_disk + t(3)*u2%R_disk - t(2)*u3%R_disk ) * scaleFactor u_out%R_disk = u1%R_disk + b + c * t_out - DO i1 = LBOUND(u_out%vind_s,1),UBOUND(u_out%vind_s,1) - b = (t(3)**2*(u1%vind_s(i1) - u2%vind_s(i1)) + t(2)**2*(-u1%vind_s(i1) + u3%vind_s(i1)))* scaleFactor - c = ( (t(2)-t(3))*u1%vind_s(i1) + t(3)*u2%vind_s(i1) - t(2)*u3%vind_s(i1) ) * scaleFactor - u_out%vind_s(i1) = u1%vind_s(i1) + b + c * t_out +IF (ALLOCATED(u_out%element) .AND. ALLOCATED(u1%element)) THEN + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + DO i1 = LBOUND(u_out%element(i01,i02)%vind_s,1),UBOUND(u_out%element(i01,i02)%vind_s,1) + b = (t(3)**2*(u1%element(i01,i02)%vind_s(i1) - u2%element(i01,i02)%vind_s(i1)) + t(2)**2*(-u1%element(i01,i02)%vind_s(i1) + u3%element(i01,i02)%vind_s(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%element(i01,i02)%vind_s(i1) + t(3)*u2%element(i01,i02)%vind_s(i1) - t(2)*u3%element(i01,i02)%vind_s(i1) ) * scaleFactor + u_out%element(i01,i02)%vind_s(i1) = u1%element(i01,i02)%vind_s(i1) + b + c * t_out END DO - b = (t(3)**2*(u1%spanRatio - u2%spanRatio) + t(2)**2*(-u1%spanRatio + u3%spanRatio))* scaleFactor - c = ( (t(2)-t(3))*u1%spanRatio + t(3)*u2%spanRatio - t(2)*u3%spanRatio ) * scaleFactor - u_out%spanRatio = u1%spanRatio + b + c * t_out + ENDDO + ENDDO + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + DO i1 = LBOUND(u_out%element(i01,i02)%vind_s_dot,1),UBOUND(u_out%element(i01,i02)%vind_s_dot,1) + b = (t(3)**2*(u1%element(i01,i02)%vind_s_dot(i1) - u2%element(i01,i02)%vind_s_dot(i1)) + t(2)**2*(-u1%element(i01,i02)%vind_s_dot(i1) + u3%element(i01,i02)%vind_s_dot(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%element(i01,i02)%vind_s_dot(i1) + t(3)*u2%element(i01,i02)%vind_s_dot(i1) - t(2)*u3%element(i01,i02)%vind_s_dot(i1) ) * scaleFactor + u_out%element(i01,i02)%vind_s_dot(i1) = u1%element(i01,i02)%vind_s_dot(i1) + b + c * t_out + END DO + ENDDO + ENDDO + DO i02 = LBOUND(u_out%element,2),UBOUND(u_out%element,2) + DO i01 = LBOUND(u_out%element,1),UBOUND(u_out%element,1) + b = (t(3)**2*(u1%element(i01,i02)%spanRatio - u2%element(i01,i02)%spanRatio) + t(2)**2*(-u1%element(i01,i02)%spanRatio + u3%element(i01,i02)%spanRatio))* scaleFactor + c = ( (t(2)-t(3))*u1%element(i01,i02)%spanRatio + t(3)*u2%element(i01,i02)%spanRatio - t(2)*u3%element(i01,i02)%spanRatio ) * scaleFactor + u_out%element(i01,i02)%spanRatio = u1%element(i01,i02)%spanRatio + b + c * t_out + ENDDO + ENDDO +END IF ! check if allocated END SUBROUTINE DBEMT_Input_ExtrapInterp2 diff --git a/modules/aerodyn/src/FVW.f90 b/modules/aerodyn/src/FVW.f90 index 0782068e39..3e1cd6912d 100644 --- a/modules/aerodyn/src/FVW.f90 +++ b/modules/aerodyn/src/FVW.f90 @@ -377,6 +377,7 @@ SUBROUTINE FVW_SetParametersFromInputs( InitInp, p, ErrStat, ErrMsg ) integer(IntKi), intent( out) :: ErrStat !< Error status of the operation character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! Local variables + character(1024) :: rootDir, baseName ! Simulation root dir and basename !integer(IntKi) :: ErrStat2 !character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'FVW_SetParametersFromInputs' @@ -388,6 +389,9 @@ SUBROUTINE FVW_SetParametersFromInputs( InitInp, p, ErrStat, ErrMsg ) p%DTaero = InitInp%DTaero ! AeroDyn Time step p%KinVisc = InitInp%KinVisc ! Kinematic air viscosity p%RootName = InitInp%RootName ! Rootname for outputs + call GetPath( p%RootName, rootDir, baseName ) + p%VTK_OutFileRoot = trim(rootDir) // 'vtk_fvw' ! Directory for VTK outputs + p%VTK_OutFileBase = trim(rootDir) // 'vtk_fvw' // PathSep // trim(baseName) ! Basename for VTK files ! Set indexing to AFI tables -- this is set from the AD15 calling code. call AllocAry(p%AFindx,size(InitInp%AFindx,1),size(InitInp%AFindx,2),'AFindx',ErrStat,ErrMsg) p%AFindx = InitInp%AFindx ! Copying in case AD15 still needs these @@ -414,7 +418,7 @@ SUBROUTINE FVW_SetParametersFromInputFile( InputFileData, p, m, ErrStat, ErrMsg p%IntMethod = InputFileData%IntMethod p%CirculationMethod = InputFileData%CirculationMethod p%CircSolvConvCrit = InputFileData%CircSolvConvCrit - p%CircSolvRelaxation = InputFileData%CircSolvRelaxation + p%CircSolvRelaxation = InputFileData%CircSolvRelaxation p%CircSolvMaxIter = InputFileData%CircSolvMaxIter p%FreeWakeStart = InputFileData%FreeWakeStart p%CircSolvPolar = InputFileData%CircSolvPolar @@ -585,7 +589,7 @@ subroutine FVW_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, AFInfo, m z_guess%Gamma_LL = m%Gamma_LL call FVW_CalcConstrStateResidual(t, uInterp, p, x, xd, z_guess, OtherState, m, z, AFInfo, ErrStat2, ErrMsg2, 1); if(Failed()) return - call UA_UpdateState_Wrapper(AFInfo, n, uInterp, p, x, xd, OtherState, m, ErrStat2, ErrMsg2); if(Failed()) return + call UA_UpdateState_Wrapper(AFInfo,t, n, uInterp, p, x, xd, OtherState, m, ErrStat2, ErrMsg2); if(Failed()) return ! Map circulation and positions between LL and NW and then NW and FW ! Changes: x only @@ -964,19 +968,19 @@ subroutine FVW_CalcOutput( t, u, p, x, xd, z, OtherState, AFInfo, y, m, ErrStat, m%VTKStep = m%iStep+1 ! We use glue code step number for outputs endif if (m%FirstCall) then - call MKDIR('vtk_fvw') + call MKDIR(p%VTK_OutFileRoot) endif if ( ( t - m%VTKlastTime ) >= p%DTvtk*OneMinusEpsilon ) then m%VTKlastTime = t if ((p%VTKCoord==2).or.(p%VTKCoord==3)) then ! Hub reference coordinates, for export only, ALL VTK Will be exported in this coordinate system! ! Note: hubOrientation and HubPosition are optional, but required for bladeFrame==TRUE - call WrVTK_FVW(p, x, z, m, 'vtk_fvw/'//trim(p%RootName)//'FVW_Hub', m%VTKStep, 9, bladeFrame=.TRUE., & + call WrVTK_FVW(p, x, z, m, trim(p%VTK_OutFileBase)//'FVW_Hub', m%VTKStep, 9, bladeFrame=.TRUE., & HubOrientation=real(u%HubOrientation,ReKi),HubPosition=real(u%HubPosition,ReKi)) endif if ((p%VTKCoord==1).or.(p%VTKCoord==3)) then ! Global coordinate system, ALL VTK will be exported in global - call WrVTK_FVW(p, x, z, m, 'vtk_fvw/'//trim(p%RootName)//'FVW_Glb', m%VTKStep, 9, bladeFrame=.FALSE.) + call WrVTK_FVW(p, x, z, m, trim(p%VTK_OutFileBase)//'FVW_Glb', m%VTKStep, 9, bladeFrame=.FALSE.) endif endif endif @@ -1037,11 +1041,11 @@ subroutine UA_Init_Wrapper(AFInfo, InitInp, interval, p, x, xd, OtherState, m, E Init_UA_Data%Flookup = InitInp%Flookup Init_UA_Data%a_s = InitInp%a_s ! m/s ! --- UA init - call UA_Init( Init_UA_Data, u_UA, m%p_UA, xd%UA, OtherState%UA, m%y_UA, m%m_UA, interval, InitOutData_UA, ErrStat2, ErrMsg2); if(Failed())return + call UA_Init( Init_UA_Data, u_UA, m%p_UA, x%UA, xd%UA, OtherState%UA, m%y_UA, m%m_UA, interval, InitOutData_UA, ErrStat2, ErrMsg2); if(Failed())return m%p_UA%ShedEffect=.False. !< Important, when coupling UA wih vortex code, shed vorticity is inherently accounted for ! --- Condensed version of "BEMT_CheckInitUA" do j = 1,InitInp%numBlades; do i = 1,InitInp%numBladeNodes; ! Loop over blades and nodes - call UA_TurnOff_param(AFInfo(p%AFindx(i,j)), ErrStat2, ErrMsg2) + call UA_TurnOff_param(m%p_UA, AFInfo(p%AFindx(i,j)), ErrStat2, ErrMsg2) if (ErrStat2 /= ErrID_None) then call WrScr( 'Warning: Turning off Unsteady Aerodynamics because '//trim(ErrMsg2)//' BladeNode = '//trim(num2lstr(i))//', Blade = '//trim(num2lstr(j)) ) OtherState%UA_Flag(i,j) = .false. @@ -1078,10 +1082,11 @@ logical function Failed() end function Failed end subroutine UA_Init_Wrapper -subroutine UA_UpdateState_Wrapper(AFInfo, n, u, p, x, xd, OtherState, m, ErrStat, ErrMsg ) +subroutine UA_UpdateState_Wrapper(AFInfo, t, n, u, p, x, xd, OtherState, m, ErrStat, ErrMsg ) use FVW_VortexTools, only: interpextrap_cp2node use UnsteadyAero, only: UA_UpdateStates, UA_TurnOff_input type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data, temporary, for UA.. + real(DbKi), intent(in ) :: t !< Current simulation time in seconds integer(IntKi), intent(in ) :: n !< time step type(FVW_ParameterType), intent(in ) :: p !< Parameters type(FVW_InputType), intent(in ) :: u !< Inputs @@ -1092,8 +1097,10 @@ subroutine UA_UpdateState_Wrapper(AFInfo, n, u, p, x, xd, OtherState, m, ErrStat integer(IntKi), intent( out) :: ErrStat !< Error status of the operation character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! Local - type(UA_InputType) :: u_UA + type(UA_InputType) :: u_UA(1) + REAL(DbKi) :: uTimes(1) integer :: i,j + integer, parameter :: k=1 ! index for u_UA (in case it is ever dimensioned differently) integer(intKi) :: ErrStat2 ! temporary Error status character(ErrMsgLen) :: ErrMsg2 real(ReKi), dimension(:,:), allocatable :: Vind_node @@ -1101,6 +1108,9 @@ subroutine UA_UpdateState_Wrapper(AFInfo, n, u, p, x, xd, OtherState, m, ErrStat ErrStat2 = ErrID_None ErrMsg = "" ErrMsg2 = "" + + uTimes = t + if (m%UA_Flag) then ! --- Induction on the lifting line control point @@ -1128,18 +1138,22 @@ subroutine UA_UpdateState_Wrapper(AFInfo, n, u, p, x, xd, OtherState, m, ErrStat !! ....... compute inputs to UA ........... ! NOTE: To be consistent with CalcOutput we take Vwind_ND that was set using m%DisturbedInflow from AeroDyn.. ! This is not clean, but done to be consistent, waiting for AeroDyn to handle UA - call AlphaVrel_Generic(u%WingsMesh(j)%Orientation(1:3,1:3,i), u%WingsMesh(j)%TranslationVel(1:3,i), Vind_node(:,i), m%Vwnd_ND(:,i,j), p%KinVisc, p%Chord(i,j), u_UA%U, u_UA%alpha, u_UA%Re) - m%m_UA%iBladeNode = i - m%m_UA%iBlade = j - u_UA%UserProp = 0 ! u1%UserProp(i,j) ! TODO + call AlphaVrel_Generic(u%WingsMesh(j)%Orientation(1:3,1:3,i), u%WingsMesh(j)%TranslationVel(1:3,i), Vind_node(:,i), m%Vwnd_ND(:,i,j), & + p%KinVisc, p%Chord(i,j), u_UA(k)%U, u_UA(k)%alpha, u_UA(k)%Re) + ! FIX ME: this is copied 3 times!!!! + u_UA%v_ac(1) = sin(u_UA%alpha)*u_UA%U + u_UA%v_ac(2) = cos(u_UA%alpha)*u_UA%U + u_UA%omega = 0.0_ReKi ! FIX ME!!!! dot_product( u%BladeMotion(j)%RotationVel( :,i), m%WithoutSweepPitchTwist(3,:,i,j) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade + u_UA(k)%UserProp = 0 ! u1%UserProp(i,j) ! TODO + !! ....... check inputs to UA ........... - call UA_TurnOff_input(AFInfo(p%AFIndx(i,j)), u_UA, ErrStat2, ErrMsg2) + call UA_TurnOff_input(m%p_UA, AFInfo(p%AFIndx(i,j)), u_UA(k), ErrStat2, ErrMsg2) if (ErrStat2 /= ErrID_None) then OtherState%UA_Flag(i,j) = .FALSE. call WrScr( 'Warning: Turning off dynamic stall due to '//trim(ErrMsg2)//' '//trim(NodeText(i,j))) else ! COMPUTE: xd%UA, OtherState%UA - call UA_UpdateStates( i, j, u_UA, m%p_UA, xd%UA, OtherState%UA, AFInfo(p%AFIndx(i,j)), m%m_UA, ErrStat2, ErrMsg2 ) + call UA_UpdateStates( i, j, t, n, u_UA, uTimes, m%p_UA, x%UA, xd%UA, OtherState%UA, AFInfo(p%AFIndx(i,j)), m%m_UA, ErrStat2, ErrMsg2 ) if (ErrStat2 /= ErrID_None) then call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'UA_UpdateState_Wrapper'//trim(NodeText(i,j))) call WrScr(trim(ErrMsg)) @@ -1149,7 +1163,7 @@ subroutine UA_UpdateState_Wrapper(AFInfo, n, u, p, x, xd, OtherState, m, ErrStat end if end do end do - call UA_DestroyInput( u_UA, ErrStat2, ErrMsg2 ); + call UA_DestroyInput( u_UA(k), ErrStat2, ErrMsg2 ); deallocate(Vind_node) endif call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'UA_UpdateState_Wrapper') diff --git a/modules/aerodyn/src/FVW_Registry.txt b/modules/aerodyn/src/FVW_Registry.txt index ec99e50ce0..fb513c41c0 100644 --- a/modules/aerodyn/src/FVW_Registry.txt +++ b/modules/aerodyn/src/FVW_Registry.txt @@ -49,6 +49,8 @@ typedef ^ ^ IntKi typedef ^ ^ DbKi DTvtk - - - "DT between vtk writes" s typedef ^ ^ IntKi VTKCoord - - - "Switch for VTK outputs coordinate system" - typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ ^ CHARACTER(1024) VTK_OutFileRoot - - - "Rootdirectory for writing VTK files" - +typedef ^ ^ CHARACTER(1024) VTK_OutFileBase - - - "Basename for writing VTK files" - # ....... MiscVars ............ # FVW_MiscVarType @@ -143,6 +145,8 @@ typedef FVW/FVW ContinuousStateType ReKi typedef ^ ^ ReKi Gamma_FW ::: - - "Circulation of the far wake panels" - typedef ^ ^ ReKi r_NW :::: - - "Position of the near wake panels" - typedef ^ ^ ReKi r_FW :::: - - "Position of the far wake panels" - +# TODO UA +typedef ^ ^ UA_ContinuousStateType UA - - - "states for UnsteadyAero" - #.......... DiscreteStateType ...... diff --git a/modules/aerodyn/src/FVW_Types.f90 b/modules/aerodyn/src/FVW_Types.f90 index f5d4452578..530c8a2dd2 100644 --- a/modules/aerodyn/src/FVW_Types.f90 +++ b/modules/aerodyn/src/FVW_Types.f90 @@ -74,6 +74,8 @@ MODULE FVW_Types REAL(DbKi) :: DTvtk !< DT between vtk writes [s] INTEGER(IntKi) :: VTKCoord !< Switch for VTK outputs coordinate system [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] + CHARACTER(1024) :: VTK_OutFileRoot !< Rootdirectory for writing VTK files [-] + CHARACTER(1024) :: VTK_OutFileBase !< Basename for writing VTK files [-] END TYPE FVW_ParameterType ! ======================= ! ========= FVW_MiscVarType ======= @@ -164,6 +166,7 @@ MODULE FVW_Types REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Gamma_FW !< Circulation of the far wake panels [-] REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: r_NW !< Position of the near wake panels [-] REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: r_FW !< Position of the far wake panels [-] + TYPE(UA_ContinuousStateType) :: UA !< states for UnsteadyAero [-] END TYPE FVW_ContinuousStateType ! ======================= ! ========= FVW_DiscreteStateType ======= @@ -340,6 +343,8 @@ SUBROUTINE FVW_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg DstParamData%DTvtk = SrcParamData%DTvtk DstParamData%VTKCoord = SrcParamData%VTKCoord DstParamData%RootName = SrcParamData%RootName + DstParamData%VTK_OutFileRoot = SrcParamData%VTK_OutFileRoot + DstParamData%VTK_OutFileBase = SrcParamData%VTK_OutFileBase END SUBROUTINE FVW_CopyParam SUBROUTINE FVW_DestroyParam( ParamData, ErrStat, ErrMsg ) @@ -446,6 +451,8 @@ SUBROUTINE FVW_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Db_BufSz = Db_BufSz + 1 ! DTvtk Int_BufSz = Int_BufSz + 1 ! VTKCoord Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Int_BufSz = Int_BufSz + 1*LEN(InData%VTK_OutFileRoot) ! VTK_OutFileRoot + Int_BufSz = Int_BufSz + 1*LEN(InData%VTK_OutFileBase) ! VTK_OutFileBase IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -598,6 +605,14 @@ SUBROUTINE FVW_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) Int_Xferred = Int_Xferred + 1 END DO ! I + DO I = 1, LEN(InData%VTK_OutFileRoot) + IntKiBuf(Int_Xferred) = ICHAR(InData%VTK_OutFileRoot(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%VTK_OutFileBase) + IntKiBuf(Int_Xferred) = ICHAR(InData%VTK_OutFileBase(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I END SUBROUTINE FVW_PackParam SUBROUTINE FVW_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -764,6 +779,14 @@ SUBROUTINE FVW_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 END DO ! I + DO I = 1, LEN(OutData%VTK_OutFileRoot) + OutData%VTK_OutFileRoot(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%VTK_OutFileBase) + OutData%VTK_OutFileBase(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I END SUBROUTINE FVW_UnPackParam SUBROUTINE FVW_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) @@ -5550,6 +5573,9 @@ SUBROUTINE FVW_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrS END IF DstContStateData%r_FW = SrcContStateData%r_FW ENDIF + CALL UA_CopyContState( SrcContStateData%UA, DstContStateData%UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE FVW_CopyContState SUBROUTINE FVW_DestroyContState( ContStateData, ErrStat, ErrMsg ) @@ -5573,6 +5599,7 @@ SUBROUTINE FVW_DestroyContState( ContStateData, ErrStat, ErrMsg ) IF (ALLOCATED(ContStateData%r_FW)) THEN DEALLOCATE(ContStateData%r_FW) ENDIF + CALL UA_DestroyContState( ContStateData%UA, ErrStat, ErrMsg ) END SUBROUTINE FVW_DestroyContState SUBROUTINE FVW_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -5630,6 +5657,24 @@ SUBROUTINE FVW_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_BufSz = Int_BufSz + 2*4 ! r_FW upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%r_FW) ! r_FW END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! UA: size of buffers for each call to pack subtype + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, .TRUE. ) ! UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -5767,6 +5812,34 @@ SUBROUTINE FVW_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs END DO END DO END IF + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%UA, ErrStat2, ErrMsg2, OnlySize ) ! UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF END SUBROUTINE FVW_PackContState SUBROUTINE FVW_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -5921,6 +5994,46 @@ SUBROUTINE FVW_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er END DO END DO END IF + 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 UA_UnpackContState( Re_Buf, Db_Buf, Int_Buf, OutData%UA, ErrStat2, ErrMsg2 ) ! UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END SUBROUTINE FVW_UnPackContState SUBROUTINE FVW_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/src/FVW_Wings.f90 b/modules/aerodyn/src/FVW_Wings.f90 index f184c2701d..431ab3403b 100644 --- a/modules/aerodyn/src/FVW_Wings.f90 +++ b/modules/aerodyn/src/FVW_Wings.f90 @@ -90,7 +90,7 @@ subroutine Wings_Panelling_Init(Meshes, p, m, ErrStat, ErrMsg ) s_in(1) = 0 do iSpan = 2, Meshes(iW)%nNodes DP = Meshes(iW)%Position(1:3, iSpan) - Meshes(iW)%Position(1:3, iSpan-1) - s_in(iSpan) = s_in(iSpan-1) + norm2(DP) + s_in(iSpan) = s_in(iSpan-1) + TwoNorm(DP) enddo ! --- Setting up Lifting line variables based on input and a "meshing" method (TODO) @@ -176,14 +176,14 @@ subroutine Wings_Panelling(Meshes, p, m, ErrStat, ErrMsg ) DP2 = P10-P9 DP3 = P7-P5 m%Norm(1:3,iSpan,iW) = cross_product(DP1,DP2) - m%Norm(1:3,iSpan,iW) = m%Norm(1:3,iSpan,iW)/norm2(m%Norm(1:3,iSpan,iW)) - m%Tang(1:3,iSpan,iW) = (DP1)/norm2(DP1) ! tangential unit vector, along chord + m%Norm(1:3,iSpan,iW) = m%Norm(1:3,iSpan,iW)/TwoNorm(m%Norm(1:3,iSpan,iW)) + m%Tang(1:3,iSpan,iW) = (DP1)/TwoNorm(DP1) ! tangential unit vector, along chord ! m%Tscoord(1:3,iSpan) = (DP3)/norm2(DP3) ! tangential unit vector, along span, follows ref line m%dl (1:3,iSpan,iW) = DP2 m%Orth(1:3,iSpan,iW) = cross_product(m%Norm(1:3,iSpan,iW),m%Tang(1:3,iSpan,iW)) ! orthogonal vector to N and T - m%Area(iSpan, iW) = norm2(cross_product(DP1,DP3)) + m%Area(iSpan, iW) = TwoNorm(cross_product(DP1,DP3)) DP3 = P1-P3 - m%diag_LL(iSpan, iW) = norm2(DP3) + m%diag_LL(iSpan, iW) = TwoNorm(DP3) end do enddo !FIXME: does it make sense to use the position mesh for this info? @@ -465,11 +465,11 @@ subroutine CirculationFromPolarData(Gamma_LL, p, m, AFInfo, ErrStat, ErrMsg) Vrel = m%Vtot_LL(1:3,icp,iW) ! "Orth": cross sectional plane of the lifting line Vrel_orth(1:3) = dot_product(Vrel,N)*N + dot_product(Vrel,Tc)*Tc - Vrel_orth_norm = norm2(Vrel_orth(1:3)) + Vrel_orth_norm = TwoNorm(Vrel_orth(1:3)) Vjouk(1:3) = cross_product(Vrel,m%dl(1:3,icp,iW)) Vjouk_orth(1:3) = dot_product(Vjouk,N)*N + dot_product(Vjouk,Tc)*Tc - Vjouk_orth_norm = norm2(Vjouk_orth) - Vrel_norm = norm2(Vrel) + Vjouk_orth_norm = TwoNorm(Vjouk_orth) + Vrel_norm = TwoNorm(Vrel) alpha = atan2(dot_product(Vrel,N) , dot_product(Vrel,Tc) ) ! [rad] Re = p%Chord(icp,iW) * Vrel_norm / p%KinVisc / 1.0E6 diff --git a/modules/aerodyn/src/UA_Dvr_Subs.f90 b/modules/aerodyn/src/UA_Dvr_Subs.f90 index 7bf5d62bc0..cb56cb2642 100644 --- a/modules/aerodyn/src/UA_Dvr_Subs.f90 +++ b/modules/aerodyn/src/UA_Dvr_Subs.f90 @@ -40,7 +40,6 @@ subroutine ReadDriverInputFile( inputFile, InitInp, ErrStat, ErrMsg ) character(*), intent( out ) :: ErrMsg ! Error message if ErrStat /= ErrID_None ! Local variables - integer :: UnIn ! Unit number for the input file integer :: UnEchoLocal ! The local unit number for this module's echo file character(1024) :: EchoFile ! Name of HydroDyn echo file @@ -384,16 +383,18 @@ end subroutine Cleanup end subroutine ReadDriverInputFile - subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, ErrStat, ErrMsg ) + subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, OmegaArr, ErrStat, ErrMsg ) character(1024), intent( in ) :: inputsFile integer, intent( out ) :: nSimSteps real(DbKi),allocatable, intent( out ) :: timeArr(:) real(ReKi),allocatable, intent( out ) :: AOAarr(:) real(ReKi),allocatable, intent( out ) :: Uarr(:) !RRD + real(ReKi),allocatable, intent( out ) :: OmegaArr(:) integer, intent( out ) :: ErrStat ! returns a non-zero value when an error occurs character(*), intent( out ) :: ErrMsg ! Error message if ErrStat /= ErrID_None - real(DbKi) :: tmpArr(3) + real(SiKi) :: dt + real(DbKi) :: tmpArr(4) integer(IntKi) :: errStat2 ! Status of error message character(1024) :: errMsg2 ! Error message if ErrStat /= ErrID_None character(*), parameter :: RoutineName = 'ReadTimeSeriesData' @@ -404,8 +405,9 @@ subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, Err ErrStat = ErrID_None ErrMsg = '' + nSimSteps = 0 ! allocate here in case errors occur + FileName = trim(inputsFile) - nSimSteps = 0 call GetNewUnit( UnIn ) call OpenFInpFile( UnIn, FileName, errStat2, errMsg2 ) @@ -420,7 +422,7 @@ subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, Err !------------------------------------------------------------------------------------------------- - ! File header 7lines + ! Determine how many lines of data are in the file: !------------------------------------------------------------------------------------------------- do i=1,hdrlines !RRD call ReadCom( UnIn, FileName, ' UnsteadyAero time-series input file header line 1', errStat2, errMsg2 ) @@ -431,9 +433,8 @@ subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, Err end if enddo - do - call ReadAry( UnIn, FileName, tmpArr, 3, 'Data', 'Time-series data', errStat2, errMsg2 ) + call ReadAry( UnIn, FileName, tmpArr, 4, 'Data', 'Time-series data', errStat2, errMsg2 ) ! The assumption is that the only parsing error occurs at the end of the file and therefore we stop reading data if (errStat2 > ErrID_None) then exit @@ -442,38 +443,58 @@ subroutine ReadTimeSeriesData( inputsFile, nSimSteps, timeArr, AOAarr, Uarr, Err end if end do - rewind(UnIn) - do i=1,hdrlines !RRD - call ReadCom( UnIn, FileName, ' UnsteadyAero time-series input file header line 1', errStat2, errMsg2 ) - enddo - allocate ( timeArr( nSimSteps ), STAT=ErrStat ) - if ( ErrStat /= 0 ) then + !------------------------------------------------------------------------------------------------- + ! Allocate arrays to be read + !------------------------------------------------------------------------------------------------- + allocate ( timeArr( nSimSteps ), STAT=ErrStat2 ) + if ( ErrStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, 'Error trying to allocate timeArr.', ErrStat, ErrMsg, RoutineName) call Cleanup() return end if - allocate ( AOAarr( nSimSteps ), STAT=ErrStat ) - if ( ErrStat /= 0 ) then + allocate ( AOAarr( nSimSteps ), STAT=ErrStat2 ) + if ( ErrStat2 /= 0 ) then call SetErrStat( ErrID_Fatal, 'Error trying to allocate AOAarr.', ErrStat, ErrMsg, RoutineName) call Cleanup() return end if - allocate ( Uarr( nSimSteps ), STAT=ErrStat ) !RRD - if ( ErrStat /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error trying to allocate Uarr.', ErrStat, ErrMsg, RoutineName) + allocate ( Uarr( nSimSteps ), OmegaArr( nSimSteps ), STAT=ErrStat2 ) + if ( ErrStat2 /= 0 ) then + call SetErrStat( ErrID_Fatal, 'Error trying to allocate Uarr and OmegaArr.', ErrStat, ErrMsg, RoutineName) call Cleanup() return end if + + !------------------------------------------------------------------------------------------------- + ! Read arrays from file + !------------------------------------------------------------------------------------------------- + rewind(UnIn) + do i=1,hdrlines !RRD + call ReadCom( UnIn, FileName, ' UnsteadyAero time-series input file header line 1', errStat2, errMsg2 ) + enddo do i = 1,nSimSteps - call ReadAry( UnIn, FileName, tmpArr, 3, 'Data', 'Time-series data', errStat2, errMsg2 ) - timeArr(i) = tmpArr(1) - AOAarr(i) = real(tmpArr(2),ReKi) - Uarr(i) = real(tmpArr(3),ReKi) + call ReadAry( UnIn, FileName, tmpArr, 4, 'Data', 'Time-series data', errStat2, errMsg2 ) + timeArr(i) = tmpArr(1) + AOAarr(i) = real(tmpArr(2),ReKi) + Uarr(i) = real(tmpArr(3),ReKi) + OmegaArr(i) = real(tmpArr(4),ReKi) end do + if (nSimSteps > 1) then + dt = timeArr(2) - timeArr(1) + + do i = 2,nSimSteps-1 + if (.not. EqualRealNos(dt, REAL(timeArr(i+1)-timeArr(i), SiKi) ) ) then + call SetErrStat( ErrID_Fatal, 'Times in InputsFile must be contain the same delta t.', ErrStat, ErrMsg, RoutineName) + exit !exit the do loop + end if + end do + end if + + call Cleanup() contains !==================================================================================================== @@ -491,14 +512,12 @@ subroutine Cleanup() end subroutine Cleanup end subroutine ReadTimeSeriesData - - subroutine Init_AFI(NumAFfiles, afNames, Flookup, UseCm, AFI_Params, ErrStat, ErrMsg) +!-------------------------------------------------------------------------------------------------------------- + subroutine Init_AFI(p, NumAFfiles, afNames, UseCm, AFI_Params, ErrStat, ErrMsg) - - + type(UA_ParameterType),intent(in) :: p integer, intent(in ) :: NumAFfiles CHARACTER(1024), intent(in ) :: afNames(NumAFfiles) - logical, intent(in ) :: Flookup logical, intent(in ) :: UseCm type(AFI_ParameterType), intent( out) :: AFI_Params(NumAFfiles) integer(IntKi), intent( out) :: ErrStat ! Error status. @@ -536,8 +555,7 @@ subroutine Init_AFI(NumAFfiles, afNames, Flookup, UseCm, AFI_Params, ErrStat, Er end if AFI_InitInputs%InCol_Cpmin = 0 - AFI_InitInputs%AFTabMod = AFITable_1 - !AFI_InitInputs%Flookup = Flookup + AFI_InitInputs%AFTabMod = AFITable_1 ! 1D-interpolation (on AoA only) do i=1,NumAFfiles @@ -552,17 +570,16 @@ subroutine Init_AFI(NumAFfiles, afNames, Flookup, UseCm, AFI_Params, ErrStat, Er call Cleanup() return end if - end do do i=1,NumAFfiles - call UA_ValidateAFI(AFI_Params(i), afNames(i), ErrStat2, ErrMsg2) + call UA_ValidateAFI(p%UAMod, AFI_Params(i), afNames(i), ErrStat2, ErrMsg2) call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) - call UA_TurnOff_param(AFI_Params(i), ErrStat2, ErrMsg2) + call UA_TurnOff_param(p, AFI_Params(i), ErrStat2, ErrMsg2) call SetErrStat(errStat2, errMsg2, ErrStat, ErrMsg, RoutineName ) end do diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index 0f525800ad..d24a730daf 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -30,19 +30,23 @@ module UnsteadyAero private + public :: UA_Init public :: UA_UpdateDiscOtherState public :: UA_UpdateStates public :: UA_CalcOutput + public :: UA_CalcContStateDeriv public :: UA_ReInit public :: UA_ValidateAFI public :: UA_TurnOff_param public :: UA_TurnOff_input + public :: UA_InitStates_AllNodes - integer(intki), parameter :: UA_Baseline = 1 ! UAMod = 1 [Baseline model (Original)] - integer(intki), parameter :: UA_Gonzalez = 2 ! UAMod = 2 [Gonzalez's variant (changes in Cn,Cc,Cm)] - integer(intki), parameter :: UA_MinnemaPierce = 3 ! UAMod = 3 [Minnema/Pierce variant (changes in Cc and Cm)] + integer(intki), parameter :: UA_Baseline = 1 ! UAMod = 1 [Baseline model (Original)] + integer(intki), parameter :: UA_Gonzalez = 2 ! UAMod = 2 [Gonzalez's variant (changes in Cn,Cc,Cm)] + integer(intki), parameter :: UA_MinnemaPierce = 3 ! UAMod = 3 [Minnema/Pierce variant (changes in Cc and Cm)] + integer(intki), parameter, public :: UA_HGM = 4 ! UAMod = 4 [continuous variant of HGM (Hansen) model] real(ReKi), parameter :: Gonzalez_factor = 0.2_ReKi ! this factor, proposed by Gonzalez (for "all" models) is used to modify Cc to account for negative values seen at f=0 (see Eqn 1.40) @@ -107,7 +111,7 @@ end function Get_ExpEqn !============================================================================== !============================================================================== -subroutine Get_f_from_Lookup( UAMod, Re, UserProp, alpha_in, alpha0_in, C_nalpha_circ, AFInfo, ErrStat, ErrMsg, f, cn_fs) +subroutine Get_f_from_Lookup( UAMod, Re, UserProp, alpha_in, alpha0, C_nalpha_circ, AFInfo, ErrStat, ErrMsg, f, cn_fs) ! Compute either fprime or fprimeprime using an analytical equation (and eventually a table lookup) ! Called by : ComputeKelvinChain ! Calls to : NONE @@ -116,7 +120,7 @@ subroutine Get_f_from_Lookup( UAMod, Re, UserProp, alpha_in, alpha0_in, C_nalpha real(ReKi), intent(in ) :: Re ! Reynolds number real(ReKi), intent(in ) :: UserProp ! User property for interpolating AFI real(ReKi), intent(in ) :: alpha_in ! angle of attack (radians) - real(ReKi), intent(in ) :: alpha0_in + real(ReKi), intent(in ) :: alpha0 real(ReKi), intent(in ) :: C_nalpha_circ type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data integer(IntKi), intent( out) :: ErrStat ! Error status of the operation @@ -131,7 +135,6 @@ subroutine Get_f_from_Lookup( UAMod, Re, UserProp, alpha_in, alpha0_in, C_nalpha real(ReKi) :: alpha ! angle of attack (radians) - real(ReKi) :: alpha0 real(ReKi) :: alpha_minus_alpha0 ErrStat = ErrID_None @@ -147,10 +150,8 @@ subroutine Get_f_from_Lookup( UAMod, Re, UserProp, alpha_in, alpha0_in, C_nalpha ! ensure that these angles are in appropriate ranges alpha = alpha_in - alpha0 = alpha0_in call MPi2Pi(alpha) - call MPi2Pi(alpha0) alpha_minus_alpha0 = alpha - alpha0 call MPi2Pi(alpha_minus_alpha0) @@ -310,14 +311,6 @@ real(ReKi) function Get_f( alpha, alpha0, alpha1, alpha2, S1, S2, S3, S4 ) end if end function Get_f -!============================================================================== - - - - - - - !============================================================================== subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_p, ErrStat, ErrMsg ) ! @@ -365,6 +358,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ 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 @@ -414,14 +408,17 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ ! Low Pass filtering of alpha, q, and Kq in order to deal with numerical issues that arise for very small values of dt ! See equations 1.7 and 1.8 of the manual + ! This filter is a Simple Infinite Impulse Response Filter + ! See https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter - LowPassConst = exp(-2.0_ReKi*PI*p%dt*BL_p%filtCutOff) ! from Eqn 1.8 [7] + dynamicFilterCutoffHz = max( 1.0_ReKi, u%U ) * BL_p%filtCutOff / PI / p%C(i,j) + LowPassConst = exp(-2.0_ReKi*PI*p%dt*dynamicFilterCutoffHz) ! from Eqn 1.8 [7] KC%alpha_filt_cur = LowPassConst*alpha_filt_minus1 + (1.0_ReKi-LowPassConst)*u%alpha ! from eq 1.8 [1: typo in documentation, though] KC%dalpha0 = KC%alpha_filt_cur - BL_p%alpha0 - + ! Compute Kalpha using Eqn 1.7 Kalpha = ( KC%alpha_filt_cur - alpha_filt_minus1 ) / p%dt ! Eqn 1.7, using filtered values of alpha @@ -491,7 +488,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%Cn_q_nc = -1.0_ReKi*KC%T_q * ( KC%Kq_f - KC%Kprime_q ) / M ! Eqn 1.19a KC%Cn_alpha_q_nc = KC%Cn_alpha_nc + KC%Cn_q_nc ! Eqn 1.17 - + if (p%ShedEffect) then KC%X1 = Get_ExpEqn( KC%ds*beta_M_Sqrd*BL_p%b1, 1.0_ReKi, xd%X1_minus1(i,j), BL_p%A1*(KC%alpha_filt_cur - alpha_filt_minus1), 0.0_ReKi ) ! Eqn 1.15a KC%X2 = Get_ExpEqn( KC%ds*beta_M_Sqrd*BL_p%b2, 1.0_ReKi, xd%X2_minus1(i,j), BL_p%A2*(KC%alpha_filt_cur - alpha_filt_minus1), 0.0_ReKi ) ! Eqn 1.15b @@ -513,7 +510,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%X3 = 0.0_ReKi ! Similar to X1 and X2, we assumed that this effect is already included KC%X4 = 0.0_ReKi endif - + KC%Cn_q_circ = KC%C_nalpha_circ*KC%q_f_cur/2.0 - KC%X3 - KC%X4 ! Eqn 1.16 else ! these aren't used (they are possibly output to UA_OUT file, though) @@ -524,7 +521,7 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ 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%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! @@ -641,16 +638,15 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%fprimeprime_m = KC%fprimeprime end if - + if ( p%UAMod == UA_Gonzalez ) then KC%Cn_FS = KC%Cn_alpha_q_nc + KC%Cn_q_circ + KC%Cn_alpha_q_circ * ( (1.0_ReKi + 2.0_ReKi*sqrt(KC%fprimeprime) ) / 3.0_ReKi )**2 ! Eqn 1.39 else + ! change proposed by Pariya: ! KC%Cn_FS = KC%Cn_alpha_q_nc + KC%Cn_alpha_q_circ * ( (1.0_ReKi + sqrt(KC%fprimeprime) ) / 2.0_ReKi )**2 ! Eqn 1.38 - ! new method proposed by Pariya: call Get_f_from_Lookup( p%UAMod, u%Re, u%UserProp, KC%alpha_e+BL_p%alpha0, BL_p%alpha0, KC%C_nalpha_circ, AFInfo, ErrStat2, ErrMsg2, cn_fs=Cn_fs_temp) KC%Cn_FS = KC%Cn_alpha_q_nc + KC%C_nalpha_circ * KC%alpha_e*KC%fprimeprime + Cn_fs_temp*(1-KC%fprimeprime) end if - if ( p%UAMod == UA_MinnemaPierce ) then if (OtherState%FirstPass(i,j)) then @@ -737,18 +733,23 @@ subroutine UA_SetParameters( dt, InitInp, p, ErrStat, ErrMsg ) p%a_s = InitInp%a_s ! this can't be 0 p%Flookup = InitInp%Flookup - + if (p%UAMod==UA_HGM) then + p%lin_nx = p%numBlades*p%nNodesPerBlade*4 + else + p%lin_nx = 0 + end if end subroutine UA_SetParameters !============================================================================== !============================================================================== -subroutine UA_InitStates_Misc( p, xd, OtherState, m, ErrStat, ErrMsg ) +subroutine UA_InitStates_Misc( p, x, xd, OtherState, m, ErrStat, ErrMsg ) ! Called by : UA_Init ! Calls to : NONE !.............................................................................. type(UA_ParameterType), intent(in ) :: p ! Parameters + type(UA_ContinuousStateType), intent(inout) :: x ! Initial continuous states type(UA_DiscreteStateType), intent(inout) :: xd ! Initial discrete states type(UA_OtherStateType), intent(inout) :: OtherState ! Initial other states type(UA_MiscVarType), intent(inout) :: m ! Initial misc/optimization variables @@ -764,121 +765,163 @@ subroutine UA_InitStates_Misc( p, xd, OtherState, m, ErrStat, ErrMsg ) ! allocate all the state arrays - call AllocAry( xd%alpha_minus1, p%nNodesPerBlade,p%numBlades, 'xd%alpha_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%alpha_filt_minus1, p%nNodesPerBlade,p%numBlades, 'xd%alpha_filt_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%q_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%q_f_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Kq_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kq_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Kalpha_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kalpha_f_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%X1_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X1_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%X2_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X2_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%X3_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X3_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%X4_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X4_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Kprime_alpha_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kprime_alpha_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Kprime_q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kprime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Kprimeprime_q_minus1,p%nNodesPerBlade,p%numBlades, 'xd%Kprimeprime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%K3prime_q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%K3prime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry( xd%Dp_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Dp_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - call AllocAry(xd%Cn_prime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_prime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Cn_pot_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_pot_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprimeprime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprimeprime_c_minus1,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprimeprime_m_minus1,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Df_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Df_c_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Df_m_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Dalphaf_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Dalphaf_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%alphaf_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%alphaf_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprime_c_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%fprime_m_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%tau_V ,p%nNodesPerBlade,p%numBlades,'xd%tau_V',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%tau_V_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%tau_V_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%Cn_v_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_v_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(xd%C_V_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%C_V_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (p%UAMod == UA_HGM) then - call AllocAry(OtherState%FirstPass,p%nNodesPerBlade,p%numBlades,'OtherState%FirstPass',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(OtherState%sigma1 ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(OtherState%sigma1c ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1c',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(OtherState%sigma1m ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1m',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(OtherState%sigma3 ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma3',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + allocate( x%element( p%nNodesPerBlade, p%numBlades ), stat=ErrStat2 ) + if (ErrStat2 /= 0) call SetErrStat(ErrID_Fatal,"Cannot allocate x%x.",ErrStat,ErrMsg,RoutineName) -#ifdef UA_OUTS - call AllocAry(m%TESF ,p%nNodesPerBlade,p%numBlades,'m%TESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(m%LESF ,p%nNodesPerBlade,p%numBlades,'m%LESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(m%VRTX ,p%nNodesPerBlade,p%numBlades,'m%VRTX',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call AllocAry(m%T_Sh ,p%nNodesPerBlade,p%numBlades,'m%T_Sh',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) -#endif + allocate( OtherState%n(p%nNodesPerBlade, p%numBlades), stat=ErrStat2) + if (ErrStat2 /= 0 ) call SetErrStat( ErrID_Fatal, " Error allocating OtherState%n.", ErrStat, ErrMsg, RoutineName) + + + else + call AllocAry( xd%alpha_minus1, p%nNodesPerBlade,p%numBlades, 'xd%alpha_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%alpha_filt_minus1, p%nNodesPerBlade,p%numBlades, 'xd%alpha_filt_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%q_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%q_f_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Kq_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kq_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Kalpha_f_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kalpha_f_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%X1_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X1_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%X2_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X2_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%X3_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X3_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%X4_minus1, p%nNodesPerBlade,p%numBlades, 'xd%X4_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Kprime_alpha_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kprime_alpha_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Kprime_q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Kprime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Kprimeprime_q_minus1,p%nNodesPerBlade,p%numBlades, 'xd%Kprimeprime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%K3prime_q_minus1, p%nNodesPerBlade,p%numBlades, 'xd%K3prime_q_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry( xd%Dp_minus1, p%nNodesPerBlade,p%numBlades, 'xd%Dp_minus1', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call AllocAry(xd%Cn_prime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_prime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Cn_pot_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_pot_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprimeprime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprimeprime_c_minus1,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprimeprime_m_minus1,p%nNodesPerBlade,p%numBlades,'xd%fprimeprime_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Df_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Df_c_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Df_m_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Df_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Dalphaf_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Dalphaf_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%alphaf_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%alphaf_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprime_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprime_c_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_c_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%fprime_m_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%fprime_m_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%tau_V ,p%nNodesPerBlade,p%numBlades,'xd%tau_V',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%tau_V_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%tau_V_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%Cn_v_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%Cn_v_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(xd%C_V_minus1 ,p%nNodesPerBlade,p%numBlades,'xd%C_V_minus1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call AllocAry(OtherState%sigma1 ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(OtherState%sigma1c ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1c',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(OtherState%sigma1m ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma1m',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(OtherState%sigma3 ,p%nNodesPerBlade,p%numBlades,'OtherState%sigma3',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + +# ifdef UA_OUTS + call AllocAry(m%TESF ,p%nNodesPerBlade,p%numBlades,'m%TESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(m%LESF ,p%nNodesPerBlade,p%numBlades,'m%LESF',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(m%VRTX ,p%nNodesPerBlade,p%numBlades,'m%VRTX',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(m%T_Sh ,p%nNodesPerBlade,p%numBlades,'m%T_Sh',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) +# endif + end if + + call AllocAry(OtherState%FirstPass,p%nNodesPerBlade,p%numBlades,'OtherState%FirstPass',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return - call UA_ReInit( p, xd, OtherState, m ) ! initializes values of states and misc vars - + call UA_ReInit( p, x, xd, OtherState, m,ErrStat2,ErrMsg2 ) ! initializes values of states and misc vars + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end subroutine UA_InitStates_Misc !============================================================================== -subroutine UA_ReInit( p, xd, OtherState, m ) +subroutine UA_ReInit( p, x, xd, OtherState, m, ErrStat, ErrMsg ) type(UA_ParameterType), intent(in ) :: p ! Parameters + type(UA_ContinuousStateType), intent(inout) :: x ! Initial continuous states type(UA_DiscreteStateType), intent(inout) :: xd ! Initial discrete states type(UA_OtherStateType), intent(inout) :: OtherState ! Initial other states type(UA_MiscVarType), intent(inout) :: m ! Initial misc/optimization variables - m%FirstWarn_M = .true. + integer(IntKi), intent( out) :: ErrStat ! Error status of the operation + character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'UA_ReInit' + integer :: i + integer :: j - OtherState%sigma1 = 1.0_ReKi - OtherState%sigma1c = 1.0_ReKi - OtherState%sigma1m = 1.0_ReKi - OtherState%sigma3 = 1.0_ReKi + ErrStat = ErrID_None + ErrMsg = "" + + m%FirstWarn_M = .true. + m%FirstWarn_UA = .true. -#ifdef UA_OUTS - m%TESF = .FALSE. - m%LESF = .FALSE. - m%VRTX = .FALSE. - m%T_sh = 0.0_ReKi -#endif - - OtherState%FirstPass = .true. + if ( p%UAMod == UA_HGM ) then - xd%Cn_prime_minus1 = 0.0_ReKi - xd%alpha_minus1 = 0.0_ReKi - xd%alpha_filt_minus1 = 0.0_ReKi - xd%q_minus1 = 0.0_ReKi - xd%q_f_minus1 = 0.0_ReKi - xd%Kq_f_minus1 = 0.0_ReKi - xd%Kalpha_f_minus1 = 0.0_ReKi - xd%X1_minus1 = 0.0_ReKi - xd%X2_minus1 = 0.0_ReKi - xd%X3_minus1 = 0.0_ReKi - xd%X4_minus1 = 0.0_ReKi - xd%Kprime_alpha_minus1 = 0.0_ReKi - xd%Kprime_q_minus1 = 0.0_ReKi - xd%Dp_minus1 = 0.0_ReKi - xd%Cn_pot_minus1 = 0.0_ReKi - xd%K3prime_q_minus1 = 0.0_ReKi - xd%Kprimeprime_q_minus1 = 0.0_ReKi - xd%fprimeprime_minus1 = 0.0_ReKi - xd%fprimeprime_c_minus1 = 0.0_ReKi - xd%fprimeprime_m_minus1 = 0.0_ReKi - xd%Df_minus1 = 0.0_ReKi - xd%Df_c_minus1 = 0.0_ReKi - xd%Df_m_minus1 = 0.0_ReKi - xd%Dalphaf_minus1 = 0.0_ReKi - xd%alphaf_minus1 = 0.0_ReKi - xd%fprime_minus1 = 0.0_ReKi - xd%fprime_c_minus1 = 0.0_ReKi - xd%fprime_m_minus1 = 0.0_ReKi - xd%tau_V = 0.0_ReKi - xd%tau_V_minus1 = 0.0_ReKi - xd%Cn_v_minus1 = 0.0_ReKi - xd%C_V_minus1 = 0.0_ReKi ! This probably should not be set to 0.0, but should be set + OtherState%n = -1 ! we haven't updated OtherState%xdot, yet + + do j=1,size(x%element,2) + do i=1,size(x%element,1) + x%element(i,j)%x = 0.0_ReKi + end do + end do + + do i = 1, size(OtherState%xdot) + call UA_CopyContState( x, OtherState%xdot(i), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! there are no meshes, so the control code is irrelevant + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end do + + else + OtherState%sigma1 = 1.0_ReKi + OtherState%sigma1c = 1.0_ReKi + OtherState%sigma1m = 1.0_ReKi + OtherState%sigma3 = 1.0_ReKi + +# ifdef UA_OUTS + m%TESF = .FALSE. + m%LESF = .FALSE. + m%VRTX = .FALSE. + m%T_sh = 0.0_ReKi +# endif + + xd%Cn_prime_minus1 = 0.0_ReKi + xd%alpha_minus1 = 0.0_ReKi + xd%alpha_filt_minus1 = 0.0_ReKi + xd%q_minus1 = 0.0_ReKi + xd%q_f_minus1 = 0.0_ReKi + xd%Kq_f_minus1 = 0.0_ReKi + xd%Kalpha_f_minus1 = 0.0_ReKi + xd%X1_minus1 = 0.0_ReKi + xd%X2_minus1 = 0.0_ReKi + xd%X3_minus1 = 0.0_ReKi + xd%X4_minus1 = 0.0_ReKi + xd%Kprime_alpha_minus1 = 0.0_ReKi + xd%Kprime_q_minus1 = 0.0_ReKi + xd%Dp_minus1 = 0.0_ReKi + xd%Cn_pot_minus1 = 0.0_ReKi + xd%K3prime_q_minus1 = 0.0_ReKi + xd%Kprimeprime_q_minus1 = 0.0_ReKi + xd%fprimeprime_minus1 = 0.0_ReKi + xd%fprimeprime_c_minus1 = 0.0_ReKi + xd%fprimeprime_m_minus1 = 0.0_ReKi + xd%Df_minus1 = 0.0_ReKi + xd%Df_c_minus1 = 0.0_ReKi + xd%Df_m_minus1 = 0.0_ReKi + xd%Dalphaf_minus1 = 0.0_ReKi + xd%alphaf_minus1 = 0.0_ReKi + xd%fprime_minus1 = 0.0_ReKi + xd%fprime_c_minus1 = 0.0_ReKi + xd%fprime_m_minus1 = 0.0_ReKi + xd%tau_V = 0.0_ReKi + xd%tau_V_minus1 = 0.0_ReKi + xd%Cn_v_minus1 = 0.0_ReKi + xd%C_V_minus1 = 0.0_ReKi ! This probably should not be set to 0.0, but should be set + end if end subroutine UA_ReInit !============================================================================== -subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & +subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & InitOut,ErrStat, ErrMsg ) ! This routine is called at the start of the simulation to perform initialization steps. ! The parameters are set here and not changed during the simulation. @@ -890,6 +933,7 @@ subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & type(UA_InitInputType), intent(inout) :: InitInp ! Input data for initialization routine, needs to be inout because there is a copy of some data in InitInp in BEMT_SetParameters() type(UA_InputType), intent(in ) :: u ! An initial guess for the input; input mesh must be defined type(UA_ParameterType), intent( out) :: p ! Parameters + type(UA_ContinuousStateType), intent( out) :: x ! Initial continuous states type(UA_DiscreteStateType), intent( out) :: xd ! Initial discrete states type(UA_OtherStateType), intent( out) :: OtherState ! Initial other states type(UA_OutputType), intent( out) :: y ! Initial system outputs (outputs are not calculated; @@ -911,7 +955,7 @@ subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & integer(IntKi) :: errStat2 ! temporary Error status of the operation character(*), parameter :: RoutineName = 'UA_Init' -#ifdef UA_OUTS +#ifdef UA_OUTS integer(IntKi) :: i,j, iNode, iOffset character(64) :: chanPrefix #endif @@ -934,14 +978,19 @@ subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & if (ErrStat >= AbortErrLev) return ! initialize the discrete states, other states, and misc variables - call UA_InitStates_Misc( p, xd, OtherState, m, ErrStat2, ErrMsg2 ) ! initialize the continuous states + call UA_InitStates_Misc( p, x, xd, OtherState, m, ErrStat2, ErrMsg2 ) ! initialize the continuous states call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return -#ifdef UA_OUTS + +#ifdef UA_OUTS ! Allocate and set the InitOut data - p%NumOuts = 42 + if (p%UAMod == UA_HGM) then + p%NumOuts = 17 + else + p%NumOuts = 42 + end if allocate(InitOut%WriteOutputHdr(p%NumOuts*p%numBlades*p%nNodesPerBlade),STAT=ErrStat2) if (ErrStat2 /= 0) call SetErrStat(ErrID_Fatal,'Error allocating WriteOutputHdr.',ErrStat,ErrMsg,RoutineName) @@ -957,93 +1006,131 @@ subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & iOffset = (i-1)*p%NumOuts + (j-1)*p%nNodesPerBlade*p%NumOuts - chanPrefix = "B"//trim(num2lstr(j))//"N"//trim(num2lstr(i)) - InitOut%WriteOutputHdr(iOffset+ 1) = trim(chanPrefix)//'ALPHA_filt' - InitOut%WriteOutputHdr(iOffset+ 2) = trim(chanPrefix)//'VREL' - InitOut%WriteOutputHdr(iOffset+ 3) = trim(chanPrefix)//'Cn' + chanPrefix = "B"//trim(num2lstr(j))//"N"//trim(num2lstr(i)) + + InitOut%WriteOutputHdr(iOffset+ 2) = trim(chanPrefix)//'VREL' + InitOut%WriteOutputHdr(iOffset+ 3) = trim(chanPrefix)//'Cn' InitOut%WriteOutputHdr(iOffset+ 4) = trim(chanPrefix)//'Cc' InitOut%WriteOutputHdr(iOffset+ 5) = trim(chanPrefix)//'Cl' InitOut%WriteOutputHdr(iOffset+ 6) = trim(chanPrefix)//'Cd' - InitOut%WriteOutputHdr(iOffset+ 7) = trim(chanPrefix)//'Cm' - InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'Cn_aq_circ' - InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'Cn_aq_nc' - InitOut%WriteOutputHdr(iOffset+10) = trim(chanPrefix)//'Cn_pot' - InitOut%WriteOutputHdr(iOffset+11) = trim(chanPrefix)//'Dp' - InitOut%WriteOutputHdr(iOffset+12) = trim(chanPrefix)//'Cn_prime' - InitOut%WriteOutputHdr(iOffset+13) = trim(chanPrefix)//'fprime' - InitOut%WriteOutputHdr(iOffset+14) = trim(chanPrefix)//'Df' - InitOut%WriteOutputHdr(iOffset+15) = trim(chanPrefix)//'Cn_v' - InitOut%WriteOutputHdr(iOffset+16) = trim(chanPrefix)//'Tau_V' - InitOut%WriteOutputHdr(iOffset+17) = trim(chanPrefix)//'LESF' - InitOut%WriteOutputHdr(iOffset+18) = trim(chanPrefix)//'TESF' - InitOut%WriteOutputHdr(iOffset+19) = trim(chanPrefix)//'VRTX' - InitOut%WriteOutputHdr(iOffset+20) = trim(chanPrefix)//'C_v' - InitOut%WriteOutputHdr(iOffset+21) = trim(chanPrefix)//'Cm_a_nc' - InitOut%WriteOutputHdr(iOffset+22) = trim(chanPrefix)//'Cm_q_nc' - InitOut%WriteOutputHdr(iOffset+23) = trim(chanPrefix)//'Cm_v' - InitOut%WriteOutputHdr(iOffset+24) = trim(chanPrefix)//'alpha_p_f' - InitOut%WriteOutputHdr(iOffset+25) = trim(chanPrefix)//'Dalphaf' - InitOut%WriteOutputHdr(iOffset+26) = trim(chanPrefix)//'PMC' - InitOut%WriteOutputHdr(iOffset+27) = trim(chanPrefix)//'T_f' - InitOut%WriteOutputHdr(iOffset+28) = trim(chanPrefix)//'T_V' - InitOut%WriteOutputHdr(iOffset+29) = trim(chanPrefix)//'dS' - InitOut%WriteOutputHdr(iOffset+30) = trim(chanPrefix)//'T_alpha' - InitOut%WriteOutputHdr(iOffset+31) = trim(chanPrefix)//'T_q' - InitOut%WriteOutputHdr(iOffset+32) = trim(chanPrefix)//'k_alpha' - InitOut%WriteOutputHdr(iOffset+33) = trim(chanPrefix)//'k_q' - InitOut%WriteOutputHdr(iOffset+34) = trim(chanPrefix)//'alpha_e' - InitOut%WriteOutputHdr(iOffset+35) = trim(chanPrefix)//'X1' - InitOut%WriteOutputHdr(iOffset+36) = trim(chanPrefix)//'X2' - InitOut%WriteOutputHdr(iOffset+37) = trim(chanPrefix)//'cn_q_nc' - InitOut%WriteOutputHdr(iOffset+38) = trim(chanPrefix)//'alpha_f' - InitOut%WriteOutputHdr(iOffset+39) = trim(chanPrefix)//'fprimeprime' - InitOut%WriteOutputHdr(iOffset+40) = trim(chanPrefix)//'sigma1' - InitOut%WriteOutputHdr(iOffset+41) = trim(chanPrefix)//'sigma3' - InitOut%WriteOutputHdr(iOffset+42) = trim(chanPrefix)//'T_sh' - + InitOut%WriteOutputHdr(iOffset+ 7) = trim(chanPrefix)//'Cm' + + InitOut%WriteOutputUnt(iOffset+ 2) ='(m/s)' + InitOut%WriteOutputUnt(iOffset+ 3) ='(-)' + InitOut%WriteOutputUnt(iOffset+ 4) ='(-)' + InitOut%WriteOutputUnt(iOffset+ 5) ='(-)' + InitOut%WriteOutputUnt(iOffset+ 6) ='(-)' + InitOut%WriteOutputUnt(iOffset+ 7) ='(-)' + + if (p%UAmod == UA_HGM) then + InitOut%WriteOutputHdr(iOffset+ 1) = trim(chanPrefix)//'ALPHA' + + InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'omega' + InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'alphaE' + InitOut%WriteOutputHdr(iOffset+10) = trim(chanPrefix)//'Tu' + InitOut%WriteOutputHdr(iOffset+11) = trim(chanPrefix)//'alpha_34' + InitOut%WriteOutputHdr(iOffset+12) = trim(chanPrefix)//'cl_fs' + InitOut%WriteOutputHdr(iOffset+13) = trim(chanPrefix)//'fs_aE' + + InitOut%WriteOutputHdr(iOffset+14) = trim(chanPrefix)//'x1' + InitOut%WriteOutputHdr(iOffset+15) = trim(chanPrefix)//'x2' + InitOut%WriteOutputHdr(iOffset+16) = trim(chanPrefix)//'x3' + InitOut%WriteOutputHdr(iOffset+17) = trim(chanPrefix)//'x4' + + + InitOut%WriteOutputUnt(iOffset+ 1) ='(deg)' + + InitOut%WriteOutputUnt(iOffset+ 8) = '(deg/sec)' + InitOut%WriteOutputUnt(iOffset+ 9) = '(deg)' + InitOut%WriteOutputUnt(iOffset+10) = '(s)' + InitOut%WriteOutputUnt(iOffset+11) = '(deg)' + InitOut%WriteOutputUnt(iOffset+12) = '(-)' + InitOut%WriteOutputUnt(iOffset+13) = '(-)' + + InitOut%WriteOutputUnt(iOffset+14) = '(rad)' + InitOut%WriteOutputUnt(iOffset+15) = '(rad)' + InitOut%WriteOutputUnt(iOffset+16) = '(-)' + InitOut%WriteOutputUnt(iOffset+17) = '(-)' + + else + InitOut%WriteOutputHdr(iOffset+ 1) = trim(chanPrefix)//'ALPHA_filt' + + InitOut%WriteOutputHdr(iOffset+ 8) = trim(chanPrefix)//'Cn_aq_circ' + InitOut%WriteOutputHdr(iOffset+ 9) = trim(chanPrefix)//'Cn_aq_nc' + InitOut%WriteOutputHdr(iOffset+10) = trim(chanPrefix)//'Cn_pot' + InitOut%WriteOutputHdr(iOffset+11) = trim(chanPrefix)//'Dp' + InitOut%WriteOutputHdr(iOffset+12) = trim(chanPrefix)//'Cn_prime' + InitOut%WriteOutputHdr(iOffset+13) = trim(chanPrefix)//'fprime' + InitOut%WriteOutputHdr(iOffset+14) = trim(chanPrefix)//'Df' + InitOut%WriteOutputHdr(iOffset+15) = trim(chanPrefix)//'Cn_v' + InitOut%WriteOutputHdr(iOffset+16) = trim(chanPrefix)//'Tau_V' + InitOut%WriteOutputHdr(iOffset+17) = trim(chanPrefix)//'LESF' + InitOut%WriteOutputHdr(iOffset+18) = trim(chanPrefix)//'TESF' + InitOut%WriteOutputHdr(iOffset+19) = trim(chanPrefix)//'VRTX' + InitOut%WriteOutputHdr(iOffset+20) = trim(chanPrefix)//'C_v' + InitOut%WriteOutputHdr(iOffset+21) = trim(chanPrefix)//'Cm_a_nc' + InitOut%WriteOutputHdr(iOffset+22) = trim(chanPrefix)//'Cm_q_nc' + InitOut%WriteOutputHdr(iOffset+23) = trim(chanPrefix)//'Cm_v' + InitOut%WriteOutputHdr(iOffset+24) = trim(chanPrefix)//'alpha_p_f' + InitOut%WriteOutputHdr(iOffset+25) = trim(chanPrefix)//'Dalphaf' + InitOut%WriteOutputHdr(iOffset+26) = trim(chanPrefix)//'PMC' + InitOut%WriteOutputHdr(iOffset+27) = trim(chanPrefix)//'T_f' + InitOut%WriteOutputHdr(iOffset+28) = trim(chanPrefix)//'T_V' + InitOut%WriteOutputHdr(iOffset+29) = trim(chanPrefix)//'dS' + InitOut%WriteOutputHdr(iOffset+30) = trim(chanPrefix)//'T_alpha' + InitOut%WriteOutputHdr(iOffset+31) = trim(chanPrefix)//'T_q' + InitOut%WriteOutputHdr(iOffset+32) = trim(chanPrefix)//'k_alpha' + InitOut%WriteOutputHdr(iOffset+33) = trim(chanPrefix)//'k_q' + InitOut%WriteOutputHdr(iOffset+34) = trim(chanPrefix)//'alpha_e' + InitOut%WriteOutputHdr(iOffset+35) = trim(chanPrefix)//'X1' + InitOut%WriteOutputHdr(iOffset+36) = trim(chanPrefix)//'X2' + InitOut%WriteOutputHdr(iOffset+37) = trim(chanPrefix)//'cn_q_nc' + InitOut%WriteOutputHdr(iOffset+38) = trim(chanPrefix)//'alpha_f' + InitOut%WriteOutputHdr(iOffset+39) = trim(chanPrefix)//'fprimeprime' + InitOut%WriteOutputHdr(iOffset+40) = trim(chanPrefix)//'sigma1' + InitOut%WriteOutputHdr(iOffset+41) = trim(chanPrefix)//'sigma3' + InitOut%WriteOutputHdr(iOffset+42) = trim(chanPrefix)//'T_sh' + + + InitOut%WriteOutputUnt(iOffset+1) ='(deg)' + + InitOut%WriteOutputUnt(iOffset+8) ='(-)' + InitOut%WriteOutputUnt(iOffset+9) ='(-)' + InitOut%WriteOutputUnt(iOffset+10) ='(-)' + InitOut%WriteOutputUnt(iOffset+11) ='(-)' + InitOut%WriteOutputUnt(iOffset+12) ='(-)' + InitOut%WriteOutputUnt(iOffset+13) ='(-)' + InitOut%WriteOutputUnt(iOffset+14) ='(-)' + InitOut%WriteOutputUnt(iOffset+15) ='(-)' + InitOut%WriteOutputUnt(iOffset+16) ='(-)' + InitOut%WriteOutputUnt(iOffset+17) ='(-)' + InitOut%WriteOutputUnt(iOffset+18) ='(-)' + InitOut%WriteOutputUnt(iOffset+19) ='(-)' + InitOut%WriteOutputUnt(iOffset+20) ='(-)' + InitOut%WriteOutputUnt(iOffset+21) ='(-)' + InitOut%WriteOutputUnt(iOffset+22) ='(-)' + InitOut%WriteOutputUnt(iOffset+23) ='(-)' + InitOut%WriteOutputUnt(iOffset+24) ='(rad)' + InitOut%WriteOutputUnt(iOffset+25) ='(-)' + InitOut%WriteOutputUnt(iOffset+26) ='(-)' + InitOut%WriteOutputUnt(iOffset+27) ='(-)' + InitOut%WriteOutputUnt(iOffset+28) ='(-)' + InitOut%WriteOutputUnt(iOffset+29) ='(-)' + InitOut%WriteOutputUnt(iOffset+30) ='(-)' + InitOut%WriteOutputUnt(iOffset+31) ='(-)' + InitOut%WriteOutputUnt(iOffset+32) ='(-)' + InitOut%WriteOutputUnt(iOffset+33) ='(-)' + InitOut%WriteOutputUnt(iOffset+34) ='(rad)' + InitOut%WriteOutputUnt(iOffset+35) ='(-)' + InitOut%WriteOutputUnt(iOffset+36) ='(-)' + InitOut%WriteOutputUnt(iOffset+37) ='(-)' + InitOut%WriteOutputUnt(iOffset+38) ='(rad)' + InitOut%WriteOutputUnt(iOffset+39) ='(-)' + InitOut%WriteOutputUnt(iOffset+40) ='(-)' + InitOut%WriteOutputUnt(iOffset+41) ='(-)' + InitOut%WriteOutputUnt(iOffset+42) ='(-)' + end if - InitOut%WriteOutputUnt(iOffset+1) ='(deg)' - InitOut%WriteOutputUnt(iOffset+2) ='(m/s)' - InitOut%WriteOutputUnt(iOffset+3) ='(-)' - InitOut%WriteOutputUnt(iOffset+4) ='(-)' - InitOut%WriteOutputUnt(iOffset+5) ='(-)' - InitOut%WriteOutputUnt(iOffset+6) ='(-)' - InitOut%WriteOutputUnt(iOffset+7) ='(-)' - InitOut%WriteOutputUnt(iOffset+8) ='(-)' - InitOut%WriteOutputUnt(iOffset+9) ='(-)' - InitOut%WriteOutputUnt(iOffset+10) ='(-)' - InitOut%WriteOutputUnt(iOffset+11) ='(-)' - InitOut%WriteOutputUnt(iOffset+12) ='(-)' - InitOut%WriteOutputUnt(iOffset+13) ='(-)' - InitOut%WriteOutputUnt(iOffset+14) ='(-)' - InitOut%WriteOutputUnt(iOffset+15) ='(-)' - InitOut%WriteOutputUnt(iOffset+16) ='(-)' - InitOut%WriteOutputUnt(iOffset+17) ='(-)' - InitOut%WriteOutputUnt(iOffset+18) ='(-)' - InitOut%WriteOutputUnt(iOffset+19) ='(-)' - InitOut%WriteOutputUnt(iOffset+20) ='(-)' - InitOut%WriteOutputUnt(iOffset+21) ='(-)' - InitOut%WriteOutputUnt(iOffset+22) ='(-)' - InitOut%WriteOutputUnt(iOffset+23) ='(-)' - InitOut%WriteOutputUnt(iOffset+24) ='(-)' - InitOut%WriteOutputUnt(iOffset+25) ='(-)' - InitOut%WriteOutputUnt(iOffset+26) ='(-)' - InitOut%WriteOutputUnt(iOffset+27) ='(-)' - InitOut%WriteOutputUnt(iOffset+28) ='(-)' - InitOut%WriteOutputUnt(iOffset+29) ='(-)' - InitOut%WriteOutputUnt(iOffset+30) ='(-)' - InitOut%WriteOutputUnt(iOffset+31) ='(-)' - InitOut%WriteOutputUnt(iOffset+32) ='(-)' - InitOut%WriteOutputUnt(iOffset+33) ='(-)' - InitOut%WriteOutputUnt(iOffset+34) ='(-)' - InitOut%WriteOutputUnt(iOffset+35) ='(-)' - InitOut%WriteOutputUnt(iOffset+36) ='(-)' - InitOut%WriteOutputUnt(iOffset+37) ='(-)' - InitOut%WriteOutputUnt(iOffset+38) ='(-)' - InitOut%WriteOutputUnt(iOffset+39) ='(-)' - InitOut%WriteOutputUnt(iOffset+40) ='(-)' - InitOut%WriteOutputUnt(iOffset+41) ='(-)' - InitOut%WriteOutputUnt(iOffset+42) ='(-)' end do end do #else @@ -1054,8 +1141,8 @@ subroutine UA_Init( InitInp, u, p, xd, OtherState, y, m, Interval, & y%cm = 0.0_ReKi InitOut%Version = ProgDesc( 'Unsteady Aero', '', '' ) !..................................... - -#endif + +#endif end subroutine UA_Init !============================================================================== @@ -1068,8 +1155,14 @@ subroutine UA_ValidateInput(InitInp, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = "" - if (InitInp%UAMod < UA_Gonzalez .or. InitInp%UAMod > UA_MinnemaPierce ) call SetErrStat( ErrID_Fatal, & - "In this version, UAMod must be 2 (Gonzalez's variant) or 3 (Minnema/Pierce variant).", ErrStat, ErrMsg, RoutineName ) ! NOTE: for later- 1 (baseline/original) + !>>> remove after this feature gets tested better: + if (InitInp%UAMod == UA_HGM ) then + call SetErrStat( ErrID_Fatal, "UAMod cannot be 4 (continuous HGM model) in this version of OpenFAST.", ErrStat, ErrMsg, RoutineName ) + end if + !<<< + + if (InitInp%UAMod < UA_Gonzalez .or. InitInp%UAMod > UA_HGM ) call SetErrStat( ErrID_Fatal, & + "In this version, UAMod must be 2 (Gonzalez's variant), 3 (Minnema/Pierce variant), or 4 (continuous HGM model).", ErrStat, ErrMsg, RoutineName ) ! NOTE: for later- 1 (baseline/original) if (.not. InitInp%FLookUp ) call SetErrStat( ErrID_Fatal, 'FLookUp must be TRUE for this version.', ErrStat, ErrMsg, RoutineName ) @@ -1077,7 +1170,8 @@ subroutine UA_ValidateInput(InitInp, ErrStat, ErrMsg) end subroutine UA_ValidateInput !============================================================================== -subroutine UA_ValidateAFI(AFInfo, afName, ErrStat, ErrMsg) +subroutine UA_ValidateAFI(UAMod, AFInfo, afName, ErrStat, ErrMsg) + integer(IntKi), intent(in ) :: UAMod ! which UA model we are using type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data character(*), intent(in ) :: afName ! The airfoil file name integer(IntKi), intent( out) :: ErrStat ! Error status of the operation @@ -1098,23 +1192,64 @@ subroutine UA_ValidateAFI(AFInfo, afName, ErrStat, ErrMsg) call SetErrStat(ErrID_Fatal, 'Airfoil file "'//trim(afName)//'", table #'//trim(num2lstr(j))// & ' does not contain parameters for UA data.', ErrStat, ErrMsg, RoutineName ) else - if ( EqualRealNos(AFInfo%Table(j)%UA_BL%St_sh, 0.0_ReKi) ) then - call SetErrStat(ErrID_Fatal, 'UA St_sh parameter must not be 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + ! parameters used only for UAMod/=UA_HGM) + if (UAMod /= UA_HGM) then + if ( EqualRealNos(AFInfo%Table(j)%UA_BL%St_sh, 0.0_ReKi) ) then + call SetErrStat(ErrID_Fatal, 'UA St_sh parameter must not be 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + if ( AFInfo%Table(j)%UA_BL%alpha1 > pi .or. AFInfo%Table(j)%UA_BL%alpha1 < -pi ) then + call SetErrStat(ErrID_Fatal, 'UA alpha1 parameter must be between -180 and 180 degrees in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + if ( AFInfo%Table(j)%UA_BL%alpha2 > pi .or. AFInfo%Table(j)%UA_BL%alpha2 < -pi ) then + call SetErrStat(ErrID_Fatal, 'UA alpha2 parameter must be between -180 and 180 degrees in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + if ( AFInfo%Table(j)%UA_BL%filtCutOff < 0 ) then + call SetErrStat(ErrID_Fatal, 'UA filtCutOff parameter must be greater than 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + end if + + ! variables used in all UA models: + if ( AFInfo%Table(j)%UA_BL%alpha0 > pi .or. AFInfo%Table(j)%UA_BL%alpha0 < -pi ) then + call SetErrStat(ErrID_Fatal, 'UA alpha0 parameter must be between -180 and 180 degrees in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + if ( AFInfo%Table(j)%UA_BL%T_f0 < 0 ) then + call SetErrStat(ErrID_Fatal, 'UA T_f0 parameter must be greater than 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + if ( AFInfo%Table(j)%UA_BL%T_p < 0 ) then + call SetErrStat(ErrID_Fatal, 'UA T_p parameter must be greater than 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + end if + + +!bjj: check that these SHOULD be used for UA_HGM (EB wasn't sure this was necessary) + if ( AFInfo%Table(j)%UA_BL%UACutout < 0.0_ReKi ) then + call SetErrStat(ErrID_Fatal, 'UA UACutout parameter must not be negative in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + end if + + + end do if (ErrStat >= AbortErrLev) return - ! check interpolated values: + if (UAMod /= UA_HGM) then + ! check interpolated values: - do j=2, AFInfo%NumTabs - if ( sign( 1.0_ReKi, AFInfo%Table(j)%UA_BL%St_sh) /= & - sign( 1.0_ReKi, AFInfo%Table(1)%UA_BL%St_sh) ) then - call SetErrStat(ErrID_Fatal, 'UA St_sh parameter (interpolated value) must not be 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) - exit - end if - end do + do j=2, AFInfo%NumTabs + if ( sign( 1.0_ReKi, AFInfo%Table(j)%UA_BL%St_sh) /= & + sign( 1.0_ReKi, AFInfo%Table(1)%UA_BL%St_sh) ) then + call SetErrStat(ErrID_Fatal, 'UA St_sh parameter (interpolated value) must not be 0 in "'//trim(afName)//'".', ErrStat, ErrMsg, RoutineName ) + exit + end if + end do + end if end if @@ -1123,7 +1258,8 @@ end subroutine UA_ValidateAFI !============================================================================== !> This routine checks if the UA parameters indicate that UA should not be used. (i.e., if C_nalpha = 0) !! This should be called at initialization. -subroutine UA_TurnOff_param(AFInfo, ErrStat, ErrMsg) +subroutine UA_TurnOff_param(p, AFInfo, ErrStat, ErrMsg) + type(UA_ParameterType), intent(in ) :: p ! The UA parameter data type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -1133,33 +1269,57 @@ subroutine UA_TurnOff_param(AFInfo, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = "" - ! unsteady aerodynamics will be turned off - do j=1, AFInfo%NumTabs - if ( EqualRealNos(AFInfo%Table(j)%UA_BL%C_nalpha, 0.0_ReKi) ) then - ErrStat = ErrID_Fatal - ErrMsg = 'C_nalpha is 0.' - return - end if - end do + if (p%UAMod == UA_HGM) then + ! unsteady aerodynamics will be turned off + do j=1, AFInfo%NumTabs + if ( EqualRealNos(AFInfo%Table(j)%UA_BL%C_lalpha, 0.0_ReKi) ) then + ErrStat = ErrID_Fatal + ErrMsg = 'C_lalpha is 0.' + return + end if + end do + + ! now check about interpolated values: + do j=2, AFInfo%NumTabs + if ( sign( 1.0_ReKi, AFInfo%Table(j)%UA_BL%C_lalpha) /= & + sign( 1.0_ReKi, AFInfo%Table(1)%UA_BL%C_lalpha) ) then + ErrStat = ErrID_Fatal + ErrMsg = 'C_lalpha (interpolated value) could be 0.' + return + end if + end do + + else + ! unsteady aerodynamics will be turned off + do j=1, AFInfo%NumTabs + if ( EqualRealNos(AFInfo%Table(j)%UA_BL%C_nalpha, 0.0_ReKi) ) then + ErrStat = ErrID_Fatal + ErrMsg = 'C_nalpha is 0.' + return + end if + end do - ! now check about interpolated values: - do j=2, AFInfo%NumTabs - if ( sign( 1.0_ReKi, AFInfo%Table(j)%UA_BL%C_nalpha) /= & - sign( 1.0_ReKi, AFInfo%Table(1)%UA_BL%C_nalpha) ) then - ErrStat = ErrID_Fatal - ErrMsg = 'C_nalpha (interpolated value) could be 0.' - return - end if - end do + ! now check about interpolated values: + do j=2, AFInfo%NumTabs + if ( sign( 1.0_ReKi, AFInfo%Table(j)%UA_BL%C_nalpha) /= & + sign( 1.0_ReKi, AFInfo%Table(1)%UA_BL%C_nalpha) ) then + ErrStat = ErrID_Fatal + ErrMsg = 'C_nalpha (interpolated value) could be 0.' + return + end if + end do + end if + end subroutine UA_TurnOff_param !============================================================================== !> This routine checks if the inputs to UA indicate that UA should not be used. !! This should be called before updating UA states (and maybe other places). -subroutine UA_TurnOff_input(AFInfo, u_UA, ErrStat, ErrMsg) +subroutine UA_TurnOff_input(p, AFInfo, u, ErrStat, ErrMsg) + type(UA_ParameterType), intent(in ) :: p ! UA parameters type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data - type(UA_InputType), intent(in ) :: u_UA ! UA input + type(UA_InputType), intent(in ) :: u ! UA input integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -1171,19 +1331,19 @@ subroutine UA_TurnOff_input(AFInfo, u_UA, ErrStat, ErrMsg) ErrMsg = "" ! check for zero relative velocity - if (EqualRealNos(u_UA%U, 0.0_ReKi) ) then + if (EqualRealNos(u%U, 0.0_ReKi) ) then ErrStat = ErrID_Fatal ErrMsg = 'zero relative velocity.' return end if - + ! check for high angle of attack (value larger than cutout specified in tables) - call AFI_ComputeUACoefs( AFInfo, u_UA%Re, u_UA%UserProp, UA_BL, ErrMsg, ErrStat ) + call AFI_ComputeUACoefs( AFInfo, u%Re, u%UserProp, UA_BL, ErrMsg, ErrStat ) if (ErrStat >= AbortErrLev) return ! put alpha in [-pi,pi] before checking its value - AoA = u_UA%alpha + AoA = u%alpha call Mpi2pi(AoA) if ( abs(AoA) >= UA_BL%UACutout ) then ! Is the angle of attack larger than the UA cut-out for this airfoil? @@ -1324,7 +1484,6 @@ subroutine UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrSt end if else ! Reattaching flow - if (.not. LESF ) then OtherState%sigma1(i,j) = 0.5_ReKi end if @@ -1332,7 +1491,7 @@ subroutine UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrSt if ( VRTX ) then ! Still shedding a vortex, i.e., the current vortex is still over the chord? OtherState%sigma1(i,j) = 0.25_ReKi end if - + if (Kafactor > 0.0_ReKi) then OtherState%sigma1(i,j) = 0.75_ReKi end if @@ -1429,7 +1588,6 @@ subroutine UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrSt xd%alphaf_minus1(i,j) = KC%alpha_f xd%Cn_v_minus1(i,j) = KC%Cn_v xd%C_V_minus1(i,j) = KC%C_V - OtherState%FirstPass(i,j) = .false. ! If we are currently tracking a vortex, or we are in the stall region, increment tau_V if (p%UAMod == UA_Gonzalez) then !Added specific logic for UAMod=UA_Gonzalez @@ -1469,17 +1627,20 @@ end subroutine UA_UpdateDiscOtherState !============================================================================== !============================================================================== - -!============================================================================== -subroutine UA_UpdateStates( i, j, u, p, xd, OtherState, AFInfo, m, ErrStat, ErrMsg ) +subroutine UA_UpdateStates( i, j, t, n, u, uTimes, p, x, xd, OtherState, AFInfo, m, ErrStat, ErrMsg ) ! Loose coupling routine for solving constraint states, integrating continuous states, and updating discrete states. ! Continuous, constraint, discrete, and other states are updated to values at t + Interval. !.............................................................................. integer(IntKi), intent(in ) :: i ! node index within a blade integer(IntKi), intent(in ) :: j ! blade index - type(UA_InputType), intent(in ) :: u ! Input at current timestep, t + REAL(DbKi), INTENT(IN ) :: t ! Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< Current simulation time step n = 0,1,... + type(UA_InputType), intent(in ) :: u(:) ! Input at current timestep, t and t+dt + real(DbKi), intent(in ) :: utimes(:) !< Times associated with u(:), in seconds type(UA_ParameterType), intent(in ) :: p ! Parameters + type(UA_ContinuousStateType), intent(inout) :: x ! Input: Continuous states at t; + ! Output: Continuous states at t + Interval type(UA_DiscreteStateType), intent(inout) :: xd ! Input: Discrete states at t; ! Output: Discrete states at t + Interval type(UA_OtherStateType), intent(inout) :: OtherState ! Input: Other states at t; @@ -1494,42 +1655,568 @@ subroutine UA_UpdateStates( i, j, u, p, xd, OtherState, AFInfo, m, ErrStat, ErrM character(ErrMsgLen) :: errMsg2 integer(IntKi) :: errStat2 character(*), parameter :: RoutineName = 'UA_UpdateStates' + type(UA_InputType) :: u_interp ! Input at current timestep, t and t+dt ! Initialize variables ErrStat = ErrID_None ! no error has occurred ErrMsg = "" + !BJJ: this seems to be the root cause of all sorts of numerical problems.... + + + if (p%UAMod == UA_HGM) then + + ! initialize states to steady-state values: + if (OtherState%FirstPass(i,j)) then + CALL UA_Input_ExtrapInterp( u, utimes, u_interp, t, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + call HGM_Steady( i, j, u_interp, p, x%element(i,j), AFInfo, ErrStat2, ErrMsg2 ) + end if + + + call UA_ABM4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + x%element(i,j)%x(4) = max( min( x%element(i,j)%x(4), 1.0_R8Ki ), 0.0_R8Ki ) + + ! these are angles that should not get too large, so I am fixing them here (should turn off UA if this exceeds reasonable numbers) + if (abs(x%element(i,j)%x(1)) > pi .or. abs(x%element(i,j)%x(2)) > pi) then + if (m%FirstWarn_UA) then + call SetErrStat(ErrID_Severe, "Divergent states in UA HGM model", ErrStat, ErrMsg, RoutineName ) + m%FirstWarn_UA = .false. + end if + + call Mpi2pi(x%element(i,j)%x(1)) + call Mpi2pi(x%element(i,j)%x(2)) + end if + + else + if (n<=0) return ! previous logic (before adding UA_HGM required n > 0 before UA_UpdateStates was called) + + CALL UA_Input_ExtrapInterp( u, utimes, u_interp, t, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + ! Update discrete states: +# ifdef DEBUG_v14 + call UA_UpdateDiscOtherState2( i, j, u_interp, p, xd, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) +# else + call UA_UpdateDiscOtherState( i, j, u_interp, p, xd, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) +# endif + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + end if + + OtherState%FirstPass(i,j) = .false. + +end subroutine UA_UpdateStates +!============================================================================== +!!---------------------------------------------------------------------------------------------------------------------------------- +!> routine to initialize the states based on inputs at t=0 +subroutine UA_InitStates_AllNodes( u, p, x, OtherState, UA_is_on, AFInfo, AFIndx ) + type(UA_InputType), intent(in ) :: u !< Inputs at t + type(UA_ParameterType), intent(in ) :: p !< Parameters + type(UA_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; + type(UA_OtherStateType), intent(inout) :: OtherState !< Other/logical states at t on input; at t+dt on output + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data + logical, intent(in) :: UA_is_on(:,:) + INTEGER(IntKi), intent(in) :: AFIndx(:,:) + + INTEGER(IntKi) :: i !< blade node counter + INTEGER(IntKi) :: j !< blade counter + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + + + !............................................................................................................................... + ! compute UA states at t=0 (with known inputs) + !............................................................................................................................... + if (p%UAMod == UA_HGM) then + + do j = 1,size(UA_is_on,2) ! blades + do i = 1,size(UA_is_on,1) ! nodes + + ! We only update the UnsteadyAero states if we have unsteady aero turned on for this node + if ( UA_is_on(i,j) .and. OtherState%FirstPass(i,j) ) then + + ! initialize states to steady-state values: + call HGM_Steady( i, j, u, p, x%element(i,j), AFInfo(AFIndx(i,j)), ErrStat2, ErrMsg2 ) + !call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + OtherState%FirstPass(i,j) = .false. + end if + + end do + end do + + end if + +end subroutine UA_InitStates_AllNodes +!============================================================================== +SUBROUTINE HGM_Steady( i, j, u, p, x, AFInfo, ErrStat, ErrMsg ) +! Routine to initialize the continuous states of the HGM model +!.................................................................................................................................. + + INTEGER(IntKi), INTENT(IN ) :: i !< blade node counter + INTEGER(IntKi), INTENT(IN ) :: j !< blade counter + TYPE(UA_InputType), INTENT(IN ) :: u ! Inputs at t + TYPE(UA_ParameterType), INTENT(IN ) :: p ! Parameters + TYPE(UA_ElementContinuousStateType), INTENT(INOUT) :: x ! Continuous states at t + type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + ! Local variables + + type(AFI_UA_BL_Type) :: BL_p ! potentially interpolated UA parameters + type(AFI_OutputType) :: AFI_Interp + character(ErrMsgLen) :: errMsg2 + integer(IntKi) :: errStat2 + character(*), parameter :: RoutineName = 'HGM_Steady' - m%iBladeNode = i; - m%iBlade = j + real(ReKi) :: Tu + real(ReKi) :: alphaE + real(ReKi) :: alphaF + real(ReKi) :: alpha_34 + - !BJJ: this seems to be the root cause of all sorts of numerical problems.... - IF (EqualRealNos(u%u, 0.0_ReKi) ) THEN - ErrStat = ErrID_Fatal - ErrMsg = 'UA_UpdateStates: U (air velocity magnitude relative to the airfoil) is zero.' - RETURN - END IF + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! Lookup values using Airfoil Info module + call AFI_ComputeUACoefs( AFInfo, u%Re, u%UserProp, BL_p, ErrMsg2, ErrStat2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + call Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) ! compute Tu, alpha_34, and alphaE + + + ! States + !x1: Downwash memory term 1 (rad) + !x2: Downwash memory term 2 (rad) + !x3: Clp', Lift coefficient with a time lag to the attached lift coeff + !x4: f'' , Final separation point function + + + ! Steady states + x%x(1) = BL_p%A1 * alpha_34 + x%x(2) = BL_p%A2 * alpha_34 + + alphaE = alpha_34 ! Eq. 12 (after substitute of x1 and x2 initializations) + x%x(3) = BL_p%c_lalpha * (alphaE-BL_p%alpha0) + + ! calculate x%x(4) = fs_aF = f_st(alphaF): + alphaF = x%x(3)/BL_p%c_lalpha + BL_p%alpha0 ! p. 13 + + call AFI_ComputeAirfoilCoefs( alphaF, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat, ErrMsg) + x%x(4) = AFI_interp%f_st + +end subroutine HGM_Steady +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine UA_CalcContStateDeriv( i, j, t, u, p, x, OtherState, AFInfo, m, dxdt, ErrStat, ErrMsg ) +! Tight coupling routine for computing derivatives of continuous states +!.................................................................................................................................. + + INTEGER(IntKi), INTENT(IN ) :: i !< blade node counter + INTEGER(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t ! Current simulation time in seconds + TYPE(UA_InputType), INTENT(IN ) :: u ! Inputs at t + TYPE(UA_ParameterType), INTENT(IN ) :: p ! Parameters + TYPE(UA_ElementContinuousStateType), INTENT(IN ) :: x ! Continuous states at t + TYPE(UA_OtherStateType), INTENT(IN ) :: OtherState ! Other states at t + type(UA_MiscVarType), intent(inout) :: m ! Misc/optimization variables + type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data + TYPE(UA_ElementContinuousStateType), INTENT( OUT) :: dxdt ! Continuous state derivatives at t + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + ! Local variables + + type(AFI_UA_BL_Type) :: BL_p ! potentially interpolated UA parameters + type(AFI_OutputType) :: AFI_Interp + character(ErrMsgLen) :: errMsg2 + integer(IntKi) :: errStat2 + character(*), parameter :: RoutineName = 'UA_CalcContStateDeriv' + + real(ReKi) :: Tu + real(ReKi) :: alphaE + real(ReKi) :: alphaF + real(ReKi) :: Clp + real(R8Ki) :: x4 + real(ReKi) :: alpha_34 + real(ReKi), parameter :: U_dot = 0.0_ReKi ! at some point we may add this term + + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! Lookup values using Airfoil Info module + call AFI_ComputeUACoefs( AFInfo, u%Re, u%UserProp, BL_p, ErrMsg2, ErrStat2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + call Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) ! compute Tu, alpha_34, and alphaE + + Clp = BL_p%c_lalpha * (alphaE - BL_p%alpha0) + pi * Tu * u%omega ! Eq. 13 + + ! calculate fs_aF (stored in AFI_interp%f_st): + + !note: BL_p%c_lalpha cannot be zero. UA is turned off at initialization if this occurs. + alphaF = x%x(3)/BL_p%c_lalpha + BL_p%alpha0 ! p. 13 + call AFI_ComputeAirfoilCoefs( alphaF, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return - ! Update discrete states: -#ifdef DEBUG_v14 - call UA_UpdateDiscOtherState2( i, j, u, p, xd, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) -#else - call UA_UpdateDiscOtherState( i, j, u, p, xd, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) -#endif - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! States + !x1: Downwash memory term 1 (rad) + !x2: Downwash memory term 2 (rad) + !x3: Clp', Lift coefficient with a time lag to the attached lift coeff + !x4: f'' , Final separation point function + + ! Constraining x4 between 0 and 1 increases numerical stability (should be done elsewhere, but we'll double check here in case there were perturbations on the state value) + x4 = max( min( x%x(4), 1.0_R8Ki ), 0.0_R8Ki ) + + dxdt%x(1) = -1.0_R8Ki / Tu * (BL_p%b1 + p%c(i,j) * U_dot/(2*u%u**2)) * x%x(1) + BL_p%b1 * BL_p%A1 / Tu * alpha_34 + dxdt%x(2) = -1.0_R8Ki / Tu * (BL_p%b2 + p%c(i,j) * U_dot/(2*u%u**2)) * x%x(2) + BL_p%b2 * BL_p%A2 / Tu * alpha_34 + dxdt%x(3) = -1.0_R8Ki / BL_p%T_p * x%x(3) + 1.0_ReKi / BL_p%T_p * Clp + dxdt%x(4) = -1.0_R8Ki / BL_p%T_f0 * x4 + 1.0_ReKi / BL_p%T_f0 * AFI_interp%f_st + +END SUBROUTINE UA_CalcContStateDeriv +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) + INTEGER(IntKi), INTENT(IN ) :: i !< blade node counter + INTEGER(IntKi), INTENT(IN ) :: j !< blade counter + TYPE(UA_InputType), INTENT(IN ) :: u ! Inputs at t + TYPE(UA_ParameterType), INTENT(IN ) :: p ! Parameters + TYPE(UA_ElementContinuousStateType), INTENT(IN ) :: x ! Continuous states at t + TYPE(AFI_UA_BL_Type), INTENT(IN ) :: BL_p ! potentially interpolated UA parameters + + REAL(ReKi), INTENT( OUT) :: alpha_34 + REAL(ReKi), INTENT( OUT) :: Tu + REAL(ReKi), INTENT( OUT) :: alphaE + + ! Local variables + real(ReKi) :: vx_34 + + + ! Variables derived from inputs + !u%u = U_ac = TwoNorm(u%v_ac) ! page 4 definitions + + Tu = p%c(i,j) / (2.0_ReKi* u%u) ! Eq. 23 + Tu = min(Tu, 50.0_ReKi) ! ensure the time constant doesn't exceed 50 s. + Tu = max(Tu, 0.001_ReKi) ! ensure the time constant doesn't get too small, either. + + vx_34 = u%v_ac(1) - u%omega * 0.5_ReKi*p%c(i,j) ! Eq. 1 + alpha_34 = atan2(vx_34, u%v_ac(2) ) ! page 5 definitions + + ! Variables derived from states + alphaE = alpha_34*(1.0_ReKi - BL_p%A1 - BL_p%A2) + x%x(1) + x%x(2) ! Eq. 12 + call MPi2Pi(alphaE) + +END SUBROUTINE Get_HGM_constants +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Runge-Kutta Method (RK4) for numerically integrating ordinary differential equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! Define constants k1, k2, k3, and k4 as +!! k1 = dt * f(t , x_t ) +!! k2 = dt * f(t + dt/2 , x_t + k1/2 ) +!! k3 = dt * f(t + dt/2 , x_t + k2/2 ), and +!! k4 = dt * f(t + dt , x_t + k3 ). +!! Then the continuous states at t = t + dt are +!! x_(t+dt) = x_t + k1/6 + k2/3 + k3/3 + k4/6 + O(dt^5) +!! +!! For details, see: +!! Press, W. H.; Flannery, B. P.; Teukolsky, S. A.; and Vetterling, W. T. "Runge-Kutta Method" and "Adaptive Step Size Control for +!! Runge-Kutta." Sections 16.1 and 16.2 in Numerical Recipes in FORTRAN: The Art of Scientific Computing, 2nd ed. Cambridge, England: +!! Cambridge University Press, pp. 704-716, 1992. +SUBROUTINE UA_RK4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(UA_InputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(UA_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(UA_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(UA_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo ! The airfoil parameter data + TYPE(UA_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + + TYPE(UA_ElementContinuousStateType) :: k1 ! RK4 constant; see above + TYPE(UA_ElementContinuousStateType) :: k2 ! RK4 constant; see above + TYPE(UA_ElementContinuousStateType) :: k3 ! RK4 constant; see above + TYPE(UA_ElementContinuousStateType) :: k4 ! RK4 constant; see above + TYPE(UA_ElementContinuousStateType) :: x_tmp ! Holds temporary modification to x + TYPE(UA_InputType) :: u_interp ! interpolated value of inputs + + REAL(DbKi) :: TPlusHalfDt + REAL(DbKi) :: TPlusDt + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'UA_RK4' + + + !NOTE: the error handling here assumes that we do not have any allocatable data in the inputs (u_interp) to be concerned with. + ! Also, We assume that if there is going to be an error in UA_CalcContStateDeriv, it will happen only on the first call + ! to the routine. + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! interpolate u to find u_interp = u(t) + CALL UA_Input_ExtrapInterp( u, utimes, u_interp, t, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + x_tmp = x%element(i,j) + + ! find xdot at t + CALL UA_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, AFInfo, m, k1, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + k1%x = p%dt * k1%x + + x_tmp%x = x%element(i,j)%x + 0.5 * k1%x + + ! interpolate u to find u_interp = u(t + dt/2) + TPlusHalfDt = t + 0.5_DbKi*p%dt + CALL UA_Input_ExtrapInterp(u, utimes, u_interp, TPlusHalfDt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! find xdot at t + dt/2 + CALL UA_CalcContStateDeriv( i, j, TPlusHalfDt, u_interp, p, x_tmp, OtherState, AFInfo, m, k2, ErrStat2, ErrMsg2 ) + + k2%x = p%dt * k2%x + + x_tmp%x = x%element(i,j)%x + 0.5 * k2%x + + ! find xdot at t + dt/2 (note x_tmp has changed) + CALL UA_CalcContStateDeriv( i, j, TPlusHalfDt, u_interp, p, x_tmp, OtherState, AFInfo, m, k3, ErrStat2, ErrMsg2 ) + + k3%x = p%dt * k3%x + + x_tmp%x = x%element(i,j)%x + k3%x + + ! interpolate u to find u_interp = u(t + dt) + TPlusDt = t + p%dt + CALL UA_Input_ExtrapInterp(u, utimes, u_interp, TPlusDt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! find xdot at t + dt + CALL UA_CalcContStateDeriv( i, j, TPlusDt, u_interp, p, x_tmp, OtherState, AFInfo, m, k4, ErrStat2, ErrMsg2 ) + + k4%x = p%dt * k4%x + + x%element(i,j)%x = x%element(i,j)%x + ( k1%x + 2. * k2%x + 2. * k3%x + k4%x ) / 6. + +END SUBROUTINE UA_RK4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Adams-Bashforth Method (RK4) for numerically integrating ordinary differential +!! equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! +!! x(t+dt) = x(t) + (dt / 24.) * ( 55.*f(t,x) - 59.*f(t-dt,x) + 37.*f(t-2.*dt,x) - 9.*f(t-3.*dt,x) ) +!! +!! See, e.g., +!! http://en.wikipedia.org/wiki/Linear_multistep_method +!! +!! or +!! +!! K. E. Atkinson, "An Introduction to Numerical Analysis", 1989, John Wiley & Sons, Inc, Second Edition. +SUBROUTINE UA_AB4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(UA_InputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(UA_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(UA_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(UA_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo ! The airfoil parameter data + TYPE(UA_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + + ! local variables + TYPE(UA_InputType) :: u_interp + TYPE(UA_ElementContinuousStateType) :: x_tmp + TYPE(UA_ElementContinuousStateType) :: xdot + + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'UA_AB4' + + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + if (OtherState%n(i,j) < n) then + + OtherState%n(i,j) = n + + OtherState%xdot(4)%element(i,j) = OtherState%xdot(3)%element(i,j) + OtherState%xdot(3)%element(i,j) = OtherState%xdot(2)%element(i,j) + OtherState%xdot(2)%element(i,j) = OtherState%xdot(1)%element(i,j) + + elseif (OtherState%n(i,j) > n) then + + CALL SetErrStat(ErrID_Fatal,'Backing up in time is not supported with a multistep method.',ErrStat,ErrMsg,RoutineName) + RETURN + + endif + + + ! need xdot at t, get inputs at t + CALL UA_Input_ExtrapInterp(u, utimes, u_interp, t, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + x_tmp = x%element(i,j) + + CALL UA_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, AFInfo, m, xdot, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! make sure OtherState%xdot( 1 ) is most up to date: + OtherState%xdot( 1 )%element(i,j) = xdot + + if (n <= 2) then + + CALL UA_RK4(i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + else + x%element(i,j)%x = x%element(i,j)%x + p%DT/24. * ( 55.*OtherState%xdot(1)%element(i,j)%x - 59.*OtherState%xdot(2)%element(i,j)%x & + + 37.*OtherState%xdot(3)%element(i,j)%x - 9.*OtherState%xdot(4)%element(i,j)%x ) + + + endif + + +END SUBROUTINE UA_AB4 +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements the fourth-order Adams-Bashforth-Moulton Method (RK4) for numerically integrating ordinary +!! differential equations: +!! +!! Let f(t, x) = xdot denote the time (t) derivative of the continuous states (x). +!! +!! Adams-Bashforth Predictor: \n +!! x^p(t+dt) = x(t) + (dt / 24.) * ( 55.*f(t,x) - 59.*f(t-dt,x) + 37.*f(t-2.*dt,x) - 9.*f(t-3.*dt,x) ) +!! +!! Adams-Moulton Corrector: \n +!! x(t+dt) = x(t) + (dt / 24.) * ( 9.*f(t+dt,x^p) + 19.*f(t,x) - 5.*f(t-dt,x) + 1.*f(t-2.*dt,x) ) +!! +!! See, e.g., +!! http://en.wikipedia.org/wiki/Linear_multistep_method +!! +!! or +!! +!! K. E. Atkinson, "An Introduction to Numerical Analysis", 1989, John Wiley & Sons, Inc, Second Edition. +SUBROUTINE UA_ABM4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(UA_InputType), INTENT(IN ) :: u(:) !< Inputs at utimes + REAL(DbKi), INTENT(IN ) :: utimes(:) !< times of input + TYPE(UA_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(UA_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(UA_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo ! The airfoil parameter data + TYPE(UA_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + + TYPE(UA_InputType) :: u_interp ! Inputs at t + TYPE(UA_ElementContinuousStateType) :: x_in ! Continuous states at t + TYPE(UA_ElementContinuousStateType) :: xdot_pred ! Derivative of continuous states at t + + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'UA_ABM4' + + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + ! save copy of x(t): + x_in = x%element(i,j) + + ! predict: (note that we are overwritting x%element(i,j) here): + CALL UA_AB4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + if (n > 2_IntKi) then + + ! correct: + + CALL UA_Input_ExtrapInterp(u, utimes, u_interp, t + p%dt, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + CALL UA_CalcContStateDeriv( i, j, t + p%dt, u_interp, p, x%element(i,j), OtherState, AFInfo, m, xdot_pred, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + + x%element(i,j)%x = x_in%x + p%DT/24. * ( 9. * xdot_pred%x + 19. * OtherState%xdot(1)%element(i,j)%x & + - 5. * OtherState%xdot(2)%element(i,j)%x & + + 1. * OtherState%xdot(3)%element(i,j)%x ) + + endif + +END SUBROUTINE UA_ABM4 +!---------------------------------------------------------------------------------------------------------------------------------- +!---------------------------------------------------------------------------------------------------------------------------------- + -end subroutine UA_UpdateStates -!============================================================================== !============================================================================== -subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg ) +subroutine UA_CalcOutput( i, j, u, p, x, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg ) ! Routine for computing outputs, used in both loose and tight coupling. !.............................................................................. + integer(IntKi), intent(in ) :: i ! node index within a blade + integer(IntKi), intent(in ) :: j ! blade index type(UA_InputType), intent(in ) :: u ! Inputs at Time type(UA_ParameterType), intent(in ) :: p ! Parameters + type(UA_ContinuousStateType), intent(in ) :: x ! Continuous states at Time type(UA_DiscreteStateType), intent(in ) :: xd ! Discrete states at Time type(UA_OtherStateType), intent(in ) :: OtherState ! Other states at Time type(AFI_ParameterType), intent(in ) :: AFInfo ! The airfoil parameter data @@ -1547,13 +2234,25 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg type(AFI_UA_BL_Type) :: BL_p ! airfoil values computed in Kelvin Chain type(UA_KelvinChainType) :: KC ! values computed in Kelvin Chain - real(ReKi) :: Cm_FS + real(ReKi) :: Cm_FS real(ReKi) :: Cc_FS real(ReKi) :: Cm_alpha_nc real(ReKi) :: M, f, k2_hat real(ReKi) :: Cm_v, alpha_prime_f real(ReKi) :: x_cp_hat ! center-of-pressure distance from LE in chord fraction real(ReKi) :: Cm_common ! + + ! for UA_HGM + real(ReKi) :: alphaE + real(ReKi) :: Tu + real(ReKi) :: alpha_34 + real(ReKi) :: fs_aE + real(ReKi) :: cl_fs + real(ReKi) :: x4 + real(ReKi) :: delta_c_df_primeprime + real(ReKi), parameter :: delta_c_mf_primeprime = 0.0_ReKi + TYPE(UA_ElementContinuousStateType) :: x_in ! Continuous states at t + type(AFI_OutputType) :: AFI_interp @@ -1569,7 +2268,7 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg AFI_interp%Cm = 0.0_ReKi ! value will be output if not computed below alpha_prime_f = 0.0_ReKi ! value will be output if not computed below - if (OtherState%FirstPass(misc%iBladeNode, misc%iBlade) .or. EqualRealNos(u%U, 0.0_ReKi) ) then ! note: if u%U is = in UpdateStates, BEMT shuts off UA; however, it could still be called with u%U=0 here + if ( (OtherState%FirstPass(i, j) .and. p%UAMod /= UA_HGM) .or. EqualRealNos(u%U, 0.0_ReKi) ) then ! note: if u%U is = 0 in UpdateStates, BEMT shuts off UA; however, it could still be called with u%U=TwoNorm(u%v_ac)=0 here call AFI_ComputeAirfoilCoefs( u%alpha, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1597,7 +2296,52 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg KC%T_f = 0.0_ReKi KC%T_V = 0.0_ReKi KC%alpha_filt_cur = 0.0_ReKi - KC%ds = 2.0_ReKi*u%U*p%dt/p%c(misc%iBladeNode, misc%iBlade) + KC%ds = 2.0_ReKi*u%U*p%dt/p%c(i, j) + + alphaE = 0.0 + Tu = 0.0 + alpha_34 = 0.0 + cl_fs = 0.0 + fs_aE = 0.0 + + elseif (p%UAMod == UA_HGM) then + x_in = x%element(i,j) + + if (OtherState%FirstPass(i,j)) then + call HGM_Steady( i, j, u, p, x_in, AFInfo, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + call AFI_ComputeUACoefs( AFInfo, u%Re, u%UserProp, BL_p, ErrMsg2, ErrStat2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + call Get_HGM_constants(i, j, p, u, x_in, BL_p, Tu, alpha_34, alphaE) ! compute Tu, alpha_34, and alphaE + + call AFI_ComputeAirfoilCoefs( alphaE, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! calculate fs_aE and cl_fs: + cl_fs = AFI_interp%cl_fs + fs_aE = AFI_interp%f_st + + ! Constraining x4 between 0 and 1 increases numerical stability (should be done elsewhere, but we'll double check here in case there were perturbations on the state value) + x4 = max( min( x_in%x(4), 1.0_R8Ki ), 0.0_R8Ki ) + + delta_c_df_primeprime = 0.5_ReKi * (sqrt(fs_aE) - sqrt(x4)) - 0.25_ReKi * (fs_aE - x4) + +! bjj: do we need to check that u%alpha is between -pi and + pi? + y%Cl = x4 * (alphaE - BL_p%alpha0) * BL_p%c_lalpha + (1.0_ReKi - x4) * cl_fs + pi * Tu * u%omega ! Eq. 78 + y%Cd = AFI_interp%Cd + (u%alpha - alphaE) * y%Cl + (AFI_interp%Cd - BL_p%Cd0) * delta_c_df_primeprime ! Eq. 79 + + if (AFInfo%ColCm == 0) then ! we don't have a cm column, so make everything 0 + y%Cm = 0.0_ReKi + else + y%Cm = AFI_interp%Cm + y%Cl * delta_c_mf_primeprime - piBy2 * Tu * u%omega ! Eq. 80 + end if + + y%Cn = y%Cl*cos(u%alpha) + y%Cd*sin(u%alpha) + y%Cc = y%Cl*sin(u%alpha) - y%Cd*cos(u%alpha) else @@ -1607,7 +2351,7 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return - call ComputeKelvinChain( misc%iBladeNode, misc%iBlade, u, p, xd, OtherState, misc, AFInfo, KC, BL_p, ErrStat2, ErrMsg2 ) + call ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_p, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -1615,7 +2359,7 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg ! Cn !............................. ! Eqn 1.53 or 1.53b depending on UAMod - if (xd%tau_v(misc%iBladeNode, misc%iBlade) > 0.0) then + if (xd%tau_v(i, j) > 0.0) then y%Cn= KC%Cn_FS + KC%Cn_v ! Eqn 1.53 else y%Cn= KC%Cn_FS @@ -1636,9 +2380,9 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg if ( p%UAMod == UA_MinnemaPierce ) then #ifdef TEST_THEORY - y%Cc = Cc_FS + KC%Cn_v*tan(KC%alpha_e)*(1-xd%tau_v(misc%iBladeNode, misc%iBlade)/(BL_p%T_VL)) ! Eqn 1.55 with Eqn. 1.40 + y%Cc = Cc_FS + KC%Cn_v*tan(KC%alpha_e)*(1-xd%tau_v(i, j)/(BL_p%T_VL)) ! Eqn 1.55 with Eqn. 1.40 #else - y%Cc = Cc_FS + KC%Cn_v* KC%alpha_e *(1.0_ReKi-xd%tau_v(misc%iBladeNode, misc%iBlade)/(BL_p%T_VL)) ! Eqn 1.55 with approximation of tan(KC%alpha_e)=KC%alpha_e and Eqn. 1.40 substitution + y%Cc = Cc_FS + KC%Cn_v* KC%alpha_e *(1.0_ReKi-xd%tau_v(i, j)/(BL_p%T_VL)) ! Eqn 1.55 with approximation of tan(KC%alpha_e)=KC%alpha_e and Eqn. 1.40 substitution #endif elseif ( p%UAMod == UA_Gonzalez ) then @@ -1733,8 +2477,8 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg end if - Cm_v = -BL_p%x_cp_bar*( 1.0_ReKi - cos( pi*xd%tau_v(misc%iBladeNode, misc%iBlade)/BL_p%T_VL ) )*KC%Cn_v ! Eqn 1.57 - if (p%UAMod == UA_Gonzalez .and. xd%tau_v(misc%iBladeNode, misc%iBlade) <= 0.0 ) then !Added specific logic for UAMod=UA_Gonzalez + Cm_v = -BL_p%x_cp_bar*( 1.0_ReKi - cos( pi*xd%tau_v(i, j)/BL_p%T_VL ) )*KC%Cn_v ! Eqn 1.57 + if (p%UAMod == UA_Gonzalez .and. xd%tau_v(i, j) <= 0.0 ) then !Added specific logic for UAMod=UA_Gonzalez y%Cm = Cm_FS else y%Cm = Cm_FS + Cm_v ! Eqn 1.58, Eqn 1.59, and Eqn 1.60 @@ -1744,64 +2488,85 @@ subroutine UA_CalcOutput( u, p, xd, OtherState, AFInfo, y, misc, ErrStat, ErrMsg end if #ifdef UA_OUTS - iOffset = (misc%iBladeNode-1)*p%NumOuts + (misc%iBlade-1)*p%nNodesPerBlade*p%NumOuts + iOffset = (i-1)*p%NumOuts + (j-1)*p%nNodesPerBlade*p%NumOuts if (allocated(y%WriteOutput)) then !bjj: because BEMT uses local variables for UA output, y%WriteOutput is not necessarially allocated. Need to figure out a better solution. - y%WriteOutput(iOffset+ 1) = KC%alpha_filt_cur*R2D - y%WriteOutput(iOffset+ 2) = u%U - y%WriteOutput(iOffset+ 3) = y%Cn - y%WriteOutput(iOffset+ 4) = y%Cc - y%WriteOutput(iOffset+ 5) = y%Cl - y%WriteOutput(iOffset+ 6) = y%Cd - y%WriteOutput(iOffset+ 7) = y%Cm - y%WriteOutput(iOffset+ 8) = KC%Cn_alpha_q_circ ! CNCP in ADv14 - y%WriteOutput(iOffset+ 9) = KC%Cn_alpha_q_nc ! CNIQ in ADv14 - y%WriteOutput(iOffset+10) = KC%Cn_pot - y%WriteOutput(iOffset+11) = KC%Dp - y%WriteOutput(iOffset+12) = KC%Cn_prime - y%WriteOutput(iOffset+13) = KC%fprime - y%WriteOutput(iOffset+14) = KC%Df - y%WriteOutput(iOffset+15) = KC%Cn_V - y%WriteOutput(iOffset+16) = xd%tau_v(misc%iBladeNode, misc%iBlade) - - if ( misc%LESF(misc%iBladeNode, misc%iBlade) ) then ! BEDSEP in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. - y%WriteOutput(iOffset+17) = 1.0_ReKi - else - y%WriteOutput(iOffset+17) = 0.0_ReKi - end if - - if ( misc%TESF(misc%iBladeNode, misc%iBlade) ) then !SHIFT in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. - y%WriteOutput(iOffset+18) = 1.0_ReKi - else - y%WriteOutput(iOffset+18) = 0.0_ReKi - end if - if ( misc%VRTX(misc%iBladeNode, misc%iBlade) ) then ! VOR in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. - y%WriteOutput(iOffset+19) = 1.0_ReKi + + y%WriteOutput(iOffset+ 2) = u%U + y%WriteOutput(iOffset+ 3) = y%Cn + y%WriteOutput(iOffset+ 4) = y%Cc + y%WriteOutput(iOffset+ 5) = y%Cl + y%WriteOutput(iOffset+ 6) = y%Cd + y%WriteOutput(iOffset+ 7) = y%Cm + + if (p%UAMod == UA_HGM) then + + y%WriteOutput(iOffset+ 1) = u%alpha*R2D + + y%WriteOutput(iOffset+ 8) = u%omega*R2D + y%WriteOutput(iOffset+ 9) = alphaE*R2D + y%WriteOutput(iOffset+10) = Tu + y%WriteOutput(iOffset+11) = alpha_34*R2D + y%WriteOutput(iOffset+12) = cl_fs + y%WriteOutput(iOffset+13) = fs_aE + + y%WriteOutput(iOffset+14) = x%element(i,j)%x(1) + y%WriteOutput(iOffset+15) = x%element(i,j)%x(2) + y%WriteOutput(iOffset+16) = x%element(i,j)%x(3) + y%WriteOutput(iOffset+17) = x%element(i,j)%x(4) + else - y%WriteOutput(iOffset+19) = 0.0_ReKi + y%WriteOutput(iOffset+ 1) = KC%alpha_filt_cur*R2D + + y%WriteOutput(iOffset+ 8) = KC%Cn_alpha_q_circ ! CNCP in ADv14 + y%WriteOutput(iOffset+ 9) = KC%Cn_alpha_q_nc ! CNIQ in ADv14 + y%WriteOutput(iOffset+10) = KC%Cn_pot + y%WriteOutput(iOffset+11) = KC%Dp + y%WriteOutput(iOffset+12) = KC%Cn_prime + y%WriteOutput(iOffset+13) = KC%fprime + y%WriteOutput(iOffset+14) = KC%Df + y%WriteOutput(iOffset+15) = KC%Cn_V + y%WriteOutput(iOffset+16) = xd%tau_v(i, j) + + if ( misc%LESF(i, j) ) then ! BEDSEP in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. + y%WriteOutput(iOffset+17) = 1.0_ReKi + else + y%WriteOutput(iOffset+17) = 0.0_ReKi + end if + + if ( misc%TESF(i, j) ) then !SHIFT in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. + y%WriteOutput(iOffset+18) = 1.0_ReKi + else + y%WriteOutput(iOffset+18) = 0.0_ReKi + end if + if ( misc%VRTX(i, j) ) then ! VOR in v14 !bjj: note that this output is calculated in UpdateDiscState, so it may be out of sync here. + y%WriteOutput(iOffset+19) = 1.0_ReKi + else + y%WriteOutput(iOffset+19) = 0.0_ReKi + end if + y%WriteOutput(iOffset+20) = KC%C_V + y%WriteOutput(iOffset+21) = Cm_alpha_nc + y%WriteOutput(iOffset+22) = KC%Cm_q_nc + y%WriteOutput(iOffset+23) = Cm_v + y%WriteOutput(iOffset+24) = alpha_prime_f + y%WriteOutput(iOffset+25) = KC%Dalphaf + y%WriteOutput(iOffset+26) = AFI_interp%Cm + y%WriteOutput(iOffset+27) = KC%T_f + y%WriteOutput(iOffset+28) = KC%T_V + y%WriteOutput(iOffset+29) = KC%ds ! Eqn 1.51 (tau_v) + y%WriteOutput(iOffset+30) = KC%T_alpha + y%WriteOutput(iOffset+31) = KC%T_q + y%WriteOutput(iOffset+32) = KC%k_alpha + y%WriteOutput(iOffset+33) = KC%k_q + y%WriteOutput(iOffset+34) = KC%alpha_e + y%WriteOutput(iOffset+35) = KC%X1 + y%WriteOutput(iOffset+36) = KC%X2 + y%WriteOutput(iOffset+37) = KC%cn_q_nc + y%WriteOutput(iOffset+38) = KC%alpha_f + y%WriteOutput(iOffset+39) = KC%fprimeprime + y%WriteOutput(iOffset+40) = OtherState%sigma1(i, j) + y%WriteOutput(iOffset+41) = OtherState%sigma3(i, j) + y%WriteOutput(iOffset+42) = misc%T_sh(i, j) end if - y%WriteOutput(iOffset+20) = KC%C_V - y%WriteOutput(iOffset+21) = Cm_alpha_nc - y%WriteOutput(iOffset+22) = KC%Cm_q_nc - y%WriteOutput(iOffset+23) = Cm_v - y%WriteOutput(iOffset+24) = alpha_prime_f - y%WriteOutput(iOffset+25) = KC%Dalphaf - y%WriteOutput(iOffset+26) = AFI_interp%Cm - y%WriteOutput(iOffset+27) = KC%T_f - y%WriteOutput(iOffset+28) = KC%T_V - y%WriteOutput(iOffset+29) = KC%ds ! Eqn 1.51 (tau_v) - y%WriteOutput(iOffset+30) = KC%T_alpha - y%WriteOutput(iOffset+31) = KC%T_q - y%WriteOutput(iOffset+32) = KC%k_alpha - y%WriteOutput(iOffset+33) = KC%k_q - y%WriteOutput(iOffset+34) = KC%alpha_e - y%WriteOutput(iOffset+35) = KC%X1 - y%WriteOutput(iOffset+36) = KC%X2 - y%WriteOutput(iOffset+37) = KC%cn_q_nc - y%WriteOutput(iOffset+38) = KC%alpha_f - y%WriteOutput(iOffset+39) = KC%fprimeprime - y%WriteOutput(iOffset+40) = OtherState%sigma1(misc%iBladeNode, misc%iBlade) - y%WriteOutput(iOffset+41) = OtherState%sigma3(misc%iBladeNode, misc%iBlade) - y%WriteOutput(iOffset+42) = misc%T_sh(misc%iBladeNode, misc%iBlade) end if #endif diff --git a/modules/aerodyn/src/UnsteadyAero_Driver.f90 b/modules/aerodyn/src/UnsteadyAero_Driver.f90 index 3ead18584c..e544a7850c 100644 --- a/modules/aerodyn/src/UnsteadyAero_Driver.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Driver.f90 @@ -41,20 +41,21 @@ program UnsteadyAero_Driver ! Variables - integer(IntKi), parameter :: NumInp = 1 ! Number of inputs sent to HydroDyn_UpdateStates + integer(IntKi), parameter :: NumInp = 2 ! Number of inputs sent to UA_UpdateStates (must be at least 2) - real(DbKi) :: dt, t - integer :: i, j, k, n + real(DbKi) :: dt, t, uTimes(NumInp) + integer :: i, j, k, n, iu type(UA_InitInputType) :: InitInData ! Input data for initialization type(UA_InitOutputType) :: InitOutData ! Output data from initialization + type(UA_ContinuousStateType) :: x ! Continuous states type(UA_DiscreteStateType) :: xd ! Discrete states type(UA_OtherStateType) :: OtherState ! Other/optimization states type(UA_MiscVarType) :: m ! Misc/optimization variables type(UA_ParameterType) :: p ! Parameters type(UA_InputType) :: u(NumInp) ! System inputs type(UA_OutputType) :: y ! System outputs - integer(IntKi) :: ErrStat, errStat2 ! Status of error message - character(ErrMsgLen) :: ErrMsg, errMsg2 ! Error message if ErrStat /= ErrID_None + integer(IntKi) :: ErrStat ! Status of error message + character(ErrMsgLen) :: ErrMsg ! Error message if ErrStat /= ErrID_None integer, parameter :: NumAFfiles = 1 character(1024) :: afNames(NumAFfiles) @@ -70,7 +71,9 @@ program UnsteadyAero_Driver character(*), parameter :: RoutineName = 'UnsteadyAero_Driver' real(DbKi), allocatable :: timeArr(:) real(ReKi), allocatable :: AOAarr(:) - real(ReKi), allocatable :: Uarr(:) !RRD + real(ReKi), allocatable :: Uarr(:) + real(ReKi), allocatable :: OmegaArr(:) + CHARACTER(200) :: git_commit TYPE(ProgDesc), PARAMETER :: version = ProgDesc( 'UnsteadyAero Driver', '', '' ) ! The version number of this program. ! Initialize the NWTC library @@ -134,10 +137,9 @@ program UnsteadyAero_Driver InitInData%Flookup = .FALSE. InitInData%a_s = 340.29 ! m/s InitInData%c(1,1) = 1.0 + dvrInitInp%InflowVel = 30.0 ! m/s dvrInitInp%Re = 75 ! million - dvrInitInp%UAMod = 1 - dvrInitInp%Flookup = .FALSE. dvrInitInp%AirFoil1 = './OSU075_FAST.txt' dvrInitInp%SimMod = 1 dvrInitInp%NCycles = 3.0 @@ -153,28 +155,27 @@ program UnsteadyAero_Driver if ( dvrInitInp%SimMod == 1 ) then ! Using the frequency and NCycles, determine how long the simulation needs to run simTime = dvrInitInp%NCycles/dvrInitInp%Frequency - nSimSteps = dvrInitInp%StepsPerCycle*dvrInitInp%NCycles + nSimSteps = dvrInitInp%StepsPerCycle*dvrInitInp%NCycles ! we could add 1 here to make this a complete cycle dt = simTime / nSimSteps else ! Read time-series data file with a 1 line header and then each row contains time-step data with 4, white-space-separated columns - ! time Angle-fo-attack - call ReadTimeSeriesData( dvrInitInp%InputsFile, nSimSteps, timeArr, AOAarr, Uarr, errStat, errMsg ) + ! time, Angle-of-attack, Vrel, omega + call ReadTimeSeriesData( dvrInitInp%InputsFile, nSimSteps, timeArr, AOAarr, Uarr, OmegaArr, errStat, errMsg ) call checkError() - dt = (timeArr(nSimSteps) - timeArr(1)) / nSimSteps - end if + dt = (timeArr(nSimSteps) - timeArr(1)) / (nSimSteps-1) + nSimSteps = nSimSteps-NumInp + 1 + end if - ! All nodes/blades are using the same 2D airfoil - afNames(1) = dvrInitInp%AirFoil1 - AFIndx(1,1) = 1 - - ! Initialize the Airfoil Info Params - call Init_AFI( NumAFfiles, afNames, InitInData%Flookup, dvrInitInp%UseCm, AFI_Params, errStat, errMsg ) - call checkError() - ! Initialize UnsteadyAero - call UA_Init( InitInData, u(1), p, xd, OtherState, y, m, dt, InitOutData, errStat, errMsg ) + call UA_Init( InitInData, u(1), p, x, xd, OtherState, y, m, dt, InitOutData, errStat, errMsg ) + call checkError() + + ! Initialize the Airfoil Info Params + afNames(1) = dvrInitInp%AirFoil1 ! All nodes/blades are using the same 2D airfoil + AFIndx(1,1) = 1 + call Init_AFI( p, NumAFfiles, afNames, dvrInitInp%UseCm, AFI_Params, errStat, errMsg ) call checkError() if (p%NumOuts > 0) then @@ -186,7 +187,6 @@ program UnsteadyAero_Driver call OpenFOutFile ( unOutFile, outFileName, errStat, errMsg ) call checkError() - ! Write the output file header p%OutSFmt = 'A19' p%OutFmt = 'ES19.5e2' @@ -211,51 +211,47 @@ program UnsteadyAero_Driver Frmt = '('//trim(Int2LStr(p%NumOuts*p%numBlades*p%nNodesPerBlade))//'(:,A,'//trim( p%OutFmt )//'))' end if + + ! set inputs: + DO iu = 1, NumInp + call setUAinputs(-iu+2, u(iu), uTimes(iu), dt, dvrInitInp, timeArr, AOAarr, Uarr, OmegaArr) + END DO + ! Set inputs which do not vary with node or time - u(1)%U = dvrInitInp%InflowVel ! m/s - u(1)%Re = dvrInitInp%Re ! not used at the moment - + ! time marching loop do n = 1, nSimSteps - if ( dvrInitInp%SimMod == 1 ) then - t = (n-1)*dt - u(1)%alpha = (dvrInitInp%Amplitude * sin((n+dvrInitInp%Phase-1)*2*pi/dvrInitInp%StepsPerCycle) + dvrInitInp%Mean)*pi/180.0 ! This needs to be in radians - - else - ! Load timestep data from the time-series inputs which were previous read from input file - t = timeArr(n) - u(1)%alpha = AOAarr (n)*pi/180.0 ! This needs to be in radians - u(1)%U = Uarr(n) - end if - - ! set the inputs for the node - - - do j = 1,InitInData%numBlades - do i = 1,InitInData%nNodesPerBlade + + i = 1 ! nodes per blade + j = 1 ! number of blades - ! Need to use MiscVar to store which element we are operating on - m%iBladeNode = i - m%iBlade = j - - ! Use existing states to compute the outputs - call UA_CalcOutput(u(1), p, xd, OtherState, AFI_Params(AFIndx(i,j)), y, m, errStat, errMsg ) - call checkError() + ! set inputs: + DO iu = NumInp-1, 1, -1 + u( iu+1) = u( iu) + uTimes(iu+1) = uTimes(iu) + END DO + + ! first value of uTimes/u contain inputs at t+dt + call setUAinputs(n+1, u(1), uTimes(1), dt, dvrInitInp, timeArr, AOAarr, Uarr, OmegaArr) + + t = uTimes(2) + + ! Use existing states to compute the outputs + call UA_CalcOutput(i, j, u(2), p, x, xd, OtherState, AFI_Params(AFIndx(i,j)), y, m, errStat, errMsg ) + call checkError() - - ! Prepare states for next time step - call UA_UpdateStates(i,j,u(1), p, xd, OtherState, AFI_Params(AFIndx(i,j)), m, errStat, errMsg ) - call checkError() - - end do - end do - ! Generate file outputs if (p%NumOuts > 0) then - write (unOutFile,TimeFrmt,ADVANCE='no') t + write (unOutFile,TimeFrmt,ADVANCE='no') t write (unOutFile,Frmt,ADVANCE='no') ( p%Delim, y%WriteOutput(k) , k=1,p%NumOuts*p%numBlades*p%nNodesPerBlade ) write (unOutFile,'()', IOSTAT=ErrStat) ! write the line return - end if + end if + + ! Prepare states for next time step + call UA_UpdateStates(i, j, t, n, u, uTimes, p, x, xd, OtherState, AFI_Params(AFIndx(i,j)), m, errStat, errMsg ) + call checkError() + + end do ! write (unOutFile,'(/,A/)', IOSTAT=ErrStat) 'This output file was closed on '//CurDate()//' at '//CurTime()//'.' @@ -297,6 +293,48 @@ subroutine checkError() end subroutine checkError !---------------------------------------------------------------------------------------------------- + subroutine setUAinputs(n,u,t,dt,dvrInitInp,timeArr,AOAarr,Uarr,OmegaArr) + + integer, intent(in) :: n + type(UA_InputType), intent(inout) :: u ! System inputs + real(DbKi), intent( out) :: t + real(DbKi), intent(in) :: dt + TYPE(UA_Dvr_InitInput), intent(in) :: dvrInitInp ! Initialization data for the driver program + real(DbKi), intent(in) :: timeArr(:) + real(ReKi), intent(in) :: AOAarr(:) + real(ReKi), intent(in) :: Uarr(:) + real(ReKi), intent(in) :: OmegaArr(:) + integer :: indx + real(ReKi) :: phase + + u%UserProp = 0 + u%Re = dvrInitInp%Re + + if ( dvrInitInp%SimMod == 1 ) then + t = (n-1)*dt + phase = (n+dvrInitInp%Phase-1)*2*pi/dvrInitInp%StepsPerCycle + u%alpha = (dvrInitInp%Amplitude * sin(phase) + dvrInitInp%Mean)*D2R ! This needs to be in radians + ! u%omega = dvrInitInp%Amplitude * cos(phase) * dvrInitInp%Frequency * pi**2 / 90.0 ! This needs to be in radians derivative: d_alpha /d_t + u%omega = dvrInitInp%Amplitude * cos(phase) * 2*pi/dvrInitInp%StepsPerCycle / dt * D2R ! This needs to be in radians derivative: d_alpha /d_t + + u%U = dvrInitInp%InflowVel ! m/s + else + indx = min(n,size(timeArr)) + + ! Load timestep data from the time-series inputs which were previous read from input file + t = timeArr(indx) + u%alpha = AOAarr(indx)*pi/180.0 ! This needs to be in radians + u%omega = OmegaArr(indx) + u%U = Uarr(indx) + if (n> size(timeArr)) then + t = t + dt*(n - size(timeArr) ) ! update for NumInp>1; + end if + end if + u%v_ac(1) = sin(u%alpha)*u%U + u%v_ac(2) = cos(u%alpha)*u%U + + end subroutine setUAinputs + !---------------------------------------------------------------------------------------------------- subroutine print_help() print '(a)', 'usage: ' diff --git a/modules/aerodyn/src/UnsteadyAero_Registry.txt b/modules/aerodyn/src/UnsteadyAero_Registry.txt index f10e9aefbe..617a09cf5c 100644 --- a/modules/aerodyn/src/UnsteadyAero_Registry.txt +++ b/modules/aerodyn/src/UnsteadyAero_Registry.txt @@ -28,14 +28,9 @@ typedef ^ ^ INTEGER typedef ^ ^ INTEGER UAMod - - - "Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema]" - typedef ^ ^ ReKi a_s - - - "speed of sound" m/s typedef ^ ^ LOGICAL Flookup - - - "Use table lookup for f' and f'' " - -#typedef ^ ^ INTEGER AFIndx {:}{:} - - "Airfoil index for given blade node" - -#typedef ^ ^ AFI_ParameterType AFI_Params - - - "Airfoil Info parameter data structure" - -#typedef ^ ^ CHARACTER(20) OutFmt - - - "Output format for numerical results" - -#typedef ^ ^ CHARACTER(20) OutSFmt - - - "Output format for header strings" - typedef ^ ^ INTEGER NumOuts - - - "The number of outputs for this module as requested in the input file" - -#typedef ^ ^ CHARACTER(ChanLen) OutList {199} - - "The user-requested output channel labels for this module. This should really be dimensioned with MaxOutPts" - -# -# + +# # Define outputs from the initialization routine here: # typedef ^ InitOutputType ProgDesc Version - - - "Version structure" - @@ -47,7 +42,6 @@ typedef ^ ^ CHARACTER(1 typedef ^ UA_KelvinChainType ReKi Cn_prime - - - "" - #typedef ^ UA_KelvinChainType ReKi Cn_prime_diff - - - "" - typedef ^ UA_KelvinChainType ReKi C_nalpha_circ - - - "slope of the circulatory normal force coefficient vs alpha curve" - -#typedef ^ UA_KelvinChainType AFI_UA_BL_Type BL_p - - - "airfoil parameters for UA" - typedef ^ UA_KelvinChainType ReKi Kalpha_f - - - "filtered backwards finite difference of alpha (xd%Kalpha_f_minus1)" - typedef ^ UA_KelvinChainType ReKi Kq_f - - - "filtered backwards finite difference of q" - typedef ^ UA_KelvinChainType ReKi alpha_filt_cur - - - "filtered angle of attack" - @@ -96,14 +90,12 @@ typedef ^ UA_KelvinChainType ReKi typedef ^ UA_KelvinChainType ReKi T_q - - - "" - typedef ^ UA_KelvinChainType ReKi ds - - - "non-dimensionalized distance parameter" - -# -# + # ..... States .................................................................................................................... # Define continuous (differentiable) states here: -# -typedef ^ ContinuousStateType ReKi DummyContState - - - "Remove this variable if you have continuous states" - -# -# +typedef ^ UA_ElementContinuousStateType R8Ki x 4 - - "continuous states when UA_Mod=4 (x1 and x2:Downwash memory terms; x3:Clp', Lift coefficient with a time lag to the attached lift coeff; x4: f'' , Final separation point function)" "{rad, rad, - -}" +typedef ^ ContinuousStateType UA_ElementContinuousStateType element {:}{:} - - "continuous states when UA_Mod=4 for each blade/node" "-" + # Define discrete (non-differentiable) states here: # typedef ^ DiscreteStateType ReKi alpha_minus1 {:}{:} - - "angle of attack, previous time step" rad @@ -151,13 +143,14 @@ typedef ^ OtherStateType ReKi typedef ^ OtherStateType ReKi sigma1c {:}{:} - - "multiplier for T_fc" - typedef ^ OtherStateType ReKi sigma1m {:}{:} - - "multiplier for T_fm" - typedef ^ OtherStateType ReKi sigma3 {:}{:} - - "multiplier for T_V" - +typedef ^ OtherStateType IntKi n {:}{:} - - "counter for continuous state integration" - +typedef ^ OtherStateType UA_ContinuousStateType xdot 4 - - "counter for continuous state integration" - # ..... Misc/Optimization variables................................................................................................. # Define any data that are used only for efficiency purposes (these variables are not associated with time): # e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. typedef ^ MiscVarType Logical FirstWarn_M - - - "flag so Mach number warning doesn't get repeated forever" - -typedef ^ MiscVarType INTEGER iBladeNode - - - "index for the blade node being operated on (within the current blade)" - -typedef ^ MiscVarType INTEGER iBlade - - - "index for the blade being operated on" - +typedef ^ MiscVarType Logical FirstWarn_UA - - - "flag so UA state warning doesn't get repeated forever" - # these COULD be OtherStates or just scalar local variables (they are calcaulted/used in UpdateDiscState and written to WriteOutput in CalcOutput) typedef ^ MiscVarType LOGICAL TESF {:}{:} - - "logical flag indicating if trailing edge separation is possible" - typedef ^ MiscVarType LOGICAL LESF {:}{:} - - "logical flag indicating if leading edge separation is possible" - @@ -168,8 +161,6 @@ typedef ^ MiscVarType LOGICAL # ..... Parameters ................................................................................................................ # Define parameters here: -# Time step for integration of continuous states (if a fixed-step integrator is used) and update of discrete states: -# typedef ^ ParameterType DbKi dt - - - "time step" s typedef ^ ^ ReKi c {:}{:} - - "Chord length at node" m typedef ^ ^ INTEGER numBlades - - - "Number nodes of all blades" - @@ -184,17 +175,18 @@ typedef ^ ^ CHARACTER(2 typedef ^ ^ CHARACTER(1) Delim - - - "Delimiter string for outputs, defaults to tab-delimiters" - typedef ^ ^ INTEGER UnOutFile - - - "File unit for the UnsteadyAero outputs" - typedef ^ ^ Logical ShedEffect - .True. - "Include the effect of shed vorticity. If False, the input alpha is assumed to already contain this effect (e.g. vortex methods)" - -# +typedef ^ ParameterType IntKi lin_nx - 0 - "Number of continuous states for linearization" - -# # ..... Inputs .................................................................................................................... # Define inputs that are contained on the mesh here: # typedef ^ InputType ReKi U - - - "air velocity magnitude relative to the airfoil" m/s -typedef ^ ^ ReKi alpha - - - "angle of attack" rad +typedef ^ ^ ReKi alpha - - 2pi "angle of attack" rad typedef ^ ^ ReKi Re - - - "Reynold's number" - typedef ^ ^ ReKi UserProp - 0.0 - "UserProp value for interpolating airfoil tables" - -# +typedef ^ ^ ReKi v_ac 2 - - "Relative fluid velocity at the aerodynamic center (UAMod=4)" m/s +typedef ^ ^ ReKi omega - - - "pitching/twisting rate of the airfoil section (UAMod=4)" rad/s + # ..... Outputs ................................................................................................................... # Define outputs that are contained on the mesh here: typedef ^ OutputType ReKi Cn - - - "2D, normal to chord, force coefficient" - diff --git a/modules/aerodyn/src/UnsteadyAero_Types.f90 b/modules/aerodyn/src/UnsteadyAero_Types.f90 index 86605ad912..cd19e10c4a 100644 --- a/modules/aerodyn/src/UnsteadyAero_Types.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Types.f90 @@ -107,9 +107,14 @@ MODULE UnsteadyAero_Types REAL(ReKi) :: ds !< non-dimensionalized distance parameter [-] END TYPE UA_KelvinChainType ! ======================= +! ========= UA_ElementContinuousStateType ======= + TYPE, PUBLIC :: UA_ElementContinuousStateType + REAL(R8Ki) , DIMENSION(1:4) :: x !< continuous states when UA_Mod=4 (x1 and x2:Downwash memory terms; x3:Clp', Lift coefficient with a time lag to the attached lift coeff; x4: f'' , Final separation point function) [{rad, rad, - -}] + END TYPE UA_ElementContinuousStateType +! ======================= ! ========= UA_ContinuousStateType ======= TYPE, PUBLIC :: UA_ContinuousStateType - REAL(ReKi) :: DummyContState !< Remove this variable if you have continuous states [-] + TYPE(UA_ElementContinuousStateType) , DIMENSION(:,:), ALLOCATABLE :: element !< continuous states when UA_Mod=4 for each blade/node [-] END TYPE UA_ContinuousStateType ! ======================= ! ========= UA_DiscreteStateType ======= @@ -160,13 +165,14 @@ MODULE UnsteadyAero_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: sigma1c !< multiplier for T_fc [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: sigma1m !< multiplier for T_fm [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: sigma3 !< multiplier for T_V [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: n !< counter for continuous state integration [-] + TYPE(UA_ContinuousStateType) , DIMENSION(1:4) :: xdot !< counter for continuous state integration [-] END TYPE UA_OtherStateType ! ======================= ! ========= UA_MiscVarType ======= TYPE, PUBLIC :: UA_MiscVarType LOGICAL :: FirstWarn_M !< flag so Mach number warning doesn't get repeated forever [-] - INTEGER(IntKi) :: iBladeNode !< index for the blade node being operated on (within the current blade) [-] - INTEGER(IntKi) :: iBlade !< index for the blade being operated on [-] + LOGICAL :: FirstWarn_UA !< flag so UA state warning doesn't get repeated forever [-] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: TESF !< logical flag indicating if trailing edge separation is possible [-] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: LESF !< logical flag indicating if leading edge separation is possible [-] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: VRTX !< logical flag indicating if a vortex is being processed [-] @@ -190,6 +196,7 @@ MODULE UnsteadyAero_Types CHARACTER(1) :: Delim !< Delimiter string for outputs, defaults to tab-delimiters [-] INTEGER(IntKi) :: UnOutFile !< File unit for the UnsteadyAero outputs [-] LOGICAL :: ShedEffect = .True. !< Include the effect of shed vorticity. If False, the input alpha is assumed to already contain this effect (e.g. vortex methods) [-] + INTEGER(IntKi) :: lin_nx = 0 !< Number of continuous states for linearization [-] END TYPE UA_ParameterType ! ======================= ! ========= UA_InputType ======= @@ -198,6 +205,8 @@ MODULE UnsteadyAero_Types REAL(ReKi) :: alpha !< angle of attack [rad] REAL(ReKi) :: Re !< Reynold's number [-] REAL(ReKi) :: UserProp = 0.0 !< UserProp value for interpolating airfoil tables [-] + REAL(ReKi) , DIMENSION(1:2) :: v_ac !< Relative fluid velocity at the aerodynamic center (UAMod=4) [m/s] + REAL(ReKi) :: omega !< pitching/twisting rate of the airfoil section (UAMod=4) [rad/s] END TYPE UA_InputType ! ======================= ! ========= UA_OutputType ======= @@ -1189,6 +1198,139 @@ SUBROUTINE UA_UnPackKelvinChainType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta Re_Xferred = Re_Xferred + 1 END SUBROUTINE UA_UnPackKelvinChainType + SUBROUTINE UA_CopyElementContinuousStateType( SrcElementContinuousStateTypeData, DstElementContinuousStateTypeData, CtrlCode, ErrStat, ErrMsg ) + TYPE(UA_ElementContinuousStateType), INTENT(IN) :: SrcElementContinuousStateTypeData + TYPE(UA_ElementContinuousStateType), INTENT(INOUT) :: DstElementContinuousStateTypeData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'UA_CopyElementContinuousStateType' +! + ErrStat = ErrID_None + ErrMsg = "" + DstElementContinuousStateTypeData%x = SrcElementContinuousStateTypeData%x + END SUBROUTINE UA_CopyElementContinuousStateType + + SUBROUTINE UA_DestroyElementContinuousStateType( ElementContinuousStateTypeData, ErrStat, ErrMsg ) + TYPE(UA_ElementContinuousStateType), INTENT(INOUT) :: ElementContinuousStateTypeData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'UA_DestroyElementContinuousStateType' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE UA_DestroyElementContinuousStateType + + SUBROUTINE UA_PackElementContinuousStateType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(UA_ElementContinuousStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'UA_PackElementContinuousStateType' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Db_BufSz = Db_BufSz + SIZE(InData%x) ! x + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DO i1 = LBOUND(InData%x,1), UBOUND(InData%x,1) + DbKiBuf(Db_Xferred) = InData%x(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END SUBROUTINE UA_PackElementContinuousStateType + + SUBROUTINE UA_UnPackElementContinuousStateType( 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(UA_ElementContinuousStateType), 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 = 'UA_UnPackElementContinuousStateType' + ! 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 + i1_l = LBOUND(OutData%x,1) + i1_u = UBOUND(OutData%x,1) + DO i1 = LBOUND(OutData%x,1), UBOUND(OutData%x,1) + OutData%x(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END SUBROUTINE UA_UnPackElementContinuousStateType + SUBROUTINE UA_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) TYPE(UA_ContinuousStateType), INTENT(IN) :: SrcContStateData TYPE(UA_ContinuousStateType), INTENT(INOUT) :: DstContStateData @@ -1197,13 +1339,34 @@ SUBROUTINE UA_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrSt CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'UA_CopyContState' ! ErrStat = ErrID_None ErrMsg = "" - DstContStateData%DummyContState = SrcContStateData%DummyContState +IF (ALLOCATED(SrcContStateData%element)) THEN + i1_l = LBOUND(SrcContStateData%element,1) + i1_u = UBOUND(SrcContStateData%element,1) + i2_l = LBOUND(SrcContStateData%element,2) + i2_u = UBOUND(SrcContStateData%element,2) + IF (.NOT. ALLOCATED(DstContStateData%element)) THEN + ALLOCATE(DstContStateData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i2 = LBOUND(SrcContStateData%element,2), UBOUND(SrcContStateData%element,2) + DO i1 = LBOUND(SrcContStateData%element,1), UBOUND(SrcContStateData%element,1) + CALL UA_Copyelementcontinuousstatetype( SrcContStateData%element(i1,i2), DstContStateData%element(i1,i2), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO + ENDDO +ENDIF END SUBROUTINE UA_CopyContState SUBROUTINE UA_DestroyContState( ContStateData, ErrStat, ErrMsg ) @@ -1215,6 +1378,14 @@ SUBROUTINE UA_DestroyContState( ContStateData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" +IF (ALLOCATED(ContStateData%element)) THEN +DO i2 = LBOUND(ContStateData%element,2), UBOUND(ContStateData%element,2) +DO i1 = LBOUND(ContStateData%element,1), UBOUND(ContStateData%element,1) + CALL UA_Destroyelementcontinuousstatetype( ContStateData%element(i1,i2), ErrStat, ErrMsg ) +ENDDO +ENDDO + DEALLOCATE(ContStateData%element) +ENDIF END SUBROUTINE UA_DestroyContState SUBROUTINE UA_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -1252,7 +1423,32 @@ SUBROUTINE UA_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyContState + Int_BufSz = Int_BufSz + 1 ! element allocated yes/no + IF ( ALLOCATED(InData%element) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! element upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + Int_BufSz = Int_BufSz + 3 ! element: size of buffers for each call to pack subtype + CALL UA_Packelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, .TRUE. ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! element + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! element + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! element + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END DO + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1280,8 +1476,52 @@ SUBROUTINE UA_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyContState - Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%element) ) 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%element,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%element,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%element,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%element,2), UBOUND(InData%element,2) + DO i1 = LBOUND(InData%element,1), UBOUND(InData%element,1) + CALL UA_Packelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, InData%element(i1,i2), ErrStat2, ErrMsg2, OnlySize ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END DO + END IF END SUBROUTINE UA_PackContState SUBROUTINE UA_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -1297,6 +1537,8 @@ SUBROUTINE UA_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err 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) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'UA_UnPackContState' @@ -1310,8 +1552,67 @@ SUBROUTINE UA_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyContState = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! element 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%element)) DEALLOCATE(OutData%element) + ALLOCATE(OutData%element(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%element.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%element,2), UBOUND(OutData%element,2) + DO i1 = LBOUND(OutData%element,1), UBOUND(OutData%element,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL UA_Unpackelementcontinuousstatetype( Re_Buf, Db_Buf, Int_Buf, OutData%element(i1,i2), ErrStat2, ErrMsg2 ) ! element + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END DO + END IF END SUBROUTINE UA_UnPackContState SUBROUTINE UA_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) @@ -3728,6 +4029,25 @@ SUBROUTINE UA_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, Er END IF DstOtherStateData%sigma3 = SrcOtherStateData%sigma3 ENDIF +IF (ALLOCATED(SrcOtherStateData%n)) THEN + i1_l = LBOUND(SrcOtherStateData%n,1) + i1_u = UBOUND(SrcOtherStateData%n,1) + i2_l = LBOUND(SrcOtherStateData%n,2) + i2_u = UBOUND(SrcOtherStateData%n,2) + IF (.NOT. ALLOCATED(DstOtherStateData%n)) THEN + ALLOCATE(DstOtherStateData%n(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOtherStateData%n.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOtherStateData%n = SrcOtherStateData%n +ENDIF + DO i1 = LBOUND(SrcOtherStateData%xdot,1), UBOUND(SrcOtherStateData%xdot,1) + CALL UA_CopyContState( SrcOtherStateData%xdot(i1), DstOtherStateData%xdot(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO END SUBROUTINE UA_CopyOtherState SUBROUTINE UA_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) @@ -3754,6 +4074,12 @@ SUBROUTINE UA_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) IF (ALLOCATED(OtherStateData%sigma3)) THEN DEALLOCATE(OtherStateData%sigma3) ENDIF +IF (ALLOCATED(OtherStateData%n)) THEN + DEALLOCATE(OtherStateData%n) +ENDIF +DO i1 = LBOUND(OtherStateData%xdot,1), UBOUND(OtherStateData%xdot,1) + CALL UA_DestroyContState( OtherStateData%xdot(i1), ErrStat, ErrMsg ) +ENDDO END SUBROUTINE UA_DestroyOtherState SUBROUTINE UA_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3816,6 +4142,31 @@ SUBROUTINE UA_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_BufSz = Int_BufSz + 2*2 ! sigma3 upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%sigma3) ! sigma3 END IF + Int_BufSz = Int_BufSz + 1 ! n allocated yes/no + IF ( ALLOCATED(InData%n) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! n upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%n) ! n + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%xdot,1), UBOUND(InData%xdot,1) + Int_BufSz = Int_BufSz + 3 ! xdot: size of buffers for each call to pack subtype + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%xdot(i1), ErrStat2, ErrMsg2, .TRUE. ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! xdot + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! xdot + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! xdot + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -3943,6 +4294,56 @@ SUBROUTINE UA_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs END DO END DO END IF + IF ( .NOT. ALLOCATED(InData%n) ) 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%n,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%n,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%n,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%n,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%n,2), UBOUND(InData%n,2) + DO i1 = LBOUND(InData%n,1), UBOUND(InData%n,1) + IntKiBuf(Int_Xferred) = InData%n(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + DO i1 = LBOUND(InData%xdot,1), UBOUND(InData%xdot,1) + CALL UA_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%xdot(i1), ErrStat2, ErrMsg2, OnlySize ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO END SUBROUTINE UA_PackOtherState SUBROUTINE UA_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -4088,6 +4489,73 @@ SUBROUTINE UA_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er END DO END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! n 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%n)) DEALLOCATE(OutData%n) + ALLOCATE(OutData%n(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%n.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%n,2), UBOUND(OutData%n,2) + DO i1 = LBOUND(OutData%n,1), UBOUND(OutData%n,1) + OutData%n(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + i1_l = LBOUND(OutData%xdot,1) + i1_u = UBOUND(OutData%xdot,1) + DO i1 = LBOUND(OutData%xdot,1), UBOUND(OutData%xdot,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL UA_UnpackContState( Re_Buf, Db_Buf, Int_Buf, OutData%xdot(i1), ErrStat2, ErrMsg2 ) ! xdot + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO END SUBROUTINE UA_UnPackOtherState SUBROUTINE UA_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) @@ -4107,8 +4575,7 @@ SUBROUTINE UA_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" DstMiscData%FirstWarn_M = SrcMiscData%FirstWarn_M - DstMiscData%iBladeNode = SrcMiscData%iBladeNode - DstMiscData%iBlade = SrcMiscData%iBlade + DstMiscData%FirstWarn_UA = SrcMiscData%FirstWarn_UA IF (ALLOCATED(SrcMiscData%TESF)) THEN i1_l = LBOUND(SrcMiscData%TESF,1) i1_u = UBOUND(SrcMiscData%TESF,1) @@ -4243,8 +4710,7 @@ SUBROUTINE UA_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Siz Db_BufSz = 0 Int_BufSz = 0 Int_BufSz = Int_BufSz + 1 ! FirstWarn_M - Int_BufSz = Int_BufSz + 1 ! iBladeNode - Int_BufSz = Int_BufSz + 1 ! iBlade + Int_BufSz = Int_BufSz + 1 ! FirstWarn_UA Int_BufSz = Int_BufSz + 1 ! TESF allocated yes/no IF ( ALLOCATED(InData%TESF) ) THEN Int_BufSz = Int_BufSz + 2*2 ! TESF upper/lower bounds for each dimension @@ -4299,9 +4765,7 @@ SUBROUTINE UA_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Siz IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstWarn_M, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%iBladeNode - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%iBlade + IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstWarn_UA, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 IF ( .NOT. ALLOCATED(InData%TESF) ) THEN IntKiBuf( Int_Xferred ) = 0 @@ -4435,9 +4899,7 @@ SUBROUTINE UA_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) Int_Xferred = 1 OutData%FirstWarn_M = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstWarn_M) Int_Xferred = Int_Xferred + 1 - OutData%iBladeNode = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%iBlade = IntKiBuf(Int_Xferred) + OutData%FirstWarn_UA = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstWarn_UA) Int_Xferred = Int_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TESF not allocated Int_Xferred = Int_Xferred + 1 @@ -4599,6 +5061,7 @@ SUBROUTINE UA_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) DstParamData%Delim = SrcParamData%Delim DstParamData%UnOutFile = SrcParamData%UnOutFile DstParamData%ShedEffect = SrcParamData%ShedEffect + DstParamData%lin_nx = SrcParamData%lin_nx END SUBROUTINE UA_CopyParam SUBROUTINE UA_DestroyParam( ParamData, ErrStat, ErrMsg ) @@ -4668,6 +5131,7 @@ SUBROUTINE UA_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Int_BufSz = Int_BufSz + 1*LEN(InData%Delim) ! Delim Int_BufSz = Int_BufSz + 1 ! UnOutFile Int_BufSz = Int_BufSz + 1 ! ShedEffect + Int_BufSz = Int_BufSz + 1 ! lin_nx IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4747,6 +5211,8 @@ SUBROUTINE UA_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = TRANSFER(InData%ShedEffect, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%lin_nx + Int_Xferred = Int_Xferred + 1 END SUBROUTINE UA_PackParam SUBROUTINE UA_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -4832,6 +5298,8 @@ SUBROUTINE UA_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Int_Xferred = Int_Xferred + 1 OutData%ShedEffect = TRANSFER(IntKiBuf(Int_Xferred), OutData%ShedEffect) Int_Xferred = Int_Xferred + 1 + OutData%lin_nx = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE UA_UnPackParam SUBROUTINE UA_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) @@ -4842,6 +5310,7 @@ SUBROUTINE UA_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'UA_CopyInput' @@ -4852,6 +5321,8 @@ SUBROUTINE UA_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) DstInputData%alpha = SrcInputData%alpha DstInputData%Re = SrcInputData%Re DstInputData%UserProp = SrcInputData%UserProp + DstInputData%v_ac = SrcInputData%v_ac + DstInputData%omega = SrcInputData%omega END SUBROUTINE UA_CopyInput SUBROUTINE UA_DestroyInput( InputData, ErrStat, ErrMsg ) @@ -4904,6 +5375,8 @@ SUBROUTINE UA_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Re_BufSz = Re_BufSz + 1 ! alpha Re_BufSz = Re_BufSz + 1 ! Re Re_BufSz = Re_BufSz + 1 ! UserProp + Re_BufSz = Re_BufSz + SIZE(InData%v_ac) ! v_ac + Re_BufSz = Re_BufSz + 1 ! omega IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4939,6 +5412,12 @@ SUBROUTINE UA_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%UserProp Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%v_ac,1), UBOUND(InData%v_ac,1) + ReKiBuf(Re_Xferred) = InData%v_ac(i1) + Re_Xferred = Re_Xferred + 1 + END DO + ReKiBuf(Re_Xferred) = InData%omega + Re_Xferred = Re_Xferred + 1 END SUBROUTINE UA_PackInput SUBROUTINE UA_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -4954,6 +5433,7 @@ SUBROUTINE UA_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg 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 = 'UA_UnPackInput' @@ -4975,6 +5455,14 @@ SUBROUTINE UA_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Re_Xferred = Re_Xferred + 1 OutData%UserProp = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%v_ac,1) + i1_u = UBOUND(OutData%v_ac,1) + DO i1 = LBOUND(OutData%v_ac,1), UBOUND(OutData%v_ac,1) + OutData%v_ac(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + OutData%omega = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 END SUBROUTINE UA_UnPackInput SUBROUTINE UA_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) @@ -5260,6 +5748,8 @@ SUBROUTINE UA_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" @@ -5276,12 +5766,17 @@ SUBROUTINE UA_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) ScaleFactor = t_out / t(2) b = -(u1%U - u2%U) u_out%U = u1%U + b * ScaleFactor - b = -(u1%alpha - u2%alpha) - u_out%alpha = u1%alpha + b * ScaleFactor + CALL Angles_ExtrapInterp( u1%alpha, u2%alpha, tin, u_out%alpha, tin_out ) b = -(u1%Re - u2%Re) u_out%Re = u1%Re + b * ScaleFactor b = -(u1%UserProp - u2%UserProp) u_out%UserProp = u1%UserProp + b * ScaleFactor + DO i1 = LBOUND(u_out%v_ac,1),UBOUND(u_out%v_ac,1) + b = -(u1%v_ac(i1) - u2%v_ac(i1)) + u_out%v_ac(i1) = u1%v_ac(i1) + b * ScaleFactor + END DO + b = -(u1%omega - u2%omega) + u_out%omega = u1%omega + b * ScaleFactor END SUBROUTINE UA_Input_ExtrapInterp1 @@ -5317,6 +5812,8 @@ SUBROUTINE UA_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrM INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors CHARACTER(*), PARAMETER :: RoutineName = 'UA_Input_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" @@ -5340,15 +5837,21 @@ SUBROUTINE UA_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrM b = (t(3)**2*(u1%U - u2%U) + t(2)**2*(-u1%U + u3%U))* scaleFactor c = ( (t(2)-t(3))*u1%U + t(3)*u2%U - t(2)*u3%U ) * scaleFactor u_out%U = u1%U + b + c * t_out - b = (t(3)**2*(u1%alpha - u2%alpha) + t(2)**2*(-u1%alpha + u3%alpha))* scaleFactor - c = ( (t(2)-t(3))*u1%alpha + t(3)*u2%alpha - t(2)*u3%alpha ) * scaleFactor - u_out%alpha = u1%alpha + b + c * t_out + CALL Angles_ExtrapInterp( u1%alpha, u2%alpha, u3%alpha, tin, u_out%alpha, tin_out ) b = (t(3)**2*(u1%Re - u2%Re) + t(2)**2*(-u1%Re + u3%Re))* scaleFactor c = ( (t(2)-t(3))*u1%Re + t(3)*u2%Re - t(2)*u3%Re ) * scaleFactor u_out%Re = u1%Re + b + c * t_out b = (t(3)**2*(u1%UserProp - u2%UserProp) + t(2)**2*(-u1%UserProp + u3%UserProp))* scaleFactor c = ( (t(2)-t(3))*u1%UserProp + t(3)*u2%UserProp - t(2)*u3%UserProp ) * scaleFactor u_out%UserProp = u1%UserProp + b + c * t_out + DO i1 = LBOUND(u_out%v_ac,1),UBOUND(u_out%v_ac,1) + b = (t(3)**2*(u1%v_ac(i1) - u2%v_ac(i1)) + t(2)**2*(-u1%v_ac(i1) + u3%v_ac(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%v_ac(i1) + t(3)*u2%v_ac(i1) - t(2)*u3%v_ac(i1) ) * scaleFactor + u_out%v_ac(i1) = u1%v_ac(i1) + b + c * t_out + END DO + b = (t(3)**2*(u1%omega - u2%omega) + t(2)**2*(-u1%omega + u3%omega))* scaleFactor + c = ( (t(2)-t(3))*u1%omega + t(3)*u2%omega - t(2)*u3%omega ) * scaleFactor + u_out%omega = u1%omega + b + c * t_out END SUBROUTINE UA_Input_ExtrapInterp2 diff --git a/modules/aerodyn/src/mod_root1dim.f90 b/modules/aerodyn/src/mod_root1dim.f90 index 8dbe20d2d7..8d68f6e57b 100644 --- a/modules/aerodyn/src/mod_root1dim.f90 +++ b/modules/aerodyn/src/mod_root1dim.f90 @@ -12,32 +12,12 @@ module mod_root1dim use NWTC_Library use AirFoilInfo_Types use BEMTUnCoupled, only: BEMTU_InductionWithResidual + use BEMT_Types implicit none - type, public :: fmin_fcnArgs - real(ReKi) :: nu - integer :: numBlades - real(ReKi) :: rlocal - real(ReKi) :: chord - real(ReKi) :: theta - real(ReKi) :: Vx - real(ReKi) :: Vy - real(ReKi) :: UserProp - logical :: useTanInd - logical :: useAIDrag - logical :: useTIDrag - logical :: useHubLoss - logical :: useTipLoss - real(ReKi) :: hubLossConst - real(ReKi) :: tipLossConst - logical :: IsValidSolution - integer(IntKi) :: errStat ! Error status of the operation - character(ErrMsgLen) :: errMsg ! Error message if ErrStat /= ErrID_None - end type fmin_fcnArgs - integer, parameter, private :: SolveKi = ReKi - real(SolveKi), parameter, private :: xtoler_def = 1d-6, toler_def = 1d-6, printmod_def = -1, maxiter_def = 100 + real(SolveKi), parameter, private :: xtoler_def = 1d-6, printmod_def = -1 contains @@ -57,25 +37,30 @@ end function bracketsRoot ! Returns a zero x of the function f in the given interval [a,b], to within a tolerance 6macheps|x| + 2t, ! where macheps is the relative machine precision and t is a positive tolerance. The procedure assumes that ! f(a) and f(b) have different signs. -subroutine sub_brent(x,a_in,b_in, toler_in,maxiter_in,fcnArgs,AFInfo,fa_in,fb_in,xtoler_in,printmod_in) +subroutine sub_brent(bemt_parameters, bemt_inputs, iBladeNode, jBlade, x,a_in,b_in, AFInfo, IsValidSolution, ErrStat, ErrMsg, fa_in,fb_in,xtoler_in,printmod_in) implicit none + type(BEMT_ParameterType), intent(in) :: bemt_parameters + type(BEMT_InputType), intent(in) :: bemt_inputs !< Inputs at t + integer(IntKi), intent(in) :: iBladeNode !< index for blade node + integer(IntKi), intent(in) :: jBlade !< index for blade + logical, intent(out):: IsValidSolution + integer(IntKi), intent(out):: errStat ! Error status of the operation + character(ErrMsgLen), intent(out):: errMsg ! Error message if ErrStat /= ErrID_None real(ReKi), intent(out) :: x !< solution real(ReKi), intent(in) :: a_in !< lower bound of solution region real(ReKi), intent(in) :: b_in !< upper bound of solution region - type(fmin_fcnArgs), intent(inout) :: fcnArgs !< function arguments TYPE (AFI_ParameterType), INTENT(IN ) :: AFInfo !< The derived type for holding the constant parameters for this airfoil. - real(ReKi), intent(in), optional :: toler_in !< induction tolerance real(ReKi), intent(in), optional :: fa_in !< starting value for f(a), if not present, will be evaluated real(ReKi), intent(in), optional :: fb_in !< starting value for f(b), if not present, will be evaluated real(ReKi), intent(in), optional :: xtoler_in !< integer, intent(in), optional :: printmod_in !< print switch; otherwise uses default printmod_deff - integer, intent(in), optional :: maxiter_in !< maximum number of iterations; otherwise uses default maxiter_def + ! local real(SolveKi), parameter :: machep = epsilon(0.0_SolveKi) - real(SolveKi) :: c,fa,fb,fc,toler,xtoler,e,d,m,p,q,tol,t,r,s + real(SolveKi) :: c,fa,fb,fc,toler,xtoler,e,d,m,p,q,tol,r,s real(ReKi) :: a,b integer :: maxiter,printmod,iter character(len=6) :: step @@ -83,39 +68,36 @@ subroutine sub_brent(x,a_in,b_in, toler_in,maxiter_in,fcnArgs,AFInfo,fa_in,fb_in integer :: ErrStat_a character(ErrMsgLen) :: ErrMsg_a logical :: ValidPhi_a - - fcnArgs%errStat = ErrID_None - fcnArgs%ErrMsg = "" - ! Set of get parameters - toler = 0.0_SolveKi; if (present(toler_in)) toler = toler_in ! Better to use custom toler here + toler = bemt_parameters%aTol + maxiter = bemt_parameters%maxIndIterations + xtoler = xtoler_def; if (present(xtoler_in)) xtoler = xtoler_in - maxiter = maxiter_def; if (present(maxiter_in)) maxiter = maxiter_in printmod = printmod_def; if (present(printmod_in)) printmod = printmod_in + + ErrStat = ErrID_None + ErrMsg = "" ! Set the user chosen tolerance t to xtoler if (xtoler<0.0_SolveKi) then CALL WrScr('WARNING: xtoler must be positive. Resetting xtoler.') xtoler = 0.0_SolveKi end if - t = xtoler ! Get initial bracket a=a_in b=b_in if (present(fa_in)) then fa = fa_in + ErrStat_a = ErrID_None + ErrMsg_a = "" else - fa = BEMTU_InductionWithResidual( a, fcnArgs%theta, fcnArgs%nu, fcnArgs%UserProp, fcnArgs%numBlades, fcnArgs%rlocal, fcnArgs%chord, AFInfo, & - fcnArgs%Vx, fcnArgs%Vy, fcnArgs%useTanInd, fcnArgs%useAIDrag, fcnArgs%useTIDrag, fcnArgs%useHubLoss, fcnArgs%useTipLoss, fcnArgs%hubLossConst, fcnArgs%tipLossConst, & - ValidPhi_a, errStat_a, errMsg_a) + fa = BEMTU_InductionWithResidual(bemt_parameters, bemt_inputs, iBladeNode, jBlade, a, AFInfo, ValidPhi_a, errStat_a, errMsg_a) end if if (present(fb_in)) then fb = fb_in else - fb = BEMTU_InductionWithResidual( b, fcnArgs%theta, fcnArgs%nu, fcnArgs%UserProp, fcnArgs%numBlades, fcnArgs%rlocal, fcnArgs%chord, AFInfo, & - fcnArgs%Vx, fcnArgs%Vy, fcnArgs%useTanInd, fcnArgs%useAIDrag, fcnArgs%useTIDrag, fcnArgs%useHubLoss, fcnArgs%useTipLoss, fcnArgs%hubLossConst, fcnArgs%tipLossConst, & - fcnArgs%IsValidSolution, fcnArgs%errStat, fcnArgs%errMsg) + fb = BEMTU_InductionWithResidual(bemt_parameters, bemt_inputs, iBladeNode, jBlade, b, AFInfo, IsValidSolution, errStat, errMsg) end if ! Test whether root is bracketed @@ -123,9 +105,9 @@ subroutine sub_brent(x,a_in,b_in, toler_in,maxiter_in,fcnArgs,AFInfo,fa_in,fb_in if (abs(fa) 0 ) CALL NormStop() + + ! Display the copyright notice CALL DispCopyrightLicense( version%Name ) - ! Obtain OpenFAST git commit hash + ! 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 ) - - IF ( command_argument_count() /= 1 ) THEN - CALL print_help() - STOP - END IF - + ! 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 ) ! Parse the driver input file and run the simulation based on that file - - IF ( command_argument_count() == 1 ) THEN - - CALL get_command_argument(1, drvrFilename) - CALL ReadDriverInputFile( drvrFilename, drvrInitInp, ErrStat, ErrMsg ) - IF ( ErrStat /= 0 ) THEN - CALL WrScr( ErrMsg ) - STOP - END IF - InitInData%Gravity = drvrInitInp%Gravity - InitInData%UseInputFile = .TRUE. - InitInData%InputFile = drvrInitInp%HDInputFile - InitInData%OutRootName = drvrInitInp%OutRootName - InitInData%TMax = drvrInitInp%NSteps * drvrInitInp%TimeInterval - InitInData%Linearize = drvrInitInp%Linearize + CALL ReadDriverInputFile( drvrFilename, drvrInitInp, ErrStat, ErrMsg ) + IF ( ErrStat /= 0 ) THEN + CALL WrScr( ErrMsg ) + STOP END IF + InitInData%Gravity = drvrInitInp%Gravity + InitInData%UseInputFile = .TRUE. + InitInData%InputFile = drvrInitInp%HDInputFile + InitInData%OutRootName = drvrInitInp%OutRootName + InitInData%TMax = drvrInitInp%NSteps * drvrInitInp%TimeInterval + InitInData%Linearize = drvrInitInp%Linearize ! Get the current time call date_and_time ( Values=StrtTime ) ! Let's time the whole simulation @@ -293,6 +291,46 @@ PROGRAM HydroDynDriver ENDIF + ! Setup mesh for input motions for Morison and WAMIT + CALL MeshCreate( BlankMesh = PMesh & + ,IOS = COMPONENT_INPUT & + ,Nnodes = 1 & + ,ErrStat = ErrStat & + ,ErrMess = ErrMsg & + ,TranslationDisp = .TRUE. & + ,Orientation = .TRUE. & + ,TranslationVel = .TRUE. & + ,RotationVel = .TRUE. & + ,TranslationAcc = .TRUE. & + ,RotationAcc = .TRUE.) + IF ( ErrStat >= ErrID_Fatal ) THEN + CALL WrScr( ErrMsg ) + STOP + END IF + + CALL MeshPositionNode (PMesh & + , 1 & + , (/0.0_ReKi, 0.0_ReKi, 0.0_ReKi/) & + , ErrStat & + , ErrMsg ) + IF ( ErrStat >= ErrID_Fatal ) THEN + CALL WrScr( ErrMsg ) + STOP + END IF + + CALL MeshConstructElement( PMesh, ELEMENT_POINT, ErrStat, ErrMsg, 1 ) + IF ( ErrStat >= ErrID_Fatal ) THEN + CALL WrScr( ErrMsg ) + STOP + END IF + + CALL MeshCommit ( PMesh, ErrStat, ErrMsg ) + IF ( ErrStat >= ErrID_Fatal ) THEN + CALL WrScr( ErrMsg ) + STOP + END IF + + ! Initialize the module Interval = drvrInitInp%TimeInterval @@ -391,7 +429,20 @@ PROGRAM HydroDynDriver END IF END IF - + + ! Setup mesh mapping for Morison motion + IF ( drvrInitInp%MorisonInputsMod == 2 ) THEN + IF ( u(1)%Morison%DistribMesh%Initialized ) THEN + ! create mapping from PMesh (used for WAMIT mesh among others) to Morison. This will be used to map the motions for Morison timeseries inputs + CALL MeshMapCreate( PMesh, u(1)%Morison%DistribMesh, Map_P_to_MorisonDist, ErrStat, ErrMsg ) + if (errStat >= AbortErrLev) call HD_DvrCleanup() + ENDIF + IF ( u(1)%Morison%LumpedMesh%Initialized ) THEN + ! create mapping from PMesh (used for WAMIT mesh among others) to Morison. This will be used to map the motions for Morison timeseries inputs + CALL MeshMapCreate( PMesh, u(1)%Morison%LumpedMesh, Map_P_to_MorisonLumped, ErrStat, ErrMsg ) + if (errStat >= AbortErrLev) call HD_DvrCleanup() + ENDIF + ENDIF !............................................................................................................................... ! Routines called in loose coupling -- the glue code may implement this in various ways @@ -434,11 +485,31 @@ PROGRAM HydroDynDriver END IF - IF ( u(1)%Morison%DistribMesh%Initialized ) THEN - IF ( drvrInitInp%MorisonInputsMod == 2 ) THEN - ! Set the Morison Inputs from a time series input file + IF ( drvrInitInp%MorisonInputsMod == 2 ) THEN + ! Set the Morison Inputs from a time series input file + PMesh%TranslationDisp(:,1) = MorisonIn(n,2:4) + + ! Compute direction cosine matrix from the rotation angles + IF ( abs(MorisonIn(n,5)) > maxAngle ) maxAngle = abs(MorisonIn(n,5)) + IF ( abs(MorisonIn(n,6)) > maxAngle ) maxAngle = abs(MorisonIn(n,6)) + IF ( abs(MorisonIn(n,7)) > maxAngle ) maxAngle = abs(MorisonIn(n,7)) + + CALL SmllRotTrans( 'InputRotation', REAL(MorisonIn(n,5),ReKi), REAL(MorisonIn(n,6),ReKi), REAL(MorisonIn(n,7),ReKi), dcm, 'Junk', ErrStat, ErrMsg ) + PMesh%Orientation(:,:,1) = dcm + + PMesh%TranslationVel(:,1) = MorisonIn(n,8:10) + PMesh%RotationVel(:,1) = MorisonIn(n,11:13) + PMesh%TranslationAcc(:,1) = MorisonIn(n,14:16) + PMesh%RotationAcc(:,1) = MorisonIn(n,17:19) + + IF ( u(1)%Morison%DistribMesh%Initialized ) THEN + CALL Transfer_Point_to_Line2( PMesh, u(1)%Morison%DistribMesh, Map_P_to_MorisonDist, ErrStat, ErrMsg ) + if (errStat >= AbortErrLev) call HD_DvrCleanup() + END IF + IF ( u(1)%Morison%LumpedMesh%Initialized ) THEN + CALL Transfer_Point_to_Point( PMesh, u(1)%Morison%LumpedMesh, Map_P_to_MorisonLumped, ErrStat, ErrMsg ) + if (errStat >= AbortErrLev) call HD_DvrCleanup() END IF - END IF diff --git a/modules/inflowwind/src/IfW_UniformWind.f90 b/modules/inflowwind/src/IfW_UniformWind.f90 index 4046dff5a7..a046da5bd2 100644 --- a/modules/inflowwind/src/IfW_UniformWind.f90 +++ b/modules/inflowwind/src/IfW_UniformWind.f90 @@ -95,7 +95,7 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS ! Passed Variables TYPE(IfW_UniformWind_InitInputType), INTENT(IN ) :: InitData !< Input data for initialization TYPE(IfW_UniformWind_ParameterType), INTENT( OUT) :: ParamData !< Parameters - TYPE(IfW_UniformWind_MiscVarType), INTENT( OUT) :: MiscVars !< Misc variables for optimization (not copied in glue code) + TYPE(IfW_UniformWind_MiscVarType), INTENT(INOUT) :: MiscVars !< Misc variables for optimization (not copied in glue code) TYPE(IfW_UniformWind_InitOutputType), INTENT( OUT) :: InitOutData !< Initial output @@ -109,14 +109,13 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS INTEGER(IntKi), PARAMETER :: MaxNumCols = 9 ! maximum number of columns in the Uniform file INTEGER(IntKi) :: NumCols ! Number of columns in the Uniform file REAL(ReKi) :: TmpData(MaxNumCols) ! Temp variable for reading all columns from a line + INTEGER(IntKi) :: LineNo REAL(ReKi) :: DelDiff ! Temp variable for storing the direction difference - INTEGER(IntKi) :: UnitWind ! Unit number for the InflowWind input file INTEGER(IntKi) :: I - INTEGER(IntKi) :: NumComments INTEGER(IntKi) :: ILine ! Counts the line number in the file INTEGER(IntKi), PARAMETER :: MaxTries = 100 - CHARACTER(1024) :: Line ! Temp variable for reading whole line from file + TYPE(FileInfoType) :: InFileInfo !< The derived type for holding the full input file for parsing -- we may pass this in the future ! Temporary variables for error handling INTEGER(IntKi) :: TmpErrStat ! Temp variable for the error status @@ -139,14 +138,6 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS RETURN END IF - - ! Get a unit number to use - - CALL GetNewUnit(UnitWind, TmpErrStat, TmpErrMsg) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - !------------------------------------------------------------------------------------------------- ! Copy things from the InitData to the ParamData !------------------------------------------------------------------------------------------------- @@ -154,192 +145,54 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS ParamData%RefHt = InitData%ReferenceHeight ParamData%RefLength = InitData%RefLength + ! Read in the data from a file, or copy from the passed InFileInfo. After this, the InFileInfo + ! should contain only a table -- all comments and empty lines have been stripped out + IF ( InitData%UseInputFile ) THEN + CALL ProcessComFile( InitData%WindFileName, InFileInfo, TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ELSE + CALL NWTC_Library_CopyFileInfoType( InitData%PassedFileData, InFileInfo, MESH_NEWCOPY, TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ENDIF - !------------------------------------------------------------------------------------------------- - ! Open the file for reading - !------------------------------------------------------------------------------------------------- - - CALL OpenFInpFile (UnitWind, TRIM(InitData%WindFileName), TmpErrStat, TmpErrMsg) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) RETURN + ! For diagnostic purposes, the following can be used to display the contents + ! of the InFileInfo data structure. + ! call Print_FileInfo_Struct( CU, InFileInfo ) ! CU is the screen -- different number on different systems. !------------------------------------------------------------------------------------------------- - ! Find the number of comment lines + ! Allocate the data arrays !------------------------------------------------------------------------------------------------- - LINE = '!' ! Initialize the line for the DO WHILE LOOP - NumComments = -1 ! the last line we read is not a comment, so we'll initialize this to -1 instead of 0 - - DO WHILE ( (INDEX( LINE, '!' ) > 0) .OR. (INDEX( LINE, '#' ) > 0) .OR. (INDEX( LINE, '%' ) > 0) ) ! Lines containing "!" are treated as comment lines - NumComments = NumComments + 1 - - READ(UnitWind,'( A )',IOSTAT=TmpErrStat) LINE - - IF ( TmpErrStat /=0 ) THEN - CALL SetErrStat(ErrID_Fatal,' Error reading from uniform wind file on line '//TRIM(Num2LStr(NumComments+1))//'.', & - ErrStat, ErrMsg, RoutineName) - CLOSE(UnitWind) - RETURN - END IF - - END DO !WHILE + ParamData%NumDataLines = InFileInfo%NumLines + CALL Alloc_ParamDataArrays( ParamData, TmpErrStat, TmpErrMsg) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN !------------------------------------------------------------------------------------------------- - ! Find the number of data lines + ! Store the data arrays !------------------------------------------------------------------------------------------------- - ParamData%NumDataLines = 0 - + ! Check if 9 columns NumCols = MaxNumCols - READ(LINE,*,IOSTAT=TmpErrStat) ( TmpData(I), I=1,NumCols ) ! this line was read when we were figuring out the comment lines; let's see if it contains all of the columns + LineNo = 1 ! Start at begining + CALL ParseAry( InFileInfo, LineNo, "Wind type 2 line", TmpData(1:NumCols), NumCols, TmpErrStat, TmpErrMsg ) if (TmpErrStat /= 0) then ! assume the upflow is 0 and try reading the rest of the files CALL SetErrStat(ErrID_Info,' Could not read upflow column in uniform wind files. Assuming upflow is 0.', ErrStat, ErrMsg, RoutineName) NumCols = NumCols - 1 - READ(LINE,*,IOSTAT=TmpErrStat) ( TmpData(I), I=1,NumCols ) ! this line was read when we were figuring out the comment lines; let's make sure it contains numeric column data end if - - - DO WHILE (TmpErrStat == 0) ! read the rest of the file (until an error occurs) - ParamData%NumDataLines = ParamData%NumDataLines + 1 - - READ(UnitWind,*,IOSTAT=TmpErrStat) ( TmpData(I), I=1,NumCols ) - - END DO !WHILE - - - IF (ParamData%NumDataLines < 1) THEN - TmpErrMsg= 'Error: '//TRIM(Num2LStr(NumComments))//' comment lines were found in the uniform wind file, '// & - 'but the first data line does not contain the proper format.' - CALL SetErrStat(ErrID_Fatal,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - CLOSE(UnitWind) - RETURN - END IF - - - !------------------------------------------------------------------------------------------------- - ! Allocate arrays for the uniform wind data - !------------------------------------------------------------------------------------------------- - ! BJJ note: If the subroutine AllocAry() is called, the CVF compiler with A2AD does not work - ! properly. The arrays are not properly read even though they've been allocated. - ! ADP note: the above note may or may not apply after conversion to the modular framework in 2013 - !------------------------------------------------------------------------------------------------- - - IF (.NOT. ALLOCATED(ParamData%Tdata) ) THEN - CALL AllocAry( ParamData%Tdata, ParamData%NumDataLines, 'Uniform wind time', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%V) ) THEN - CALL AllocAry( ParamData%V, ParamData%NumDataLines, 'Uniform wind horizontal wind speed', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%Delta) ) THEN - CALL AllocAry( ParamData%Delta, ParamData%NumDataLines, 'Uniform wind direction', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%Upflow) ) THEN - CALL AllocAry( ParamData%Upflow, ParamData%NumDataLines, 'Uniform wind upflow', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - ParamData%Upflow = 0.0_ReKi - - IF (.NOT. ALLOCATED(ParamData%VZ) ) THEN - CALL AllocAry( ParamData%VZ, ParamData%NumDataLines, 'Uniform vertical wind speed', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%HShr) ) THEN - CALL AllocAry( ParamData%HShr, ParamData%NumDataLines, 'Uniform horizontal linear shear', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%VShr) ) THEN - CALL AllocAry( ParamData%VShr, ParamData%NumDataLines, 'Uniform vertical power-law shear exponent', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%VLinShr) ) THEN - CALL AllocAry( ParamData%VLinShr, ParamData%NumDataLines, 'Uniform vertical linear shear', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - IF (.NOT. ALLOCATED(ParamData%VGust) ) THEN - CALL AllocAry( ParamData%VGust, ParamData%NumDataLines, 'Uniform gust velocity', TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END IF - - - !------------------------------------------------------------------------------------------------- - ! Rewind the file (to the beginning) and skip the comment lines - !------------------------------------------------------------------------------------------------- - - REWIND( UnitWind ) - - DO I=1,NumComments - CALL ReadCom( UnitWind, TRIM(InitData%WindFileName), 'Header line #'//TRIM(Num2LStr(I)), TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF - END DO !I - !------------------------------------------------------------------------------------------------- - ! Read the data arrays - !------------------------------------------------------------------------------------------------- - + ! Parse the data and store it + LineNo = 1 DO I=1,ParamData%NumDataLines - - CALL ReadAry( UnitWind, TRIM(InitData%WindFileName), TmpData(1:NumCols), NumCols, 'TmpData', & - 'Data from uniform wind file line '//TRIM(Num2LStr(NumComments+I)), TmpErrStat, TmpErrMsg) - CALL SetErrStat(TmpErrStat,'Error retrieving data from the uniform wind file line'//TRIM(Num2LStr(NumComments+I)), & - ErrStat,ErrMsg,RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CLOSE(UnitWind) - RETURN - ENDIF + CALL ParseAry( InFileInfo, LineNo, "Wind type 2 file line", TmpData(1:NumCols), NumCols, TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN ParamData%Tdata( I) = TmpData(1) ParamData%V( I) = TmpData(2) @@ -349,12 +202,10 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS ParamData%VShr( I) = TmpData(6) ParamData%VLinShr(I) = TmpData(7) ParamData%VGust( I) = TmpData(8) - - if (NumCols > 8) ParamData%Upflow( I) = TmpData(9)*D2R - END DO !I + !------------------------------------------------------------------------------------------------- ! Make sure the wind direction isn't jumping more than 180 degrees between any 2 consecutive ! input times. (Avoids interpolation errors with modular arithemetic.) @@ -386,8 +237,6 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS END DO !I - - !------------------------------------------------------------------------------------------------- ! Find out information on the timesteps and range !------------------------------------------------------------------------------------------------- @@ -423,15 +272,6 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS ! Number of timesteps InitOutData%WindFileNumTSteps = ParamData%NumDataLines - - - !------------------------------------------------------------------------------------------------- - ! Close the file - !------------------------------------------------------------------------------------------------- - - CLOSE( UnitWind ) - - !------------------------------------------------------------------------------------------------- ! Print warnings and messages !------------------------------------------------------------------------------------------------- @@ -496,6 +336,89 @@ SUBROUTINE IfW_UniformWind_Init(InitData, ParamData, MiscVars, InitOutData, ErrS END SUBROUTINE IfW_UniformWind_Init +SUBROUTINE Alloc_ParamDataArrays( ParamData, ErrStat, ErrMsg ) + + IMPLICIT NONE + CHARACTER(*), PARAMETER :: RoutineName="Alloc_ParamDataArrays" + + TYPE(IfW_UniformWind_ParameterType), INTENT(INOUT) :: ParamData !< Parameters + + ! Error handling + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< determines if an error has been encountered + CHARACTER(*), INTENT( OUT) :: ErrMsg !< A message about the error + + ! Temporary variables for error handling + INTEGER(IntKi) :: TmpErrStat ! Temp variable for the error status + CHARACTER(ErrMsgLen) :: TmpErrMsg ! Temporary error message + + ErrStat = ErrID_None + ErrMsg = "" + + !------------------------------------------------------------------------------------------------- + ! Allocate arrays for the uniform wind data + !------------------------------------------------------------------------------------------------- + ! BJJ note: If the subroutine AllocAry() is called, the CVF compiler with A2AD does not work + ! properly. The arrays are not properly read even though they've been allocated. + ! ADP note: the above note may or may not apply after conversion to the modular framework in 2013 + !------------------------------------------------------------------------------------------------- + + IF (.NOT. ALLOCATED(ParamData%Tdata) ) THEN + CALL AllocAry( ParamData%Tdata, ParamData%NumDataLines, 'Uniform wind time', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%V) ) THEN + CALL AllocAry( ParamData%V, ParamData%NumDataLines, 'Uniform wind horizontal wind speed', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%Delta) ) THEN + CALL AllocAry( ParamData%Delta, ParamData%NumDataLines, 'Uniform wind direction', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%VZ) ) THEN + CALL AllocAry( ParamData%VZ, ParamData%NumDataLines, 'Uniform vertical wind speed', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%HShr) ) THEN + CALL AllocAry( ParamData%HShr, ParamData%NumDataLines, 'Uniform horizontal linear shear', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%VShr) ) THEN + CALL AllocAry( ParamData%VShr, ParamData%NumDataLines, 'Uniform vertical power-law shear exponent', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%VLinShr) ) THEN + CALL AllocAry( ParamData%VLinShr, ParamData%NumDataLines, 'Uniform vertical linear shear', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%VGust) ) THEN + CALL AllocAry( ParamData%VGust, ParamData%NumDataLines, 'Uniform gust velocity', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + IF (.NOT. ALLOCATED(ParamData%Upflow) ) THEN + CALL AllocAry( ParamData%Upflow, ParamData%NumDataLines, 'Uniform wind upflow', TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + ParamData%Upflow = 0.0_ReKi + +END SUBROUTINE Alloc_ParamDataArrays + !==================================================================================================== !------------------------------------------------------------------------------------------------- diff --git a/modules/inflowwind/src/IfW_UniformWind.txt b/modules/inflowwind/src/IfW_UniformWind.txt index 7282fb5878..df99ddd79e 100644 --- a/modules/inflowwind/src/IfW_UniformWind.txt +++ b/modules/inflowwind/src/IfW_UniformWind.txt @@ -12,10 +12,12 @@ include Registry_NWTC_Library.txt ######################### -typedef IfW_UniformWind/IfW_UniformWind InitInputType CHARACTER(1024) WindFileName - - - "Name of the wind file to use" - -typedef ^ ^ ReKi ReferenceHeight - - - "Hub height of the turbine" meters -typedef ^ ^ ReKi RefLength - - - "RefLength of the wind field to use" meters -typedef ^ ^ IntKi SumFileUnit - - - "Unit number for the summary file (-1 for none). Provided by IfW." - +typedef IfW_UniformWind/IfW_UniformWind InitInputType CHARACTER(1024) WindFileName - - - "Name of the wind file to use" - +typedef ^ ^ ReKi ReferenceHeight - - - "Hub height of the turbine" meters +typedef ^ ^ ReKi RefLength - - - "RefLength of the wind field to use" meters +typedef ^ ^ IntKi SumFileUnit - - - "Unit number for the summary file (-1 for none). Provided by IfW." - +typedef ^ ^ LOGICAL UseInputFile - .TRUE. - "Flag for toggling file based IO in wind type 2." - +typedef ^ ^ FileInfoType PassedFileData - - - "Optional slot for wind type 2 data if file IO is not used." - @@ -30,7 +32,7 @@ typedef ^ ^ LOGICAL WindFileConsta # ..... Misc/Optimization variables................................................................................................. # Define any data that are used only for efficiency purposes (these variables are not associated with time): # e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. -typedef ^ MiscVarType IntKi TimeIndex - - - "An Index into the TData array" - +typedef ^ MiscVarType IntKi TimeIndex - 0 - "An Index into the TData array" - # ..... Parameters ................................................................................................................ diff --git a/modules/inflowwind/src/IfW_UniformWind_Types.f90 b/modules/inflowwind/src/IfW_UniformWind_Types.f90 index d5e26773e9..8c344bd7c5 100644 --- a/modules/inflowwind/src/IfW_UniformWind_Types.f90 +++ b/modules/inflowwind/src/IfW_UniformWind_Types.f90 @@ -39,6 +39,8 @@ MODULE IfW_UniformWind_Types REAL(ReKi) :: ReferenceHeight !< Hub height of the turbine [meters] REAL(ReKi) :: RefLength !< RefLength of the wind field to use [meters] INTEGER(IntKi) :: SumFileUnit !< Unit number for the summary file (-1 for none). Provided by IfW. [-] + LOGICAL :: UseInputFile = .TRUE. !< Flag for toggling file based IO in wind type 2. [-] + TYPE(FileInfoType) :: PassedFileData !< Optional slot for wind type 2 data if file IO is not used. [-] END TYPE IfW_UniformWind_InitInputType ! ======================= ! ========= IfW_UniformWind_InitOutputType ======= @@ -52,7 +54,7 @@ MODULE IfW_UniformWind_Types ! ======================= ! ========= IfW_UniformWind_MiscVarType ======= TYPE, PUBLIC :: IfW_UniformWind_MiscVarType - INTEGER(IntKi) :: TimeIndex !< An Index into the TData array [-] + INTEGER(IntKi) :: TimeIndex = 0 !< An Index into the TData array [-] END TYPE IfW_UniformWind_MiscVarType ! ======================= ! ========= IfW_UniformWind_ParameterType ======= @@ -103,6 +105,10 @@ SUBROUTINE IfW_UniformWind_CopyInitInput( SrcInitInputData, DstInitInputData, Ct DstInitInputData%ReferenceHeight = SrcInitInputData%ReferenceHeight DstInitInputData%RefLength = SrcInitInputData%RefLength DstInitInputData%SumFileUnit = SrcInitInputData%SumFileUnit + DstInitInputData%UseInputFile = SrcInitInputData%UseInputFile + CALL NWTC_Library_Copyfileinfotype( SrcInitInputData%PassedFileData, DstInitInputData%PassedFileData, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE IfW_UniformWind_CopyInitInput SUBROUTINE IfW_UniformWind_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) @@ -114,6 +120,7 @@ SUBROUTINE IfW_UniformWind_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" + CALL NWTC_Library_Destroyfileinfotype( InitInputData%PassedFileData, ErrStat, ErrMsg ) END SUBROUTINE IfW_UniformWind_DestroyInitInput SUBROUTINE IfW_UniformWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -155,6 +162,25 @@ SUBROUTINE IfW_UniformWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, Er Re_BufSz = Re_BufSz + 1 ! ReferenceHeight Re_BufSz = Re_BufSz + 1 ! RefLength Int_BufSz = Int_BufSz + 1 ! SumFileUnit + Int_BufSz = Int_BufSz + 1 ! UseInputFile + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! PassedFileData: size of buffers for each call to pack subtype + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, .TRUE. ) ! PassedFileData + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! PassedFileData + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! PassedFileData + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! PassedFileData + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -192,6 +218,36 @@ SUBROUTINE IfW_UniformWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, Er Re_Xferred = Re_Xferred + 1 IntKiBuf(Int_Xferred) = InData%SumFileUnit Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%UseInputFile, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, OnlySize ) ! PassedFileData + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF END SUBROUTINE IfW_UniformWind_PackInitInput SUBROUTINE IfW_UniformWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -231,6 +287,48 @@ SUBROUTINE IfW_UniformWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, Re_Xferred = Re_Xferred + 1 OutData%SumFileUnit = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%UseInputFile = TRANSFER(IntKiBuf(Int_Xferred), OutData%UseInputFile) + Int_Xferred = Int_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackfileinfotype( Re_Buf, Db_Buf, Int_Buf, OutData%PassedFileData, ErrStat2, ErrMsg2 ) ! PassedFileData + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END SUBROUTINE IfW_UniformWind_UnPackInitInput SUBROUTINE IfW_UniformWind_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 358246933c..ee9701f585 100644 --- a/modules/inflowwind/src/InflowWind.f90 +++ b/modules/inflowwind/src/InflowWind.f90 @@ -146,13 +146,14 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, TYPE(IfW_4Dext_InitOutputType) :: FDext_InitOutData !< initialization info + TYPE(FileInfoType) :: InFileInfo !< The derived type for holding the full input file for parsing -- we may pass this in the future !!! TYPE(CTBladed_Backgr) :: BackGrndValues ! Temporary variables for error handling INTEGER(IntKi) :: TmpErrStat CHARACTER(ErrMsgLen) :: TmpErrMsg !< temporary error message - + CHARACTER(1024) :: PriPath ! Local Variables INTEGER(IntKi) :: I, j !< Generic counter @@ -189,37 +190,51 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, EchoFileName = TRIM(p%RootFileName)//".ech" SumFileName = TRIM(p%RootFileName)//".sum" + ! these values (and others hard-coded in lidar_init) should be set in the input file, too + InputFileData%SensorType = InitInp%lidar%SensorType + InputFileData%NumPulseGate = InitInp%lidar%NumPulseGate + InputFileData%RotorApexOffsetPos = InitInp%lidar%RotorApexOffsetPos + InputFileData%LidRadialVel = InitInp%lidar%LidRadialVel ! Parse all the InflowWind related input files and populate the *_InitDataType derived types + CALL GetPath( InitInp%InputFileName, PriPath ) IF ( InitInp%UseInputFile ) THEN - CALL InflowWind_ReadInput( InitInp%InputFileName, EchoFileName, InputFileData, TmpErrStat, TmpErrMsg ) + CALL ProcessComFile( InitInp%InputFileName, InFileInfo, TmpErrStat, TmpErrMsg ) + ! For diagnostic purposes, the following can be used to display the contents + ! of the InFileInfo data structure. + ! call Print_FileInfo_Struct( CU, InFileInfo ) ! CU is the screen -- different number on different systems. + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() RETURN ENDIF - - ! these values (and others hard-coded in lidar_init) should be set in the input file, too - InputFileData%SensorType = InitInp%lidar%SensorType - InputFileData%NumPulseGate = InitInp%lidar%NumPulseGate - InputFileData%RotorApexOffsetPos = InitInp%lidar%RotorApexOffsetPos - InputFileData%LidRadialVel = InitInp%lidar%LidRadialVel ELSE - - CALL InflowWind_CopyInputFile( InitInp%PassedFileData, InputFileData, MESH_NEWCOPY, TmpErrStat, TmpErrMsg ) - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + CALL NWTC_Library_CopyFileInfoType( InitInp%PassedFileData, InFileInfo, MESH_NEWCOPY, TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + RETURN + ENDIF ENDIF + CALL InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, TmpErrStat, TmpErrMsg ) + CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) THEN + CALL Cleanup() + CALL InflowWind_DestroyInputFile( InputFileData, TmpErrStat, TmpErrMsg ) + RETURN + ENDIF ! let's tell InflowWind if an external module (e.g., FAST.Farm) is going to set the velocity grids. + IF ( InitInp%Use4Dext) then InputFileData%WindType = FDext_WindNumber InputFileData%PropagationDir = 0.0_ReKi ! wind is in XYZ coordinates (already rotated if necessary), so don't rotate it again END IF - - + ! initialize sensor data: CALL Lidar_Init( InitInp, InputGuess, p, ContStates, DiscStates, ConstrStateGuess, OtherStates, & y, m, TimeInterval, InitOutData, TmpErrStat, TmpErrMsg ) @@ -391,6 +406,9 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Uniform_InitData%WindFileName = InputFileData%Uniform_FileName Uniform_InitData%SumFileUnit = SumFileUnit + Uniform_InitData%UseInputFile = InitInp%WindType2UseInputFile + Uniform_InitData%PassedFileData = InitInp%WindType2Data + ! Initialize the UniformWind module CALL IfW_UniformWind_Init(Uniform_InitData, p%UniformWind, & m%UniformWind, Uniform_InitOutData, TmpErrStat, TmpErrMsg) diff --git a/modules/inflowwind/src/InflowWind.txt b/modules/inflowwind/src/InflowWind.txt index aae6825d9a..98d21cb8d5 100644 --- a/modules/inflowwind/src/InflowWind.txt +++ b/modules/inflowwind/src/InflowWind.txt @@ -76,7 +76,7 @@ typedef ^ ^ ReKi Uniform_Ref typedef ^ ^ CHARACTER(1024) TSFF_FileName - - - "TurbSim Full-Field -- filename" - typedef ^ ^ CHARACTER(1024) BladedFF_FileName - - - "Bladed-style Full-Field -- filename" - typedef ^ ^ LOGICAL BladedFF_TowerFile - - - "Bladed-style Full-Field -- tower file exists" - -typedef ^ ^ LOGICAL CTTS_CoherentTurb - - - "Coherent turbulence data exists" - +typedef ^ ^ LOGICAL CTTS_CoherentTurb - .FALSE. - "Coherent turbulence data exists" - typedef ^ ^ CHARACTER(1024) CTTS_FileName - - - "Name of coherent turbulence file" - typedef ^ ^ CHARACTER(1024) CTTS_Path - - - "Path to coherent turbulence binary data files" - typedef ^ ^ CHARACTER(1024) HAWC_FileName_u - - - "HAWC -- u component binary data file name" - @@ -104,8 +104,10 @@ typedef ^ ^ LOGICAL Linearize typedef ^ ^ LOGICAL Use4Dext - .FALSE. - "Flag that tells this module if an external module will pass it 4-D velocity grids." - typedef ^ ^ IntKi NumWindPoints - - - "Number of wind velocity points expected" - typedef ^ ^ LOGICAL UseInputFile - .TRUE. - "Should we read everthing from an input file, or do we get it some other way" - -typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" -typedef ^ ^ InflowWind_InputFile PassedFileData - - - "If we don't use the input file, pass everything through this" - +typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" +typedef ^ ^ FileInfoType PassedFileData - - - "If we don't use the input file, pass everything through this" - +typedef ^ ^ LOGICAL WindType2UseInputFile - .TRUE. - "Flag for toggling file based IO in wind type 2." - +typedef ^ ^ FileInfoType WindType2Data - - - "Optional slot for wind type 2 data if file IO is not used." - typedef ^ ^ Lidar_InitInputType lidar - - - "InitInput for lidar data" - typedef ^ ^ IfW_4Dext_InitInputType FDext - - - "InitInput for lidar data" - diff --git a/modules/inflowwind/src/InflowWind_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index 9f0a2dd13c..b9251606f7 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -154,203 +154,72 @@ MODULE InflowWind_Subs CONTAINS - !==================================================================================================== -!> This public subroutine reads the input required for InflowWind from the file whose name is an -!! input parameter. -SUBROUTINE InflowWind_ReadInput( InputFileName, EchoFileName, InputFileData, ErrStat, ErrMsg ) +!> This public subroutine parses the array of strings in InputFileData for the input parameters. +SUBROUTINE InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, ErrStat, ErrMsg ) !---------------------------------------------------------------------------------------------------- - IMPLICIT NONE - - CHARACTER(*), PARAMETER :: RoutineName="InflowWind_ReadInput" - + IMPLICIT NONE + CHARACTER(*), PARAMETER :: RoutineName="InflowWind_ParseInputFileInfo" ! Passed variables - CHARACTER(*), INTENT(IN ) :: InputFileName !< name of the input file - CHARACTER(*), INTENT(IN ) :: EchoFileName !< name of the echo file - TYPE(InflowWind_InputFile), INTENT(INOUT) :: InputFileData !< The data for initialization - INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Returned error status from this subroutine - CHARACTER(*), INTENT( OUT) :: ErrMsg !< Returned error message from this subroutine + TYPE(InflowWind_InputFile), INTENT(INOUT) :: InputFileData !< Data of the InflowWind Input File + TYPE(FileInfoType), INTENT(IN ) :: InFileInfo !< The derived type for holding the file information + CHARACTER(*), INTENT(IN ) :: PriPath !< Path to InflowWind input files + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Returned error status from this subroutine + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Returned error message from this subroutine ! Local variables - INTEGER(IntKi) :: UnitInput !< Unit number for the input file - INTEGER(IntKi) :: UnitEcho !< The local unit number for this module's echo file - CHARACTER(35) :: Frmt !< Output format for logical parameters. (matches NWTC Subroutine Library format) - + INTEGER(IntKi) :: CurLine !< Current entry in InFileInfo%Lines array ! Temoporary messages INTEGER(IntKi) :: TmpErrStat CHARACTER(ErrMsgLen) :: TmpErrMsg - CHARACTER(1024) :: PriPath ! Path name of the primary file - - InputFileData%VFlowAngle = 0.0 ! default vertical flow angle - - ! Initialize local data - - UnitEcho = -1 - Frmt = "( 2X, L11, 2X, A, T30, ' - ', A )" + ! Initializatio ErrStat = ErrID_None ErrMsg = "" - InputFileData%EchoFlag = .FALSE. ! initialize for error handling (cleanup() routine) - CALL GetPath( InputFileName, PriPath ) ! Input files will be relative to the path where the primary input file is located. - + InputFileData%EchoFlag = .FALSE. ! initialize for error handling (cleanup() routine) - ! allocate the array for the OutList + ! Allocate the array for the OutList CALL AllocAry( InputFileData%OutList, MaxOutPts, "InflowWind Input File's OutList", TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - !------------------------------------------------------------------------------------------------- - ! Open the file - !------------------------------------------------------------------------------------------------- + IF (ErrStat >= AbortErrLev) RETURN - CALL GetNewUnit( UnitInput, TmpErrStat, TmpErrMsg ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + !--------------------------------------------------------------------------------------------- + ! General settings with wind type, direction and output point list (applies to all wind types) + !--------------------------------------------------------------------------------------------- - CALL OpenFInpFile( UnitInput, TRIM(InputFileName), TmpErrStat, TmpErrMsg ) + CurLine = 4 + CALL ParseVar( InFileInfo, CurLine, "Echo", InputFileData%EchoFlag, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - ! Tell the users what we are doing... though this part should be rather quick. - ! CALL WrScr( ' Opening InflowWind input file: '//InputFileName ) - - - !------------------------------------------------------------------------------------------------- - ! File header - !------------------------------------------------------------------------------------------------- + IF (ErrStat >= AbortErrLev) RETURN - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file header line 1', TmpErrStat, TmpErrMsg ) + ! switch for wind file type (1=steady; 2=uniform; 3=binary TurbSim FF; 4=binary Bladed-style FF; 5=HAWC format; 6=User defined; 7=native Bladed FF) + CALL ParseVar( InFileInfo, CurLine, "WindType", InputFileData%WindType, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file header line 2', TmpErrStat, TmpErrMsg ) + ! Direction of wind propagation (meteorological direction) (deg) + CALL ParseVar( InFileInfo, CurLine, "PropagationDir", InputFileData%PropagationDir, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg ) + ! VFlowAngle: Upflow angle (deg) + CALL ParseVarWDefault( InFileInfo, CurLine, "VFlowAng", InputFileData%VFlowAngle, 0.0_ReKi, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - ! Echo Input Files. + IF (ErrStat >= AbortErrLev) RETURN - CALL ReadVar ( UnitInput, InputFileName, InputFileData%EchoFlag, 'Echo', 'Echo Input', TmpErrStat, TmpErrMsg ) + ! NWindVel: Number of points to output the wind velocity (0 to 9) + CALL ParseVar( InFileInfo, CurLine, "NWindVel", InputFileData%NWindVel, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! If we are Echoing the input then we should re-read the first three lines so that we can echo them - ! using the NWTC_Library routines. The echoing is done inside those routines via a global variable - ! which we must store, set, and then replace on error or completion. - - IF ( InputFileData%EchoFlag ) THEN - - CALL OpenEcho ( UnitEcho, TRIM(EchoFileName), TmpErrStat, TmpErrMsg ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - END IF - - REWIND(UnitInput) - - - ! The input file was already successfully read through up to this point, so we shouldn't have any read - ! errors in the first four lines. So, we won't worry about checking the error status here. - - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file header line 1', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file header line 2', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - ! Echo Input Files. - - CALL ReadVar ( UnitInput, InputFileName, InputFileData%EchoFlag, 'Echo', 'Echo the input file data', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - - END IF - - - - !------------------------------------------------------------------------------------------------- - !> Read general section with wind type, direction, and output point list (applies to all wind types) - !------------------------------------------------------------------------------------------------- - - - ! Read WindType - CALL ReadVar( UnitInput, InputFileName, InputFileData%WindType, 'WindType', & - 'switch for wind file type (1=steady; 2=uniform; 3=binary TurbSim FF; '//& - '4=binary Bladed-style FF; 5=HAWC format; 6=User defined; 7=native Bladed FF)', & - TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - - ! Read PropagationDir - CALL ReadVar( UnitInput, InputFileName, InputFileData%PropagationDir, 'PropagationDir', & - 'Direction of wind propagation (meteorological direction) (deg)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - - ! Read Upflow angle: - CALL ReadVar( UnitInput, InputFileName, InputFileData%VFlowAngle, 'VFlowAngle', & - 'Upflow angle (deg)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - - - ! Read the number of points for the wind velocity output - CALL ReadVar( UnitInput, InputFileName, InputFileData%NWindVel, 'NWindVel', & - 'Number of points to output the wind velocity (0 to 9)', & - TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN ! Before proceeding, make sure that NWindVel makes sense IF ( InputFileData%NWindVel < 0 .OR. InputFileData%NwindVel > 9 ) THEN CALL SetErrStat( ErrID_Fatal, 'NWindVel must be greater than or equal to zero and less than 10.', & ErrStat, ErrMsg, RoutineName ) - CALL CleanUp() RETURN ELSE @@ -361,551 +230,241 @@ SUBROUTINE InflowWind_ReadInput( InputFileName, EchoFileName, InputFileData, Err CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) CALL AllocAry( InputFileData%WindVziList, InputFileData%NWindVel, 'WindVziList', TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN ENDIF - ! Read in the values of WindVxiList - CALL ReadAry( UnitInput, InputFileName, InputFileData%WindVxiList, InputFileData%NWindVel, 'WindVxiList', & - 'List of coordinates in the inertial X direction (m)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - ! Read in the values of WindVxiList - CALL ReadAry( UnitInput, InputFileName, InputFileData%WindVyiList, InputFileData%NWindVel, 'WindVyiList', & - 'List of coordinates in the inertial Y direction (m)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + CALL ParseAry( InFileInfo, CurLine, 'WindVxiList', InputFileData%WindVxiList, InputFileData%NWindVel, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN - ! Read in the values of WindVziList - CALL ReadAry( UnitInput, InputFileName, InputFileData%WindVziList, InputFileData%NWindVel, 'WindVziList', & - 'List of coordinates in the inertial Z direction (m)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + CALL ParseAry( InFileInfo, CurLine, 'WindVyiList', InputFileData%WindVyiList, InputFileData%NWindVel, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN + CALL ParseAry( InFileInfo, CurLine, 'WindVziList', InputFileData%WindVziList, InputFileData%NWindVel, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN !------------------------------------------------------------------------------------------------- !> Read the _Parameters for Steady Wind Conditions [used only for WindType = 1]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "HWindSpeed", InputFileData%Steady_HWindSpeed, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - ! Read HWindSpeed - CALL ReadVar( UnitInput, InputFileName, InputFileData%Steady_HWindSpeed, 'HWindSpeed', & - 'Horizontal windspeed for steady wind', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - ! Read RefHt - CALL ReadVar( UnitInput, InputFileName, InputFileData%Steady_RefHt, 'RefHt', & - 'Reference height for horizontal wind speed for steady wind', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN - ! Read PLexp - CALL ReadVar( UnitInput, InputFileName, InputFileData%Steady_PLexp, 'PLexp', & - 'Power law exponent for steady wind', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + CALL ParseVar( InFileInfo, CurLine, "RefHt", InputFileData%Steady_RefHt, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN + CALL ParseVar( InFileInfo, CurLine, "PLexp", InputFileData%Steady_PLexp, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN !------------------------------------------------------------------------------------------------- !> Read the _Parameters for Uniform wind file [used only for WindType = 2]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "FileName_Uni", InputFileData%Uniform_FileName, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! Read UniformWindFile - CALL ReadVar( UnitInput, InputFileName, InputFileData%Uniform_FileName, 'WindFileName', & - 'Filename of time series data for uniform wind field', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%Uniform_FileName ) ) InputFileData%Uniform_FileName = TRIM(PriPath)//TRIM(InputFileData%Uniform_FileName) - ! Read RefHt - CALL ReadVar( UnitInput, InputFileName, InputFileData%Uniform_RefHt, 'RefHt', & - 'Reference height for uniform wind file', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - ! Read RefLength - CALL ReadVar( UnitInput, InputFileName, InputFileData%Uniform_RefLength, 'RefLength', & - 'Reference length for uniform wind file', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + CALL ParseVar( InFileInfo, CurLine, "RefHt_Uni", InputFileData%Uniform_RefHt, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN + CALL ParseVar( InFileInfo, CurLine, "RefLength", InputFileData%Uniform_RefLength, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN !------------------------------------------------------------------------------------------------- !> Read the _Parameters for Binary TurbSim Full-Field files [used only for WindType = 3]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "FileName_BTS", InputFileData%TSFF_FileName, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! Read TSFFWind info - CALL ReadVar( UnitInput, InputFileName, InputFileData%TSFF_FileName, 'FileName', & - 'Name of the TurbSim full field wind file to use (.bts)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%TSFF_FileName ) ) InputFileData%TSFF_FileName = TRIM(PriPath)//TRIM(InputFileData%TSFF_FileName) - !------------------------------------------------------------------------------------------------- !> Read the _Parameters for Binary Bladed-style Full-Field files [used only for WindType = 4]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "FilenameRoot", InputFileData%BladedFF_FileName, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! Read BladedStyle%WindFileName - CALL ReadVar( UnitInput, InputFileName, InputFileData%BladedFF_FileName, 'FileName', & - 'Rootname of the full-field wind file to use (.wnd, .sum)', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%BladedFF_FileName ) ) InputFileData%BladedFF_FileName = TRIM(PriPath)//TRIM(InputFileData%BladedFF_FileName) - - ! Read TowerFileFlag - CALL ReadVar( UnitInput, InputFileName, InputFileData%BladedFF_TowerFile, 'TowerFileFlag', & - 'Have tower file (.twr) [flag]', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF -#ifdef UNUSED_INPUTFILE_LINES + CALL ParseVar( InFileInfo, CurLine, "TowerFile", InputFileData%BladedFF_TowerFile, TmpErrStat, TmpErrMsg ) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN !------------------------------------------------------------------------------------------------- !> Read the _Parameters for coherent turbulence [used only for WindType = 3 or 4]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + ! CurLine = CurLine + 1 ! Skip section break + ! CALL ParseVar( InFileInfo, CurLine, "CTTS_CoherentTurbFlag", InputFileData%CTTS_CoherentTurb, TmpErrStat, TmpErrMsg ) + ! CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + ! IF (ErrStat >= AbortErrLev) RETURN - ! Read CTTS_Flag - CALL ReadVar( UnitInput, InputFileName, InputFileData%CTTS_CoherentTurb, 'CTTS_CoherentTurbFlag', & - 'Flag to coherent turbulence', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - - ! Read CTWind%WindFileName - CALL ReadVar( UnitInput, InputFileName, InputFileData%CTTS_FileName, 'CTTS_FileName', & - 'Name of coherent turbulence file', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - IF ( PathIsRelative( InputFileData%CTTS_FileName ) ) InputFileData%CTTS_FileName = TRIM(PriPath)//TRIM(InputFileData%CTTS_FileName) - - ! Read CTWind%PathName - CALL ReadVar( UnitInput, InputFileName, InputFileData%CTTS_Path, 'CTTS_Path', & - 'Path to coherent turbulence binary files', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) THEN - CALL CleanUp() - RETURN - ENDIF - IF ( PathIsRelative( InputFileData%CTTS_Path ) ) InputFileData%CTTS_Path = TRIM(PriPath)//TRIM(InputFileData%CTTS_Path) + ! CALL ParseVar( InFileInfo, CurLine, "CTTS_FileName", InputFileData%CTTS_FileName, TmpErrStat, TmpErrMsg ) + ! CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + ! IF (ErrStat >= AbortErrLev) RETURN + ! IF ( PathIsRelative( InputFileData%CTTS_FileName ) ) InputFileData%CTTS_FileName = TRIM(PriPath)//TRIM(InputFileData%CTTS_FileName) -#else - InputFileData%CTTS_CoherentTurb = .FALSE. -#endif + ! CALL ParseVar( InFileInfo, CurLine, "CTTS_Path", InputFileData%CTTS_Path, TmpErrStat, TmpErrMsg ) + ! CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + ! IF (ErrStat >= AbortErrLev) RETURN + ! IF ( PathIsRelative( InputFileData%CTTS_Path ) ) InputFileData%CTTS_Path = TRIM(PriPath)//TRIM(InputFileData%CTTS_Path) !------------------------------------------------------------------------------------------------- !> Read the _Parameters for HAWC-formatted binary files [used only for WindType = 5]_ section !------------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "FileName_u", InputFileData%HAWC_FileName_u, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! Read HAWC_FileName_u - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_FileName_u, 'HAWC_FileName_u', & - 'Name of the file containing the u-component fluctuating wind', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%HAWC_FileName_u ) ) InputFileData%HAWC_FileName_u = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_u) - ! Read HAWC_FileName_v - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_FileName_v, 'HAWC_FileName_v', & - 'Name of the file containing the v-component fluctuating wind', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "FileName_v", InputFileData%HAWC_FileName_v, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%HAWC_FileName_v ) ) InputFileData%HAWC_FileName_v = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_v) - ! Read HAWC_FileName_w - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_FileName_w, 'HAWC_FileName_w', & - 'Name of the file containing the w-component fluctuating wind', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "FileName_w", InputFileData%HAWC_FileName_w, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN IF ( PathIsRelative( InputFileData%HAWC_FileName_w ) ) InputFileData%HAWC_FileName_w = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_w) - ! Read HAWC_nx - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_nx, 'HAWC_nx', & - 'Number of grids in the x direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "nx", InputFileData%HAWC_nx, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_ny - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_ny, 'HAWC_ny', & - 'Number of grids in the y direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "ny", InputFileData%HAWC_ny, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_nz - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_nz, 'HAWC_nz', & - 'Number of grids in the z direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "nz", InputFileData%HAWC_nz, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_dx - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_dx, 'HAWC_dx', & - 'Number of grids in the x direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "dx", InputFileData%HAWC_dx, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_dy - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_dy, 'HAWC_dy', & - 'Number of grids in the y direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "dy", InputFileData%HAWC_dy, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_dz - CALL ReadVar( UnitInput, InputFileName, InputFileData%HAWC_dz, 'HAWC_dz', & - 'Number of grids in the z direction (in the 3 files above)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "dz", InputFileData%HAWC_dz, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_RefHt - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%RefHt, 'HAWC_RefHt', & - 'Reference (hub) height of the grid', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "RefHt_HAWC", InputFileData%FF%RefHt, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - - !---------------------------------------------------------------------------------------------- - !> Read the _Scaling parameters for turbulence (HAWC-format files) [used only for WindType = 5]_ subsection - !---------------------------------------------------------------------------------------------- + IF (ErrStat >= AbortErrLev) RETURN - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + !---------------------------------------------------------------------------------------------- + !> Read the _Scaling parameters for turbulence (HAWC-format files) [used only for WindType = 5]_ subsection + !---------------------------------------------------------------------------------------------- - ! Read HAWC_ScaleMethod - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%ScaleMethod, 'HAWC_ScaleMethod', & - 'Turbulence scaling method [0=none, 1=direct scaling, 2= calculate scaling '// & - 'factor based on a desired standard deviation]', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + ! ScaleMethod: Turbulence scaling method [0=none, 1=direct scaling, 2= calculate scaling factor based on a desired standard deviation] + CALL ParseVar( InFileInfo, CurLine, "ScaleMethod", InputFileData%FF%ScaleMethod, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SFx - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SF(1), 'HAWC_SFx', & - 'Turbulence scaling factor for the x direction [ScaleMethod=1]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SFx", InputFileData%FF%SF(1), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SFy - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SF(2), 'HAWC_SFy', & - 'Turbulence scaling factor for the y direction [ScaleMethod=1]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SFy", InputFileData%FF%SF(2), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SFz - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SF(3), 'HAWC_SFz', & - 'Turbulence scaling factor for the z direction [ScaleMethod=1]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SFz", InputFileData%FF%SF(3), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SigmaFx - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SigmaF(1), 'HAWC_SigmaFx', & - 'Turbulence standard deviation to calculate scaling from in x direction [ScaleMethod=2]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SigmaFx", InputFileData%FF%SigmaF(1), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SigmaFy - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SigmaF(2), 'HAWC_SigmaFy', & - 'Turbulence standard deviation to calculate scaling from in y direction [ScaleMethod=2]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SigmaFy", InputFileData%FF%SigmaF(2), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_SigmaFz - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%SigmaF(3), 'HAWC_SigmaFz', & - 'Turbulence standard deviation to calculate scaling from in z direction [ScaleMethod=2]', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "SigmaFz", InputFileData%FF%SigmaF(3), TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - -#ifdef UNUSED_INPUTFILE_LINES + IF (ErrStat >= AbortErrLev) RETURN -!FIXME: TStart has no comment - ! Read HAWC_TStart - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%TStart, 'HAWC_TStart', & - '', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + ! CALL ParseVar( InFileInfo, CurLine, "HAWC_TStart", InputFileData%FF%TStart, TmpErrStat, TmpErrMsg ) + ! CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + ! IF (ErrStat >= AbortErrLev) THEN + ! RETURN + ! ENDIF -!FIXME: TEnd has no comment - ! Read HAWC_TEnd - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%TEnd, 'HAWC_TEnd', & - '', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - -#endif + ! CALL ParseVar( InFileInfo, CurLine, "HAWC_TEnd", InputFileData%FF%TEnd, TmpErrStat, TmpErrMsg ) + ! CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + ! IF (ErrStat >= AbortErrLev) THEN + ! RETURN + ! ENDIF - !---------------------------------------------------------------------------------------------- - !> Read the _Mean wind profile paramters (added to HAWC-format files) [used only for WindType = 5]_ subsection - !---------------------------------------------------------------------------------------------- + !---------------------------------------------------------------------------------------------- + !> Read the _Mean wind profile paramters (added to HAWC-format files) [used only for WindType = 5]_ subsection + !---------------------------------------------------------------------------------------------- - ! Section separator line - CALL ReadCom( UnitInput, InputFileName, 'InflowWind input file separator line', TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "URef", InputFileData%FF%URef, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_URef - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%URef, 'HAWC_URef', & - 'Mean u-component wind speed at the reference height', TmpErrStat, TmpErrMsg, UnitEcho ) + ! WindProfileType: Wind profile type (0=constant;1=logarithmic;2=power law) + CALL ParseVar( InFileInfo, CurLine, "WindProfile", InputFileData%FF%WindProfileType, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_ProfileType - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%WindProfileType, 'HAWC_ProfileType', & - 'Wind profile type (0=constant;1=logarithmic;2=power law)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "PLExp_HAWC", InputFileData%FF%PLExp, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_PLExp - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%PLExp, 'HAWC_PLExp', & - 'Power law exponent (used for PL wind profile type only)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVar( InFileInfo, CurLine, "Z0", InputFileData%FF%Z0, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_Z0 - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%Z0, 'HAWC_Z0', & - 'Surface roughness length (used for LOG wind profile type only)', TmpErrStat, TmpErrMsg, UnitEcho ) + CALL ParseVarWDefault( InFileInfo, CurLine, "XOffset", InputFileData%FF%XOffset, 0.0_ReKi, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) RETURN - ! Read HAWC_InitPosition (Shift of wind box) NOTE: This an optional input!!!! - CALL ReadVar( UnitInput, InputFileName, InputFileData%FF%XOffset, 'HAWC_Position', & - 'Initial position of the wind file (shift along X)', TmpErrStat, TmpErrMsg, UnitEcho ) - if (TmpErrStat == ErrID_None) then - !---------------------- OUTPUT -------------------------------------------------- - CALL ReadCom( UnitInput, InputFileName, 'Section Header: Output', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - else - InputFileData%FF%XOffset = 0.0_ReKi - TmpErrStat = ErrID_None ! reset - TmpErrMsg = "" - ! NOTE: since we read in a line that wasn't a number, what we actually read was the header. - endif - - ! SumPrint - Print summary data to .IfW.sum (flag): - CALL ReadVar( UnitInput, InputFileName, InputFileData%SumPrint, "SumPrint", "Print summary data to .IfW.sum (flag)", TmpErrStat, TmpErrMsg, UnitEcho) + !---------------------------------------------------------------------------------------------- + !> Read the _OUTPUT_ subsection + !---------------------------------------------------------------------------------------------- + CurLine = CurLine + 1 ! Skip section break + CALL ParseVar( InFileInfo, CurLine, "SumPrint", InputFileData%SumPrint, TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - + IF (ErrStat >= AbortErrLev) RETURN !---------------------- OUTLIST -------------------------------------------- - CALL ReadCom( UnitInput, InputFileName, 'Section Header: OutList', TmpErrStat, TmpErrMsg, UnitEcho ) - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - ! OutList - List of user-requested output channels (-): -- uses routine from the NWTC_Library - CALL ReadOutputList ( UnitInput, InputFileName, InputFileData%OutList, InputFileData%NumOuts, 'OutList', & - "List of user-requested output channels", TmpErrStat, TmpErrMsg, UnitEcho ) + CurLine = CurLine + 1 ! Skip comment line + CALL ReadOutputListFromFileInfo( InFileInfo, CurLine, InputFileData%OutList, & + InputFileData%NumOuts, "OutList", "List of user-requested output channels", TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF - - - + IF (ErrStat >= AbortErrLev) RETURN !------------------------------------------------------------------------------------------------- ! This is the end of the input file !------------------------------------------------------------------------------------------------- - CALL Cleanup() - RETURN - CONTAINS - !.............................. - SUBROUTINE Cleanup() - - - ! Close input file - CLOSE ( UnitInput ) - - ! Cleanup the Echo file and global variables - IF ( InputFileData%EchoFlag ) THEN - CLOSE(UnitEcho) - END IF - - - END SUBROUTINE Cleanup - -END SUBROUTINE InflowWind_ReadInput - + END SUBROUTINE InflowWind_ParseInputFileInfo !==================================================================================================== !> This private subroutine verifies the input required for InflowWind is correctly specified. This @@ -1008,7 +567,8 @@ SUBROUTINE InflowWind_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) CALL Steady_ValidateInput() CASE ( Uniform_WindNumber ) - CALL Uniform_ValidateInput() + + IF ( InitInp%WindType2UseInputFile ) CALL Uniform_ValidateInput() CASE ( TSFF_WindNumber ) CALL TSFF_ValidateInput() diff --git a/modules/inflowwind/src/InflowWind_Types.f90 b/modules/inflowwind/src/InflowWind_Types.f90 index c5c4e14c60..a3f726ff6d 100644 --- a/modules/inflowwind/src/InflowWind_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Types.f90 @@ -92,7 +92,7 @@ MODULE InflowWind_Types CHARACTER(1024) :: TSFF_FileName !< TurbSim Full-Field -- filename [-] CHARACTER(1024) :: BladedFF_FileName !< Bladed-style Full-Field -- filename [-] LOGICAL :: BladedFF_TowerFile !< Bladed-style Full-Field -- tower file exists [-] - LOGICAL :: CTTS_CoherentTurb !< Coherent turbulence data exists [-] + LOGICAL :: CTTS_CoherentTurb = .FALSE. !< Coherent turbulence data exists [-] CHARACTER(1024) :: CTTS_FileName !< Name of coherent turbulence file [-] CHARACTER(1024) :: CTTS_Path !< Path to coherent turbulence binary data files [-] CHARACTER(1024) :: HAWC_FileName_u !< HAWC -- u component binary data file name [-] @@ -122,7 +122,9 @@ MODULE InflowWind_Types INTEGER(IntKi) :: NumWindPoints !< Number of wind velocity points expected [-] LOGICAL :: UseInputFile = .TRUE. !< Should we read everthing from an input file, or do we get it some other way [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] - TYPE(InflowWind_InputFile) :: PassedFileData !< If we don't use the input file, pass everything through this [-] + TYPE(FileInfoType) :: PassedFileData !< If we don't use the input file, pass everything through this [-] + LOGICAL :: WindType2UseInputFile = .TRUE. !< Flag for toggling file based IO in wind type 2. [-] + TYPE(FileInfoType) :: WindType2Data !< Optional slot for wind type 2 data if file IO is not used. [-] TYPE(Lidar_InitInputType) :: lidar !< InitInput for lidar data [-] TYPE(IfW_4Dext_InitInputType) :: FDext !< InitInput for lidar data [-] END TYPE InflowWind_InitInputType @@ -1152,7 +1154,11 @@ SUBROUTINE InflowWind_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCod DstInitInputData%NumWindPoints = SrcInitInputData%NumWindPoints DstInitInputData%UseInputFile = SrcInitInputData%UseInputFile DstInitInputData%RootName = SrcInitInputData%RootName - CALL InflowWind_Copyinputfile( SrcInitInputData%PassedFileData, DstInitInputData%PassedFileData, CtrlCode, ErrStat2, ErrMsg2 ) + CALL NWTC_Library_Copyfileinfotype( SrcInitInputData%PassedFileData, DstInitInputData%PassedFileData, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstInitInputData%WindType2UseInputFile = SrcInitInputData%WindType2UseInputFile + CALL NWTC_Library_Copyfileinfotype( SrcInitInputData%WindType2Data, DstInitInputData%WindType2Data, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN CALL Lidar_CopyInitInput( SrcInitInputData%lidar, DstInitInputData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) @@ -1172,7 +1178,8 @@ SUBROUTINE InflowWind_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" - CALL InflowWind_Destroyinputfile( InitInputData%PassedFileData, ErrStat, ErrMsg ) + CALL NWTC_Library_Destroyfileinfotype( InitInputData%PassedFileData, ErrStat, ErrMsg ) + CALL NWTC_Library_Destroyfileinfotype( InitInputData%WindType2Data, ErrStat, ErrMsg ) CALL Lidar_DestroyInitInput( InitInputData%lidar, ErrStat, ErrMsg ) CALL IfW_4Dext_DestroyInitInput( InitInputData%FDext, ErrStat, ErrMsg ) END SUBROUTINE InflowWind_DestroyInitInput @@ -1220,7 +1227,7 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName ! Allocate buffers for subtypes, if any (we'll get sizes from these) Int_BufSz = Int_BufSz + 3 ! PassedFileData: size of buffers for each call to pack subtype - CALL InflowWind_Packinputfile( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, .TRUE. ) ! PassedFileData + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, .TRUE. ) ! PassedFileData CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -1236,6 +1243,24 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 1 ! WindType2UseInputFile + Int_BufSz = Int_BufSz + 3 ! WindType2Data: size of buffers for each call to pack subtype + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%WindType2Data, ErrStat2, ErrMsg2, .TRUE. ) ! WindType2Data + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! WindType2Data + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! WindType2Data + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! WindType2Data + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype CALL Lidar_PackInitInput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1313,7 +1338,37 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) Int_Xferred = Int_Xferred + 1 END DO ! I - CALL InflowWind_Packinputfile( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, OnlySize ) ! PassedFileData + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, OnlySize ) ! PassedFileData + 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 + IntKiBuf(Int_Xferred) = TRANSFER(InData%WindType2UseInputFile, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%WindType2Data, ErrStat2, ErrMsg2, OnlySize ) ! WindType2Data CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -1474,7 +1529,49 @@ SUBROUTINE InflowWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL InflowWind_Unpackinputfile( Re_Buf, Db_Buf, Int_Buf, OutData%PassedFileData, ErrStat2, ErrMsg2 ) ! PassedFileData + CALL NWTC_Library_Unpackfileinfotype( Re_Buf, Db_Buf, Int_Buf, OutData%PassedFileData, ErrStat2, ErrMsg2 ) ! PassedFileData + 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) + OutData%WindType2UseInputFile = TRANSFER(IntKiBuf(Int_Xferred), OutData%WindType2UseInputFile) + Int_Xferred = Int_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackfileinfotype( Re_Buf, Db_Buf, Int_Buf, OutData%WindType2Data, ErrStat2, ErrMsg2 ) ! WindType2Data CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN diff --git a/modules/inflowwind/tests/ifw_test_tools.F90 b/modules/inflowwind/tests/ifw_test_tools.F90 new file mode 100644 index 0000000000..0adeb610d1 --- /dev/null +++ b/modules/inflowwind/tests/ifw_test_tools.F90 @@ -0,0 +1,145 @@ +module ifw_test_tools + + use NWTC_IO + use NWTC_Library + use NWTC_Library_Types + + implicit none + +contains + + function getInputFileData() + + INTEGER :: ErrStat + CHARACTER(ErrMsgLen) :: ErrMsg + TYPE(FileInfoType) :: getInputFileData + CHARACTER(1024), DIMENSION(55) :: data = (/ & + '------- InflowWind v3.01.* INPUT FILE ------------------------------------------------------------------------- ', & + 'Steady 8 m/s winds with no shear for FAST CertTests #20 and #25 ', & + '--------------------------------------------------------------------------------------------------------------- ', & + ' true Echo - Echo input data to .ech (flag) ', & + ' 1 WindType - switch for wind file type (1=steady; 2=uniform; 3=binary TurbSim FF; 4=binary Bladed-style FF; 5=HAWC format; 6=User defined; 7=native Bladed FF) ', & + ' 0 PropagationDir - Direction of wind propagation (meteoroligical rotation from aligned with X (positive rotates towards -Y) -- degrees) ', & + ' 0 VFlowAng - Upflow angle (degrees) (not used for native Bladed format WindType=7) ', & + ' 1 NWindVel - Number of points to output the wind velocity (0 to 9) ', & + ' 0 WindVxiList - List of coordinates in the inertial X direction (m) ', & + ' 0 WindVyiList - List of coordinates in the inertial Y direction (m) ', & + ' 90 WindVziList - List of coordinates in the inertial Z direction (m) ', & + '================== Parameters for Steady Wind Conditions [used only for WindType = 1] ========================= ', & + ' 8.0 HWindSpeed - Horizontal windspeed (m/s) ', & + ' 90 RefHt - Reference height for horizontal wind speed (m) ', & + ' 0.1 PLexp - Power law exponent (-) ', & + '================== Parameters for Uniform wind file [used only for WindType = 2] ============================ ', & + '"Wind/08ms.wnd" FileName_Uni - Filename of time series data for uniform wind field. (-) ', & + ' 90 RefHt_Uni - Reference height for horizontal wind speed (m) ', & + ' 125.88 RefLength - Reference length for linear horizontal and vertical sheer (-) ', & + '================== Parameters for Binary TurbSim Full-Field files [used only for WindType = 3] ============== ', & + '"Wind/08ms.wnd" filename_bts - name of the full field wind file to use (.bts) ', & + '================== Parameters for Binary Bladed-style Full-Field files [used only for WindType = 4] ========= ', & + '"unused" FilenameRoot - Rootname of the full-field wind file to use (.wnd, .sum) ', & + 'False TowerFile - Have tower file (.twr) (flag) ', & + '================== Parameters for HAWC-format binary files [Only used with WindType = 5] ===================== ', & + '"wasp\Output\basic_5u.bin" FileName_u - name of the file containing the u-component fluctuating wind (.bin) ', & + '"wasp\Output\basic_5v.bin" FileName_v - name of the file containing the v-component fluctuating wind (.bin) ', & + '"wasp\Output\basic_5w.bin" FileName_w - name of the file containing the w-component fluctuating wind (.bin) ', & + ' 64 nx - number of grids in the x direction (in the 3 files above) (-) ', & + ' 32 ny - number of grids in the y direction (in the 3 files above) (-) ', & + ' 32 nz - number of grids in the z direction (in the 3 files above) (-) ', & + ' 16 dx - distance (in meters) between points in the x direction (m) ', & + ' 3 dy - distance (in meters) between points in the y direction (m) ', & + ' 3 dz - distance (in meters) between points in the z direction (m) ', & + ' 90 RefHt_HAWC - reference height; the height (in meters) of the vertical center of the grid (m) ', & + ' ------------- Scaling parameters for turbulence --------------------------------------------------------- ', & + ' 1 ScaleMethod - Turbulence scaling method [0 = none, 1 = direct scaling, 2 = calculate scaling factor based on a desired standard deviation] ', & + ' 1 SFx - Turbulence scaling factor for the x direction (-) [ScaleMethod=1] ', & + ' 1 SFy - Turbulence scaling factor for the y direction (-) [ScaleMethod=1] ', & + ' 1 SFz - Turbulence scaling factor for the z direction (-) [ScaleMethod=1] ', & + ' 12 SigmaFx - Turbulence standard deviation to calculate scaling from in x direction (m/s) [ScaleMethod=2] ', & + ' 8 SigmaFy - Turbulence standard deviation to calculate scaling from in y direction (m/s) [ScaleMethod=2] ', & + ' 2 SigmaFz - Turbulence standard deviation to calculate scaling from in z direction (m/s) [ScaleMethod=2] ', & + ' ------------- Mean wind profile parameters (added to HAWC-format files) --------------------------------- ', & + ' 5 URef - Mean u-component wind speed at the reference height (m/s) ', & + ' 2 WindProfile - Wind profile type (0=constant;1=logarithmic,2=power law) ', & + ' 0 PLExp_HAWC - Power law exponent (-) (used for PL wind profile type only) ', & + ' 0.03 Z0 - Surface roughness length (m) (used for LG wind profile type only) ', & + ' 0 XOffset - Initial offset in +x direction (shift of wind box) ', & + '====================== OUTPUT ================================================== ', & + 'False SumPrint - Print summary data to .IfW.sum (flag) ', & + ' OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx for a listing of available output channels, (-) ', & + '"Wind1VelX,Wind1VelY,Wind1VelZ" - Wind velocity at point WindVxiList(1),WindVyiList(1),WindVziList(1). X, Y, and Z direction components. ', & + 'END of input file (the word "END" must appear in the first 3 columns of this last OutList line) ', & + '--------------------------------------------------------------------------------------- ' & + /) + + CALL InitFileInfo(data, getInputFileData, ErrStat, ErrMsg) + + end function + + function getInputFileDataWindType2() + + INTEGER :: ErrStat + CHARACTER(ErrMsgLen) :: ErrMsg + TYPE(FileInfoType) :: getInputFileDataWindType2 + CHARACTER(1024), DIMENSION(55) :: data = (/ & + '------- InflowWind v3.01.* INPUT FILE ------------------------------------------------------------------------- ', & + 'Steady 8 m/s winds with no shear for FAST CertTests #20 and #25 ', & + '--------------------------------------------------------------------------------------------------------------- ', & + ' true Echo - Echo input data to .ech (flag) ', & + ' 2 WindType - switch for wind file type (1=steady; 2=uniform; 3=binary TurbSim FF; 4=binary Bladed-style FF; 5=HAWC format; 6=User defined; 7=native Bladed FF) ', & + ' 0 PropagationDir - Direction of wind propagation (meteoroligical rotation from aligned with X (positive rotates towards -Y) -- degrees) ', & + ' 0 VFlowAng - Upflow angle (degrees) (not used for native Bladed format WindType=7) ', & + ' 1 NWindVel - Number of points to output the wind velocity (0 to 9) ', & + ' 0 WindVxiList - List of coordinates in the inertial X direction (m) ', & + ' 0 WindVyiList - List of coordinates in the inertial Y direction (m) ', & + ' 90 WindVziList - List of coordinates in the inertial Z direction (m) ', & + '================== Parameters for Steady Wind Conditions [used only for WindType = 1] ========================= ', & + ' 8.0 HWindSpeed - Horizontal windspeed (m/s) ', & + ' 90 RefHt - Reference height for horizontal wind speed (m) ', & + ' 0.1 PLexp - Power law exponent (-) ', & + '================== Parameters for Uniform wind file [used only for WindType = 2] ============================ ', & + '"Wind/08ms.wnd" FileName_Uni - Filename of time series data for uniform wind field. (-) ', & + ' 90 RefHt_Uni - Reference height for horizontal wind speed (m) ', & + ' 125.88 RefLength - Reference length for linear horizontal and vertical sheer (-) ', & + '================== Parameters for Binary TurbSim Full-Field files [used only for WindType = 3] ============== ', & + '"Wind/08ms.wnd" FileName_BTS - Filename of time series data for uniform wind field. (-) ', & + '================== Parameters for Binary Bladed-style Full-Field files [used only for WindType = 4] ========= ', & + '"unused" FilenameRoot - Rootname of the full-field wind file to use (.wnd, .sum) ', & + 'False TowerFile - Have tower file (.twr) (flag) ', & + '================== Parameters for HAWC-format binary files [Only used with WindType = 5] ===================== ', & + '"wasp\Output\basic_5u.bin" FileName_u - name of the file containing the u-component fluctuating wind (.bin) ', & + '"wasp\Output\basic_5v.bin" FileName_v - name of the file containing the v-component fluctuating wind (.bin) ', & + '"wasp\Output\basic_5w.bin" FileName_w - name of the file containing the w-component fluctuating wind (.bin) ', & + ' 64 nx - number of grids in the x direction (in the 3 files above) (-) ', & + ' 32 ny - number of grids in the y direction (in the 3 files above) (-) ', & + ' 32 nz - number of grids in the z direction (in the 3 files above) (-) ', & + ' 16 dx - distance (in meters) between points in the x direction (m) ', & + ' 3 dy - distance (in meters) between points in the y direction (m) ', & + ' 3 dz - distance (in meters) between points in the z direction (m) ', & + ' 90 RefHt_HAWC - reference height; the height (in meters) of the vertical center of the grid (m) ', & + ' ------------- Scaling parameters for turbulence --------------------------------------------------------- ', & + ' 1 ScaleMethod - Turbulence scaling method [0 = none, 1 = direct scaling, 2 = calculate scaling factor based on a desired standard deviation] ', & + ' 1 SFx - Turbulence scaling factor for the x direction (-) [ScaleMethod=1] ', & + ' 1 SFy - Turbulence scaling factor for the y direction (-) [ScaleMethod=1] ', & + ' 1 SFz - Turbulence scaling factor for the z direction (-) [ScaleMethod=1] ', & + ' 12 SigmaFx - Turbulence standard deviation to calculate scaling from in x direction (m/s) [ScaleMethod=2] ', & + ' 8 SigmaFy - Turbulence standard deviation to calculate scaling from in y direction (m/s) [ScaleMethod=2] ', & + ' 2 SigmaFz - Turbulence standard deviation to calculate scaling from in z direction (m/s) [ScaleMethod=2] ', & + ' ------------- Mean wind profile parameters (added to HAWC-format files) --------------------------------- ', & + ' 5 URef - Mean u-component wind speed at the reference height (m/s) ', & + ' 2 WindProfile - Wind profile type (0=constant;1=logarithmic,2=power law) ', & + ' 0 PLExp_HAWC - Power law exponent (-) (used for PL wind profile type only) ', & + ' 0.03 Z0 - Surface roughness length (m) (used for LG wind profile type only) ', & + ' 0 XOffset - Initial offset in +x direction (shift of wind box) ', & + '====================== OUTPUT ================================================== ', & + 'False SumPrint - Print summary data to .IfW.sum (flag) ', & + ' OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx for a listing of available output channels, (-) ', & + '"Wind1VelX,Wind1VelY,Wind1VelZ" - Wind velocity at point WindVxiList(1),WindVyiList(1),WindVziList(1). X, Y, and Z direction components. ', & + 'END of input file (the word "END" must appear in the first 3 columns of this last OutList line) ', & + '--------------------------------------------------------------------------------------- ' & + /) + + CALL InitFileInfo(data, getInputFileDataWindType2, ErrStat, ErrMsg) + + end function + +end module diff --git a/modules/inflowwind/tests/test_bladed_wind.F90 b/modules/inflowwind/tests/test_bladed_wind.F90 new file mode 100644 index 0000000000..72bbd35f00 --- /dev/null +++ b/modules/inflowwind/tests/test_bladed_wind.F90 @@ -0,0 +1,35 @@ +module test_bladed_wind + + use pFUnit_mod + use ifw_test_tools + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_bladed_wind_input() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + CHARACTER(16) :: expected + + expected = "unused" + PriPath = "" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(trim(expected), InputFileData%BladedFF_FileName) + @assertEqual(.FALSE., InputFileData%BladedFF_TowerFile) + + end subroutine + +end module diff --git a/modules/inflowwind/tests/test_hawc_wind.F90 b/modules/inflowwind/tests/test_hawc_wind.F90 new file mode 100644 index 0000000000..4de432a9af --- /dev/null +++ b/modules/inflowwind/tests/test_hawc_wind.F90 @@ -0,0 +1,62 @@ +module test_hawc_wind + + use pFUnit_mod + use ifw_test_tools + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_hawc_wind_input() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + CHARACTER(32) :: expected_fnu + CHARACTER(32) :: expected_fnv + CHARACTER(32) :: expected_fnw + + PriPath = "" + expected_fnu = "wasp\Output\basic_5u.bin" + expected_fnv = "wasp\Output\basic_5v.bin" + expected_fnw = "wasp\Output\basic_5w.bin" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + + @assertEqual(trim(expected_fnu), InputFileData%HAWC_FileName_u) + @assertEqual(trim(expected_fnv), InputFileData%HAWC_FileName_v) + @assertEqual(trim(expected_fnw), InputFileData%HAWC_FileName_w) + @assertEqual(64, InputFileData%HAWC_nx) + @assertEqual(32, InputFileData%HAWC_ny) + @assertEqual(32, InputFileData%HAWC_nz) + @assertEqual(16, InputFileData%HAWC_dx) + @assertEqual(3, InputFileData%HAWC_dy) + @assertEqual(3, InputFileData%HAWC_dz) + @assertEqual(90, InputFileData%FF%RefHt) + + @assertEqual(1, InputFileData%FF%ScaleMethod) + @assertEqual(1, InputFileData%FF%SF(1)) + @assertEqual(1, InputFileData%FF%SF(2)) + @assertEqual(1, InputFileData%FF%SF(3)) + @assertEqual(12, InputFileData%FF%SigmaF(1)) + @assertEqual(8, InputFileData%FF%SigmaF(2)) + @assertEqual(2, InputFileData%FF%SigmaF(3)) + + @assertEqual(5, InputFileData%FF%URef) + @assertEqual(2, InputFileData%FF%WindProfileType) + @assertEqual(0, InputFileData%FF%PLExp) + @assertEqual(0.03, InputFileData%FF%Z0) + @assertEqual(0, InputFileData%FF%XOffset) + + end subroutine + +end module diff --git a/modules/inflowwind/tests/test_outputs.F90 b/modules/inflowwind/tests/test_outputs.F90 new file mode 100644 index 0000000000..b6af55a79c --- /dev/null +++ b/modules/inflowwind/tests/test_outputs.F90 @@ -0,0 +1,62 @@ +module test_outputs + + use pFUnit_mod + use ifw_test_tools + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_outputs_parsing() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + PriPath = "" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(.FALSE., InputFileData%SumPrint) + @assertEqual("Wind1VelX", InputFileData%OutList(1)) + @assertEqual("Wind1VelY", InputFileData%OutList(2)) + @assertEqual("Wind1VelZ", InputFileData%OutList(3)) + + end subroutine + + + @test + subroutine test_outputs_parsing_alternate() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + PriPath = "" + + InFileInfo = getInputFileData() + InFileInfo%Lines(51:53) = (/ & + 'True SumPrint - Print summary data to .IfW.sum (flag) ', & + ' OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx for a listing of available output channels, (-)', & + '"Wind1VelX,Wind1VelY" - Wind velocity at point WindVxiList(1),WindVyiList(1),WindVziList(1). X, Y, and Z direction components. ' & + /) + + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(.TRUE., InputFileData%SumPrint) + @assertEqual("Wind1VelX", InputFileData%OutList(1)) + @assertEqual("Wind1VelY", InputFileData%OutList(2)) + + end subroutine + +end module diff --git a/modules/inflowwind/tests/test_steady_wind.F90 b/modules/inflowwind/tests/test_steady_wind.F90 new file mode 100644 index 0000000000..1e6f86c794 --- /dev/null +++ b/modules/inflowwind/tests/test_steady_wind.F90 @@ -0,0 +1,63 @@ +module test_steady_wind + + use pFUnit_mod + use ifw_test_tools + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_steady_wind_input_single_height() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + PriPath = "" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(1, InputFileData%WindType) + @assertEqual(1, InputFileData%NWindVel) + @assertEqual(90, InputFileData%WindVziList(1)) + + end subroutine + + + @test + subroutine test_steady_wind_input_mult_heights() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + PriPath = "" + + InFileInfo = getInputFileData() + InFileInfo%Lines(8:11) = (/ & + ' 2 NWindVel - Number of points to output the wind velocity (0 to 9) ', & + ' 0,0 WindVxiList - List of coordinates in the inertial X direction (m) ', & + ' 0,0 WindVyiList - List of coordinates in the inertial Y direction (m) ', & + ' 80,100 WindVziList - List of coordinates in the inertial Z direction (m) ' & + /) + + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(1, InputFileData%WindType) + @assertEqual(2, InputFileData%NWindVel) + @assertEqual(80, InputFileData%WindVziList(1)) + @assertEqual(100, InputFileData%WindVziList(2)) + + end subroutine + +end module diff --git a/modules/inflowwind/tests/test_turbsim_wind.F90 b/modules/inflowwind/tests/test_turbsim_wind.F90 new file mode 100644 index 0000000000..975e34cf39 --- /dev/null +++ b/modules/inflowwind/tests/test_turbsim_wind.F90 @@ -0,0 +1,34 @@ +module test_turbsim_wind + + use pFUnit_mod + use ifw_test_tools + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_steady_wind_input_single_height() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + CHARACTER(16) :: expected + + expected = "Wind/08ms.wnd" + PriPath = "" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(trim(expected), InputFileData%TSFF_FileName) + + end subroutine + +end module diff --git a/modules/inflowwind/tests/test_uniform_wind.F90 b/modules/inflowwind/tests/test_uniform_wind.F90 new file mode 100644 index 0000000000..2d636c0f24 --- /dev/null +++ b/modules/inflowwind/tests/test_uniform_wind.F90 @@ -0,0 +1,103 @@ +module test_uniform_wind + + use pFUnit_mod + use ifw_test_tools + use InflowWind + use InflowWind_Subs + use InflowWind_Types + + implicit none + +contains + + @test + subroutine test_uniform_wind_input() + + TYPE(FileInfoType) :: InFileInfo + TYPE(InflowWind_InputFile) :: InputFileData + CHARACTER(1024) :: PriPath + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg + + CHARACTER(16) :: expected + + expected = "Wind/08ms.wnd" + PriPath = "" + + InFileInfo = getInputFileData() + CALL InflowWind_ParseInputFileInfo(InputFileData , InFileInfo, PriPath, TmpErrStat, TmpErrMsg) + + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(trim(expected), InputFileData%Uniform_FileName) + @assertEqual(90, InputFileData%Uniform_RefHt) + @assertEqual(125.88, InputFileData%Uniform_RefLength) + + end subroutine + + @test + subroutine test_uniform_wind_direct_data() + + ! Types for setting up module + TYPE(InflowWind_InitInputType) :: InitInp !< Input data for initialization + TYPE(InflowWind_InputType) :: InputGuess !< An initial guess for the input; the input mesh must be defined + 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_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) + REAL(DbKi) :: TimeInterval !< Coupling time interval in seconds: InflowWind does not change this. + TYPE(InflowWind_InitOutputType) :: InitOutData + + ! Variables for testing + INTEGER :: ErrStat + CHARACTER(ErrMsgLen) :: ErrMsg + TYPE(FileInfoType) :: InFileInfo + TYPE(FileInfoType) :: WindType2Data + CHARACTER(1024), DIMENSION(6) :: data = (/ & + '! Wind file for sheared 18 m/s wind with 30 degree direction. ', & + '! Time Wind Wind Vert. Horiz. Vert. LinV Gust ', & + '! Speed Dir Speed Shear Shear Shear Speed ', & + ' 0.0 12.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ', & + ' 0.1 12.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ', & + ' 999.9 12.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ' & + /) + + ! Error handling + INTEGER(IntKi) :: TmpErrStat + CHARACTER(ErrMsgLen) :: TmpErrMsg !< temporary error message + + InFileInfo = getInputFileDataWindType2() + CALL InitFileInfo(data, WindType2Data, ErrStat, ErrMsg) + + ! For diagnostic purposes, the following can be used to display the contents + ! of the InFileInfo data structure. + ! call Print_FileInfo_Struct( CU, InFileInfo ) ! CU is the screen -- different number on different systems. + + ! Variable definitions + InitInp%InputFileName = "" + InitInp%NumWindPoints = 5 + InitInp%UseInputFile = .FALSE. + InitInp%RootName = "" + InitInp%PassedFileData = InFileInfo + InitInp%WindType2UseInputFile = .FALSE. + InitInp%WindType2Data = WindType2Data + + CALL InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, & + ConstrStateGuess, OtherStates, y, m, TimeInterval, & + InitOutData, TmpErrStat, TmpErrMsg) + + ! Results + @assertEqual(0, TmpErrStat, message='Error message: '//trim(TmpErrMsg)//NewLine//'ErrStat: ') + @assertEqual(0.0, p%UniformWind%TData(1)) + @assertEqual(0.1, p%UniformWind%TData(2)) + @assertEqual(999.9, p%UniformWind%TData(3)) + + @assertEqual(12.0, p%UniformWind%V(1)) + @assertEqual(12.0, p%UniformWind%V(2)) + @assertEqual(12.0, p%UniformWind%V(3)) + + end subroutine + +end module diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 457f3b5dc9..cbbf213653 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -153,6 +153,7 @@ MODULE NWTC_IO MODULE PROCEDURE ParseInAry ! Parse an array of whole numbers. MODULE PROCEDURE ParseLoAry ! Parse an array of LOGICAL values. MODULE PROCEDURE ParseSiAry ! Parse an array of single-precision REAL values. + MODULE PROCEDURE ParseChAry END INTERFACE !> \copydoc nwtc_io::checkr4var @@ -2486,8 +2487,12 @@ FUNCTION GetNVD ( ProgInfo ) ! Function delcaration CHARACTER(200) :: GetNVD !< A single string containing the name, date, and version info - ! Store all the version info into a single string - GetNVD = TRIM( ProgInfo%Name ) !//' ('//Trim( ProgInfo%Ver )//', '//Trim( ProgInfo%Date )//')' + ! 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 )//')' + else + GetNVD = TRIM( ProgInfo%Name ) + end if END FUNCTION GetNVD !======================================================================= @@ -2679,6 +2684,9 @@ SUBROUTINE GetWords ( Line, Words, NumWords ) IW = IW + 1 Words(IW) = Line(Ch+1:Ch+NextWhite-1) + if (NextWhite > len(words(iw)) ) then + call ProgWarn('Error reading field from file. There are too many characters in the input file to store in the field. Value may be truncated.') + end if IF ( IW == NumWords ) EXIT @@ -3313,6 +3321,93 @@ SUBROUTINE OpenUOutfile ( Un, OutFile, ErrStat, ErrMsg ) RETURN END SUBROUTINE OpenUOutfile !======================================================================= +!> This subroutine prints the contents of the FileInfo data structure to the screen +!! This may be useful for diagnostic purposes. this is written to unit U + subroutine Print_FileInfo_Struct( U, FileInfo ) + integer(IntKi), intent(in ) :: U !< Unit number to print to + type(FileInfoType), intent(in ) :: FileInfo !< derived type containing everything read from file + integer(IntKi) :: i !< generic counter + character(20) :: TmpStr20 + character(45) :: TmpStr45 + write(U,*) '-------------- Print_FileInfo_Struct ------------' + write(U,*) ' info stored in the FileInfo data type' + write(U,*) ' %NumLines (integer): ',FileInfo%NumLines + write(U,*) ' %NumFiles (integer): ',FileInfo%NumFiles + write(U,*) ' %FileList (array of strings): ',size(FileInfo%FileList) + write(U,*) ' %FileIndx (array of integer): ',size(FileInfo%FileIndx) + write(U,*) ' %FileLine (array of integer): ',size(FileInfo%FileLine) + write(U,*) ' %Lines (array of strings): ',size(FileInfo%Lines ) + if (allocated(FileInfo%FileList)) then + write(U,*) ' list of files read:' + write(U,*) ' FileIdx FileName' + do i=1,FileInfo%NumFiles + write(TmpStr20,'(7x,I3,10x)') i + write(U,*) TmpStr20//trim(FileInfo%FileList(i)) + enddo + endif + if (allocated(FileInfo%FileLine) .and. allocated(FileInfo%FileIndx) .and. allocated(FileInfo%Lines)) then + write(U,*) ' Non-comment lines stored in memory from files:' + write(U,*) ' i FileIndx FileLine Lines(i)' + do i=1,FileInfo%NumLines + write(TmpStr45, '(5x,I5,10x,I5,10x,I5,5x)') i, FileInfo%FileIndx(i), FileInfo%FileLine(i) + write(U,*) TmpStr45, trim(FileInfo%Lines(i)) + enddo + endif + end subroutine Print_FileInfo_Struct +!======================================================================= +!> This subroutine parses the specified line of text for AryLen CHARACTER values. +!! Generate an error message if the value is the wrong type. +!! Use ParseAry (nwtc_io::parseary) instead of directly calling a specific routine in the generic interface. + SUBROUTINE ParseChAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg, UnEc ) + + ! Arguments declarations. + + TYPE (FileInfoType), INTENT(IN) :: FileInfo !< The derived type for holding the file information. + INTEGER(IntKi), INTENT(INOUT) :: LineNum !< The number of the line to parse. + CHARACTER(*), INTENT(IN) :: AryName !< The array name we are trying to fill. + CHARACTER(*), INTENT(OUT) :: Ary(AryLen) !< The array to receive the input values. + INTEGER, INTENT(IN) :: AryLen !< The length of the array to parse. + INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status. + CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if ErrStat /= 0. + INTEGER, INTENT(IN), OPTIONAL :: UnEc !< I/O unit for echo file. If present and > 0, write to UnEc. + + ! Local declarations. + + INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. + INTEGER(IntKi) :: i ! Error status local to this routine. + + CHARACTER(*), PARAMETER :: RoutineName = 'ParseChAry' + + ErrStat = ErrID_None + ErrMsg = "" + + IF (LineNum > size(FileInfo%Lines) ) THEN + CALL SetErrStat ( ErrID_Fatal, NewLine//' >> A fatal error occurred when parsing data.'//NewLine// & + ' >> The "'//TRIM( AryName )//'" array was not assigned because the file is too short.' & + , ErrStat, ErrMsg, RoutineName ) + RETURN + END IF + + READ (FileInfo%Lines(LineNum),*,IOSTAT=ErrStatLcl) Ary + IF ( ErrStatLcl /= 0 ) THEN + CALL SetErrStat ( ErrID_Fatal, 'A fatal error occurred when parsing data from "' & + //TRIM( FileInfo%FileList(FileInfo%FileIndx(LineNum)) )//'".'//NewLine// & + ' >> The "'//TRIM( AryName )//'" array was not assigned valid REAL values on line #' & + //TRIM( Num2LStr( FileInfo%FileLine(LineNum) ) )//'.'//NewLine//' >> The text being parsed was :'//NewLine & + //' "'//TRIM( FileInfo%Lines(LineNum) )//'"',ErrStat,ErrMsg,RoutineName ) + RETURN + ENDIF + + IF ( PRESENT(UnEc) ) THEN + IF ( UnEc > 0 ) WRITE (UnEc,'(A)') TRIM( FileInfo%Lines(LineNum) ) + END IF + + LineNum = LineNum + 1 + + RETURN + + END SUBROUTINE ParseChAry +!======================================================================= !> This subroutine parses the specified line of text for two words. One should be a !! the name of a variable and the other the value of the variable. !! Generate an error message if the value is the wrong type or if only one "word" is found. @@ -3525,7 +3620,7 @@ SUBROUTINE ParseDbVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. INTEGER(IntKi) :: NameIndx ! The index into the Words array that points to the variable name. - CHARACTER(20) :: Words (2) ! The two "words" parsed from the line. + CHARACTER(200) :: Words (2) ! The two "words" parsed from the line. CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ParseDbVar' @@ -3639,7 +3734,6 @@ SUBROUTINE ParseInAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. - CHARACTER(20), ALLOCATABLE :: Words (:) ! The array "words" parsed from the line. CHARACTER(*), PARAMETER :: RoutineName = 'ParseInAry' ErrStat = ErrID_None @@ -3652,13 +3746,6 @@ SUBROUTINE ParseInAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg RETURN END IF - ALLOCATE ( Words( AryLen ) , STAT=ErrStatLcl ) - IF ( ErrStatLcl /= 0 ) THEN - CALL SetErrStat ( ErrID_Fatal, 'Fatal error allocating memory for the Words array.',ErrStat,ErrMsg,RoutineName ) - CALL Cleanup() - RETURN - ENDIF - READ (FileInfo%Lines(LineNum),*,IOSTAT=ErrStatLcl) Ary IF ( ErrStatLcl /= 0 ) THEN @@ -3667,7 +3754,6 @@ SUBROUTINE ParseInAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg ' >> The "'//TRIM( AryName )//'" array was not assigned valid INTEGER values on line #' & //TRIM( Num2LStr( FileInfo%FileLine(LineNum) ) )//'.'//NewLine//' >> The text being parsed was :'//NewLine & //' "'//TRIM( FileInfo%Lines(LineNum) )//'"',ErrStat,ErrMsg,RoutineName ) - CALL Cleanup() RETURN ENDIF @@ -3677,25 +3763,9 @@ SUBROUTINE ParseInAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg LineNum = LineNum + 1 - CALL Cleanup() - - RETURN - - !======================================================================= - CONTAINS - !======================================================================= - SUBROUTINE Cleanup ( ) - - ! This subroutine cleans up the parent routine before exiting. - - ! Deallocate the Words array if it had been allocated. - - IF ( ALLOCATED( Words ) ) DEALLOCATE( Words ) + RETURN - RETURN - - END SUBROUTINE Cleanup END SUBROUTINE ParseInAry !======================================================================= @@ -3846,7 +3916,7 @@ SUBROUTINE ParseInVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. INTEGER(IntKi) :: NameIndx ! The index into the Words array that points to the variable name. - CHARACTER(20) :: Words (2) ! The two "words" parsed from the line. + CHARACTER(200) :: Words (2) ! The two "words" parsed from the line. CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ParseInVar' @@ -3970,7 +4040,6 @@ SUBROUTINE ParseLoAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. - CHARACTER(20), ALLOCATABLE :: Words (:) ! The array "words" parsed from the line. CHARACTER(*), PARAMETER :: RoutineName = 'ParseLoAry' ErrStat = ErrID_None @@ -3982,14 +4051,6 @@ SUBROUTINE ParseLoAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg , ErrStat, ErrMsg, RoutineName ) RETURN END IF - - - ALLOCATE ( Words( AryLen ) , STAT=ErrStatLcl ) - IF ( ErrStatLcl /= 0 ) THEN - CALL SetErrStat ( ErrID_Fatal, NewLine//'Fatal error allocating memory for the Words array.',ErrStat,ErrMsg,RoutineName ) - CALL Cleanup() - RETURN - ENDIF READ (FileInfo%Lines(LineNum),*,IOSTAT=ErrStatLcl) Ary @@ -3999,7 +4060,6 @@ SUBROUTINE ParseLoAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg ' >> The "'//TRIM( AryName )//'" array was not assigned valid LOGICAL values on line #' & //TRIM( Num2LStr( FileInfo%FileLine(LineNum) ) )//'.'//NewLine//' >> The text being parsed was :'//NewLine & //' "'//TRIM( FileInfo%Lines(LineNum) )//'"',ErrStat,ErrMsg,RoutineName ) - CALL Cleanup() RETURN ENDIF @@ -4008,25 +4068,9 @@ SUBROUTINE ParseLoAry ( FileInfo, LineNum, AryName, Ary, AryLen, ErrStat, ErrMsg END IF LineNum = LineNum + 1 - CALL Cleanup() RETURN - !======================================================================= - CONTAINS - !======================================================================= - SUBROUTINE Cleanup ( ) - - ! This subroutine cleans up the parent routine before exiting. - - ! Deallocate the Words array if it had been allocated. - - IF ( ALLOCATED( Words ) ) DEALLOCATE( Words ) - - RETURN - - END SUBROUTINE Cleanup - END SUBROUTINE ParseLoAry !======================================================================= !> \copydoc nwtc_io::parsechvar @@ -4057,7 +4101,7 @@ SUBROUTINE ParseLoVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. INTEGER(IntKi) :: NameIndx ! The index into the Words array that points to the variable name. - CHARACTER(20) :: Words (2) ! The two "words" parsed from the line. + CHARACTER(200) :: Words (2) ! The two "words" parsed from the line. CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ParseLoVar' @@ -4233,7 +4277,7 @@ SUBROUTINE ParseSiVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. INTEGER(IntKi) :: NameIndx ! The index into the Words array that points to the variable name. - CHARACTER(20) :: Words (2) ! The two "words" parsed from the line. + CHARACTER(200) :: Words (2) ! The two "words" parsed from the line. CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ParseSiVar' @@ -4394,6 +4438,70 @@ SUBROUTINE PremEOF ( Fil , Variable, TrapErrors, ErrMsg ) RETURN END SUBROUTINE PremEOF +!======================================================================= + SUBROUTINE InitFileInfo( StringArray, FileInfo, ErrStat, ErrMsg ) + + CHARACTER(*), DIMENSION(:), INTENT(IN ) :: StringArray + TYPE(FileInfoType), INTENT( OUT) :: FileInfo + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + character(len=len(StringArray)) :: TmpStringArray(size(StringArray)) + character(len=len(StringArray)) :: Line + integer :: TmpFileLine(size(StringArray)) + + CHARACTER(*), PARAMETER :: RoutineName = 'InitFileInfo' + INTEGER :: i, NumLines, IC, NumCommChars, LineLen, FirstComm, CommLoc + + ErrStat = ErrID_None + ErrMsg = "" + NumLines = 0 ! Initialize counter for non-comment populated lines + TmpFileLine = 0 ! Line number that was passed in + NumCommChars = LEN_TRIM( CommChars ) ! Number of globally specified CommChars + + ! Find how many non-comment lines we have + do i=1,size(StringArray) + Line=StringArray(i) + LineLen = LEN_TRIM( Line ) + IF ( ( NumCommChars == 0 ) .OR. ( LineLen == 0 ) ) CYCLE + + FirstComm = MIN( LEN( Line ), LineLen + 1 ) + + DO IC=1,NumCommChars + CommLoc = INDEX( Line, CommChars(IC:IC) ) + IF ( CommLoc > 0 ) THEN + FirstComm = MIN( CommLoc, FirstComm ) + ENDIF + END DO + + ! Only keep lines with no comments and some sort of length + if ( LEN_TRIM( Line(:FirstComm-1) ) > 0 ) then + NumLines=NumLines+1 + TmpStringArray(NumLines) = Line(:FirstComm-1) ! Store non-comment line + TmpFileLine(NumLines) = i ! Corresponding line number of passed in info + endif + enddo + + ! Now save the FileInfo + FileInfo%NumLines = NumLines ! only lines that contained anything + FileInfo%NumFiles = 1 + ALLOCATE( FileInfo%Lines(FileInfo%NumLines) ) + ALLOCATE( FileInfo%FileLine(FileInfo%NumLines) ) + ALLOCATE( FileInfo%FileIndx(FileInfo%NumLines) ) + ALLOCATE( FileInfo%FileList(FileInfo%NumFiles) ) + + DO i = 1, FileInfo%NumLines + IF ( LEN(TmpStringArray(i)) > LEN(FileInfo%Lines(i)) ) THEN + CALL SetErrStat( ErrID_Fatal, 'Input string exceeds the bounds of FileInfoType.' , ErrStat, ErrMsg, RoutineName ) + RETURN + END IF + FileInfo%Lines(i) = TmpStringArray(i) + FileInfo%FileLine(i) = TmpFileLine(i) + END DO + FileInfo%FileIndx = FileInfo%NumFiles + FileInfo%FileList = (/ "passed file info" /) + + END SUBROUTINE !======================================================================= !> This routine calls ScanComFile (nwtc_io::scancomfile) and ReadComFile (nwtc_io::readcomfile) !! to move non-comments in a set of nested files starting with TopFile into the FileInfo (nwtc_io::fileinfo) structure. @@ -4635,16 +4743,18 @@ END SUBROUTINE ProgWarn !======================================================================= !> \copydoc nwtc_io::int2lstr - FUNCTION R2LStr4 ( Num ) + FUNCTION R2LStr4 ( Num, Fmt_in ) ! Function declaration. CHARACTER(15) :: R2LStr4 ! This function. + CHARACTER(*), OPTIONAL :: Fmt_in ! Argument declarations. REAL(SiKi), INTENT(IN) :: Num ! The number to convert. + CHARACTER(15) :: Fmt ! format for output ! Return a 0 if that's what we have. @@ -4656,8 +4766,14 @@ FUNCTION R2LStr4 ( Num ) ! Write the number into the string using G format and left justify it. + if ( present( Fmt_in ) ) then + Fmt = '('//Fmt_in//')' + else + Fmt = '(1PG15.5)' + end if + - WRITE (R2LStr4,'(1PG15.5)') Num + WRITE (R2LStr4,Fmt) Num CALL AdjRealStr( R2LStr4 ) @@ -4666,16 +4782,18 @@ FUNCTION R2LStr4 ( Num ) END FUNCTION R2LStr4 !======================================================================= !> \copydoc nwtc_io::int2lstr - FUNCTION R2LStr8 ( Num ) + FUNCTION R2LStr8 ( Num, Fmt_in ) ! Function declaration. CHARACTER(15) :: R2LStr8 ! This function. + CHARACTER(*), OPTIONAL :: Fmt_in ! Argument declarations. REAL(R8Ki), INTENT(IN) :: Num ! The floating-point number to convert. + CHARACTER(15) :: Fmt ! format for output ! Return a 0 if that's what we have. @@ -4687,8 +4805,13 @@ FUNCTION R2LStr8 ( Num ) ! Write the number into the string using G format and left justify it. + if ( present( Fmt_in ) ) then + Fmt = '('//Fmt_in//')' + else + Fmt = '(1PG15.5)' + end if - WRITE (R2LStr8,'(1PG15.5)') Num + WRITE (R2LStr8,Fmt) Num CALL AdjRealStr( R2LStr8 ) @@ -4697,7 +4820,7 @@ FUNCTION R2LStr8 ( Num ) END FUNCTION R2LStr8 !======================================================================= !> \copydoc nwtc_io::int2lstr - FUNCTION R2LStr16 ( Num ) + FUNCTION R2LStr16 ( Num, Fmt_in ) ! This function converts a 16-byte floating point number to ! a left-aligned string. It eliminates trailing zeroes @@ -4707,11 +4830,13 @@ FUNCTION R2LStr16 ( Num ) ! Function declaration. CHARACTER(15) :: R2LStr16 ! This function. + CHARACTER(*), OPTIONAL :: Fmt_in ! Argument declarations. REAL(QuKi), INTENT(IN) :: Num ! The floating-point number to convert. + CHARACTER(15) :: Fmt ! format for output ! Return a 0 if that's what we have. @@ -4723,8 +4848,13 @@ FUNCTION R2LStr16 ( Num ) ! Write the number into the string using G format and left justify it. + if ( present( Fmt_in ) ) then + Fmt = '('//Fmt_in//')' + else + Fmt = '(1PG15.5)' + end if - WRITE (R2LStr16,'(1PG15.5)') Num + WRITE (R2LStr16,Fmt) Num CALL AdjRealStr( R2LStr16 ) @@ -5972,6 +6102,99 @@ SUBROUTINE ReadOutputList ( UnIn, Fil, CharAry, AryLenRead, AryName, AryDescr, E RETURN END SUBROUTINE ReadOutputList !======================================================================= +!> This routine reads up to MaxAryLen values from an input file and store them in CharAry(:). +!! These values represent the names of output channels, and they are specified in the format +!! required for OutList(:) in FAST input files. +!! The end of this list is specified with the line beginning with the 3 characters "END". + SUBROUTINE ReadOutputListFromFileInfo ( FileInfo, LineNum, CharAry, AryLenRead, AryName, AryDescr, ErrStat, ErrMsg, UnEc ) + + ! Argument declarations: + + TYPE (FileInfoType), INTENT(IN) :: FileInfo !< The derived type for holding the file information. + INTEGER(IntKi), INTENT(INOUT):: LineNum !< The number of the line to parse. + INTEGER, INTENT(OUT) :: AryLenRead !< Length of the array that was actually read. + INTEGER, INTENT(IN), OPTIONAL :: UnEc !< I/O unit for echo file (if > 0). + INTEGER, INTENT(OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message + + CHARACTER(*), INTENT(OUT) :: CharAry(:) !< Character array being read (calling routine dimensions it to max allowable size). + + CHARACTER(*), INTENT(IN) :: AryDescr !< Text string describing the variable. + CHARACTER(*), INTENT(IN) :: AryName !< Text string containing the variable name. + + + ! Local declarations: + + INTEGER :: MaxAryLen ! Maximum length of the array being read + INTEGER :: NumWords ! Number of words contained on a line + + INTEGER :: QuoteCh ! Character position. + + CHARACTER(1000) :: OutLine ! Character string read from file, containing output list + CHARACTER(3) :: EndOfFile + + + ! Initialize some values + + ErrStat = ErrID_None + ErrMsg = '' + MaxAryLen = SIZE(CharAry) + AryLenRead = 0 + + CharAry = '' + + + ! Read in all of the lines containing output parameters and store them in CharAry(:). + ! The end of this list is specified with the line beginning with END. + + DO + + IF ( PRESENT(UnEc) ) THEN + if (UnEc > 0) WRITE(UnEc, '(A)') FileInfo%Lines(LineNum) + ENDIF + OutLine = adjustl(trim(FileInfo%Lines(LineNum))) ! remove leading whitespace + + EndOfFile = OutLine(1:3) ! EndOfFile is the 1st 3 characters of OutLine + CALL Conv2UC( EndOfFile ) ! Convert EndOfFile to upper case + IF ( EndOfFile == 'END' ) THEN + LineNum = LineNum + 1 + EXIT ! End of OutList has been reached; therefore, exit this DO + ENDIF + + ! Check if we have a quoted string at the begining. Ignore anything outside the quotes if so (this is the ReadVar behaviour for quoted strings). + if (SCAN(OutLine(1:1), '''"' ) == 1_IntKi ) then + QuoteCh = SCAN( OutLine(2:), '''"' ) ! last quote + if (QuoteCh < 1) QuoteCh = LEN_TRIM(OutLine) ! in case no end quote + OutLine(QuoteCh+2:) = ' ' ! blank out everything after last quote + endif + + NumWords = CountWords( OutLine ) ! The number of words in OutLine. + + AryLenRead = AryLenRead + NumWords ! The total number of output channels read in so far. + + ! Check to see if the maximum # allowable in the array has been reached. + + IF ( AryLenRead > MaxAryLen ) THEN + + ErrStat = ErrID_Fatal + ErrMsg = 'ReadOutputList:The maximum number of output channels allowed is '//TRIM( Int2LStr(MaxAryLen) )//'.' + RETURN + + ELSE + + CALL GetWords ( OutLine, CharAry((AryLenRead - NumWords + 1):AryLenRead), NumWords ) + + END IF + + LineNum = LineNum+1 + + END DO + + + RETURN + END SUBROUTINE ReadOutputListFromFileInfo + +!======================================================================= !> \copydoc nwtc_io::readcary SUBROUTINE ReadR4Ary ( UnIn, Fil, Ary, AryLen, AryName, AryDescr, ErrStat, ErrMsg, UnEc ) diff --git a/modules/nwtc-library/src/NWTC_Library_Types.f90 b/modules/nwtc-library/src/NWTC_Library_Types.f90 index 957edd0505..9967947fb1 100644 --- a/modules/nwtc-library/src/NWTC_Library_Types.f90 +++ b/modules/nwtc-library/src/NWTC_Library_Types.f90 @@ -70,11 +70,11 @@ MODULE NWTC_Library_Types ! ========= FileInfoType ======= TYPE, PUBLIC :: FileInfoType INTEGER(IntKi) :: NumLines - INTEGER(IntKi) :: NumFiles + CHARACTER(1024) , DIMENSION(:), ALLOCATABLE :: Lines INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: FileLine + INTEGER(IntKi) :: NumFiles INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: FileIndx CHARACTER(1024) , DIMENSION(:), ALLOCATABLE :: FileList - CHARACTER(512) , DIMENSION(:), ALLOCATABLE :: Lines END TYPE FileInfoType ! ======================= ! ========= Quaternion ======= diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 4c0803b8e3..2b0786ed44 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -214,9 +214,15 @@ MODULE NWTC_Num MODULE PROCEDURE Angles_ExtrapInterp1_R4 MODULE PROCEDURE Angles_ExtrapInterp1_R8 MODULE PROCEDURE Angles_ExtrapInterp1_R16 + MODULE PROCEDURE Angles_ExtrapInterp1_R4R + MODULE PROCEDURE Angles_ExtrapInterp1_R8R + MODULE PROCEDURE Angles_ExtrapInterp1_R16R MODULE PROCEDURE Angles_ExtrapInterp2_R4 MODULE PROCEDURE Angles_ExtrapInterp2_R8 MODULE PROCEDURE Angles_ExtrapInterp2_R16 + MODULE PROCEDURE Angles_ExtrapInterp2_R4R + MODULE PROCEDURE Angles_ExtrapInterp2_R8R + MODULE PROCEDURE Angles_ExtrapInterp2_R16R END INTERFACE !> \copydoc nwtc_num::addorsub2pi_r4 @@ -334,6 +340,25 @@ SUBROUTINE AddOrSub2Pi_R16 ( OldAngle, NewAngle ) RETURN END SUBROUTINE AddOrSub2Pi_R16 +!======================================================================= + FUNCTION BlendCosine( x, LowerBound, UpperBound ) RESULT(S) + + REAL(ReKi), INTENT(IN) :: x ! + REAL(ReKi), INTENT(IN) :: LowerBound !< if x <= LowerBound, S=0 + REAL(ReKi), INTENT(IN) :: UpperBound !< if x >= UpperBound, S=1 + REAL(ReKi) :: S + + if (x >= UpperBound) then + S = 1.0_ReKi + elseif (x <= LowerBound) then + S = 0.0_ReKi + elseif (LowerBound < UpperBound) then + S = 0.5_ReKi*(1.0_ReKi - cos((x-LowerBound) / (UpperBound-LowerBound)*pi)) + else ! can only get here if LowerBound>=UpperBound>x , which should be an error + S = 0.0_ReKi + end if + + END FUNCTION BlendCosine !======================================================================= !> This routine sorts a list of real numbers. It uses the bubble sort algorithm, !! which is only suitable for short lists. @@ -5397,7 +5422,7 @@ END SUBROUTINE SimStatus_FirstTime !======================================================================= !> This routine displays a message that gives that status of the simulation and the predicted end time of day. !! It is intended to be used with RunTimes (nwtc_num::runtimes) and SimStatus_FirstTime (nwtc_num::simstatus_firsttime). - SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) + SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn, StatInfoIn) IMPLICIT NONE @@ -5408,7 +5433,8 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) REAL(DbKi), INTENT(INOUT) :: PrevSimTime !< Previous time message was written to screen (s > 0) REAL(ReKi), INTENT(INOUT) :: PrevClockTime !< Previous clock time in seconds past midnight - CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus + CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print at start of SimStatus + CHARACTER(*), INTENT(IN), OPTIONAL :: StatInfoIn !< optional additional string to print at end of SimStatus ! Local variables. @@ -5428,7 +5454,8 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) CHARACTER(MaxWrScrLen) :: BlankLine CHARACTER( 8) :: ETimeStr ! String containing the end time. - CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + CHARACTER( 10) :: DescStr !< optional additional string to print for SimStatus + CHARACTER(200) :: StatInfo !< optional additional string to print for SimStatus IF ( ZTime <= PrevSimTime ) RETURN @@ -5439,6 +5466,12 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) else DescStr = "" end if + + if (present(StatInfoIn)) then + StatInfo = StatInfoIn + else + StatInfo = "" + end if ! How many seconds past midnight? @@ -5471,7 +5504,8 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) BlankLine = "" CALL WrOver( BlankLine ) ! BlankLine contains MaxWrScrLen spaces CALL WrOver ( trim(DescStr)//' Time: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )// & - ' seconds. Estimated final completion at '//ETimeStr//'.' ) + ' seconds. '//trim(StatInfo)// & + ' Estimated final completion at '//ETimeStr//'.') ! Let's save this time as the previous time for the next call to the routine PrevClockTime = CurrClockTime @@ -6365,6 +6399,136 @@ SUBROUTINE Angles_ExtrapInterp1_R16(Angle1, Angle2, tin, Angle_out, tin_out) ! call MPi2Pi(Angle_out) END SUBROUTINE Angles_ExtrapInterp1_R16 +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp1_R4R(Angle1, Angle2, tin, Angle_out, tin_out ) + REAL(SiKi), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 + REAL(SiKi), INTENT(IN ) :: Angle2 !< Angle at t2 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(SiKi), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 1 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(SiKi) :: Angle2_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! ! some error checking: + ! + ! if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: size(t) must equal 2.' + ! RETURN + ! end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + call AddOrSub2Pi( Angle1, Angle2_mod ) + + Angle_out = Angle1 + (Angle2_mod - Angle1) * t_out / t(2) + +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp1_R4R +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp1_R8R(Angle1, Angle2, tin, Angle_out, tin_out) + REAL(R8Ki), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 + REAL(R8Ki), INTENT(IN ) :: Angle2 !< Angle at t2 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(R8Ki), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 1 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(R8Ki) :: Angle2_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! ! some error checking: + ! + ! if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: size(t) must equal 2.' + ! RETURN + ! end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + call AddOrSub2Pi( Angle1, Angle2_mod ) + + Angle_out = Angle1 + (Angle2_mod - Angle1) * t_out / t(2) +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp1_R8R +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp1_R16R(Angle1, Angle2, tin, Angle_out, tin_out) + REAL(QuKi), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 + REAL(QuKi), INTENT(IN ) :: Angle2 !< Angle at t2 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(QuKi), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 1 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(QuKi) :: Angle2_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! ! some error checking: + ! + ! if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: size(t) must equal 2.' + ! RETURN + ! end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp1: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + call AddOrSub2Pi( Angle1, Angle2_mod ) + + Angle_out = Angle1 + (Angle2_mod - Angle1) * t_out / t(2) +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp1_R16R !======================================================================= !< This routine extrapolates or interpolates between angles SUBROUTINE Angles_ExtrapInterp2_R4(Angle1, Angle2, Angle3, tin, Angle_out, tin_out ) @@ -6552,5 +6716,192 @@ SUBROUTINE Angles_ExtrapInterp2_R16(Angle1, Angle2, Angle3, tin, Angle_out, tin_ ! call MPi2Pi(Angle_out) END SUBROUTINE Angles_ExtrapInterp2_R16 +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp2_R4R(Angle1, Angle2, Angle3, tin, Angle_out, tin_out ) + REAL(SiKi), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 > t3 + REAL(SiKi), INTENT(IN ) :: Angle2 !< Angle at t2 > t3 + REAL(SiKi), INTENT(IN ) :: Angle3 !< Angle at t3 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(SiKi), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 2 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(DbKi) :: scaleFactor ! temporary for extrapolation/interpolation + REAL(SiKi) :: Angle2_mod + REAL(SiKi) :: Angle3_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! ! some error checking: + ! + !if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: size(t) must equal 3.' + ! RETURN + !end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(2), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(2) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(1), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + Angle3_mod = Angle3 + call AddOrSub2Pi( Angle1, Angle2_mod ) + call AddOrSub2Pi( Angle2_mod, Angle3_mod ) + + scaleFactor = t_out / ( t(2) * t(3) * (t(2) - t(3)) ) + + Angle_out = Angle1 & + + ( t(3)**2 * (Angle1 - Angle2_mod) + t(2)**2*(-Angle1 + Angle3_mod) ) * scaleFactor & + + ( (t(2)-t(3))*Angle1 + t(3)*Angle2_mod - t(2)*Angle3_mod ) *scaleFactor * t_out + +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp2_R4R +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp2_R8R(Angle1, Angle2, Angle3, tin, Angle_out, tin_out) + REAL(R8Ki), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 > t3 + REAL(R8Ki), INTENT(IN ) :: Angle2 !< Angle at t2 > t3 + REAL(R8Ki), INTENT(IN ) :: Angle3 !< Angle at t3 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(R8Ki), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 2 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(DbKi) :: scaleFactor ! temporary for extrapolation/interpolation + REAL(R8Ki) :: Angle2_mod + REAL(R8Ki) :: Angle3_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! some error checking: + + !if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: size(t) must equal 3.' + ! RETURN + !end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(2), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(2) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(1), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + Angle3_mod = Angle3 + call AddOrSub2Pi( Angle1, Angle2_mod ) + call AddOrSub2Pi( Angle2_mod, Angle3_mod ) + + scaleFactor = t_out / ( t(2) * t(3) * (t(2) - t(3)) ) + + Angle_out = Angle1 & + + ( t(3)**2 * (Angle1 - Angle2_mod) + t(2)**2*(-Angle1 + Angle3_mod) ) * scaleFactor & + + ( (t(2)-t(3))*Angle1 + t(3)*Angle2_mod - t(2)*Angle3_mod ) *scaleFactor * t_out +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp2_R8R +!======================================================================= + !< This routine extrapolates or interpolates between angles + SUBROUTINE Angles_ExtrapInterp2_R16R(Angle1, Angle2, Angle3, tin, Angle_out, tin_out ) + REAL(QuKi), INTENT(IN ) :: Angle1 !< Angle at t1 > t2 > t3 + REAL(QuKi), INTENT(IN ) :: Angle2 !< Angle at t2 > t3 + REAL(QuKi), INTENT(IN ) :: Angle3 !< Angle at t3 + REAL(ReKi), INTENT(IN ) :: tin(:) !< Times associated with the inputs + REAL(QuKi), INTENT(INOUT) :: Angle_out !< Input at tin_out + REAL(ReKi), INTENT(IN ) :: tin_out !< time to be extrap/interp'd to + + ! local variables + INTEGER(IntKi), parameter :: order = 2 ! order of polynomial fit (max 2) + REAL(ReKi) :: t(SIZE(tin)) ! Times associated with the inputs + REAL(ReKi) :: t_out ! Time to which to be extrap/interpd + + REAL(DbKi) :: scaleFactor ! temporary for extrapolation/interpolation + REAL(QuKi) :: Angle2_mod + REAL(QuKi) :: Angle3_mod + + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + ! some error checking: + + !if ( size(t) .ne. order+1) then + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: size(t) must equal 3.' + ! RETURN + !end if + ! + !IF ( EqualRealNos( t(1), t(2) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(2) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(2), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(2) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + !IF ( EqualRealNos( t(1), t(3) ) ) THEN + ! ErrStat = ErrID_Fatal + ! ErrMsg = 'Angles_ExtrapInterp2: t(1) must not equal t(3) to avoid a division-by-zero error.' + ! RETURN + !END IF + + Angle2_mod = Angle2 + Angle3_mod = Angle3 + call AddOrSub2Pi( Angle1, Angle2_mod ) + call AddOrSub2Pi( Angle2_mod, Angle3_mod ) + + scaleFactor = t_out / ( t(2) * t(3) * (t(2) - t(3)) ) + + Angle_out = Angle1 & + + ( t(3)**2 * (Angle1 - Angle2_mod) + t(2)**2*(-Angle1 + Angle3_mod) ) * scaleFactor & + + ( (t(2)-t(3))*Angle1 + t(3)*Angle2_mod - t(2)*Angle3_mod ) *scaleFactor * t_out +! call Zero2TwoPi(Angle_out) +! call MPi2Pi(Angle_out) + + END SUBROUTINE Angles_ExtrapInterp2_R16R !======================================================================= END MODULE NWTC_Num diff --git a/modules/nwtc-library/src/Registry_NWTC_Library.txt b/modules/nwtc-library/src/Registry_NWTC_Library.txt index d8eb0b0c72..eb3d0b0d0b 100644 --- a/modules/nwtc-library/src/Registry_NWTC_Library.txt +++ b/modules/nwtc-library/src/Registry_NWTC_Library.txt @@ -25,11 +25,11 @@ usefrom ^ ^ CHARACTER(ChanLen) Units usefrom ^ ^ IntKi SignM usefrom NWTC_Library FileInfoType IntKi NumLines -usefrom ^ ^ IntKi NumFiles +usefrom ^ ^ CHARACTER(1024) Lines {:} usefrom ^ ^ IntKi FileLine {:} +usefrom ^ ^ IntKi NumFiles usefrom ^ ^ IntKi FileIndx {:} usefrom ^ ^ CHARACTER(1024) FileList {:} -usefrom ^ ^ CHARACTER(512) Lines {:} usefrom NWTC_Library Quaternion ReKi q0 usefrom ^ ^ ReKi v {3} diff --git a/modules/nwtc-library/src/SysIVF.f90 b/modules/nwtc-library/src/SysIVF.f90 index ac0c2aefdc..84848626c7 100644 --- a/modules/nwtc-library/src/SysIVF.f90 +++ b/modules/nwtc-library/src/SysIVF.f90 @@ -338,8 +338,15 @@ END SUBROUTINE WrNR ! ( Str ) SUBROUTINE WrOver ( Str ) CHARACTER(*), INTENT(IN) :: Str !< The string to write to the screen. + + INTEGER :: MaxLen !< maximum length of string to be written to the screen (cannot exceed ConRecL here) - WRITE (CU,'(''+'',A)') Str + ! When the file is opened using CARRIAGECONTROL='FORTRAN', the "+" character allows writing over the previous line. However, the Fortran carriage control has been deleted from the Fortran standard. + + MaxLen = min(ConRecL-1, len(Str)) + if (MaxLen > 0) then + WRITE (CU,'("+",A)') Str(1:MaxLen) + end if RETURN END SUBROUTINE WrOver ! ( Str ) diff --git a/modules/nwtc-library/tests/test_NWTC_IO_FileInfo.F90 b/modules/nwtc-library/tests/test_NWTC_IO_FileInfo.F90 new file mode 100644 index 0000000000..3dd9a6ea37 --- /dev/null +++ b/modules/nwtc-library/tests/test_NWTC_IO_FileInfo.F90 @@ -0,0 +1,84 @@ +module test_NWTC_IO_FileInfo + + use pFUnit_mod + use NWTC_IO + + implicit none + +contains + +@test +subroutine test_initfileinfo() + + ! This case should result in error status 0. + ! It's a normal initialization of FileInfoType. + + integer, parameter :: num_lines = 5 + integer, parameter :: num_files = 1 + + integer(IntKi) :: error_status + character(ErrMsgLen) :: error_message + character(1024) :: input_strings(num_lines) + type(FileInfoType) :: file_info_type + integer :: i + + input_strings = (/ & + "line 0", & + "line 1", & + "line 2", & + "line 3", & + "line 4" & + /) + call InitFileInfo( input_strings, file_info_type, error_status, error_message ) + + @assertEqual(num_lines, file_info_type%NumLines) + @assertEqual(num_files, file_info_type%NumFiles) + do i = 1, num_lines + @assertEqual(i, file_info_type%FileLine(i)) + end do + do i = 1, num_files + @assertEqual(i, file_info_type%FileIndx(i)) + end do + + ! TODO: test FileList when we actually use it + + do i = 1, num_lines + @assertEqual( trim(input_strings(i)), trim(file_info_type%Lines(i)) ) + end do + + @assertEqual( 0, error_status ) + @assertEqual( "", error_message ) +end subroutine + +@test +subroutine test_initfileinfo2() + + ! This case should result in a non-zero error status. + ! It attempts to initialize FileInfoType without having + ! properly initializing the input strings array. + + integer, parameter :: num_lines = 5 + integer, parameter :: num_files = 1 + + integer(IntKi) :: error_status + character(ErrMsgLen) :: error_message + character(1025) :: input_strings(num_lines) + type(FileInfoType) :: file_info_type + integer :: i + + input_strings = (/ & + "line 0", & + "line 1", & + "line 2", & + "line 3", & + "line 4" & + /) + call InitFileInfo( input_strings, file_info_type, error_status, error_message ) + + @assertEqual(num_lines, file_info_type%NumLines) + @assertEqual(num_files, file_info_type%NumFiles) + @assertEqual( 4, error_status ) + +end subroutine + +end module \ No newline at end of file diff --git a/modules/openfast-library/src/FAST_Lin.f90 b/modules/openfast-library/src/FAST_Lin.f90 index d31d3c4070..8b05043ad2 100644 --- a/modules/openfast-library/src/FAST_Lin.f90 +++ b/modules/openfast-library/src/FAST_Lin.f90 @@ -239,7 +239,7 @@ SUBROUTINE Init_Lin(p_FAST, y_FAST, m_FAST, AD, ED, NumBl, ErrStat, ErrMsg) if (y_FAST%Lin%Modules(ThisModule)%Instance(k)%SizeLin(LIN_ContSTATE_COL) > 0) then if (p_FAST%WrVTK == VTK_ModeShapes) then ! allocate these for restart later if (ThisModule == Module_ED) then - ! ED states are only the active DOFs, but when we perturb the OP [in PerturbOP()], we need the index + ! ED has only the active DOFs as the continuous states, but to perturb the OP [Perterb_OP()], we need all of the DOFs NumStates = ED%p%NDOF*2 else NumStates = y_FAST%Lin%Modules(ThisModule)%Instance(k)%SizeLin(LIN_ContSTATE_COL) @@ -251,7 +251,7 @@ SUBROUTINE Init_Lin(p_FAST, y_FAST, m_FAST, AD, ED, NumBl, ErrStat, ErrMsg) call SetErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return - + y_FAST%Lin%Modules(ThisModule)%Instance(k)%op_x_eig_mag = 0.0_R8Ki y_FAST%Lin%Modules(ThisModule)%Instance(k)%op_x_eig_phase = 0.0_R8Ki end if @@ -589,16 +589,13 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Linearize_OP' REAL(R8Ki), ALLOCATABLE :: dUdu(:,:), dUdy(:,:) ! variables for glue-code linearization -#ifdef OLD_AD_LINEAR - REAL(R8Ki), ALLOCATABLE :: dYdz(:,:), dZdz(:,:), dZdu(:,:) - INTEGER(IntKi), ALLOCATABLE :: ipiv(:) -#endif integer(intki) :: NumBl integer(intki) :: k CHARACTER(1024) :: LinRootName CHARACTER(1024) :: OutFileName CHARACTER(200) :: SimStr CHARACTER(MaxWrScrLen) :: BlankLine + CHARACTER(*), PARAMETER :: Fmt = 'F10.2' @@ -607,7 +604,7 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, Un = -1 !..................... - SimStr = '(RotSpeed='//trim(num2lstr(ED%y%RotSpeed*RPS2RPM))//' rpm, BldPitch1='//trim(num2lstr(ED%y%BlPitch(1)*R2D))//' deg)' + SimStr = '(RotSpeed='//trim(num2lstr(ED%y%RotSpeed*RPS2RPM,Fmt))//' rpm, BldPitch1='//trim(num2lstr(ED%y%BlPitch(1)*R2D,Fmt))//' deg)' BlankLine = "" CALL WrOver( BlankLine ) ! BlankLine contains MaxWrScrLen spaces @@ -625,128 +622,130 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, end if - NumBl = size(ED%Input(1)%BlPitchCom) - y_FAST%Lin%RotSpeed = ED%y%RotSpeed - y_FAST%Lin%Azimuth = ED%y%LSSTipPxa - !..................... - ! ElastoDyn - !..................... - ! get the jacobians - call ED_JacobianPInput( t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & - ED%y, ED%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, dXdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%B ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + NumBl = size(ED%Input(1)%BlPitchCom) + y_FAST%Lin%RotSpeed = ED%y%RotSpeed + y_FAST%Lin%Azimuth = ED%y%LSSTipPxa + !..................... + ! ElastoDyn + !..................... + ! get the jacobians + call ED_JacobianPInput( t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + ED%y, ED%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, dXdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%B ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call ED_JacobianPContState( t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & - ED%y, ED%m, ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, dXdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%A ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call ED_JacobianPContState( t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + ED%y, ED%m, ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, dXdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%A ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get the operating point - 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, ED%m, ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_u, y_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_y, & - x_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_x, dx_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_dx ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - - ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_ED)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) + ! get the operating point + 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, ED%m, ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_u, & + y_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_y, & + x_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_x, & + dx_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_dx ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then call cleanup() return end if + + + ! write the module matrices: + if (p_FAST%LinOutMod) then + + OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_ED)) + call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if - if (p_FAST%LinOutJac) then - ! Jacobians - !dXdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) + if (p_FAST%LinOutJac) then + ! Jacobians + !dXdx: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) - !dXdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) + !dXdu: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) - ! dYdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y ) + ! dYdx: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y ) - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) + !dYdu: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y, & + UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) - end if + end if - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1) ) + ! finish writing the file + call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1) ) - end if + end if - !..................... - ! BeamDyn - !..................... - if ( p_FAST%CompElast == Module_BD ) then - do k=1,p_FAST%nBeams + !..................... + ! BeamDyn + !..................... + if ( p_FAST%CompElast == Module_BD ) then + do k=1,p_FAST%nBeams - ! get the jacobians - call BD_JacobianPInput( t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & - BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, & - dXdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, & - StateRel_x =y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_x, & - StateRel_xdot=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_xdot ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! get the jacobians + call BD_JacobianPInput( t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & + BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, & + dXdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, & + StateRel_x =y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_x, & + StateRel_xdot=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_xdot ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call BD_JacobianPContState( t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & - BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, dXdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, & - StateRotation=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRotation) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call BD_JacobianPContState( t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & + BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, dXdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, & + StateRotation=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRotation) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get the operating point - 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(k), BD%m(k), ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_u, y_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_y, & - x_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_x, dx_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_dx ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - - ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_BD))//TRIM(num2lstr(k)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k), OutFileName, Un, ErrStat2, ErrMsg2 ) + ! get the operating point + 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(k), BD%m(k), ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_u, y_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_y, & + x_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_x, dx_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_dx ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then call cleanup() return end if + + + ! write the module matrices: + if (p_FAST%LinOutMod) then + + OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_BD))//TRIM(num2lstr(k)) + call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k), OutFileName, Un, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if - if (p_FAST%LinOutJac) then - ! Jacobians - !dXdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, Un, p_FAST%OutFmt, 'dXdx' ) + if (p_FAST%LinOutJac) then + ! Jacobians + !dXdx: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, Un, p_FAST%OutFmt, 'dXdx' ) - !dXdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) + !dXdu: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) - !dYdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y ) + !dYdx: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y ) - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) - end if + !dYdu: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y, & + UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) + end if - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k) ) - end if + ! finish writing the file + call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k) ) + end if - end do - end if !BeamDyn + end do + end if !BeamDyn !..................... @@ -843,34 +842,35 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, !..................... if ( p_FAST%CompAero == Module_AD ) then ! get the jacobians -#ifdef OLD_AD_LINEAR - call AD_JacobianPInput_orig( t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & - AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_AD)%Instance(1)%D, dZdu=dZdu ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - call AD_JacobianPConstrState( t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & - AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, dYdz=dYdz, dZdz=dZdz ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) -#else call AD_JacobianPInput( t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & - AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_AD)%Instance(1)%D ) + AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, & + dXdu=y_FAST%Lin%Modules(Module_AD)%Instance(1)%B, & + dYdu=y_FAST%Lin%Modules(Module_AD)%Instance(1)%D ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) -#endif + call AD_JacobianPContState( t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & + AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, & + dXdx=y_FAST%Lin%Modules(Module_AD)%Instance(1)%A, & + dYdx=y_FAST%Lin%Modules(Module_AD)%Instance(1)%C ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ! get the operating point call AD_GetOP( t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & - AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_u, & - y_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_y, z_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_z ) + AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, & + u_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_u, & + y_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_y, & + x_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_x, & + dx_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_dx ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then call cleanup() return - end if + end if ! write the module matrices: if (p_FAST%LinOutMod) then - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_AD)) + OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_AD)) call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_AD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then @@ -880,59 +880,22 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, if (p_FAST%LinOutJac) then ! Jacobians -#ifdef OLD_AD_LINEAR - ! dZdz: - call WrPartialMatrix( dZdz, Un, p_FAST%OutFmt, 'dZdz' ) - - ! dZdu: - call WrPartialMatrix( dZdu, Un, p_FAST%OutFmt, 'dZdu', UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) - - ! dYdz: - call WrPartialMatrix( dYdz, Un, p_FAST%OutFmt, 'dYdz', UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y ) -#endif - !dYdu: + call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) + + call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', & + UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) + + call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', & + UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y ) + call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', & - UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y, UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) - - end if - -#ifdef OLD_AD_LINEAR - end if - - call allocAry( ipiv, size(dZdz,1), 'ipiv', ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >= AbortErrLev) then - call cleanup() - return + UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y, & + UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) end if - - CALL LAPACK_getrf( M=size(dZdz,1), N=size(dZdz,2), A=dZdz, IPIV=ipiv, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >= AbortErrLev) then - call cleanup() - return - end if - - CALL LAPACK_getrs( trans='N', N=size(dZdz,2), A=dZdz, IPIV=ipiv, B=dZdu, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! note that after the above solve, dZdu is now matmul(dZdz^-1, dZdu) - !y_FAST%Lin%Modules(Module_AD)%D = y_FAST%Lin%Modules(Module_AD)%D - matmul(dYdz, dZdu ) - call LAPACK_GEMM( 'N', 'N', -1.0_R8Ki, dYdz, dZdu, 1.0_R8Ki, y_FAST%Lin%Modules(Module_AD)%Instance(1)%D, ErrStat2, ErrMsg2 ) - - if (p_FAST%LinOutMod) then -#endif ! finish writing the file call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_AD)%Instance(1) ) end if - -#ifdef OLD_AD_LINEAR - ! AD doesn't need these any more, and we may need them for other modules - if (allocated(dYdz)) deallocate(dYdz) - if (allocated(dZdz)) deallocate(dZdz) - if (allocated(dZdu)) deallocate(dZdu) - if (allocated(ipiv)) deallocate(ipiv) -#endif end if @@ -978,7 +941,7 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, !dXdu: call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_u ) - ! dYdx: + !dYdx: call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_y ) !dYdu: @@ -1140,12 +1103,6 @@ logical function Failed() if(Failed) call cleanup() end function Failed subroutine cleanup() -#ifdef OLD_AD_LINEAR - if (allocated(dYdz)) deallocate(dYdz) - if (allocated(dZdz)) deallocate(dZdz) - if (allocated(dZdu)) deallocate(dZdu) - if (allocated(ipiv)) deallocate(ipiv) -#endif if (allocated(dUdu)) deallocate(dUdu) if (allocated(dUdy)) deallocate(dUdy) @@ -1626,23 +1583,24 @@ 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^{ED}}{\partial u^{AD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{BD}} \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, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - !............ - ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial u^{AD}} \end{bmatrix} = \f$ and - ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial u^{BD}} \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 ) + !............ + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{AD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{BD}} \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, MAPp, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - END IF + + !............ + ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial u^{AD}} \end{bmatrix} = \f$ and + ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial u^{BD}} \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 SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + END IF !............ ! \f$ \frac{\partial U_\Lambda^{AD}}{\partial u^{AD}} \end{bmatrix} = \f$ (dUdu block row 5=AD) @@ -1702,25 +1660,25 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, 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$ (dUdy block row 3=ED) - !............ + !............ + ! \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$ (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, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - !............ - ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial y^{ED}} \end{bmatrix} = \f$ - ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial y^{BD}} \end{bmatrix} = \f$ - ! \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_ED_InputSolve_dy( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, MAPp, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - end if + + !............ + ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial y^{ED}} \end{bmatrix} = \f$ + ! \f$ \frac{\partial U_\Lambda^{BD}}{\partial y^{BD}} \end{bmatrix} = \f$ + ! \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 SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if !............ ! \f$ \frac{\partial U_\Lambda^{AD}}{\partial y^{IfW}} \end{bmatrix} = \f$ @@ -2115,11 +2073,12 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, ! Local variables: - INTEGER(IntKi) :: K ! Loops through blades - INTEGER(IntKi) :: AD_Start_td ! starting index of dUdu (column) where AD translation displacements are located - INTEGER(IntKi) :: AD_Start_tv ! starting index of dUdu (column) where AD translation velocities are located + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Start_td ! starting index of dUdu (column) where AD translation displacements are located + INTEGER(IntKi) :: AD_Start_tv ! starting index of dUdu (column) where AD translation velocities are located + INTEGER(IntKi) :: AD_Start_ta ! starting index of dUdu (column) where AD translation accelerations are located INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'Linear_AD_InputSolve_du' @@ -2136,14 +2095,15 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, ! tower IF (u_AD%TowerMotion%Committed) THEN - CALL Linearize_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%TowerMotion, MeshMapData%ED_L_2_AD_L_T, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%TowerMotion' ) - - AD_Start_td = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) - AD_Start_tv = AD_Start_td + u_AD%TowerMotion%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field + CALL Linearize_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%TowerMotion, MeshMapData%ED_L_2_AD_L_T, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%TowerMotion' ) + !AD is the destination here, so we need tv_ud if (allocated( MeshMapData%ED_L_2_AD_L_T%dM%tv_ud)) then + AD_Start_td = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) + AD_Start_tv = AD_Start_td + u_AD%TowerMotion%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field + call SetBlockMatrix( dUdu, MeshMapData%ED_L_2_AD_L_T%dM%tv_ud, AD_Start_tv, AD_Start_td ) end if @@ -2176,10 +2136,16 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, !AD is the destination here, so we need tv_ud if (allocated( MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud)) then ! index for u_AD%BladeMotion(k+1)%translationVel field - AD_Start_tv = AD_Start_td + u_AD%BladeMotion(k)%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field + AD_Start_tv = AD_Start_td + u_AD%BladeMotion(k)%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field call SetBlockMatrix( dUdu, MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud, AD_Start_tv, AD_Start_td ) end if + + if (allocated( MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud)) then + AD_Start_ta = AD_Start_td + u_AD%BladeMotion(k)%NNodes * 12 ! 4 fields (TranslationDisp, Orientation, TranslationVel, and RotationVel) with 3 components before translational velocity field + + call SetBlockMatrix( dUdu, MeshMapData%BDED_L_2_AD_L_B(k)%dM%ta_ud, AD_Start_ta, AD_Start_td ) + end if END DO @@ -2203,7 +2169,7 @@ SUBROUTINE Linear_SrvD_InputSolve_dy( p_FAST, y_FAST, dUdy ) CHARACTER(*), PARAMETER :: RoutineName = 'Linear_SrvD_InputSolve_dy' - thisModule = Module_ED + 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) do i=1,size(SrvD_Indx_Y_BlPitchCom) @@ -2605,59 +2571,60 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa AD_Start = Indx_u_AD_Tower_Start(u_AD, y_FAST) ! start of u_AD%TowerMotion%TranslationDisp field - ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of y_ED%TowerLn2Mesh%TranslationDisp field - call Assemble_dUdy_Motions(y_ED%TowerLn2Mesh, u_AD%TowerMotion, MeshMapData%ED_L_2_AD_L_T, AD_Start, ED_Out_Start, dUdy, .true.) + ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of y_ED%TowerLn2Mesh%TranslationDisp field + call Assemble_dUdy_Motions(y_ED%TowerLn2Mesh, u_AD%TowerMotion, MeshMapData%ED_L_2_AD_L_T, AD_Start, ED_Out_Start, dUdy, skipRotVel=.true.) + END IF !................................... ! hub !................................... - CALL Linearize_Point_to_Point( y_ED%HubPtMotion, u_AD%HubMotion, MeshMapData%ED_P_2_AD_P_H, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%HubMotion' ) - if (errStat>=AbortErrLev) return - - ! *** AD translational displacement: from ED translational displacement (MeshMapData%ED_P_2_AD_P_H%dM%mi) and orientation (MeshMapData%ED_P_2_AD_P_H%dM%fx_p) - AD_Start = Indx_u_AD_Hub_Start(u_AD, y_FAST) ! start of u_AD%HubMotion%TranslationDisp field - ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) ! start of y_ED%HubPtMotion%TranslationDisp field - call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) - - ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) + y_ED%HubPtMotion%NNodes * 3 ! start of y_ED%HubPtMotion%Orientation field - call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%fx_p, AD_Start, ED_Out_Start ) - - ! *** AD orientation: from ED orientation - AD_Start = AD_Start + u_AD%HubMotion%NNodes * 3 ! move past the AD translation disp field to orientation field - call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) - - ! *** AD rotational velocity: from ED rotational velocity - AD_Start = AD_Start + u_AD%HubMotion%NNodes * 3 ! move past the AD orientation field to rotational velocity field - ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) + y_ED%HubPtMotion%NNodes * 6 ! ! start of y_ED%HubPtMotion%RotationVel field - call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) - + CALL Linearize_Point_to_Point( y_ED%HubPtMotion, u_AD%HubMotion, MeshMapData%ED_P_2_AD_P_H, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%HubMotion' ) + if (errStat>=AbortErrLev) return + + ! *** AD translational displacement: from ED translational displacement (MeshMapData%ED_P_2_AD_P_H%dM%mi) and orientation (MeshMapData%ED_P_2_AD_P_H%dM%fx_p) + AD_Start = Indx_u_AD_Hub_Start(u_AD, y_FAST) ! start of u_AD%HubMotion%TranslationDisp field + ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) ! start of y_ED%HubPtMotion%TranslationDisp field + call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) + + ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) + y_ED%HubPtMotion%NNodes * 3 ! start of y_ED%HubPtMotion%Orientation field + call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%fx_p, AD_Start, ED_Out_Start ) + + ! *** AD orientation: from ED orientation + AD_Start = AD_Start + u_AD%HubMotion%NNodes * 3 ! move past the AD translation disp field to orientation field + call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) + + ! *** AD rotational velocity: from ED rotational velocity + AD_Start = AD_Start + u_AD%HubMotion%NNodes * 3 ! move past the AD orientation field to rotational velocity field + ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) + y_ED%HubPtMotion%NNodes * 6 ! ! start of y_ED%HubPtMotion%RotationVel field + call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) + !................................... ! blade root !................................... - DO k=1,size(y_ED%BladeRootMotion) - CALL Linearize_Point_to_Point( y_ED%BladeRootMotion(k), u_AD%BladeRootMotion(k), MeshMapData%ED_P_2_AD_P_R(k), ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeRootMotion('//trim(num2lstr(k))//')' ) - if (errStat>=AbortErrLev) return + DO k=1,size(y_ED%BladeRootMotion) + CALL Linearize_Point_to_Point( y_ED%BladeRootMotion(k), u_AD%BladeRootMotion(k), MeshMapData%ED_P_2_AD_P_R(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeRootMotion('//trim(num2lstr(k))//')' ) + if (errStat>=AbortErrLev) return - ! *** AD orientation: from ED orientation - AD_Start = Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, k) ! start of u_AD%BladeRootMotion(k)%Orientation field + ! *** AD orientation: from ED orientation + AD_Start = Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, k) ! start of u_AD%BladeRootMotion(k)%Orientation field - ED_Out_Start = Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, k) & ! start of y_ED%BladeRootMotion(k)%TranslationDisp field - + y_ED%BladeRootMotion(k)%NNodes * 3 ! start of y_ED%BladeRootMotion(k)%Orientation field - call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_R(k)%dM%mi, AD_Start, ED_Out_Start ) + ED_Out_Start = Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, k) & ! start of y_ED%BladeRootMotion(k)%TranslationDisp field + + y_ED%BladeRootMotion(k)%NNodes * 3 ! start of y_ED%BladeRootMotion(k)%Orientation field + call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_R(k)%dM%mi, AD_Start, ED_Out_Start ) - END DO - + END DO + !................................... ! blades !................................... IF (p_FAST%CompElast == Module_ED ) THEN - + DO k=1,size(y_ED%BladeLn2Mesh) !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices @@ -2666,7 +2633,7 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of y_ED%BladeLn2Mesh(k)%TranslationDisp field - CALL Assemble_dUdy_Motions(y_ED%BladeLn2Mesh(k), u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, ED_Out_Start, dUdy, .true.) + CALL Assemble_dUdy_Motions(y_ED%BladeLn2Mesh(k), u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, ED_Out_Start, dUdy, skipRotAcc=.true.) END DO @@ -2679,9 +2646,9 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field BD_Out_Start = y_FAST%Lin%Modules(Module_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) - CALL Assemble_dUdy_Motions(BD%y(k)%BldMotion, u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, BD_Out_Start, dUdy, .true.) + CALL Assemble_dUdy_Motions(BD%y(k)%BldMotion, u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, BD_Out_Start, dUdy, skipRotAcc=.true.) END DO - + END IF @@ -2740,7 +2707,7 @@ SUBROUTINE Linear_HD_InputSolve_du( p_FAST, y_FAST, u_HD, y_ED, MeshMapData, dUd ! y_ED%PlatformPtMesh and u_HD%Morison%DistribMesh !=================================================== - ! Transfer ED motions to HD motion input (HD inputs depend on previously calculated HD inputs from ED): + ! Transfer ED motions to HD motion input (HD inputs depend on previously calculated HD inputs from ED): call Linearize_Point_to_Line2( y_ED%PlatformPtMesh, u_HD%Morison%DistribMesh, MeshMapData%ED_P_2_HD_M_L, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -2845,8 +2812,8 @@ SUBROUTINE Linear_HD_InputSolve_dy( p_FAST, y_FAST, u_HD, y_ED, MeshMapData, dUd !!!call Linearize_Point_to_Line2( y_ED%PlatformPtMesh, u_HD%Morison%DistribMesh, MeshMapData%ED_P_2_HD_M_L, ErrStat2, ErrMsg2 ) HD_Start = Indx_u_HD_Distrib_Start(u_HD, y_FAST) ! start of u_HD%Morison%DistribMesh%TranslationDisp field - ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field - call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Morison%DistribMesh, MeshMapData%ED_P_2_HD_M_L, HD_Start, ED_Out_Start, dUdy, .false.) + ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field + call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Morison%DistribMesh, MeshMapData%ED_P_2_HD_M_L, HD_Start, ED_Out_Start, dUdy) END IF !................................... @@ -2860,8 +2827,8 @@ SUBROUTINE Linear_HD_InputSolve_dy( p_FAST, y_FAST, u_HD, y_ED, MeshMapData, dUd HD_Start = Indx_u_HD_Lumped_Start(u_HD, y_FAST) ! start of u_HD%Morison%LumpedMesh%TranslationDisp field - ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field - call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Morison%LumpedMesh, MeshMapData%ED_P_2_HD_M_P, HD_Start, ED_Out_Start, dUdy, .false.) + ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field + call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Morison%LumpedMesh, MeshMapData%ED_P_2_HD_M_P, HD_Start, ED_Out_Start, dUdy) END IF !................................... @@ -2875,8 +2842,9 @@ SUBROUTINE Linear_HD_InputSolve_dy( p_FAST, y_FAST, u_HD, y_ED, MeshMapData, dUd HD_Start = Indx_u_HD_PlatformRef_Start(u_HD, y_FAST) ! start of u_HD%Mesh%TranslationDisp field - ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field - call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Mesh, MeshMapData%ED_P_2_HD_W_P, HD_Start, ED_Out_Start, dUdy, .false.) + ED_Out_Start = Indx_y_ED_Platform_Start(y_ED, y_FAST) ! start of y_ED%PlatformPtMesh%TranslationDisp field + call Assemble_dUdy_Motions(y_ED%PlatformPtMesh, u_HD%Mesh, MeshMapData%ED_P_2_HD_W_P, HD_Start, ED_Out_Start, dUdy) + END IF @@ -3499,15 +3467,16 @@ END SUBROUTINE SumBlockMatrix !! \vec{a}^S \\ !! \vec{\alpha}^S \\ !! \end{matrix} \right\} \f$ -SUBROUTINE Assemble_dUdy_Motions(y, u, MeshMap, BlockRowStart, BlockColStart, dUdy, skipRotVel, onlyTranslationDisp) - TYPE(MeshType), INTENT(IN) :: y !< the output (source) mesh that is transfering motions - TYPE(MeshType), INTENT(IN) :: u !< the input (destination) mesh that is receiving motions - TYPE(MeshMapType), INTENT(IN) :: MeshMap !< the mesh mapping from y to u - INTEGER(IntKi), INTENT(IN) :: BlockRowStart !< the index of the row defining the block of dUdy to be set - INTEGER(IntKi), INTENT(IN) :: BlockColStart !< the index of the column defining the block of dUdy to be set - REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< full Jacobian matrix - LOGICAL, OPTIONAL, INTENT(IN) :: skipRotVel !< if present and true, we skip the rotational velocity and acceleration fields and return early +SUBROUTINE Assemble_dUdy_Motions(y, u, MeshMap, BlockRowStart, BlockColStart, dUdy, skipRotVel, skipRotAcc, onlyTranslationDisp) + TYPE(MeshType), INTENT(IN) :: y !< the output (source) mesh that is transfering motions + TYPE(MeshType), INTENT(IN) :: u !< the input (destination) mesh that is receiving motions + TYPE(MeshMapType), INTENT(IN) :: MeshMap !< the mesh mapping from y to u + INTEGER(IntKi), INTENT(IN) :: BlockRowStart !< the index of the row defining the block of dUdy to be set + INTEGER(IntKi), INTENT(IN) :: BlockColStart !< the index of the column defining the block of dUdy to be set + REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< full Jacobian matrix + LOGICAL, OPTIONAL, INTENT(IN) :: skipRotVel !< if present and true, we skip the rotational velocity and both acceleration fields and return early LOGICAL, OPTIONAL, INTENT(IN) :: onlyTranslationDisp !< if present and true, we set only the destination translationDisp fields and return early + LOGICAL, OPTIONAL, INTENT(IN) :: skipRotAcc !< if present and true, we skip the rotational acceleration field INTEGER(IntKi) :: row INTEGER(IntKi) :: col @@ -3595,6 +3564,11 @@ SUBROUTINE Assemble_dUdy_Motions(y, u, MeshMap, BlockRowStart, BlockColStart, dU call SetBlockMatrix( dUdy, MeshMap%dM%fx_p, row, col ) + if (PRESENT(skipRotAcc)) then + if (skipRotAcc) return ! destination does not include rotational accelerations, so we'll just return + end if + + !*** row for rotational acceleration *** ! source rotational acceleration to destination rotational acceleration row = BlockRowStart + u%NNodes*15 ! start of u%RotationAcc field [skip 5 fields with 3 components] @@ -3854,7 +3828,7 @@ FUNCTION Indx_u_AD_Blade_Start(u_AD, y_FAST, BladeNum) RESULT(AD_Start) AD_Start = Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, MaxNBlades+1) do k = 1,min(BladeNum-1,size(u_AD%BladeMotion)) - AD_Start = AD_Start + u_AD%BladeMotion(k)%NNodes * 9 ! 3 fields (TranslationDisp, MASKID_Orientation, TranslationVel) with 3 components + AD_Start = AD_Start + u_AD%BladeMotion(k)%NNodes * 15 ! 5 fields (TranslationDisp, MASKID_Orientation, TranslationVel, RotationVel, TranslationAcc) with 3 components end do END FUNCTION Indx_u_AD_Blade_Start !---------------------------------------------------------------------------------------------------------------------------------- @@ -4512,8 +4486,46 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, !!! ! AeroDyn: copy final predictions to actual states; copy current outputs to next !!!!IF ( p_FAST%CompAero == Module_AD14 ) THEN !!!!ELSE - !!!IF ( p_FAST%CompAero == Module_AD ) THEN - !!!END IF + IF ( p_FAST%CompAero == Module_AD ) THEN + ThisModule = Module_AD + if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag)) then + + indx = 1 + ! set linearization operating points: + if (AD%p%BEMT%DBEMT%lin_nx>0) then + do j=1,size(AD%x(STATE_CURR)%BEMT%DBEMT%element,2) + do i=1,size(AD%x(STATE_CURR)%BEMT%DBEMT%element,1) + indx_last = indx + size(AD%x(STATE_CURR)%BEMT%DBEMT%element(i,j)%vind) - 1 + call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%BEMT%DBEMT%element(i,j)%vind, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & + y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) + indx = indx_last + 1 + end do + end do + + do j=1,size(AD%x(STATE_CURR)%BEMT%DBEMT%element,2) + do i=1,size(AD%x(STATE_CURR)%BEMT%DBEMT%element,1) + indx_last = indx + size(AD%x(STATE_CURR)%BEMT%DBEMT%element(i,j)%vind_dot) - 1 + call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%BEMT%DBEMT%element(i,j)%vind_dot, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & + y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) + indx = indx_last + 1 + end do + end do + + end if + + if (AD%p%BEMT%UA%lin_nx>0) then + do j=1,size(AD%x(STATE_CURR)%BEMT%UA%element,2) + do i=1,size(AD%x(STATE_CURR)%BEMT%UA%element,1) + indx_last = indx + size(AD%x(STATE_CURR)%BEMT%UA%element(i,j)%x) - 1 + call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%BEMT%UA%element(i,j)%x, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & + y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) + indx = indx_last + 1 + end do + end do + end if + + end if + END IF !!! !!!! InflowWind: copy op to actual states and inputs !!!IF ( p_FAST%CompInflow == Module_IfW ) THEN @@ -4631,7 +4643,7 @@ SUBROUTINE SetOperatingPoint(i, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, O CALL BD_CopyOtherState (y_FAST%op%OtherSt_BD(k, i), BD%OtherSt( k,STATE_CURR), MESH_UPDATECOPY, Errstat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - CALL BD_CopyInput (y_FAST%op%u_BD(k, i), BD%Input(1, k), MESH_UPDATECOPY, Errstat2, ErrMsg2) + CALL BD_CopyInput (y_FAST%op%u_BD(k, i), BD%Input(1,k), MESH_UPDATECOPY, Errstat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END DO @@ -5221,7 +5233,7 @@ SUBROUTINE FAST_SaveOutputs( psi, p_FAST, m_FAST, ED, BD, SrvD, AD, IfW, HD, SD, END DO ! k=p_FAST%nBeams END IF ! BeamDyn - + ! AeroDyn IF ( p_FAST%CompAero == Module_AD ) THEN @@ -5539,7 +5551,7 @@ SUBROUTINE calc_error(p_FAST, y_FAST, m_FAST, y_SrvD, eps_squared) ! special cases for angles: - indx = Indx_y_Yaw_Start(y_FAST, Module_ED) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) + indx = Indx_y_Yaw_Start(y_FAST, Module_ED) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) call AddOrSub2Pi(m_FAST%Lin%Y_prevRot( indx, m_FAST%Lin%AzimIndx ), m_FAST%Lin%y_interp( indx )) if (p_FAST%CompServo == Module_SrvD) then @@ -5603,7 +5615,7 @@ SUBROUTINE ComputeOutputRanges(p_FAST, y_FAST, m_FAST, y_SrvD) end do ! special case for angles: - indx = Indx_y_Yaw_Start(y_FAST, Module_ED) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) + indx = Indx_y_Yaw_Start(y_FAST, Module_ED) ! start of ED where Yaw, YawRate, HSS_Spd occur (right before WriteOutputs) m_FAST%Lin%y_ref(indx) = min( m_FAST%Lin%y_ref(indx), Pi ) if (p_FAST%CompServo == Module_SrvD) then diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 1ba775af77..2cbe6cd786 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -472,14 +472,15 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, if (ErrStat2 /= 0 ) then call SetErrStat(ErrID_Fatal, "Error allocating Lin%Modules(AD).", ErrStat, ErrMsg, RoutineName ) else - if (allocated(Init%OutData_AD%LinNames_u)) call move_alloc(Init%OutData_AD%LinNames_u,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_u ) - if (allocated(Init%OutData_AD%LinNames_y)) call move_alloc(Init%OutData_AD%LinNames_y,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_y ) - if (allocated(Init%OutData_AD%LinNames_z)) call move_alloc(Init%OutData_AD%LinNames_z,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_z ) - if (allocated(Init%OutData_AD%RotFrame_u)) call move_alloc(Init%OutData_AD%RotFrame_u,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_u ) - if (allocated(Init%OutData_AD%RotFrame_y)) call move_alloc(Init%OutData_AD%RotFrame_y,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_y ) - if (allocated(Init%OutData_AD%RotFrame_z)) call move_alloc(Init%OutData_AD%RotFrame_z,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_z ) - if (allocated(Init%OutData_AD%IsLoad_u )) call move_alloc(Init%OutData_AD%IsLoad_u ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%IsLoad_u ) - + if (allocated(Init%OutData_AD%LinNames_u )) call move_alloc(Init%OutData_AD%LinNames_u ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_u ) + if (allocated(Init%OutData_AD%LinNames_y )) call move_alloc(Init%OutData_AD%LinNames_y ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_y ) + if (allocated(Init%OutData_AD%LinNames_x )) call move_alloc(Init%OutData_AD%LinNames_x ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%Names_x ) + if (allocated(Init%OutData_AD%RotFrame_u )) call move_alloc(Init%OutData_AD%RotFrame_u ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_u ) + if (allocated(Init%OutData_AD%RotFrame_y )) call move_alloc(Init%OutData_AD%RotFrame_y ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_y ) + if (allocated(Init%OutData_AD%RotFrame_x )) call move_alloc(Init%OutData_AD%RotFrame_x ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%RotFrame_x ) + if (allocated(Init%OutData_AD%IsLoad_u )) call move_alloc(Init%OutData_AD%IsLoad_u ,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%IsLoad_u ) + if (allocated(Init%OutData_AD%DerivOrder_x)) call move_alloc(Init%OutData_AD%DerivOrder_x,y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%DerivOrder_x ) + if (allocated(Init%OutData_AD%WriteOutputHdr)) y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%NumOutputs = size(Init%OutData_AD%WriteOutputHdr) end if @@ -5088,8 +5089,8 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H if (.not. p_FAST%BD_OutputSibling) then !otherwise this mesh has been put with the DistrLoad mesh do K=1,NumBl ! BeamDyn outputs - call MeshWrVTK(p_FAST%TurbinePos, BD%y(k)%BldMotion, trim(p_FAST%VTK_OutFileRoot)//'.BD_BldMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) - end do + call MeshWrVTK(p_FAST%TurbinePos, BD%y(k)%BldMotion, trim(p_FAST%VTK_OutFileRoot)//'.BD_BldMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + end do end if diff --git a/modules/openfast-registry/src/gen_module_files.c b/modules/openfast-registry/src/gen_module_files.c index 7e44d315f6..df4acfe9db 100644 --- a/modules/openfast-registry/src/gen_module_files.c +++ b/modules/openfast-registry/src/gen_module_files.c @@ -2250,10 +2250,16 @@ gen_module( FILE * fp , node_t * ModName, char * prog_ver ) // gen_modname_pack( fp, ModName ) ; // gen_modname_unpack( fp, ModName ) ; // gen_rk4( fp, ModName ) ; + if (strcmp(make_lower_temp(ModName->name), "airfoilinfo") == 0) { // make interpolation routines for AirfoilInfo module gen_ExtrapInterp(fp, ModName, "Output", "OutputType","ReKi"); gen_ExtrapInterp(fp, ModName, "UA_BL_Type", "UA_BL_Type", "ReKi"); } else if (!sw_noextrap) { + if (strcmp(make_lower_temp(ModName->name), "dbemt") == 0) { // make interpolation routines for element-level DBEMT module + + gen_ExtrapInterp(fp, ModName, "ElementInputType", "ElementInputType", "DbKi"); + } + gen_ExtrapInterp(fp, ModName, "Input", "InputType", "DbKi"); gen_ExtrapInterp(fp, ModName, "Output", "OutputType", "DbKi"); } diff --git a/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 6272de3e4c..71350e7981 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -37,6 +37,9 @@ option(CTEST_PLOT_ERRORS "Generate plots of regression test errors." OFF) # Set the OpenFAST executable configuration option and default set(CTEST_OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast" CACHE FILEPATH "Specify the OpenFAST executable to use in testing.") +# Set the AeroDyn executable configuration option and default +set(CTEST_AERODYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/aerodyn/aerodyn_driver" CACHE FILEPATH "Specify the AeroDyn driver executable to use in testing.") + # Set the BeamDyn executable configuration option and default set(CTEST_BEAMDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/beamdyn/beamdyn_driver" CACHE FILEPATH "Specify the BeamDyn driver executable to use in testing.") @@ -64,7 +67,7 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/r-test") # build and seed the test directories with the data they need to run the tests file(MAKE_DIRECTORY ${CTEST_BINARY_DIR}) -foreach(regTest glue-codes/openfast modules/beamdyn modules/hydrodyn) +foreach(regTest glue-codes/openfast modules/aerodyn modules/beamdyn modules/hydrodyn) file(MAKE_DIRECTORY ${CTEST_BINARY_DIR}/${regTest}) endforeach() @@ -76,3 +79,26 @@ endforeach() # add the tests include(${CMAKE_CURRENT_LIST_DIR}/CTestList.cmake) + +set(src "${CMAKE_CURRENT_LIST_DIR}/r-test/glue-codes/openfast/5MW_Baseline/ServoData") +set(dest "${CTEST_BINARY_DIR}/glue-codes/openfast/5MW_Baseline/ServoData/") +add_custom_command( + OUTPUT "${dest}/DISCON.dll" + DEPENDS DISCON + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON/build/DISCON.dll" "${dest}" +) +add_custom_command( + OUTPUT "${dest}/DISCON_ITIBarge.dll" + DEPENDS DISCON_ITIBarge + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON_ITI/build/DISCON_ITIBarge.dll" "${dest}" + ) +add_custom_command( + OUTPUT "${dest}/DISCON_OC3Hywind.dll" + DEPENDS DISCON_OC3Hywind + COMMAND "${CMAKE_COMMAND}" -E copy "${src}/DISCON_OC3/build/DISCON_OC3Hywind.dll" "${dest}" +) + +add_custom_target( + regression_tests + DEPENDS openfast "${dest}/DISCON.dll" "${dest}/DISCON_ITIBarge.dll" "${dest}/DISCON_OC3Hywind.dll" +) diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index c0c1c03c03..6c02090505 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -84,6 +84,15 @@ function(of_regression_linear TESTNAME LABEL) regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(of_regression_linear) +# aerodyn +function(ad_regression TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeAerodynRegressionCase.py") + set(AERODYN_EXECUTABLE "${CTEST_AERODYN_EXECUTABLE}") + set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") + set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/aerodyn") + regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") +endfunction(ad_regression) + # beamdyn function(bd_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeBeamdynRegressionCase.py") @@ -124,13 +133,13 @@ of_regression("SWRT_YFree_VS_EDG01" "openfast;elastodyn;aerodyn15;se of_regression("SWRT_YFree_VS_EDC01" "openfast;elastodyn;aerodyn14;servodyn") of_regression("SWRT_YFree_VS_WTurb" "openfast;elastodyn;aerodyn14;servodyn") of_regression("5MW_Land_DLL_WTurb" "openfast;elastodyn;aerodyn15;servodyn") -of_regression("5MW_OC3Mnpl_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn") -of_regression("5MW_OC3Trpd_DLL_WSt_WavesReg" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn") -of_regression("5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn") -of_regression("5MW_ITIBarge_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn14;servodyn;hydrodyn;map") -of_regression("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map") -of_regression("5MW_OC3Spar_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map") -of_regression("5MW_OC4Semi_WSt_WavesWN" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn") +of_regression("5MW_OC3Mnpl_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") +of_regression("5MW_OC3Trpd_DLL_WSt_WavesReg" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") +of_regression("5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") +of_regression("5MW_ITIBarge_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") +of_regression("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression("5MW_OC3Spar_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression("5MW_OC4Semi_WSt_WavesWN" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn;offshore") of_regression("5MW_Land_BD_DLL_WTurb" "openfast;beamdyn;aerodyn15;servodyn") of_regression("5MW_OC4Jckt_ExtPtfm" "openfast;elastodyn;extptfm") of_regression("HelicalWake_OLAF" "openfast;aerodyn15;olaf") @@ -146,6 +155,9 @@ 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") +# AeroDyn regression tests +ad_regression("ad_timeseries_shutdown" "aerodyn;bem") + # BeamDyn regression tests bd_regression("bd_5MW_dynamic" "beamdyn;dynamic") bd_regression("bd_5MW_dynamic_gravity_Az00" "beamdyn;dynamic") @@ -156,4 +168,8 @@ bd_regression("bd_static_cantilever_beam" "beamdyn;static") bd_regression("bd_static_twisted_with_k1" "beamdyn;static") # HydroDyn regression tests -hd_regression("hd_OC3tripod_offshore_fixedbottom_wavesirr" "hydrodyn;offshore") +hd_regression("hd_OC3tripod_offshore_fixedbottom_wavesirr" "hydrodyn;offshore") +hd_regression("hd_5MW_ITIBarge_DLL_WTurb_WavesIrr" "hydrodyn;offshore") +hd_regression("hd_5MW_OC3Spar_DLL_WTurb_WavesIrr" "hydrodyn;offshore") +hd_regression("hd_5MW_OC4Semi_WSt_WavesWN" "hydrodyn;offshore") +hd_regression("hd_5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "hydrodyn;offshore") diff --git a/reg_tests/executeAerodynRegressionCase.py b/reg_tests/executeAerodynRegressionCase.py new file mode 100644 index 0000000000..8bcd869d5f --- /dev/null +++ b/reg_tests/executeAerodynRegressionCase.py @@ -0,0 +1,138 @@ +# +# 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 AeroDyn 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: `executeAerodynRegressionCase.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"])) +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 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="AeroDyn-Driver", type=str, nargs=1, help="The path to the AeroDyn driver 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", 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] +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", "aerodyn") +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,"ad_*inp")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + +### Run aerodyn on the test case +if not noExec: + caseInputFile = os.path.join(testBuildDirectory, "ad_driver.inp") + returnCode = openfastDrivers.runAerodynDriverCase(caseInputFile, executable) + if returnCode != 0: + rtl.exitWithError("") + +### Build the filesystem navigation variables for running the regression test +localOutFile = os.path.join(testBuildDirectory, "ad_driver.out") +baselineOutFile = os.path.join(targetOutputDirectory, "ad_driver.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/executeHydrodynRegressionCase.py b/reg_tests/executeHydrodynRegressionCase.py index a18ab1ad91..1f559a6a53 100644 --- a/reg_tests/executeHydrodynRegressionCase.py +++ b/reg_tests/executeHydrodynRegressionCase.py @@ -28,6 +28,7 @@ sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse import shutil +import glob import subprocess import rtestlib as rtl import openfastDrivers @@ -90,8 +91,12 @@ # and initialize it with input files for all test cases if not os.path.isdir(testBuildDirectory): os.makedirs(testBuildDirectory) - shutil.copy(os.path.join(inputsDirectory,"hd_driver.inp"), os.path.join(testBuildDirectory,"hd_driver.inp")) - shutil.copy(os.path.join(inputsDirectory,"hd_primary.inp"), os.path.join(testBuildDirectory,"hd_primary.inp")) + 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: diff --git a/reg_tests/lib/errorPlotting.py b/reg_tests/lib/errorPlotting.py index 94315bf71a..1778f3fe75 100644 --- a/reg_tests/lib/errorPlotting.py +++ b/reg_tests/lib/errorPlotting.py @@ -1,3 +1,4 @@ + # # Copyright 2017 National Renewable Energy Laboratory # @@ -58,14 +59,14 @@ def _plotError(xseries, y1series, y2series, xlabel, title1, title2): p1.xaxis.axis_label = 'Time (s)' p1.line(xseries, y2series, color='green', line_width=3, legend_label='Baseline') p1.line(xseries, y1series, color='red', line_width=1, legend_label='Local') - p1.add_tools(HoverTool(tooltips=[('Time','$x'), ('Value', '$y')],mode='vline')) + p1.add_tools(HoverTool(tooltips=[('Time','@x'), ('Value', '@y')],mode='vline')) p2 = figure(title=title2, x_range=p1.x_range) p2.title.align = 'center' p2.grid.grid_line_alpha = 0 p2.xaxis.axis_label = 'Time (s)' p2.line(xseries, abs(y2series - y1series), color='blue') - p2.add_tools(HoverTool(tooltips=[('Time','$x'), ('Error', '$y')], mode='vline')) + p2.add_tools(HoverTool(tooltips=[('Time','@x'), ('Error', '@y')], mode='vline')) grid = gridplot([[p1, p2]], plot_width=650, plot_height=375, sizing_mode="scale_both") script, div = components(grid) diff --git a/reg_tests/lib/openfastDrivers.py b/reg_tests/lib/openfastDrivers.py index e06350eeca..b06fd76218 100644 --- a/reg_tests/lib/openfastDrivers.py +++ b/reg_tests/lib/openfastDrivers.py @@ -50,6 +50,11 @@ def _runGenericCase(inputFile, executable, verbose=False): def runOpenfastCase(inputFile, executable, verbose=False): return _runGenericCase(inputFile, executable, verbose) +def runAerodynDriverCase(inputFile, executable, verbose=False): + caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) + os.chdir(caseDirectory) + return _runGenericCase(inputFile, executable, verbose) + def runBeamdynDriverCase(inputFile, executable, verbose=False): caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) os.chdir(caseDirectory) diff --git a/reg_tests/r-test b/reg_tests/r-test index f9397ac4de..8061079778 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit f9397ac4de4e4800eaf4b76d2517246d397b50d2 +Subproject commit 8061079778e1feac82118bb7d1027140d7f6a191 diff --git a/share/docker/openfast_dev/Dockerfile b/share/docker/openfast_dev/Dockerfile index eea9ec75da..5042c7bbbd 100644 --- a/share/docker/openfast_dev/Dockerfile +++ b/share/docker/openfast_dev/Dockerfile @@ -14,32 +14,16 @@ # limitations under the License. # -FROM rafmudaf/openfast-ubuntu:dev +FROM rafmudaf/openfast-ubuntu:v2.3.0 # Move into the openfast directory and update WORKDIR /openfast -RUN git fetch -RUN git pull -RUN git submodule update +RUN git fetch && \ + git checkout -b dev origin/dev && \ + git submodule update # Move into the "build" directory, remove the old reg tests, and compile WORKDIR /openfast/build -RUN rm -rf reg_tests -RUN cmake .. -RUN make -j4 install - -# Run the tests - -# BeamDyn-specific tests -RUN ctest -VV -j7 -R bd_ -RUN ctest -VV -R beamdyn_utest - -# OpenFAST linearization tests -# Dont run these in parallel, copying the case files can fail in a race condition -RUN ctest -VV -L linear - -# Subset of OpenFAST regression tests; do not run -## - 9, 16 because they're very sensitive -## - 19, 20 because theyre too long -## - 17, 22, 23 becuase we dont know why they fail :( -RUN ctest -VV -j8 -I 1,1,1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,21,24,25,27,28,29 +RUN rm -rf reg_tests && \ + cmake .. && \ + make -j4 install diff --git a/share/docker/openfast_ubuntu/Dockerfile b/share/docker/openfast_ubuntu/Dockerfile index 447b38bbfe..8470e56230 100644 --- a/share/docker/openfast_ubuntu/Dockerfile +++ b/share/docker/openfast_ubuntu/Dockerfile @@ -22,14 +22,18 @@ FROM ubuntu:bionic # RUN add-apt-repository ppa:ubuntu-toolchain-r/test -y # apt-get install gfortran-8 -RUN apt update -qq -RUN apt install -y software-properties-common build-essential -RUN apt install -y python3-pip -RUN apt install -y cmake cmake-curses-gui -RUN apt install -y gcc gfortran make -RUN apt install -y libblas-dev liblapack-dev -RUN apt install -y git -RUN apt install -y nano +ENV DEBIAN_FRONTEND=noninteractive TZ=America/Denver + +RUN apt update -qq && \ + apt install -y software-properties-common build-essential && \ + add-apt-repository ppa:git-core/ppa -y && \ + apt install -y python3-pip && \ + apt install -y cmake cmake-curses-gui && \ + apt install -y gcc gfortran make && \ + apt install -y libblas-dev liblapack-dev && \ + apt install -y git && \ + apt install -y nano + RUN pip3 install numpy # Configure the environment @@ -38,7 +42,6 @@ ENV FC=/usr/bin/gfortran # Clone the project RUN git clone --recursive https://github.com/openfast/openfast.git openfast WORKDIR /openfast -RUN git checkout -b dev origin/dev # Build the project RUN mkdir build @@ -47,5 +50,5 @@ WORKDIR /openfast/build # NOTE: building with optimizations on (RELEASE or RELWITHDEBINFO), the virtual machine # will require about 6GB of memoery. Otherwise, the gfortran compiler will exit with an # "internal error" -RUN cmake .. -DBUILD_TESTING=ON -DDOUBLE_PRECISION=ON -DCMAKE_BUILD_TYPE=DEBUG +RUN cmake .. -DBUILD_TESTING=ON -DDOUBLE_PRECISION=ON -DCMAKE_BUILD_TYPE=RELWITHDEBINFO RUN make -j4 install diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 4caee9fa32..4339b0c437 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -72,3 +72,9 @@ endif() add_subdirectory("beamdyn") add_subdirectory("nwtc-library") add_subdirectory("aerodyn") +add_subdirectory("inflowwind") + +add_custom_target( + unit_tests + DEPENDS beamdyn_utest nwtc_library_utest fvw_utest inflowwind_utest +) diff --git a/unit_tests/inflowwind/CMakeLists.txt b/unit_tests/inflowwind/CMakeLists.txt new file mode 100644 index 0000000000..b1a41ef679 --- /dev/null +++ b/unit_tests/inflowwind/CMakeLists.txt @@ -0,0 +1,67 @@ +# +# 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. +# + +set_source_files_properties(${pfunit_directory}/include/driver.F90 PROPERTIES GENERATED 1) + +set(module_name "inflowwind") +set(module_directory "inflowwind") +set(module_library "ifwlib") + +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 + ifw_test_tools + test_steady_wind + test_turbsim_wind + test_bladed_wind + test_hawc_wind + test_outputs + test_uniform_wind +) +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/unit_tests/nwtc-library/CMakeLists.txt b/unit_tests/nwtc-library/CMakeLists.txt index 6138fc7617..7b425944ab 100644 --- a/unit_tests/nwtc-library/CMakeLists.txt +++ b/unit_tests/nwtc-library/CMakeLists.txt @@ -32,6 +32,7 @@ include_directories( set(testlist test_NWTC_IO_CheckArgs + test_NWTC_IO_FileInfo test_NWTC_RandomNumber ) foreach(test ${testlist}) diff --git a/vs-build/AFI/AFI-w-registry.sln b/vs-build/AFI/AFI-w-registry.sln deleted file mode 100644 index 89d0fec855..0000000000 --- a/vs-build/AFI/AFI-w-registry.sln +++ /dev/null @@ -1,61 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "AFI", "AFI.vfproj", "{2854302F-A93D-4C22-9329-717B085113C0}" - 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 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug_Double|Win32.ActiveCfg = Debug_Double|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug_Double|Win32.Build.0 = Debug_Double|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug_Double|x64.ActiveCfg = Debug_Double|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug_Double|x64.Build.0 = Debug_Double|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.ActiveCfg = Debug|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.Build.0 = Debug|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug|x64.ActiveCfg = Debug|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Debug|x64.Build.0 = Debug|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Release_Double|Win32.ActiveCfg = Release_Double|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Release_Double|Win32.Build.0 = Release_Double|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Release_Double|x64.ActiveCfg = Release_Double|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Release_Double|x64.Build.0 = Release_Double|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Release|Win32.ActiveCfg = Release|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 - {2854302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 - {2854302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Debug-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Debug-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Debug-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Debug-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs-build/AeroDyn/AeroDyn_Driver-with-registry.sln b/vs-build/AeroDyn/AeroDyn_Driver-with-registry.sln deleted file mode 100644 index 0ebea868b3..0000000000 --- a/vs-build/AeroDyn/AeroDyn_Driver-with-registry.sln +++ /dev/null @@ -1,61 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "AeroDyn_Driver", "AeroDyn_Driver.vfproj", "{97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}" - 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 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug_Double|Win32.ActiveCfg = Debug_Double|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug_Double|Win32.Build.0 = Debug_Double|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug_Double|x64.ActiveCfg = Debug_Double|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug_Double|x64.Build.0 = Debug_Double|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug|Win32.ActiveCfg = Debug|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug|Win32.Build.0 = Debug|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug|x64.ActiveCfg = Debug|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Debug|x64.Build.0 = Debug|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release_Double|Win32.ActiveCfg = Release_Double|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release_Double|Win32.Build.0 = Release_Double|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release_Double|x64.ActiveCfg = Release_Double|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release_Double|x64.Build.0 = Release_Double|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|Win32.ActiveCfg = Release|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|Win32.Build.0 = Release|Win32 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.ActiveCfg = Release|x64 - {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs-build/AeroDyn/AeroDyn_Driver.sln b/vs-build/AeroDyn/AeroDyn_Driver.sln index f7815f6590..032b12d2f2 100644 --- a/vs-build/AeroDyn/AeroDyn_Driver.sln +++ b/vs-build/AeroDyn/AeroDyn_Driver.sln @@ -4,6 +4,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "AeroDyn_Driver", "AeroDyn_Driver.vfproj", "{97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}" + 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 @@ -33,6 +38,22 @@ Global {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|Win32.Build.0 = Release|Win32 {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.ActiveCfg = Release|x64 {97CEFEB9-1DCB-470E-A231-E1DA2F21A9CE}.Release|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|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 diff --git a/vs-build/BeamDyn/BeamDyn-w-registry.sln b/vs-build/BeamDyn/BeamDyn-w-registry.sln index 5c99185653..0261cbdc7e 100644 --- a/vs-build/BeamDyn/BeamDyn-w-registry.sln +++ b/vs-build/BeamDyn/BeamDyn-w-registry.sln @@ -38,22 +38,22 @@ Global {815C302F-A93D-4C22-9329-7112345113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-7112345113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-7112345113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Debug|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.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|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|x64 + {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|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 + {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 diff --git a/vs-build/FASTlib/FASTlib.sln b/vs-build/FASTlib/FASTlib.sln deleted file mode 100644 index c9bac235e3..0000000000 --- a/vs-build/FASTlib/FASTlib.sln +++ /dev/null @@ -1,79 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "FASTlib", "FASTlib.vfproj", "{1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}" - ProjectSection(ProjectDependencies) = postProject - {BF86702A-CB17-4050-8AE9-078CDC5910D3} = {BF86702A-CB17-4050-8AE9-078CDC5910D3} - {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 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MAP_dll", "..\MAPlib\MAP_dll.vcxproj", "{BF86702A-CB17-4050-8AE9-078CDC5910D3}" - ProjectSection(ProjectDependencies) = postProject - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} = {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug_Matlab|Win32 = Debug_Matlab|Win32 - Debug_Matlab|x64 = Debug_Matlab|x64 - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release_Matlab|Win32 = Release_Matlab|Win32 - Release_Matlab|x64 = Release_Matlab|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug_Matlab|Win32.ActiveCfg = Debug_Matlab|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug_Matlab|Win32.Build.0 = Debug_Matlab|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug_Matlab|x64.ActiveCfg = Debug_Matlab|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug_Matlab|x64.Build.0 = Debug_Matlab|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug|Win32.ActiveCfg = Debug|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug|Win32.Build.0 = Debug|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug|x64.ActiveCfg = Debug|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Debug|x64.Build.0 = Debug|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release_Matlab|Win32.ActiveCfg = Release_Matlab|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release_Matlab|Win32.Build.0 = Release_Matlab|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release_Matlab|x64.ActiveCfg = Release_Matlab|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release_Matlab|x64.Build.0 = Release_Matlab|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release|Win32.ActiveCfg = Release|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release|Win32.Build.0 = Release|Win32 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release|x64.ActiveCfg = Release|x64 - {1A440C5B-CBA6-47D9-9CC2-C1CBA8C00BF9}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Matlab|x64.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Matlab|x64.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|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 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug_Matlab|Win32.ActiveCfg = Debug|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug_Matlab|Win32.Build.0 = Debug|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug_Matlab|x64.ActiveCfg = Debug|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug_Matlab|x64.Build.0 = Debug|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug|Win32.ActiveCfg = Debug|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug|Win32.Build.0 = Debug|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug|x64.ActiveCfg = Debug|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Debug|x64.Build.0 = Debug|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release_Matlab|Win32.ActiveCfg = Release|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release_Matlab|Win32.Build.0 = Release|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release_Matlab|x64.ActiveCfg = Release|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release_Matlab|x64.Build.0 = Release|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|Win32.ActiveCfg = Release|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|Win32.Build.0 = Release|Win32 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.ActiveCfg = Release|x64 - {BF86702A-CB17-4050-8AE9-078CDC5910D3}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs-build/FASTlib/FASTlib.vfproj b/vs-build/FASTlib/FASTlib.vfproj index 8c0557d939..18a52174ac 100644 --- a/vs-build/FASTlib/FASTlib.vfproj +++ b/vs-build/FASTlib/FASTlib.vfproj @@ -59,8 +59,8 @@ - - + + @@ -68,8 +68,8 @@ - - + + diff --git a/vs-build/GetGitHash.bat b/vs-build/GetGitHash.bat deleted file mode 100644 index ff44967bcc..0000000000 --- a/vs-build/GetGitHash.bat +++ /dev/null @@ -1 +0,0 @@ -git describe --abbrev=8 --dirty --tags > ..\githash.txt diff --git a/vs-build/ReadMe.md b/vs-build/ReadMe.md new file mode 100644 index 0000000000..fb7e8fabd5 --- /dev/null +++ b/vs-build/ReadMe.md @@ -0,0 +1,19 @@ +# Visual Studio builds for Windows +The following solution files are available for code development on Windows using the Intel Fortran compiler with Visual Studio. + +- [OpenFAST](FAST/FAST.sln) + This contains builds for both the command-line OpenFAST executable as well as the DLL for use with the OpenFAST-Simulink interface. +- Module-level drivers: + - AeroDynamics: + - [AeroDyn driver](AeroDyn/AeroDyn_Driver.sln) + - [UnsteadyAero driver](UnsteadyAero/UnsteadyAero.sln) + - Structural: + - [BeamDyn driver](BeamDyn/BeamDyn-w-registry.sln) + - [SubDyn driver](SubDyn/SubDyn.sln) + - Wind/Wave conditions + - [TurbSim](TurbSim/TurbSim.sln) + - [HydroDyn driver](HydroDyn/HydroDynDriver.sln) +- Other: + - [Discon](Discon/Discon.sln) This solution file contains all 3 controllers used in the OpenFAST r-test (with the NREL 5MW model). + - [OpenFAST Registry](Registry/Registry.sln) + The Registry project is included in almost every other solution file, so this solution file is only for debugging changes to the OpenFAST Registry. diff --git a/vs-build/SubDyn/SubDyn-with-registry.sln b/vs-build/SubDyn/SubDyn-with-registry.sln deleted file mode 100644 index f4104b7975..0000000000 --- a/vs-build/SubDyn/SubDyn-with-registry.sln +++ /dev/null @@ -1,41 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "SubDyn", "SubDyn.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" - 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|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.ActiveCfg = Debug|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.Build.0 = Debug|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|x64.ActiveCfg = Debug|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|x64.Build.0 = Debug|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.ActiveCfg = Release|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs-build/SubDyn/SubDyn.sln b/vs-build/SubDyn/SubDyn.sln index 981a6bac1f..0aa100f6f8 100644 --- a/vs-build/SubDyn/SubDyn.sln +++ b/vs-build/SubDyn/SubDyn.sln @@ -4,6 +4,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "SubDyn", "SubDyn.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" + 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 @@ -21,6 +26,14 @@ Global {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|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|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 diff --git a/vs-build/UnsteadyAero/UnsteadyAero-w-registry.sln b/vs-build/UnsteadyAero/UnsteadyAero-w-registry.sln deleted file mode 100644 index a18412f19e..0000000000 --- a/vs-build/UnsteadyAero/UnsteadyAero-w-registry.sln +++ /dev/null @@ -1,61 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "UnsteadyAero", "UnsteadyAero.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" - 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 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug_Double|Win32.ActiveCfg = Debug_Double|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug_Double|Win32.Build.0 = Debug_Double|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug_Double|x64.ActiveCfg = Debug_Double|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug_Double|x64.Build.0 = Debug_Double|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.ActiveCfg = Debug|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|Win32.Build.0 = Debug|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|x64.ActiveCfg = Debug|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Debug|x64.Build.0 = Debug|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release_Double|Win32.ActiveCfg = Release_Double|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release_Double|Win32.Build.0 = Release_Double|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release_Double|x64.ActiveCfg = Release_Double|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release_Double|x64.Build.0 = Release_Double|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.ActiveCfg = Release|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 - {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Debug-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Debug-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Debug-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Debug-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Debug|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Debug|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release-Double Precision|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release-Double Precision|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|x64 - {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs-build/UnsteadyAero/UnsteadyAero.sln b/vs-build/UnsteadyAero/UnsteadyAero.sln index 385b7f0f44..4daa940c63 100644 --- a/vs-build/UnsteadyAero/UnsteadyAero.sln +++ b/vs-build/UnsteadyAero/UnsteadyAero.sln @@ -1,9 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "UnsteadyAero", "UnsteadyAero.vfproj", "{815C302F-A93D-4C22-9329-717B085113C0}" + 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 @@ -33,8 +38,27 @@ Global {815C302F-A93D-4C22-9329-717B085113C0}.Release|Win32.Build.0 = Release|Win32 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.ActiveCfg = Release|x64 {815C302F-A93D-4C22-9329-717B085113C0}.Release|x64.Build.0 = Release|x64 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug_Double|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Debug|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release_Double|x64.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|Win32.Build.0 = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.ActiveCfg = Release|Win32 + {DA16A3A6-3297-4628-9E46-C6FA0E3C4D16}.Release|x64.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {367EADB6-7C90-46F7-B3DD-31AFA0C0D727} + EndGlobalSection EndGlobal