diff --git a/.github/actions/compile-and-test/entrypoint.sh b/.github/actions/compile-and-test/entrypoint.sh index 62de74efd8..ccbc16a7af 100755 --- a/.github/actions/compile-and-test/entrypoint.sh +++ b/.github/actions/compile-and-test/entrypoint.sh @@ -41,6 +41,9 @@ ctest -VV -R nwtc_library_utest ctest -VV -j7 -R bd_ 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 ctest -VV -L linear @@ -49,4 +52,4 @@ ctest -VV -L linear ## - 9, 16 because they're very sensitive ## - 19, 20 because theyre too long ## - 17, 22, 23 becuase we dont know why they fail :( -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 +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 diff --git a/.gitmodules b/.gitmodules index 5fb3759b96..9650d9f067 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "reg_tests/r-test"] path = reg_tests/r-test - url = https://github.com/openfast/r-test.git + url = https://github.com/OpenFAST/r-test.git [submodule "unit_tests/pfunit"] path = unit_tests/pfunit url = https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ca7973818..e98907948c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,9 @@ option(BUILD_SHARED_LIBS "Enable building shared libraries" off) option(DOUBLE_PRECISION "Treat REAL as double precision" on) option(USE_DLL_INTERFACE "Enable runtime loading of dynamic libraries" on) option(FPE_TRAP_ENABLED "Enable FPE trap in compiler options" off) -option(ORCA_DLL_LOAD "Enable OrcaFlex Library Load" off) +option(ORCA_DLL_LOAD "Enable OrcaFlex Library Load" on) option(BUILD_OPENFAST_CPP_API "Enable building OpenFAST - C++ API" off) +option(OPENMP "Enable OpenMP support" off) # Precompiler/preprocessor flag configuration # Do this before configuring modules so that the flags are included @@ -169,4 +170,4 @@ endif() option(BUILD_DOCUMENTATION "Build documentation." OFF) if(BUILD_DOCUMENTATION) add_subdirectory(docs) -endif() \ No newline at end of file +endif() diff --git a/cmake/OpenfastFortranOptions.cmake b/cmake/OpenfastFortranOptions.cmake index 786217cf8f..4b0ba01e4f 100644 --- a/cmake/OpenfastFortranOptions.cmake +++ b/cmake/OpenfastFortranOptions.cmake @@ -83,6 +83,7 @@ macro(set_fast_gfortran) endif(NOT WIN32) # Fix free-form compilation for OpenFAST + #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") # Deal with Double/Single precision @@ -93,7 +94,7 @@ macro(set_fast_gfortran) # debug flags if(CMAKE_BUILD_TYPE MATCHES Debug) - set( CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fcheck=all -pedantic -fbacktrace" ) + set( CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fcheck=all -pedantic -fbacktrace " ) endif() if(CYGWIN) @@ -102,6 +103,12 @@ macro(set_fast_gfortran) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS},--stack,${stack_size}") endif() + # OPENMP + if (OPENMP) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fopenmp") + set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fopenmp" ) + endif() + endmacro(set_fast_gfortran) # @@ -131,6 +138,12 @@ macro(set_fast_intel_fortran_posix) if(CMAKE_BUILD_TYPE MATCHES Debug) set( CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -check all -traceback" ) endif() + + # OPENMP + if (OPENMP) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qopenmp") + set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -qopenmp" ) + endif() endmacro(set_fast_intel_fortran_posix) # @@ -157,4 +170,11 @@ macro(set_fast_intel_fortran_windows) if(CMAKE_BUILD_TYPE MATCHES Debug) set( CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} /check:all /traceback" ) endif() + + # OPENMP + if (OPENMP) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} /qopenmp") + set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} /qopenmp" ) + endif() + endmacro(set_fast_intel_fortran_windows) diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index ceca7ef7db..98bf58db1a 100644 Binary files a/docs/OtherSupporting/OutListParameters.xlsx and b/docs/OtherSupporting/OutListParameters.xlsx differ diff --git a/docs/_static/css/math_eq.css b/docs/_static/css/math_eq.css new file mode 100644 index 0000000000..ffc5f20ea4 --- /dev/null +++ b/docs/_static/css/math_eq.css @@ -0,0 +1,6 @@ +.math { + text-align: left; +} +.eqno { + float: right; +} diff --git a/docs/conf.py b/docs/conf.py index a2b5f1734f..85bf5c061b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -245,6 +245,7 @@ def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): ] def setup(app): + app.add_css_file('css/math_eq.css') app.add_object_type( "confval", "confval", @@ -257,3 +258,4 @@ def setup(app): objname="CMake configuration value", indextemplate="pair: %s; CMake configuration" ) + diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst index 816e0e4bd9..1e1b5d7677 100644 --- a/docs/source/install/index.rst +++ b/docs/source/install/index.rst @@ -236,6 +236,7 @@ The CMake options specific to OpenFAST and their default settings are: GENERATE_TYPES - Use the openfast-regsitry to autogenerate types modules ORCA_DLL_LOAD - Enable OrcaFlex library load (Default: OFF) USE_DLL_INTERFACE - Enable runtime loading of dynamic libraries (Default: ON) + OPENMP - Enable OpenMP parallelization in FVW (Default: OFF) Additional system-specific options may exist for a given system, but those should not impact the OpenFAST configuration. As mentioned above, the diff --git a/docs/source/user/aerodyn-olaf/Acknowledgments.txt b/docs/source/user/aerodyn-olaf/Acknowledgments.txt new file mode 100644 index 0000000000..3656506102 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/Acknowledgments.txt @@ -0,0 +1,19 @@ +.. _Acknowledgments: + +Acknowledgments +=============== + +This work was authored by the National Renewable Energy Laboratory, +operated by Alliance for Sustainable Energy, LLC, for the U.S. +Department of Energy (DOE) under Contract No. DE-AC36-08GO28308. Funding +provided by the U.S. Department of Energy Office of Energy Efficiency +and Renewable Energy Wind Energy Technologies Office. The views +expressed in the article do not necessarily represent the views of the +DOE or the U.S. Government. The U.S. Government retains and the +publisher, by accepting the article for publication, acknowledges that +the U.S. Government retains a nonexclusive, paid-up, irrevocable, +worldwide license to publish or reproduce the published form of this +work, or allow others to do so, for U.S. Government purposes. + +The authors are also grateful to the Big Adaptive Rotor program for +supporting the development of this software. diff --git a/docs/source/user/aerodyn-olaf/Acronyms.rst b/docs/source/user/aerodyn-olaf/Acronyms.rst new file mode 100644 index 0000000000..fb0d492fa6 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/Acronyms.rst @@ -0,0 +1,52 @@ +.. _Acronyms: + +List of Symbols +=============== + ++-----------------------------+---------------------------------------+ +| BEM | blade-element momentum | ++-----------------------------+---------------------------------------+ +| CFD | computational fluid dynamics | ++-----------------------------+---------------------------------------+ +| DOE | U.S. Department of Energy | ++-----------------------------+---------------------------------------+ +| :math:`F_v` | core radius factor | ++-----------------------------+---------------------------------------+ +| :math:`t` | time | ++-----------------------------+---------------------------------------+ +| FVW | free vortex wake | ++-----------------------------+---------------------------------------+ +| :math:`N` | number of rotor revolutions before | +| | wake cutoff condition | ++-----------------------------+---------------------------------------+ +| :math:`\vec{r}` | vector between point of interest and | +| | vortex segment | ++-----------------------------+---------------------------------------+ +| :math:`\vec{r}(\psi,\zeta)` | position vector of Lagrangian markers | ++-----------------------------+---------------------------------------+ +| :math:`r_c` | core radius | ++-----------------------------+---------------------------------------+ +| :math:`r_{c0}` | initial core radius | ++-----------------------------+---------------------------------------+ +| OLAF | cOnvecting LAgrangian Filaments | ++-----------------------------+---------------------------------------+ +| :math:`\alpha` | numerical constant :math:`=1.25643` | ++-----------------------------+---------------------------------------+ +| :math:`\Gamma` | circulation strength | ++-----------------------------+---------------------------------------+ +| :math:`\delta` | measure of viscous diffusion | ++-----------------------------+---------------------------------------+ +| :math:`\epsilon` | measure of strain | ++-----------------------------+---------------------------------------+ +| :math:`\Delta \psi` | step size for blade rotation | ++-----------------------------+---------------------------------------+ +| :math:`\Omega` | rotational speed of wind turbine | ++-----------------------------+---------------------------------------+ +| :math:`\zeta` | vortex wake age | ++-----------------------------+---------------------------------------+ +| :math:`\zeta_0` | vortex wake age offset | ++-----------------------------+---------------------------------------+ +| :math:`\nu` | kinematic viscosity | ++-----------------------------+---------------------------------------+ +| :math:`\psi` | azimuth blade position | ++-----------------------------+---------------------------------------+ diff --git a/docs/source/user/aerodyn-olaf/AppendixA.rst b/docs/source/user/aerodyn-olaf/AppendixA.rst new file mode 100644 index 0000000000..8b15288450 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/AppendixA.rst @@ -0,0 +1,13 @@ +.. _OLAF-Primary-Input-File: + +Appendix A: OLAF Primary Input File +=================================== + + +**Check the regression test cases for updates to this input file.** + +.. container:: + :name: Tab:OLAFinputfile + + .. literalinclude:: ExampleFiles/ExampleFile--OLAF.txt + :linenos: diff --git a/docs/source/user/aerodyn-olaf/AppendixB.rst b/docs/source/user/aerodyn-olaf/AppendixB.rst new file mode 100644 index 0000000000..274aa7437f --- /dev/null +++ b/docs/source/user/aerodyn-olaf/AppendixB.rst @@ -0,0 +1,12 @@ +.. _Prescribed-Circulation-Input-File: + +Appendix B: Prescribed Circulation Input File +============================================= + +**Check the regression tests for updated versions of this file.** + +.. container:: + :name: TabPrescribeCirc + + .. literalinclude:: ExampleFiles/ExampleFile--PrescribeCirc.txt + :linenos: diff --git a/docs/source/user/aerodyn-olaf/AppendixC.rst b/docs/source/user/aerodyn-olaf/AppendixC.rst new file mode 100644 index 0000000000..66613d90b7 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/AppendixC.rst @@ -0,0 +1,35 @@ +.. _OLAF-List-of-Output-Channels: + +Appendix C: OLAF List of Output Channels +======================================== + +This is a list of all possible output parameters from the OLAF module. +The names are grouped by meaning, but can be ordered in the OUTPUTS +section of the *AeroDyn15* primary input file, as the user sees fit. +:math:`N\beta` refers to output node, :math:`\beta`, where :math:`\beta` +is a number in the range [1,9], corresponding to entry, :math:`\beta`, +in the **OutNd** list. :math:`B\alpha` is prefixed to each output name, +where :math:`\alpha` is a number in the range [1,3], corresponding to +the blade number. + + +.. list-table:: Available OLAF Output Channels + :widths: 25 15 50 + :header-rows: 1 + :align: center + :name: Tab:OLAFoutputs + + * - Channel Name(s) + - Units + - Description + * - :math:`B \alpha N \beta Gam` + - :math:`m^2/s` + - Circulation along the blade + + +.. + ============================ ============= =========================== + Channel Name(s) Units Description + ============================ ============= =========================== + :math:`B \alpha N \beta Gam` :math:`m^2/s` Circulation along the blade + ============================ ============= =========================== diff --git a/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--OLAF.txt b/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--OLAF.txt new file mode 100644 index 0000000000..e0d341697f --- /dev/null +++ b/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--OLAF.txt @@ -0,0 +1,42 @@ +--------------------------- OLAF (cOnvecting LAgrangian Filaments) INPUT FILE ----------------- +Free wake input file for the Helix test case +--------------------------- GENERAL OPTIONS --------------------------------------------------- +5 IntMethod Integration method {5: Forward Euler 1st order, default: 5} (switch) +0.2 DTfvw Time interval for wake propagation. {default: dtaero} (s) +5 FreeWakeStart Time when wake is free. (-) value = always free. {default: 0.0} (s) +2.0 FullCircStart Time at which full circulation is reached. {default: 0.0} (s) +--------------------------- CIRCULATION SPECIFICATIONS ---------------------------------------- +1 CircSolvingMethod Circulation solving method {1: Cl-Based, 2: No-Flow Through, 3: Prescribed, default: 1 }(switch) +0.01 CircSolvConvCrit Convergence criteria {default: 0.001} [only if CircSolvingMethod=1] (-) +0.1 CircSolvRelaxation Relaxation factor {default: 0.1} [only if CircSolvingMethod=1] (-) +30 CircSolvMaxIter Maximum number of iterations for circulation solving {default: 30} (-) + "NA" PrescribedCircFile File containing prescribed circulation [only if CircSolvingMethod=3] (quoted string) +=============================================================================================== +--------------------------- WAKE OPTIONS ------------------------------------------------------ +------------------- WAKE EXTENT AND DISCRETIZATION -------------------------------------------- +50 nNWPanel Number of near-wake panels [integer] (-) +400 WakeLength Total wake distance [integer] (number of time steps) +default FreeWakeLength Wake length that is free [integer] (number of time steps) {default: WakeLength} +False FWShedVorticity Include shed vorticity in the far wake {default: false} +------------------- WAKE REGULARIZATIONS AND DIFFUSION ----------------------------------------- +0 DiffusionMethod Diffusion method to account for viscous effects {0: None, 1: Core Spreading, "default": 0} +0 RegDeterMethod Method to determine the regularization parameters {0: Manual, 1: Optimized, default: 0 } +2 RegFunction Viscous diffusion function {0: None, 1: Rankine, 2: LambOseen, 3: Vatistas, 4: Denominator, "default": 3} (switch) +0 WakeRegMethod Wake regularization method {1: Constant, 2: Stretching, 3: Age, default: 1} (switch) +2.0 WakeRegFactor Wake regularization factor (m) +2.0 WingRegFactor Wing regularization factor (m) +100 CoreSpreadEddyVisc Eddy viscosity in core spreading methods, typical values 1-1000 +------------------- WAKE TREATMENT OPTIONS --------------------------------------------------- +False TwrShadowOnWake Include tower flow disturbance effects on wake convection {default:false} [only if TwrPotent or TwrShadow] +0 ShearModel Shear Model {0: No treatment, 1: Mirrored vorticity, default: 0} +------------------- SPEEDUP OPTIONS ----------------------------------------------------------- +2 VelocityMethod Method to determine the velocity {1:Biot-Savart Segment, 2:Particle tree, default: 1} +1.5 TreeBranchFactor Branch radius fraction above which a multipole calculation is used {default: 2.0} [only if VelocityMethod=2] +1 PartPerSegment Number of particles per segment [only if VelocityMethod=2] +=============================================================================================== +--------------------------- OUTPUT OPTIONS --------------------------------------------------- +1 WrVTk Outputs Visualization Toolkit (VTK) (independent of .fst option) {0: NoVTK, 1: Write VTK at each time step} (flag) +1 nVTKBlades Number of blades for which VTK files are exported {0: No VTK per blade, n: VTK for blade 1 to n} (-) +2 VTKCoord Coordinate system used for VTK export. {1: Global, 2: Hub, "default": 1} +1 VTK_fps Frame rate for VTK output (frames per second) {"all" for all glue code timesteps, "default" for all OLAF timesteps} [used only if WrVTK=1] +------------------------------------------------------------------------------------------------ diff --git a/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--PrescribeCirc.txt b/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--PrescribeCirc.txt new file mode 100644 index 0000000000..b174db2ca0 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/ExampleFiles/ExampleFile--PrescribeCirc.txt @@ -0,0 +1,26 @@ +r/R [-], Gamma [m^2/s] +0.048488, 0.000000 +0.087326, 0.442312 +0.126163, 6.909277 +0.165000, 23.678557 +0.203837, 55.650700 +0.242674, 74.091529 +0.281512, 84.205843 +0.320349, 88.740429 +0.359186, 89.730814 +0.398023, 88.568114 +0.436860, 87.114743 +0.475698, 86.110557 +0.514535, 85.705529 +0.553372, 85.215829 +0.592209, 84.547371 +0.631047, 83.774329 +0.669884, 82.889157 +0.708721, 81.635600 +0.747558, 79.788700 +0.786395, 77.195200 +0.825233, 73.765100 +0.864070, 69.275900 +0.902907, 62.965400 +0.941744, 53.603300 +0.980581, 39.854000 diff --git a/docs/source/user/aerodyn-olaf/FutureWork.rst b/docs/source/user/aerodyn-olaf/FutureWork.rst new file mode 100644 index 0000000000..f755317574 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/FutureWork.rst @@ -0,0 +1,31 @@ +.. _Future-Work: + +Future Work +=========== + +This first implementation phase focused on single-turbine capabilities, +fulfilling the basic requirements for the design of large and novel +rotor concepts. Future development work will turn toward the +implementation of features enabling multiple-turbine simulations on +medium-to-large-scale computational clusters. The reduction of the +computational time will also be of focus. This may be achieved using +tree techniques such as the fast multipole method. Further algorithmic +options, such as vortex amalgamation in the far wake, will be considered +to speed up the simulation. The framework presented in this manual is +compatible with grid-free or grid-based vortex particle formulations. +Such particle-based implementations will also be envisaged in the +future. Further validation of the code against measurements and +higher-order tools will be pursued. Applications to cases known to be +challenging for the BEM algorithm will also be investigated, such as +highly flexible rotors, offshore floating turbines, small-scale wind +farms, multiple-rotor turbines, or kites. + +The following list contains future work on OLAF software: + +- Lagrangian particles + +- Multiple turbines, integration into FAST.Farm + +- Code speed-up + +- Dedicated dynamic stall model diff --git a/docs/source/user/aerodyn-olaf/InputFiles.rst b/docs/source/user/aerodyn-olaf/InputFiles.rst new file mode 100644 index 0000000000..163032ff52 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/InputFiles.rst @@ -0,0 +1,239 @@ +.. _Input-files: + +Input Files +=========== + +No lines should be added or removed from the input files, except in tables where +the number of rows is specified. + +Units +----- + +OLAF uses the International System of Units (e.g., kg, m, s, N). Angles are +assumed to be in degrees unless otherwise specified. + +OLAF Primary Input File +----------------------- + +The primary OLAF input file defines general free wake options, circulation model +selection and specification, near- and far-wake length, and wake visualization +options. Each section within the file corresponds to an aspect of the OLAF model. For most parameters, the user may +specify the value "default" (with or without quotes), in which case a default +value, defined below, is used by the program. + +See :numref:`OLAF-Primary-Input-File` for a sample OLAF primary input file. + +General Options +~~~~~~~~~~~~~~~ + +**IntMethod** [switch] specifies which integration method will be used to +convect the Lagrangian markers. There are four options: 1) fourth-order +Runge-Kutta *[1]*, 2) fourth-order Adams-Bashforth *[2]*, 3) fourth-order +Adams-Bashforth-Moulton *[3]*, and 4) first-order forward Euler *[5]*. The +default option is *[5]*. These methods are specified in :numref:`sec:vortconv`. + +**DTfvw** [sec] specifies the time interval at which the module will update the +wake. The time interval must be a multiple of the time step used by +*AeroDyn15*. The blade circulation is updated at each intermediate time +step based on the intermediate blades positions and wind velocities. The default +value is :math:`dt_{aero}`, where :math:`dt_{aero}` is the time step used by +AeroDyn. + +**FreeWakeStart** [sec] specifies at what time the wake evolution is classified +as “free." Before this point is reached, the Lagrangian markers are simply +convected with the freestream velocity. After this point, induced velocities are +computed and affect the marker convection. If a time less than or equal to zero +is given, the wake is “free" from the beginning of the simulation. The default +value is :math:`0`. + +**FullCircStart** [sec] specifies at what time the blade circulation reaches its +full strength. If this value is specified to be :math:`>0`, the circulation is +multiplied by a factor of :math:`0` at :math:`t=0` and linearly increasing to a +factor of :math:`1` for :math:`t>\textit{FullCircStart}`. The default +value is :math:`0`. + +Circulation Specifications +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**CircSolvMethod** [switch] specifies which circulation method is used. There +are three options: 1) :math:`C_l`-based iterative procedure *[1]*, 2) no-flow +through *[2]*, and 3) prescribed *[3]*. The default option is *[1]*. These +methods are described in :numref:`sec:circ`. + +**CircSolvConvCrit** [-] specifies the dimensionless convergence criteria used +for solving the circulation. This variable is only used if +*CircSolvMethod* = *[1]*. The default value is +:math:`0.001`, corresponding to :math:`0.1\%` error in the circulation between +two iterations. + +**CircSolvRelaxation** [-] specifies the relaxation factor used to solve the +circulation. This variable is only used if *CircSolvMethod* = +*[1]*. The default value is :math:`0.1`. + +**CircSolvMaxIter** [-] specifies the maximum number of iterations used to solve +the circulation. This variable is only used if *CircSolvMethod* = *[1]*. The +default value is :math:`30`. + +**PrescribedCircFile** [quoted string] specifies the file containing the +prescribed blade circulation. This option is only used if *CircSolvMethod* = +*[3]*. The circulation file format is a delimited file with one header line and +two columns. The first column is the dimensionless radial position [r/R]; the +second column is the bound circulation value in [m\ :math:`^2`/s]. The radial +positions do not need to match the AeroDyn node locations. A sample prescribed +circulation file is given in :numref:`Prescribed-Circulation-Input-File`. + + +Wake Extent and Discretization Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**nNWPanel** [-] specifies the number of FVW time steps (**DTfvw**) for which +the near-wake lattice is computed. In the future, this value will be defined as +an azimuthal span in degrees or a downstream distance in rotor diameter. + +**WakeLength** [D] specifies the length, in rotor diameters, of the far wake. +The default value is :math:`8`. [1]_ + +**FreeWakeLength** [D] specifies the length, in rotor diameters, for which the +turbine wake is convected as “free." If *FreeWakeLength* is greater than +*WakeLength*, then the entire wake is free. Otherwise, the Lagrangian markers +located within the buffer zone delimited by *FreeWakeLength* and *WakeLength* +are convected with the average velocity. The default value is :math:`6`. [2]_ + +**FWShedVorticity** [flag] specifies whether shed vorticity is included in the +far wake. The default value is *[False]*, specifying that the far wake consists +only of the trailed vorticity from the root and tip vortices. + +Wake Regularization and Diffusion Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**DiffusionMethod** [switch] specifies which diffusion method is used to account +for viscous diffusion. There are two options: 1) no diffusion *[0]* and 2) the +core-spreading method *[1]*. The default option is *[0]*. + +**RegDetMethod** [switch] specifies which method is used to determine the +regularization parameters. There are two options: 1) manual *[0]* and 2) +optimized *[1]*. The manual option requires the user to specify the parameters +listed in this subsection. The optimized option determines the parameters for +the user. The default option is *[0]*. + +**RegFunction** [switch] specifies the regularization function used to remove +the singularity of the vortex elements, as specified in +:numref:`sec:vortconv`. There are five options: 1) no correction *[0]*, +2) the Rankine method *[1]*, 3) the Lamb-Oseen method *[2]*, 4) the Vatistas +method *[3]*, and 5) the denominator offset method *[4]*. The functions are +given in . The default option is *[3]*. + +**WakeRegMethod** [switch] specifies the method of determining viscous core +radius (i.e., the regularization parameter). There are three options: 1) +constant *[1]*, 2) stretching *[2]*, and 3) age *[3]*. The methods are +described in :numref:`sec:corerad`. The default option is *[1]*. + +**WakeRegParam** [m] specifies the wake regularization parameter, which is the +regularization value used at the initialization of a vortex element. If the +regularization method is “constant”, this value is used throughout the wake. + +**BladeRegParam** [m] specifies the bound vorticity regularization parameter, +which is the regularization value used for the vorticity elements bound to the +blades. + +**CoreSpreadEddyVisc** [-] specifies the eddy viscosity parameter +:math:`\delta`. The parameter is used for the core-spreading method +(*DiffusionMethod* = *[1]*) and the regularization method with age +(*WakeRegMethod* = *[3]*). The variable :math:`\delta` is described in +:numref:`sec:corerad`. The default value is :math:`100`. + +Wake Treatment Options +~~~~~~~~~~~~~~~~~~~~~~ + +**TwrShadowOnWake** [flag] specifies whether the tower potential flow and tower +shadow have an influence on the wake convection. The tower shadow model, when +activated in AeroDyn, always has an influence on the lifting line, hence the +induction and loads on the blade. This option only concerns the wake. The +default option is *[False]*. + +**ShearVorticityModel** [switch] specifies whether shear vorticity is modeled in +addition to the sheared inflow prescribed by *InflowWind*. There are two +options: 1) no treatment *[0]* and 2) mirrored vorticity *[1]*. The mirrored +vorticity accounts for the ground effect. Dedicated options to account for the +shear vorticity will be implemented at a later time. The shear velocity profile +is handled by *InflowWind* irrespective of this input. The default option is +*[0]*. + + +Speedup Options +~~~~~~~~~~~~~~~ + +**VelocityMethod** [switch] specifies the method used to determine the velocity. +There are two options: 1) Biot-Savart law applied to the vortex segments *[1]* +and 2) tree formulation using a particle representation *[2]*. The default +option is *[1]*. + +**TreeBranchFactor** [-] specifies the dimensionless distance, in branch radius, +above which a multipole calculation is used instead of a direct evaluation. This +option is only used in conjunction with the tree code +(*VelocityMethod* = *[2]*). + +**PartPerSegment** [-] specifies the number of particles that are used when a +vortex segment is represented by vortex particles. The default value is +:math:`1`. + +Output Options +~~~~~~~~~~~~~~ + +**WrVTK** [flag] specifies if Visualization Toolkit (VTK) visualization files +are to be written out. *WrVTK* = *[0]* does not write out any VTK files. *WrVTK* += *[1]* outputs a VTK file at every time step. The outputs are written in the +folder, ``vtk_fvw.`` The parameters *WrVTK*, *VTKCoord*, and *VTK_fps* are +independent of the glue code VTK output options. + + +**VTKBlades** [-] specifies how many blade VTK files are to be written out. +*VTKBlades* :math:`= n` outputs VTK files for :math:`n` blades, with :math:`0` +being an acceptable value. The default value is :math:`1`. + +**VTKCoord** [switch] specifies in which coordinate system the VTK files are +written. There are two options: 1) global coordinate system *[1]* and 2) hub +coordinate system *[2]*. The default option is *[1]*. + +**VTK_fps** [:math:`1`/sec] specifies the output frequency of the VTK files. The +provided value is rounded to the nearest allowable multiple of the time step. +The default value is :math:`1/dt_\text{fvw}`. Specifying *VTK_fps* = *[all]*, +is equivalent to using the value :math:`1/dt_\text{aero}`. + +AeroDyn15 Input File +-------------------- +Input file modifications +~~~~~~~~~~~~~~~~~~~~~~~~ + +As OLAF is incorporated into the *AeroDyn15* module, a wake computation option +has been added to the *AeroDyn15* input file and a line has been added. These +additions are as follows. + +**WakeMod** specifies the type of wake model that is used. *WakeMod* = *[3]* has +been added to allow the user to switch from the traditional BEM method to the +OLAF method. + +**FVWFile** [string] specifies the OLAF module file, the path is relative to the +AeroDyn file, unless an absolute path is provided. + + +Relevant sections +~~~~~~~~~~~~~~~~~ +The BEM options (e.g. tip-loss, skew, and dynamic models) are read and discarded +when *WakeMod* = *[3]*. The following sections and parameters remain relevant and +are used by the vortex code: + + - general options (e.g., airfoil and tower modeling); + - environmental conditions; + - dynamic stall model options; + - airfoil and blade information; + - tower aerodynamics; and + - outputs. + +.. [1] + At present, this variable is called nFWPanel and specified as the number of far + wake panels. This will be changed soon. + +.. [2] + At present, this variable is called nFWPanelFree and specified as the number of + free far wake panels. This will be changed soon. diff --git a/docs/source/user/aerodyn-olaf/Introduction.rst b/docs/source/user/aerodyn-olaf/Introduction.rst new file mode 100644 index 0000000000..b6adb2be68 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/Introduction.rst @@ -0,0 +1,156 @@ +.. _Introduction: + +Introduction +============ +Over the past few decades, substantial reductions in the cost of wind energy +have come from large increases in rotor size. One important consideration for +such large turbines is increased blade flexibility. In particular, large blade +deflections may lead to a swept area that deviates significantly from the rotor +plane. Such deviations violate assumptions used by common aerodynamic models, +such as the blade element momentum (BEM) method. Such methods rely on +actuator-disk assumptions that are only valid for axisymmetric rotor loads +contained in a plane. Large blade deflections may also cause near wake of the +turbine to diverge from a uniform helical shape. Further, interactions between +turbine blades and the local near wake may increase, thus violating assumptions +of models that do not account for the position and dynamics of the near wake. +Additionally, highly flexible blades will likely cause increased unsteadiness +and three-dimensionality of aerodynamic effects, increasing the importance of +accurate and robust dynamic stall models. There are many other complex wind +turbine situations that violate simple engineering assumptions. Such situations +include obtaining accurate aerodynamic loads for nonstraight blade geometries +(e.g., built-in curvature or sweep); skewed flow caused by yawed inflow or +turbine tilt; and large rotor motion as a result of placing the turbine atop a +compliant offshore floating platform. + +Higher-fidelity aerodynamic models are necessary to account for the increased +complexity of flexible and floating rotors. Although computational fluid +dynamics (CFD) methods are able to capture such features, their computational +cost limits the number of simulations that can be feasibly performed, which is +an important consideration in load analysis for turbine design. FVW methods are +less computationally expensive than CFD methods while modeling similarly complex +physics. As opposed to the BEM methods, FVW methods do not rely on ad-hoc +engineering models to account for dynamic inflow, skewed wake, tip losses, or +ground effects. These effects are inherently part of the model. Numerous +vorticity-based tools have been implemented, ranging from the early treatments +by Rosenhead (:cite:`Rosenhead31_1`), the formulation of vortex particle methods +by Winckelmans and Leonard (:cite:`Winckelmans93_1`), to the recent mixed +Eulerian-Lagrangian compressible formulations of +Papadakis (:cite:`Papadakis14_1`). Examples of long-standing codes that have been +applied in the field of wind energy are GENUVP (:cite:`Voutsinas06_1`), using +vortex particles methods, and AWSM (:cite:`Garrel03_1`), using vortex filament +methods. Both tools have successfully been coupled to structural solvers. The +method was extended by Branlard et al. (:cite:`Branlard15_1`) to consistently use +vortex methods to perform aero-elastic simulations of wind turbines in sheared +and turbulent inflow. Most formulations rely on a lifting-line representation of +the blades, but recently, a viscous-inviscid representation was used in +combination with a structural solver (:cite:`Miras17_1`). + +cOnvecting LAgrangian Filaments (OLAF) is a free vortex wake (FVW) module used +to compute the aerodynamic forces on moving two- or three-bladed horizontal-axis +wind turbines. This module has been incorporated into the National Renewable +Energy Laboratory physics-based engineering tool, OpenFAST, which solves the +aero-hydro-servo-elastic dynamics of individual wind turbines. OLAF is +incorporated into the OpenFAST module, *AeroDyn15*, as an alternative to the +traditional blade-element momentum (BEM) option, as shown in +Figures :numref:`figOpenFAST_a` and :numref:`figOpenFAST_b`. + +.. _figOpenFAST_a: + +.. figure:: Schematics/OpenFAST.png + :alt: OpenFAST schematic + :width: 100% + :align: center + + OpenFAST schematic + +.. _figOpenFAST_b: + +.. figure:: Schematics/FVWwithOpenFAST.png + :alt: OpenFAST overview schematic and OLAF integration + :width: 100% + :align: center + + OLAF and BEM integration with *AeroDyn15* + +Incorporating the OLAF module within OpenFAST allows for the modeling of +highly flexible turbines along with the aero-hydro-servo-elastic +response capabilities of OpenFAST. The OLAF module follows the +requirements of the OpenFAST modularization framework  +(:cite:`Sprague15_1,Jonkman13_1`). + +The OLAF module uses a lifting-line representation of the blades, which +is characterized by a distribution of bound circulation. The spatial and +time variation of the bound circulation results in free vorticity being +emitted in the wake. OLAF solves for the turbine wake in a time-accurate +manner, which allows the vortices to convect, stretch, and diffuse. The +OLAF model is based on a Lagrangian approach, in which the turbine wake +is discretized into Lagrangian markers. There are many methods of +representing the wake with Lagrangian +markers (:cite:`Branlard17_1`). In this work, a hybrid +lattice/filament method is used, as depicted in +Figure :numref:`Lagrangian`. + +.. figure:: Schematics/LagrangianMarkers.png + :alt: Evolution of near-wake lattice, blade-tip vortex, and Lagrangian markers + :name: Lagrangian + :width: 100% + :align: center + + Evolution of near-wake lattice, blade-tip vortex, and Lagrangian + markers + +Here, the position of the Lagrangian markers is defined in terms of wake +age, :math:`\zeta`, and azimuthal position, :math:`\psi`. A lattice +method is used in the near wake of the blade. The near wake spans over a +user-specified angle or distance for nonrotating cases. Though past +research has indicated that a near-wake region of :math:`30^\circ` is +sufficient (:cite:`Leishman_book,Ananthan02_1`), it has been shown that a larger +near wake is required for high thrust and other challenging conditions. After +the near wake region, the wake is assumed to instantaneously roll up into a tip +vortex and a root vortex, which are assumed to be the most dominant features for +the remainder of the wake (:cite:`Leishman02_1`). Each Lagrangian marker is +connected to adjacent markers by straight-line vortex filaments, approximated to +second-order accuracy (:cite:`Gupta05_1`). The wake is discretized based on the +spanwise location of the blade sections and a specified time step (:math:`dt`), +which may be different from the time step of AeroDyn. After an optional +initialization period, the wake is allowed to move and distort, thus changing +the wake structure as the markers are convected downstream. To limit +computational expense, the root and tip vortices are truncated after a specified +distance (**WakeLength**) downstream from the turbine. The wake truncation +violates Helmholtz's first law and hence introduces an erroneous boundary +condition. To alleviate this, the wake is "frozen" in a buffer zone between a +specified buffer distance, **FreeWakeLength**, and **WakeLength**. In this +buffer zone, the markers convect at the average ambient velocity. In this way, +truncation error is minimized~(:cite:`Leishman02_1`). The buffer zone is +typically chosen as the convected distance over one rotor revolution. + +As part of OpenFAST, induced velocities at the lifting line/blade are +transferred to *AeroDyn15* and used to compute the effective blade angle of +attack at each blade section, which is then used to compute the aerodynamic +forces on the blades. The OLAF method returns the same information as the BEM +method, but allows for more accurate calculations in areas where BEM assumptions +are violated, such as those discussed above. As the OLAF method is more +computationally expensive than BEM, both methods remain available in OpenFAST, +and the user may specify in the *AeroDyn15* input file which method is +used. + +The OLAF input file defines the wake convection and circulation solution +methods; wake size and length options; Lagrangian marker regularization (viscous +core) method; and other simulation and output parameters. The extents of the +near and far wakes are specified by a nondimensional length in terms of rotor +diameter. Different regularization functions for the vortex elements are +available. Additionally, different methods to compute the regularization +parameters of the bound and wake vorticity may be selected. In particular, +viscous diffusion may be accounted for by dynamically changing the +regularization parameter. Wake visualization output options are also available. + +This document is organized as follows. :numref:`Running-OLAF` covers +downloading, compiling, and running OLAF. :numref:`Input-Files` describes the +OLAF input file and modifications to the *AeroDyn15* input file. +:numref:`Output-Files` details the OLAF output file. :numref:`OLAF-Theory` +provides an overview of the OLAF theory, including the free vortex wake method +as well as integration into the *AeroDyn15* module. Example input files and a +list of output channels are detailed in Appendices A, B, and C. + + + diff --git a/docs/source/user/aerodyn-olaf/OLAFTheory.rst b/docs/source/user/aerodyn-olaf/OLAFTheory.rst new file mode 100644 index 0000000000..6396497e15 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/OLAFTheory.rst @@ -0,0 +1,630 @@ +.. _OLAF-Theory: + +OLAF Theory +=========== + +This section details the OLAF method and provides an overview of the +computational method, followed by a brief explanation of its integration +with OpenFAST. + + +.. _sec:vorticityformulation: + +Introduction - Vorticity Formulation +------------------------------------ + +The vorticity equation for incompressible homogeneous flows in the +absence of non-conservative force is given by +Eq. :eq:`eq:vorticityconservationincompr` + +.. math:: + \begin{aligned} + \frac{d\vec{\omega}}{dt} = \frac{\partial\vec{\omega}}{\partial{t}} + \underbrace{(\vec{u} \cdot \nabla)}_{\text{convection}}\vec{\omega} = \underbrace{(\vec{\omega}\cdot\nabla)\vec{u}}_{\text{strain}} +\underbrace{\nu\Delta\vec{\omega}}_{\text{diffusion}} + \end{aligned} + :label: eq:vorticityconservationincompr + + +Here, :math:`\vec{\omega}` is the vorticity, :math:`\vec{u}` is the +velocity, and :math:`\nu` is the viscosity. In free vortex wake methods, +the vorticity equation is used to describe the evolution of the wake +vorticity. Different approximations are introduced to ease its +resolution, such as projecting the vorticity onto a discrete number of +vortex elements (here vortex filaments), and separately treating the +convection and diffusion steps, known as viscous-splitting. Several +complications arise from the method; in particular, the discretization +requires a regularization of the vorticity field (or velocity field) to +ensure a smooth approximation. + +The forces exerted by the blades onto the flow are expressed in +vorticity formulation as well. This vorticity is bound to the blade and +has a circulation associated with the lift force. A lifting-line +formulation is used here to model the bound vorticity. + +The different models of the implemented free vortex code are described +in the following sections. + +.. _sec:discretization: + +Discretization - Projection +--------------------------- + +The numerical method uses a finite number of states to model the +continuous vorticity distribution. To achieve this, the vorticity +distribution is projected onto basis function which is referred to +as vortex elements. Vortex filaments are here used as elements that +represents the vorticity field. A vortex filament is delimited by two +points and hence assumes a direction formed by these two points. A +vorticity tube is oriented along the unit vector :math:`\vec{e}_x` of +cross section :math:`dS` and length :math:`l`. It can then be +approximated by a vortex filament of length :math:`l` oriented along the +same direction. The total vorticity of the tube and the vortex filaments +are the same and related by: + +.. math:: + \begin{aligned} + \vec{\omega} \, dS = \vec{\Gamma} + \end{aligned} + :label: OmegaGamma + +where :math:`\vec{\Gamma}` is the circulation intensity of the vortex +filament. If the vorticity tubes are complex and occupy a large volume, +the projection onto vortex filaments is difficult and the projection +onto vortex particle is more appropriate. Assuming the wake is confined +to a thin vorticity layer which defines a velocity jump of know +direction, it is possible to approximate the wake vorticity sheet as a +mesh of vortex filaments. This is the basis of vortex filament wake +methods. Vortex filaments are a singular representation of the vorticity +field, as they occupy a line instead of a volume. To better represent +the vorticity field, the filaments are “inflated”, a process referred to +as regularization (see :numref:`sec:Regularization`). The +regularization of the vorticity field also regularizes the velocity +field and avoids the singularities that would otherwise occur. + + +.. _sec:circ: + +Lifting-Line Representation +--------------------------- + +The code relies on a lifting-line formulation. Lifting-line methods effectively +lump the loads at each cross-section of the blade onto the mean line of the +blade and do not account directly for the geometry of each cross-section. In the +vorticity-based version of the lifting-line method, the blade is represented by +a line of varying circulation. The line follows the motion of the blade and is +referred to as “bound” circulation. The bound circulation does not follow the +same dynamic equation as the free vorticity of the wake. Instead, the intensity +is linked to airfoil lift via the Kutta-Joukowski theorem. Spanwise variation of +the bound circulation results in vorticity being emitted into the the wake. This +is referred to as “trailed vorticity”. Time changes of the bound circulation are +also emitted in the wake, referred to as “shed” vorticity. The subsequent +paragraphs describe the representation of the bound vorticity. + +Lifting-Line Panels and Emitted Wake Panels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The lifting-line and wake representation is illustrated in +:numref:`fig:VortexLatticeMethod`. The blade lifting-line is discretized into a +finite number of panels, each of them forming a four sided vortex rings. The +spanwise discretization follows the discretization of the AeroDyn blade input +file. The number of spanwise panels, :math:`n_\text{LL}`, is one less than the +total number of AeroDyn nodes, **NumBlNds**. The sides of the panels coincide +with the lifting-line and the trailing edge of the blade. The lifting-line is +currently defined as the 1/4 chord location from the leading edge (LE). More +details on the panelling is provided in :numref:`sec:Panelling`. At a given time +step, the circulation of each lifting-line panel is determined according to one +of the three methods developed in :numref:`sec:CirculationMethods`. At the end +of the time step, the circulation of each lifting-line panel is emitted into the +wake, forming free vorticity panels. To satisfy the Kutta condition, the +circulation of the first near wake panel and the bound circulation are +equivalent (see :numref:`fig:VortexLatticeMethod` b). The wake panels model the +thin shear layer resulting from the continuation of the blade boundary layer. +This shear layer can be modelled using a continuous distribution of vortex +doublets. A constant doublet strength is assumed on each panel, which in turn is +equivalent to a vortex ring of constant circulation. + +.. figure:: Schematics/VortexLatticeMethod.png + :alt: Wake and lifting-line vorticity discretized into vortex ring panels. + :name: fig:VortexLatticeMethod + :width: 100.0% + + Wake and lifting-line vorticity discretized into vortex ring panels. + (a) Overview. (b) Cross-sectional view, defining the leading-edge, + trailing edge, and lifting-line. (c) Circulation of panels and + corresponding circulation for vorticity segments between panels. (d) + Geometrical quantities for a lifting-line panel. + +The current implementation stores the positions and circulations of the panel +corner points. In the vortex ring formulation, the boundary between two panels +corresponds to a vortex segment of intensity equal to the difference of +circulation between the two panels. The convention used to define the segment +intensity based on the panels intensity is shown in +:numref:`fig:VortexLatticeMethod` c. Since the circulation of the bound panels +and the first row of near wake panels are equal, the vortex segments located on +the trailing edge have no circulation. + +.. _sec:Panelling: + +Panelling +~~~~~~~~~ + +The definitions used for the panelling of the blade are given in +:numref:`fig:VortexLatticeMethod` d, following the notations of van +Garrel (:cite:`Garrel03_1`). The leading edge and +trailing edge (TE) locations are directly obtained from the AeroDyn +mesh. At two spanwise locations, the LE and TE define the corner points: +:math:`\vec{x}_1`, :math:`\vec{x}_2`, :math:`\vec{x}_3`, and +:math:`\vec{x}_4`. The current implementation assumes that the +aerodynamic center, the lifting-line, and the 1/4 chord location all +coincide. For a given panel, the lifting-line is then delimited by the +points :math:`\vec{x}_9= 3/4\,\vec{x}_1 + 1/4\, \vec{x}_2` and +:math:`\vec{x}_{10}=3/4\,\vec{x}_4 + 1/4\, \vec{x}_3`. The mid points of +the four panel sides are noted :math:`\vec{x}_5`, :math:`\vec{x}_6`, +:math:`\vec{x}_7`, and :math:`\vec{x}_8`. The lifting-line vector +(:math:`\vec{dl}`) as well as the vectors tangential (:math:`\vec{T}`) +and normal (:math:`\vec{N}`) to the panel are defined as: + +.. math:: + \begin{aligned} + \vec{dl} = \vec{x}_{10}-\vec{x}_9 + ,\qquad + \vec{T} = \frac{\vec{x}_6-\vec{x}_8}{|\vec{x}_6-\vec{x}_8|} + ,\qquad + \vec{N} = \frac{\vec{T}\times\vec{dl}}{|\vec{T}\times\vec{dl}|} + \end{aligned} + :label: eq:GeometricDefinitions + +The area of the panel is obtained as :math:`dA = +|(\vec{x}_6-\vec{x}_8)\times(\vec{x}_{7}-\vec{x}_5)|`. For +**CircSolvMethod=[1]**, the control points are located on the lifting-line at +the location :math:`\vec{x}_9+\eta_j \vec{dl}`. The factor :math:`\eta_j` is +determined based on the full-cosine approximation of van Garrel. This is based +on the spanwise widths of the current panel, :math:`w_j`, and the neighboring +panels :math:`w_{j-1}` and :math:`w_{j+1}`: + +.. math:: + \begin{aligned} + \eta_j=\frac{1}{4}\left[\frac{w_{j-1}}{w_{j-1}+w_j} + \frac{w_j}{w_j+w_{j+1}} +1 \right] + ,\ j=2..n-1 + ,\quad + \eta_1 = \frac{w_1}{w_1+w_2} + ,\quad + \eta_{n} = \frac{w_{n-1}}{w_{n-1}+w_{n}} + \end{aligned} + +For an equidistant spacing, this discretization places the control points at the +middle of the lifting-line (:math:`\eta=0.5`). Theoretical circulation results +for an elliptic wing with a cosine spacing are retrieved with such +discretization since it places the control points closer to stronger trailing +segments at the wing extremities (see e.g. :cite:`Kerwin:lecturenotes`). + +.. _sec:CirculationMethods: + +Circulation Solving Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Three methods are implemented to determine the bound circulation strength. They +are selected using the input **CircSolvMethod**, and are presented in the +following sections. + +Cl-Based Iterative Method +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Cl-based iterative method determines the circulation within a +nonlinear iterative solver that makes use of the polar data at each +control point located on the lifting line. The algorithm ensures that +the lift obtained using the angle of attack and the polar data matches +the lift obtained with the Kutta-Joukowski theorem. At present, it is +the preferred method to compute the circulation along the blade span. It is +selected with **CircSolvMethod=[1]**. The method is described in the work from +van Garrel (:cite:`Garrel03_1`). The algorithm is implemented in at iterative +approach using the following steps: + +#. The circulation distribution from the previous time step is used as a + guessed circulation, :math:`\Gamma_\text{prev}`. + +#. The velocity at each control points :math:`j` is computed as the sum + of the wind velocity, the structural velocity, and the velocity + induced by all the vorticity in the domain, evaluated at the control + point location. + + .. math:: + \begin{aligned} + \vec{v}_j = \vec{V}_0 - \vec{V}_\text{elast} + \vec{v}_{\omega,\text{free}} + \vec{v}_{\Gamma_{ll}} + \end{aligned} + + :math:`\vec{v}_{\omega,\text{free}}` is the velocity induced by all free + vortex filaments, as introduced in Eq. :eq:`eq:eq510` . The contribution + of :math:`\vec{v}_{\Gamma_{ll}}` comes from the lifting-line panels and + the first row of near wake panels, for which the circulation is set to + :math:`\Gamma_\text{prev}` + +#. The circulation for all lifting-line panels :math:`j` is obtained as + follows. + + .. math:: + \begin{aligned} + \Gamma_{ll,j} =\frac{1}{2} C_{l,j}(\alpha_j) \frac{\left[ (\vec{v}_j \cdot \vec{N})^2 + (\vec{v}_j \cdot \vec{T})^2\right]^2\,dA}{ + \sqrt{\left[(\vec{v}_j\times \vec{dl})\cdot\vec{N}\right]^2 + \left[(\vec{v}_j\times \vec{dl})\cdot\vec{T}\right]^2} + } %\label{eq:} + ,\quad\text{with} + \quad + \alpha_j = \operatorname{atan}\left(\frac{\vec{v}_j\cdot\vec{N}}{\vec{v}_j \cdot \vec{T}} \right) + \end{aligned} + + The function :math:`C_{l,j}` is the lift coefficient obtained from + the polar data of blade section :math:`j` and :math:`\alpha_j` is the + angle of attack at the control point. + +#. The new circulation is set using the relaxation factor + :math:`k_\text{relax}` (**CircSolvRelaxation**): + + .. math:: + \begin{aligned} + \Gamma_\text{new}= \Gamma_\text{prev} + k_\text{relax} \Delta \Gamma + ,\qquad + \Delta \Gamma = \Gamma_{ll} - \Gamma_\text{prev} %\label{eq:} + \end{aligned} + +#. Convergence is checked using the criterion :math:`k_\text{crit}` + (**CircSolvConvCrit**): + + .. math:: + \begin{aligned} + \frac{ \operatorname{max}(|\Delta \Gamma|}{\operatorname{mean}(|\Gamma_\text{new}|)} < k_\text{crit} + \end{aligned} + + If convergence is not reached, steps 2-5 are repeated using + :math:`\Gamma_\text{new}` as the guessed circulation + :math:`\Gamma_\text{prev}`. + +No-flow-through Method +^^^^^^^^^^^^^^^^^^^^^^ + +A Weissinger-L-based representation (:cite:`Weissinger47_1`) +of the lifting surface is also +available (:cite:`Bagai94_1,Gupta06_1,Ribera07_1`). In this +method, the circulation is solved by satisfying a no-flow through +condition at the 1/4-chord points. It is selected with **CircSolvMethod=[2]**. + +Prescribed Circulation +^^^^^^^^^^^^^^^^^^^^^^ + +The final available method prescribes a constant circulation. A user +specified spanwise distribution of circulation is prescribed onto the +blades. It is selected with **CircSolvMethod=[3]**. + + +.. _sec:vortconv: + +Free Vorticity Convection +------------------------- + +The governing equation of motion for a vortex filament is given by the +convection equation of a Lagrangian marker: + +.. math:: + \frac{d\vec{r}}{dt}=\vec{V}(\vec{r},t) + :label: VortFilCart + +where :math:`\vec{r}` is the position of a Lagrangian marker. The Lagrangian +markers are the end points of the vortex filaments. The Lagrangian convection of +the filaments stretches the filaments and thus automatically accounts for strain +in the vorticity equation. + +At present, a first-order forward Euler method is used to numerically solve the +left-hand side of Eq. :eq:`VortFilCart` for the vortex filament location +(**IntMethod=[5]**). This is an explicit method solved using +Eq. :eq:`eq:Euler`. + +.. math:: + \vec{r} = \vec{r} + \vec{V} \Delta t + :label: eq:Euler + + +.. _sec:vortconvPolar: + +Free Vorticity Convection in Polar Coordinates +---------------------------------------------- + +The governing equation of motion for a vortex filament is given by: + +.. math:: + \frac{d\vec{r}(\psi,\zeta)}{dt}=\vec{V}[\vec{r}(\psi,\zeta),t] + :label: VortFil + +Using the chain rule, Eq. :eq:`VortFil` is rewritten as: + +.. math:: + \frac{\partial\vec{r}(\psi,\zeta)}{\partial\psi}+\frac{\partial\vec{r}(\psi,\zeta)}{\partial\zeta}=\frac{\vec{V}[\vec{r}(\psi,\zeta),t]}{\Omega} + :label: VortFil_expanded + +where :math:`d\psi/dt=\Omega` and +:math:`d\psi=d\zeta` (:cite:`Leishman02_1`). Here, +:math:`\vec{r}(\psi,\zeta)` is the position vector of a Lagrangian +marker, and :math:`\vec{V}[\vec{r}(\psi,\zeta)]` is the velocity. + +.. + At present, first-order forward Euler method is used to numerically solve the + left-hand side of Eq. :eq:`VortFil_expanded` for the vortex-filament location + [**IntMethod=5**]. This is an explicit method solved using Eq. :eq:`Euler`. + + .. math:: + \vec{r}(\psi+\Delta\psi_i,\zeta+\Delta\zeta) = \vec{r}(\psi,\zeta) + \vec{V}(\psi,\zeta) \Delta t + :label: Euler + +Induced Velocity and Velocity Field +----------------------------------- + +The velocity term on the right-hand side of +Eq. :eq:`VortFilCart` is a nonlinear function of the +vortex position, representing a combination of the freestream and +induced velocities (:cite:`Hansen08_1`). The induced +velocities at point :math:`\vec{x}`, caused by each straight-line +filament, are computed using the Biot-Savart law, which considers the +locations of the Lagrangian markers and the intensity of the vortex +elements (:cite:`Leishman02_1`): + +.. math:: + d\vec{v}(\vec{x})=\frac{\Gamma}{4\pi}\frac{d\vec{l}\times\vec{r}}{r^3} + :label: BiotSavart + +Here, :math:`\Gamma` is the circulation strength of the filament, +:math:`\vec{dl}` is an elementary length along the filament, :math:`\vec{r}` is +the vector between a point on the filament and the control point +:math:`\vec{x}`, and :math:`r=|\vec{r}|` is the norm of the vector. The +integration of the Biot-Savart law along the filament length, delimited by the +points :math:`\vec{x}_1` and :math:`\vec{x}_2` leads to: + +.. math:: + \begin{aligned} + \vec{v}(\vec{x}) + = F_\nu \frac{\Gamma}{4\pi} \frac{(r_1+r_2)}{r_1r_2(r_1r_2+\vec{r}_1\cdot\vec{r}_2) }\vec{r}_1\times\vec{r}_2 + \end{aligned} + :label: eq:BiotSavartSegment + +with :math:`\vec{r}_1= \vec{x}-\vec{x}_1` and :math:`\vec{r}_2= +\vec{x}-\vec{x}_2`. The factor :math:`F_\nu` is a regularization parameter, +discussed in :numref:`sec:RegularizationFunction`. :math:`r_0` is the filament +length, where :math:`\vec{r}_0= \vec{x}_2-\vec{x}_1`. The distance orthogonal to +the filament is: + +.. math:: + \begin{aligned} + \rho = \frac{|\vec{r}_1\times\vec{r}_2|}{r_0} + \end{aligned} + +The velocity at any point of the domain is obtained by superposition of +the velocity induced by all vortex filaments, and by superposition of +the primary flow, :math:`\vec{V}_0`, (here assumed divergence free): + +.. math:: + \begin{aligned} + \vec{V}(\vec{x}) = \vec{V}_0(\vec{x}) + \vec{v}_\omega(\vec{x}), \quad\text{with}\quad \vec{v}_\omega(\vec{x}) = \sum_{k} \vec{v}_k(\vec{x}) + \end{aligned} + :label: eq:eq510 + +where the sum is over all the vortex filaments, each of intensity +:math:`\Gamma_k`. The intensity of each filament is determined by spanwise and +time changes of the bound circulation, as discussed in :numref:`sec:circ`. In +tree-based methods, the sum over all vortex elements is reduced by lumping +together the elements that are far away from the control points. + + +.. _sec:Regularization: + +Regularization +-------------- + +Regularization and viscous diffusion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The singularity that occurs in Eq. :eq:`BiotSavart` greatly affects the +numerical accuracy of vortex methods. By regularizing the “1-over-r” kernel of +the Biot-Savart law, it is possible to obtain a numerical method that converges +to the Navier-Stokes equations. The regularization is used to improve the +regularity of the discrete vorticity field, as compared to the “true” continuous +vorticity field. This regularization is usually obtained by convolution with a +smooth function. In this case, the regularization of the vorticity field and the +velocity field are the same. Some engineering models also perform regularization +by directly introducing additional terms in the denominator of the Biot-Savart +velocity kernel. The factor, :math:`F_\nu`, was introduced in +Eq. :eq:`eq:BiotSavartSegment` to account for this regularization. + +In the convergence proofs of vortex methods, regularization and viscous +diffusion are two distinct aspects. It is common practice in vortex filament +methods to blur the notion of regularization with the notion of viscous +diffusion. Indeed, for a physical vortex filament, viscous effects prevent the +singularity from occurring and diffuse the vortex strength with time. The +circular zone where the velocity drops to zero around the vortex is referred to +as the vortex core. A length increase of the vortex segment will result in a +vortex core radius decrease, and vice versa. Diffusion, on the other hand, +continually spreads the vortex radially. + +Because of the previously mentioned analogy, practitioners of vortex filament +methods often refer to regularization as "viscous-core" models and +regularization parameters as "core-radii." Additionally, viscous diffusion is +often introduced by modifying the regularization parameter in space and time +instead of solving the diffusion from the vorticity equation. The distinction is +made explicit in this document when clarification is required, but a loose +terminology is used when the context is clear. + +Determination of the regularization parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The regularization parameter is both a function of the physics being modeled +(blade boundary layer and wake) and the choice of discretization. Contributing +factors are the chord length, the boundary layer height, and the volume that +each vortex filament is approximating. Currently the choice is left to the user +(**RegDetMethod=[0]**). Empirical results for a rotating blade are found in the +work of Gupta (:cite:`Gupta06_1`). As a guideline, the regularization parameter +may be chosen as twice the average spanwise discretization of the blade. This +guideline is implemented when the user chooses **RegDetMethod=[1]**. Further +refinement of this option will be considered in the future. + +.. _sec:RegularizationFunction: + +Implemented regularization functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Several regularization functions have been +developed (:cite:`Rankine58_1,Scully75_1,Vatistas91_1`). At present, five +options are available: 1) No correction, 2) the Rankine method, 3) the +Lamb-Oseen method, 4) the Vatistas method, or 5) the denominator offset method. +If no correction method is used, (**RegFunction=[0]**), :math:`F_\nu=1`. The +remaining methods are detailed in the following sections. Here, :math:`r_c` is +the regularization parameter (**WakeRegParam**) and :math:`\rho` is the distance +to the filament. Both variables are expressed in meters. + +Rankine +^^^^^^^ + +The Rankine method (:cite:`Rankine58_1`) is the simplest +regularization model. With this method, the Rankine vortex has a finite +core with a solid body rotation near the vortex center and a potential +vortex away from the center. If this method is used +(**RegFunction=[1]**), the viscous core correction is given by +Eq. :eq:`rankine`. + +.. math:: + F_\nu= \begin{cases} \rho^2/r_c^2 & 0 < \rho < 1 \\ + 1 & \rho > 1 \end{cases} + :label: rankine + +Here, :math:`r_c` is the viscous core radius of a vortex filament, +detailed in :numref:`sec:corerad`. + +Lamb-Oseen +^^^^^^^^^^ + +If the Lamb-Oseen method is used [**RegFunction=[2]**], the viscous core +correction is given by Eq. :eq:`lamboseen`. + +.. math:: + F_\nu= \bigg[1-\text{exp}(-\frac{\rho^2}{r_c^2})\bigg] + :label: lamboseen + +Vatistas +^^^^^^^^ + +If the Vatistas method is used [**RegFunction=[3]**], the viscous core +correction is given by Eq. :eq:`vatistas`. + +.. math:: + F_\nu + = \frac{\rho^2}{(\rho^{2n}+r_c^{2n})^{1/n}} + = \frac{(\rho/r_c)^2}{(1 + (\rho/r_c)^{2n})^{1/n}} + :label: vatistas + +Here, :math:`\rho` is the distance from a vortex segment to an arbitrary +point (:cite:`Abedi16_1`). Research from rotorcraft applications suggests a +value of :math:`n=2`, which is used in this work (:cite:`Bagai93_1`). + +Denominator Offset/Cut-Off +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the denominator offfset method is used [**RegFunction=[4]**], the viscous +core correction is given by Eq. :eq:`denom` + +.. math:: + \begin{aligned} + \vec{v}(\vec{x}) + = \frac{\Gamma}{4\pi} \frac{(r_1+r_2)}{r_1r_2(r_1r_2+\vec{r}_1\cdot\vec{r}_2) + r_c^2 r_0^2} \vec{r}_1\times\vec{r}_2 + \end{aligned} + :label: denom + +Here, the singularity is removed by introducing an additive factor in the +denominator of Eq. :eq:`eq:BiotSavartSegment`, proportional to the filament +length :math:`r_0`. In this case, :math:`F_\nu=1`. This method is found in the +work of van Garrel (:cite:`Garrel03_1`). + +.. _sec:corerad: + +Time Evolution of the Regularization Parameter–Core Spreading Method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are four available methods by which the regularization parameter may +evolve with time: 1) constant value, 2) stretching, 3) wake age, or 4) +stretching and wake age. The three latter methods blend the notions of viscous +diffusion and regularization. The notation :math:`r_{c0}` used in this section +corresponds to input file parameter value **WakeRegParam**. + +Constant +^^^^^^^^ + +If a constant value is selected, (**WakeRegMethod=[1]**), the value of +:math:`r_c` remains unchanged for all Lagrangian markers throughout the +simulation and is taken as the value given with the parameter **WakeRegParam** +in meters. + +.. math:: + r_c(\zeta) = r_{c0} + :label: cst + +Here, :math:`\zeta` is the vortex wake age, measured from its emission time. + +Stretching +^^^^^^^^^^ + +If the stretching method is selected, (**WakeRegMethod=[2]**), the viscous core +radius is modeled by Eq. :eq:`stretch`. + +.. math:: + r_c(\zeta,\epsilon) = r_{c0} (1+\epsilon)^{-1} + :label: stretch + +.. math:: + \epsilon = \frac{\Delta l}{l} + +Here, :math:`\epsilon` is the vortex-filament strain, :math:`l` is the filament +length, and :math:`\Delta l` is the change of length between two time steps. The +integral in Eq. :eq:`stretch` represents strain effects. + +Wake Age / Core-Spreading +^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the wake age method is selected, (**WakeRegMethod=[3]**), the viscous core +radius is modeled by Eq. :eq:`age`. + +.. math:: + r_c(\zeta) = \sqrt{r_{c0}^2+4\alpha\delta\nu \zeta} + :label: age + +where :math:`\alpha=1.25643`, :math:`\nu` is kinematic viscosity, and +:math:`\delta` is a viscous diffusion parameter (typically between :math:`1` and +:math:`1,000`). The parameter :math:`\delta` is provided in the input file as +**CoreSpreadEddyVisc**. Here, the term :math:`4\alpha\delta\nu \zeta`, accounts +for viscous effects as the wake propagates downstream. The higher the background +turbulence, the more diffusion of the vorticity with time, and the higher the +value of :math:`\delta` should be. This method partially accounts for viscous +diffusion of the vorticity while neglecting the interaction between the wake +vorticity itself or between the wake vorticity and the background flow. It is +often referred to as the core-spreading method. Setting **DiffusionMethod=[1]** +is the same as using the wake age method (**WakeRegMethod=[3]**). + +Stretching and Wake Age +^^^^^^^^^^^^^^^^^^^^^^^ + +If the stretching and wake-age method is selected (**WakeRegMethod=[4]**), +the viscous core radius is modeled by +Eq. :eq:`stretchandage`. + +.. math:: + r_c(\zeta,\epsilon) = \sqrt{r_{c0}^2 + 4\alpha\delta\nu \zeta \big(1+\epsilon\big)^{-1} } + :label: stretchandage + +.. _sec:diffusion: + +Diffusion +--------- + +The viscous-splitting assumption is used to solve for the convection and +diffusion of the vorticity separately. The diffusion term :math:`\nu \Delta +\vec{\omega}` represents molecular diffusion. This term allows for viscous +connection of vorticity lines. Also, turbulent flows will diffuse the vorticity +in a similar manner based on a turbulent eddy viscosity. + +The parameter **DiffusionMethod** is used to switch between viscous diffusion +methods. Currently, only the core-spreading method is implemented. The method +is described in :numref:`sec:corerad` since it is equivalent to the increase of +the regularization parameter with the wake age. + diff --git a/docs/source/user/aerodyn-olaf/OutputFiles.rst b/docs/source/user/aerodyn-olaf/OutputFiles.rst new file mode 100644 index 0000000000..8068e64b21 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/OutputFiles.rst @@ -0,0 +1,24 @@ +.. _Output-Files: + +Output Files +============ + +The OLAF module itself does not produce its own output file. However, additional +output channels are made available in *AeroDyn15*. As such, the *AeroDyn15* +output file is briefly described as well as the outputs made available with +OLAF. Visualization files are generated by using the parameter, **WrVTK**. This +parameter is available in the OLAF input file, in which case the VTK files are +written to the folder ``vtk_fvw``, or the primary ``.fst`` file, in which case +the VTK files are written to the folder ``vtk``. + + +Results File +------------ + +OpenFAST generates a master results file that includes the *AeroDyn15* +results. The results are in table format, where each column is a data +channel, and each row corresponds to a simulation-output time step. The +data channels are specified in the *OUTPUTS* section in the *AeroDyn15* +primary input file. The column format of the AeroDyn-generated files is +specified using the **OutFmt** parameter of the OpenFAST driver input +file. diff --git a/docs/source/user/aerodyn-olaf/RunningOLAF.rst b/docs/source/user/aerodyn-olaf/RunningOLAF.rst new file mode 100644 index 0000000000..4b91c6150c --- /dev/null +++ b/docs/source/user/aerodyn-olaf/RunningOLAF.rst @@ -0,0 +1,12 @@ +.. _Running-OLAF: + +Running OLAF +============ + +As OLAF is a module of OpenFAST, the process of downloading, compiling, +and running OLAF is the same as that for OpenFAST. Such instructions are +available in the :ref:`installation` documentation. + +.. note:: + To improve the speed of FVW module, the user may wish to compile with + `OpenMP`. To do so, add the `-DOPENMP=ON` option with CMake. diff --git a/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.pdf b/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.pdf new file mode 100644 index 0000000000..554dfa9386 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.png b/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.png new file mode 100644 index 0000000000..e474d79c1e Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/FVWwithOpenFAST.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.pdf b/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.pdf new file mode 100644 index 0000000000..09d2d50321 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.png b/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.png new file mode 100644 index 0000000000..77a97adfce Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/FilamentRegularization.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.pdf b/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.pdf new file mode 100644 index 0000000000..4d911dadaf Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.png b/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.png new file mode 100644 index 0000000000..ea4628c990 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/LagrangianMarkers.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.pdf b/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.pdf new file mode 100644 index 0000000000..7a922ec760 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.png b/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.png new file mode 100644 index 0000000000..c3d9084e3f Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/OpenFAST.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/Stencil.pdf b/docs/source/user/aerodyn-olaf/Schematics/Stencil.pdf new file mode 100644 index 0000000000..064309fe64 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/Stencil.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/Stencil.png b/docs/source/user/aerodyn-olaf/Schematics/Stencil.png new file mode 100644 index 0000000000..7097d3b0b2 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/Stencil.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.pdf b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.pdf new file mode 100644 index 0000000000..b0c1fb9c10 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.png b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.png new file mode 100644 index 0000000000..a4973027c1 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.png differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.tex b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.tex new file mode 100644 index 0000000000..4f2289dd56 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/Schematics/VortexCodeWorkFlow.tex @@ -0,0 +1,80 @@ +%% Creator: Inkscape inkscape 0.92.3, www.inkscape.org +%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010 +%% Accompanies image file 'VortexCodeWorkFlow.pdf' (pdf, eps, ps) +%% +%% To include the image in your LaTeX document, write +%% \input{.pdf_tex} +%% instead of +%% \includegraphics{.pdf} +%% To scale the image, write +%% \def\svgwidth{} +%% \input{.pdf_tex} +%% instead of +%% \includegraphics[width=]{.pdf} +%% +%% Images with a different path to the parent latex file can +%% be accessed with the `import' package (which may need to be +%% installed) using +%% \usepackage{import} +%% in the preamble, and then including the image with +%% \import{}{.pdf_tex} +%% Alternatively, one can specify +%% \graphicspath{{/}} +%% +%% For more information, please see info/svg-inkscape on CTAN: +%% http://tug.ctan.org/tex-archive/info/svg-inkscape +%% +\begingroup% + \makeatletter% + \providecommand\color[2][]{% + \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}% + \renewcommand\color[2][]{}% + }% + \providecommand\transparent[1]{% + \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}% + \renewcommand\transparent[1]{}% + }% + \providecommand\rotatebox[2]{#2}% + \newcommand*\fsize{\dimexpr\f@size pt\relax}% + \newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}% + \ifx\svgwidth\undefined% + \setlength{\unitlength}{1584.33259703bp}% + \ifx\svgscale\undefined% + \relax% + \else% + \setlength{\unitlength}{\unitlength * \real{\svgscale}}% + \fi% + \else% + \setlength{\unitlength}{\svgwidth}% + \fi% + \global\let\svgwidth\undefined% + \global\let\svgscale\undefined% + \makeatother% + \begin{picture}(1,0.37987951)% + \lineheight{1}% + \setlength\tabcolsep{0pt}% + \put(0,0){\includegraphics[width=\unitlength,page=1]{VortexCodeWorkFlow.pdf}}% + \put(0.65944109,0.11446444){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.25535428\unitlength}\centering $\vec{v}_{i,ll}, (\vec{r}_{r})$\end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=2]{VortexCodeWorkFlow.pdf}}% + \put(0.63558708,0.20735708){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.20717198\unitlength}\centering \textbf{Vortex code}\end{minipage}}}% + \put(0.60215168,0.18502836){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.27356877\unitlength}\centering $\vec{r}, \vec{\Gamma}_v$\end{minipage}}}% + \put(0.32921211,0.30084711){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.30485953\unitlength}\raggedright 1. Tower shadow model\\ \ \ \ \ (update of $\vec{V}_{\infty}$)\end{minipage}}}% + \put(0.32826903,0.23341478){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.3956149\unitlength}\raggedright 2. Induction computation\end{minipage}}}% + \put(0.32826903,0.13392726){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.5344643\unitlength}\raggedright 3. Quasi steady forces on the lifting lines\end{minipage}}}% + \put(0.32826903,0.08442459){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.51629305\unitlength}\raggedright 4. Dynamic stall model\end{minipage}}}% + \put(0.49325791,0.33819968){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.20355574\unitlength}\centering \textbf{AeroDyn15}\end{minipage}}}% + \put(0.79169925,0.10320964){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.25535428\unitlength}\centering $\vec{f}_{ll}$\end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=3]{VortexCodeWorkFlow.pdf}}% + \put(0.79577993,0.29769798){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.25535428\unitlength}\centering $\vec{r}_{ll}, \vec{r}_{r}$\end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=4]{VortexCodeWorkFlow.pdf}}% + \put(-0.00885268,0.27822337){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.20355574\unitlength}\centering \textbf{InflowWind}\end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=5]{VortexCodeWorkFlow.pdf}}% + \put(0.69583824,0.27908716){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.08495527\unitlength}\centering \textbf{BEM}\end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=6]{VortexCodeWorkFlow.pdf}}% + \put(0.01537801,0.32400133){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.44217675\unitlength}\centering $\vec{V}_\infty=$\\ $[\vec{V}_{\infty,ll}, \vec{V}_{\infty,r}] $\end{minipage}}}% + \put(0.02471082,0.17907865){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.41731078\unitlength}\centering $\vec{x}_{\text{elast},ll} =$\\ $ [\vec{r}_{ll}, \vec{\Lambda}_{ll}, \vec{\dot{r}}_{ll}, \vec{\omega}_{ll}]$\\ \end{minipage}}}% + \put(0,0){\includegraphics[width=\unitlength,page=7]{VortexCodeWorkFlow.pdf}}% + \put(-0.01097736,0.13673){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.20355574\unitlength}\centering \textbf{ElastoDyn}\end{minipage}}}% + \put(0.57551823,0.27600282){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\begin{minipage}{0.41731078\unitlength}\raggedright $\vec{r}_{\text{elast},ll}$\\ $\vec{V}_\infty$\end{minipage}}}% + \end{picture}% +\endgroup% diff --git a/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.pdf b/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.pdf new file mode 100644 index 0000000000..d4486621d8 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.pdf differ diff --git a/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.png b/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.png new file mode 100644 index 0000000000..2db30e3972 Binary files /dev/null and b/docs/source/user/aerodyn-olaf/Schematics/VortexLatticeMethod.png differ diff --git a/docs/source/user/aerodyn-olaf/StateSpace.rst b/docs/source/user/aerodyn-olaf/StateSpace.rst new file mode 100644 index 0000000000..ecfa470b10 --- /dev/null +++ b/docs/source/user/aerodyn-olaf/StateSpace.rst @@ -0,0 +1,185 @@ +.. role:: raw-latex(raw) + :format: latex +.. + +State-Space Representation and Integration with OpenFAST +======================================================== + +State, Constraint, Input, and Output Variables +---------------------------------------------- + +The OLAF module has been integrated into the latest version of OpenFAST via +*AeroDyn15*, following the OpenFAST modularization +framework (:cite:`Jonkman13_1,Sprague15_1`). To follow the OpenFAST framework, +the vortex code is written as a module, and its formulation comprises state, +constraint, and output equations. The data manipulated by the module include the +following vectors: constant parameters, :math:`\vec{p}`; inputs, +:math:`\vec{u}`; constrained state, :math:`\vec{z}`; states, :math:`\vec{x}`; +and outputs, :math:`\vec{y}`. The vectors are defined as follows: + +- Parameters, :math:`\vec{p}~-` a set of internal system values that are + independent of the states and inputs. The parameters can be fully defined at + initialization and characterize the system state and output equations. + +- Inputs, :math:`\vec{u}~-` a set of values supplied to the module that, along + with the states, are needed to calculate future states and the system output. + +- Constraint states, :math:`\vec{z}~-` algebraic variables that are calculated + using a nonlinear solver, based on values from the current time step. + +- States, :math:`\vec{x}~-` a set of internal values of the module. They are + influenced by the inputs and used to calculate future state values and + output. Continuous states are employed, meaning that the states are + differentiable in time and characterized by continuous time-differential + equations. + +- Outputs, :math:`\vec{y}~-` a set of values calculated and returned by the + module that depend on the states, inputs, and/or parameters through output + equations. + +The parameters of the vortex code include: + +- Fluid characteristics: kinematic viscosity, :math:`\nu`. + +- Airfoil characteristics: chord :math:`c` and polar data -- + :math:`C_l(\alpha)`, :math:`C_d(\alpha)`, :math:`C_m(\alpha)`). + +- Algorithmic methods and parameters, e.g., regularization, viscous + diffusion, discretization, wake geometry, and acceleration. + +The inputs of the vortex code are: + +- Position, orientation, translational velocity, and rotational + velocity of the different nodes of the lifting lines + (:math:`\vec{r}_{ll}`, :math:`\Lambda_{ll}`, + :math:`\vec{\dot{r}}_{ll}`, and :math:`\vec{\omega}_{ll}`, + respectively), gathered into the vector, + :math:`\vec{x}_{\text{elast},ll}`, for conciseness. These quantities + are handled using the mesh-mapping functionality and data structure + of OpenFAST. + +- Disturbed velocity field at requested locations, written + :math:`\vec{V}_0=[\vec{V}_{0,ll}, \vec{V}_{0,m}]`. Locations are requested + for lifting-line points, :math:`\vec{r}_{ll}`, and Lagrangian markers, + :math:`\vec{r}_m`. Based on the parameters, this disturbed velocity field may + contain the following influences: freestream, shear, veer, turbulence, tower, + and nacelle disturbance. The locations where the velocity field is requested + are typically the location of the Lagrangian markers. + +The constraint states are: + +- The circulation intensity along the lifting lines, + :math:`\Gamma_{ll}`. + +The continuous states are: + +- The position of the Lagrangian markers, :math:`\vec{r}_m` + +- The vorticity associated with each vortex element, :math:`\vec{\omega}_e`. + For a projection of the vorticity onto vortex segments, this corresponds to + the circulation, :math:`\vec{\Gamma}_e`. For each segment, + :math:`\vec{\Gamma}_e= \Gamma_e \vec{dl}_e =\vec{\omega}_e dV_e`, with + :math:`\vec{dl}_e` and :math:`dV_e`, the vortex segment length and its + equivalent vortex volume. + +The outputs are [1]_: + +- The induced velocity at the lifting-line nodes, + :math:`\vec{v}_{i,ll}` + +- The locations where the undisturbed wind is computed, :math:`\vec{r}_{r}` + (typically :math:`\vec{r_{r}}=\vec{r}_m`). + +State, Constraint, and Output Equations +--------------------------------------- + +An overview of the states, constraints, and output equations is given here. More +details are provided in :numref:`OLAF-Theory`. The constraint equation is used +to determine the circulation distribution along the span of each lifting line. +For the van Garrel method, this circulation is a function of the angle of attack +along the blade and the airfoil coefficients. The angle of attack at a given +lifting-line node is a function of the undisturbed velocity, +:math:`\vec{v}_{0,ll}`, and the velocity induced by the vorticity, +:math:`\vec{v}_{i,ll}`, at that point. Part of the induced velocity is caused by +the vorticity being shed and trailed at the current time step, which in turn is +a function of the circulation distribution along the lifting line. This +constraint equation may be written as: + +.. math:: + \vec{Z} = \vec{0} = \vec{\Gamma}_{ll} - \vec{\Gamma}_p\bigg(\vec{\alpha}(\vec{x},\vec{u}),\vec{p}\bigg) + +where :math:`\vec{\Gamma}_p` is the function that returns the circulation along +the blade span, according to one of the methods presented in :numref:`sec:circ`. + +The state equation specifies the time evolution of the vorticity and the +convection of the Lagrangian markers: + +.. math:: + \begin{aligned} + \frac{d \vec{\omega}_e}{dt} &= \bigg[(\vec{\omega}\cdot\nabla)\vec{v} + \nu\nabla^2 \vec{\omega} \bigg]_e + \end{aligned} + +.. math:: + \begin{aligned} + \frac{d \vec{r}_m}{dt} &= \vec{V}(\vec{r}_m) + =\vec{V}_0(\vec{r}_m) + \vec{v}_\omega(\vec{r}_m) + =\vec{V}_0(\vec{r}_m) + \vec{V}_\omega(\vec{r}_m, \vec{r}_m, \vec{\omega}) + \end{aligned} + :label: eq:Convection + +Here, + +- :math:`\vec{v}_\omega` is the velocity induced by the vorticity in the + domain; +- :math:`\vec{V}_\omega(\vec{r},\vec{r}_m,\vec{\omega})` is the function that + computes this induced velocity at a given point, :math:`\vec{r}`, based on + the location of the Lagrangian markers and the intensity of the vortex elements; +- the subscript :math:`e` indicates that a quantity is applied to an element; + and +- the vorticity, :math:`\vec{\omega}`, is recovered from the vorticity of the + vortex elements by means of discrete convolutions. + +For vortex-segment simulations, the viscous-splitting algorithm is used, and the +convection step (Eq. :eq:`eq:Convection`) is the main state equation being +solved for. The vorticity stretching is automatically accounted for, and the +diffusion is performed *a posteriori*. The velocity function, +:math:`\vec{V}_\omega`, uses the Biot-Savart law. The output equation is: + +.. math:: + \begin{aligned} + \vec{y}_1&=\vec{v}_{i,ll} = \vec{V}_\omega ( \vec{r}_{ll}, \vec{r}_m, \vec{\omega}) \\ + \vec{y}_2&=\vec{r}_{r} + \end{aligned} + +Integration with AeroDyn15 +-------------------------- + +The vortex code has been integrated as a submodule of the aerodynamic module of +OpenFAST, *AeroDyn15*. The data workflow between the different modules and +submodules of OpenFAST is illustrated in :numref:`AD15-OLAF`. +AeroDyn inputs such as BEM options (e.g., tip-loss factor), skew model, and +dynamic inflow are discarded when the vortex code is used. The environmental +conditions, tower shadow, and dynamic stall model options are used. This +integration required a restructuring of the *AeroDyn15* module to isolate the +parts of the code related to tower shadow modeling, induction computation, +lifting-line-forces computations, and dynamic stall. The dynamic stall model is +adapted when used in conjunction with the vortex code to ensure the effect of +shed vorticity is not accounted for twice. The interface between *AeroDyn15* and +the inflow module, *InflowWind*, was accommodated to include the additionally +requested points by the vortex code. + + +.. _AD15-OLAF: + +.. figure:: Schematics/VortexCodeWorkFlow.png + :alt: OpenFAST-FVW code integration workflow + :width: 100% + :align: center + + OpenFAST-OLAF code integration workflow + + + +.. [1] + The loads on the lifting line are not an output of the vortex code; + their calculation is handled by a separate submodule of *AeroDyn*. diff --git a/docs/source/user/aerodyn-olaf/bibliography.bib b/docs/source/user/aerodyn-olaf/bibliography.bib new file mode 100644 index 0000000000..90f791db4b --- /dev/null +++ b/docs/source/user/aerodyn-olaf/bibliography.bib @@ -0,0 +1,438 @@ +@article{Larsen08_1, + title= {Wake Meander: A Pragmatic Approach}, + author= {G. C. Larsen and H. A. Madsen and K. Thomsen and et al.}, + journal= {Wind Energy}, + volume= {11}, + pages= {337-95}, + year= {2008}, + publisher={John Wiley \& Sons, Ltd.}, + doi = {http://onlinelibrary.wiley.com/doi/10.1002/we.267/epdf} +} + +@inproceedings{Bagai94_1, + author= {A. Bagai and J. G. Leishman}, + title= {Rotor Free-Wake Modeling using a Pseudo-Implicit Technique Including Comparisons with Experimental Data}, + booktitle= {50th Annual Forum of the American Helicopter Society}, + year= {1994}, + address= {Washington, D.C.} +} + +@article{Quon18_1, + title= {Comparison of Wake Characterization Methods for Large-Eddy Simulations of a Rotor in Stratified Flow}, + author= {E. Quon and M. Churchfield and J. Jonkman}, + journal= {Computers & Fluids}, + year= {2018} +} + +@article{Martinez17_1, + title= {Optimal Smoothing Length Scale for Actuator Line Models of Wind Turbine Blades Based on Gaussian Body Force Distribution}, + author= {L. A. Martinez-Tossas and M. J. Churchfield and C. Meneveau}, + journal= {Wind Energy}, + volume= {20}, + pages= {1083-1096}, + year= {2017}, + publisher={John Wiley \& Sons, Ltd.}, + doi = {http://onlinelibrary.wiley.com/doi/10.1002/we.2081/epdf} +} + +@article{Vatistas91_1, + Author = {G. H. Vatistas and V. Koezel and W. C. Mih}, + Title = {A Simpler Model for Concentrated Vortices}, + Journal = {Experiments in Fluids}, + Volume = {11}, + Number = {1}, + Pages = {73-76}, + Year = {1991}} + +@article{Quon19_1, + title= {Comparison of Wake Characterization Methods for Large-Eddy Simulations of a Rotor in Stratified Flow}, + author= {E. Quon and M. Churchfield and J. Jonkman}, + journal= {Computers \& Fluids}, + year= {2019 (Forthcoming)} +} + +@inproceedings{Jonkman18_1, + title= {Validation of FAST.Farm Against Large-Eddy Simulations}, + author= {J. Jonkman and P. Doubrawa and N. Hamilton and et al.}, + series= {TORQUE 2018}, + date = {20-22}, + month = {June}, + year= {2018}, + publisher={EAWE}, + address= {Milano, Italy} +} + +@Book{Hansen08_1, + author = {M. O. L. Hansen}, + title = {Aerodynamics of Wind Turbines}, + publisher = {Earthscan}, + year = {2008}, + address = {London; Sterling, VA} +} + +@techreport{Weissinger47_1, + Author = {J. Weissinger}, + Title = {The Lift Distribution of Swept-Back Wings}, + Institution = {NACA}, + Type = {Technical report}, + Number = {TM 1120}, + Year = {1947} +} + +@techreport{Jonkman13_1, + Author = {J. Jonkman}, + Title = {The New Modularization Framework for the FAST Wind Turbine CAE Tool}, + Institution = {National Renewable Energy Laboratory}, + Type = {Technical report}, + Number = {NREL/CP-5000-57228}, + Year = {2013} +} + +@techreport{Jonkman15_1, + Author = {J. Jonkman and M. A. Sprague and B. J. Jonkman}, + Title = {FAST Modular Framework for Wind Turbine Simulation: New Algorithms and Numerical Examples}, + Institution = {National Renewable Energy Laboratory}, + Type = {Technical report}, + Number = {NREL/CP-2C00-63203}, + Year = {2015} +} + +@phdthesis{Gupta06_1, + Author = {S. Gupta}, + Title = {Development of a Time-Accurate Viscous Lagrangian Vortex Wake Model for Wind Turbine Applications}, + School = {Univeristy of Maryland}, + Address = {College Park, MD}, + Type = {PhD thesis}, + Year = {2006} +} + +@phdthesis{Scully75_1, + Author = {M. P. Scully}, + Title = {Computation of Helicopter Rotor Wake Geometry and Its Influence on Rotor Harmonic Airloads}, + School = {Massachusetts Institute of Technology}, + Address = {Cambridga, MA}, + Type = {PhD thesis}, + Year = {1975} +} + + +@phdthesis{Ribera07_1, + Author = {M. Ribera}, + Title = {Helicopter Flight Dynamics Simulation with a Time-Accurate Free-Vortex Wake Model}, + School = {University of Maryland}, + Address = {College Park, MD}, + Type = {PhD thesis}, + Year = {2007}} + +@inproceedings{Doubrawa18_1, + author= {P. Doubrawa and J. Annoni and J. Jonkman and et al.}, + title= {Optimization-Based Calibration of FAST.Farm Parameters Against SOWFA}, + booktitle={AIAA SciTech Forum}, + series= {36th Wind Energy Symposium}, + date = {8-13}, + month = {January}, + year= {2018}, + publisher={AIAA}, + address= {Kissimmee, FL}, + doi = {https://arc.aiaa.org/doi/pdf/10.2514/6.2018-0512} +} + +@inproceedings{Shaler19_1, + title= {FAST.Farm Response of Varying Wind Inflow Techniques}, + author= {K. Shaler and J. Jonkman and P. Doubrawa and N. Hamilton}, + booktitle={AIAA SciTech Forum}, + series= {37th Wind Energy Symposium}, + date = {7-11}, + month = {January}, + year= {2019}, + publisher={AIAA}, + address= {San Diego, CA}, + doi = {https://arc.aiaa.org/doi/pdf/10.2514/6.2019-2086} +} + +@inproceedings{Jonkman17_1, + title= {Development of FAST.Farm: A New MultiPhysics Engineering Tool for Wind-Farm Design and Analysis}, + author= {J. Jonkman and J. Annoni and G. Hayman and B. Jonkman and A. purkayastha}, + booktitle={AIAA SciTech Forum}, + series= {35th Wind Energy Symposium}, + date = {9-13}, + month = {January}, + year= {2017}, + publisher={AIAA}, + address= {Grapevine, TX}, + doi = {http://arc.aiaa.org/doi/pdf/10.2514/6.2017-0454} +} + +@inproceedings{Churchfield15_1, + title= {A Comparison of the Dynamic Wake Meandering Model, Large-Eddy Simulations, and Field Data at the Egmond aan Zee Offshore Wind Plant}, + author= {M. J. Churchfield and P. J. Moriarty and Y. Hao and et al.}, + booktitle={AIAA SciTech Forum}, + series= {33rd Wind Energy Symposium}, + date = {5-9}, + month = {January}, + year= {2015}, + publisher={AIAA}, + address= {Kissimmee, FL}, + doi = {http://dx.doi.org/10.2514/6.2015-0724} +} + +@inproceedings{Churchfield12_1, + title= {A Large-Eddy Simulation of Wind-Plant Aerodynamics}, + author= {M. J. Churchfield and P. J. Moriarty and L. A. Martinez and et al.}, + series= {50th AIAA Aerospace Sciences Meeting}, + date = {9-12}, + month = {January}, + year= {2012}, + publisher={AIAA}, + address= {Nashville, TN}, + doi = {http://dx.doi.org/10.2514/6.2012-537} +} + +@techreport{Jonkman09_1, + title= {Definition of a 5-MW Reference Wind Turbine for Offshore System Development}, + author= {Jonkman, J. and Butterfield, S. and Musial, W. and Scott, G.}, + number= {NREL/TP-500-38060}, + institution={National Renewable Energy Laboratory}, + address= {Golden, CO}, + month= {February}, + year= {2009} +} + +@techreport{TurbSim_1, + title= {TurbSim User's Guide v2.00.00}, + author= {Jonkman, B.}, + number= {NREL/TP-xxxx-xxxxx}, + institution={National Renewable Energy Laboratory}, + address= {Golden, CO}, + month= {October}, + year= {2014} +} + +@techreport{IEC_1, + title= {Wind Turbines - Part 1: Design Requirements}, + author= {IEC 61400-1}, + number= {3rd edition}, + institution={International Electrotechnical Commission}, + address= {Geneva, Switzerland}, + month= {March}, + year= {2006} +} + +@techreport{Simms01_1, + title= {NREL Unsteady Aerodynamics Experiment in the NASA-Ames Wind Tunnel: A Comparison of Predictions to Measurements}, + author= {Simms, D. and Schreck, S. and Hand, M. and Fingersh, L.J.}, + number= {NREL/TP-500-29494}, + institution={National Renewable Energy Laboratory}, + address= {Golden, CO}, + month= {June}, + year= {2001} +} + +@techreport{Jonkman18_2, + title= {FAST.Farm User's Guide and Theory Manual}, + author= {J. M. Jonkman}, + number= {NREL/TP-xxxx-xxxxx}, + institution={National Renewable Energy Laboratory}, + address= {Golden, CO}, + month= {Unpublished}, + year= {2018} +} + +@misc{FAST, +title = {OpenFAST Documentation}, +month = {November}, +year = {2017}, +url = {http://openfast.readthedocs.io/en/master/} +} + +@misc{SAMWICH, + author = {E. Quon}, + title = {SAMWICH Wake-Tracking Toolbox}, + publisher = {GitHub}, + journal = {GitHub repository}, + howpublished = {\url{https://github.com/ewquon/waketracking}}, + year= {2017} +} + +@phdthesis{Krista12_1, + Author = {K. Kecskemety}, + Title = {Assessing the Influence of Wake Dynamics on the Performance and Aeroelastic Behavior of Wind Turbines}, + School = {Ohio State University}, + Address = {Columbus, OH}, + Type = {PhD thesis}, + Year = {2012}} + +@book{Leishman_book, + Author = {J. Leishman}, + Title = {Principles of Helicopter Aerodynamics}, + Publisher = {Cambridge Univ. Press}, + Address = {Cambridge, MA}, + Year = {2006}} + +@book{Rankine58_1, + Author = {W. J. M. Rankine}, + Title = {Manual of Applied Mechanics}, + Publisher = {Griffen Co.}, + Address = {London}, + Year = {1858}} + +@article{Leishman02_1, + Author = {J. G. Leishman and M. J. Bhagwat and A. Bagai}, + Title = {Free-Vortex Filament Methods for the Analysis of Helicopter Rotor Wakes}, + Journal = {Journal of Aircraft}, + Volume = {39}, + Number = {5}, + Pages = {759-775}, + Year = {2002}} + +@inproceedings{Ananthan02_1, + Author = {S. Ananthan and J. G. Leishman and M. Ramasamy}, + Title = {The Role of Filament Stretching in the Free-Vortex Modeling of Rotor Wakes}, + booktitle = {58th Annual Forum and Technology Display of the American Helicopter Society International}, + year = {2002}, + address = {Montreal, Canada}} + +@article{Gupta05_1, + Author = {S. Gupta and J. G. Leishman}, + Title = {Free-Vortex Filament Methods for the Analysis of Helicopter Rotor Wakes}, + Journal = {Journal of Aircraft}, + Volume = {39}, + Number = {5}, + Pages = {759-775}, + Year = {2002}} + +@techreport{Wiser17_1, + title= {2016 Wind Technologies Market Report}, + author= {R. Wiser and M. Bolinger}, + number= {DOE/GO-102917-5033}, + institution={Lawrence Berkeley National Laboratory}, + address= {Berkeley, CA}, + month= {August}, + year= {2017}, + doi = {10.2172/1393638}} + +@phdthesis{Shaler19_2, + Author = {K. Shaler}, + Title = {Wake Interaction Modeling Using A Parallelized Free Vortex Wake Model}, + School = {Ohio State University}, + Address = {Columbus, OH}, + Type = {PhD thesis}, + Year = {2020}} + +@phdthesis{Abedi16_1, + Author = {H. Abedi}, + Title = {Development of Vortex Filament Method for Wind Power Aerodynamics}, + School = {Chalmers University of Technology}, + Address = {Gothenburg, Sweden}, + Type = {PhD thesis}, + Year = {2016}} + + +@techreport{Johnson19_1, + Author={N. Johnson and P. Bortolotti and K. Dykes and et al.}, + Title={Investigation of Innovative Rotor Concepts for the Big Adaptive Rotor Project}, + institution={National Renewable Energy Laboratory}, + number={NREL/TP-5000-73605}, + Year=2019 + } + +@techreport{Sprague15_1, + title={FAST Modular Framework for Wind Turbine Simulation: New Algorithms and Numerical Examples}, + author={Michael A. Sprague and Jason M. Jonkman and Bonnie J. Jonkman}, + institution={National Renewable Energy Laboratory}, + number={NREL/CP-2C00-63203}, + year={2015} +} + +@article{Miras17_1, + author = {M. Sessarego and N. Ramos Garc{\'i}a and J. N. S{\o}rensen and W. Z. Shen}, + title = {Development of an aeroelastic code based on three-dimensional viscous-inviscid method for wind turbine computations}, + year = {2017}, + doi = {10.1002/we.2085}, + volume = {20}, + pages = {1145-1170}, + journal = {Wind Energy}, + number = {7}, +} + +@article{Bagai93_1, + author = {A. Bagai and J. G. Leishman}, + title = {Flow Visualization of Compressible Vortex Structures Using Density Gradient Techniques}, + year = {1993}, + volume = {15}, + pages = {431-442}, + journal = {Experiments in Fluids}, + number = {6} +} + +@phdthesis{Papadakis14_1, + author = {G. Papadakis}, + title = {Development of a hybrid compressible vortex particle method and application to external problems including helicopter flows}, + school = {National Technical University of Athens}, + year = {2014}, +} +@article{Voutsinas06_1, + author = {S. G. Voutsinas}, + title = {Vortex methods in aeronautics: how to make things work}, + journal = {International Journal of Computational Fluid Dynamics}, + year = {2006}, +} + +@article{Rosenhead31_1, + author = {L. Rosenhead}, + title = {The Formation of Vortices from a Surface of Discontinuity}, + journal = {Proceedings of the Royal Society of London. Series A, Containing Papers of a Mathematical and Physical Character}, + volume = {134}, + number = {823}, + pages = {170-192}, + url = {http://www.jstor.org/stable/95835}, + ISSN = {09501207}, + year = {1931}, + publisher = {The Royal Society}, +} + +@article{Winckelmans93_1, + author = {G. S. Winckelmans and A. Leonard}, + title = {Contributions to vortex particle methods for the computation of 3-dimensional incompressible unsteady flows}, + publisher = {Academic Press Inc. JNL-Comp Subscriptions}, + journal = {Journal Of Computational Physics}, + volume = {109}, + number = {2}, + pages = {247-273}, + year = {1993}, + issn = {00219991, 10902716} +} + +@article{Branlard15_1, +author = {E. Branlard and G. Papadakis and M. Gaunaa and G. Winckelmans and T. J. Larsen}, +title = {Aeroelastic large eddy simulations using vortex methods: unfrozen turbulent and sheared inflow}, +journal = {Journal of Physics: Conference Series (Online)}, +year = {2015}, +doi = {10.1088/1742-6596/625/1/012019}, +volume = {625}, +issn = {1742-6596}, +} + +@book{Branlard17_1, + author = {E. Branlard}, + title = {Wind Turbine Aerodynamics and Vorticity-Based Methods: Fundamentals and Recent Applications}, + year = {2017}, + publisher= {Springer International Publishing}, + doi={10.1007/978-3-319-55164-7}, + isbn={ 978-3-319-55163-0} +} + +@TECHREPORT{Garrel03_1, + author = {A. van Garrel}, + title = {Development of a Wind Turbine Aerodynamics Simulation Module}, + institution = {ECN}, + year = {2003}, + number = {ECN-C--03-079} +} + +@TECHREPORT{Kerwin:lecturenotes, + author = {J. Kerwin}, + title = {Lecture Notes Hydrofoil and propellers}, + institution = {M.I.T.}, + year = {2000} +} diff --git a/docs/source/user/aerodyn-olaf/index.rst b/docs/source/user/aerodyn-olaf/index.rst new file mode 100644 index 0000000000..d8b0fccc1f --- /dev/null +++ b/docs/source/user/aerodyn-olaf/index.rst @@ -0,0 +1,34 @@ +OLAF User's Guide and Theory Manual (Free Vortex Wake in AeroDyn15) +=================================================================== + +.. only:: html + + This document offers a quick reference guide for the free vortex wake module + named OLAF that is included in the AeroDyn module of OpenFAST. It is + intended to be used by the general user in combination with other features + of AeroDyn and other OpenFAST modules. The manual will be updated as new + releases are issued and as needed to provide further information on + advancements or modifications to the software. + + The documentaiton here was derived from the OLAF users manual by K. Shaler, + E. Branlard, and A. Platt. (`https://www.nrel.gov/docs/fy20osti/75959.pdf + `_) + + +.. toctree:: + :maxdepth: 2 + + Introduction.rst + Acronyms.rst + RunningOLAF.rst + InputFiles.rst + OutputFiles.rst + OLAFTheory.rst + StateSpace.rst + FutureWork.rst + zrefs.rst + AppendixA.rst + AppendixB.rst + AppendixC.rst + +.. Acknowledgments.rst diff --git a/docs/source/user/aerodyn-olaf/zrefs.rst b/docs/source/user/aerodyn-olaf/zrefs.rst new file mode 100644 index 0000000000..da9c3ea9fb --- /dev/null +++ b/docs/source/user/aerodyn-olaf/zrefs.rst @@ -0,0 +1,9 @@ +.. only:: html + + References + ---------- + +.. bibliography:: bibliography.bib + + + diff --git a/docs/source/user/aerodyn/examples/NodalOutputs.txt b/docs/source/user/aerodyn/examples/NodalOutputs.txt index 3445cec6ec..2e1f3ec9b2 100644 --- a/docs/source/user/aerodyn/examples/NodalOutputs.txt +++ b/docs/source/user/aerodyn/examples/NodalOutputs.txt @@ -3,46 +3,56 @@ END of input file (the word "END" must appear in the first 3 columns of this las 3 BldNd_BladesOut - Blades to output 99 BldNd_BlOutNd - Blade nodes on each blade (currently unused) OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx, AeroDyn_Nodes tab for a listing of available output channels, (-) -"VUndx" - x-component of undisturbed wind velocity at each node -"VUndy" - y-component of undisturbed wind velocity at each node -"VUndz" - z-component of undisturbed wind velocity at each node -"VDisx" - x-component of disturbed wind velocity at each node -"VDisy" - y-component of disturbed wind velocity at each node -"VDisz" - z-component of disturbed wind velocity at each node -"STVx" - x-component of structural translational velocity at each node -"STVy" - y-component of structural translational velocity at each node -"STVz" - z-component of structural translational velocity at each node -"VRel" - Relvative wind speed at each node -"DynP" - Dynamic pressure at each node -"Re" - Reynolds number (in millions) at each node -"M" - Mach number at each node -"Vindx" - Axial induced wind velocity at each node -"Vindy" - Tangential induced wind velocity at each node -"AxInd" - Axial induction factor at each node -"TnInd" - Tangential induction factor at each node -"Alpha" - Angle of attack at each node -"Theta" - Pitch+Twist angle at each node -"Phi" - Inflow angle at each node -"Curve" - Curvature angle at each node -"Cl" - Lift force coefficient at each node -"Cd" - Drag force coefficient at each node -"Cm" - Pitching moment coefficient at each node -"Cx" - Normal force (to plane) coefficient at each node -"Cy" - Tangential force (to plane) coefficient at each node -"Cn" - Normal force (to chord) coefficient at each node -"Ct" - Tangential force (to chord) coefficient at each node -"Fl" - Lift force per unit length at each node -"Fd" - Drag force per unit length at each node -"Mm" - Pitching moment per unit length at each node -"Fx" - Normal force (to plane) per unit length at each node -"Fy" - Tangential force (to plane) per unit length at each node -"Fn" - Normal force (to chord) per unit length at each node -"Ft" - Tangential force (to chord) per unit length at each node -"Clrnc" - Tower clearance at each node (based on the absolute distance to the nearest point in the tower from blade node B#N# minus the local tower radius, in the deflected configuration); please note that this clearance is only approximate because the calculation assumes that the blade is a line with no volume (however, the calculation does use the local tower radius); when blade node B#N# is above the tower top (or below the tower base), the absolute distance to the tower top (or base) minus the local tower radius, in the deflected configuration, is output -"Vx" - Local axial velocity -"Vy" - Local tangential velocity -"GeomPhi" - Geometric phi? If phi was solved using normal BEMT equations, GeomPhi = 1; otherwise, if it was solved geometrically, GeomPhi = 0. -"Chi" - Skew angle (used in skewed wake correction) -"UA_Flag" - Flag indicating if UA is turned on for this node. +"VUndx" - x-component of undisturbed wind velocity at each node +"VUndy" - y-component of undisturbed wind velocity at each node +"VUndz" - z-component of undisturbed wind velocity at each node +"VDisx" - x-component of disturbed wind velocity at each node +"VDisy" - y-component of disturbed wind velocity at each node +"VDisz" - z-component of disturbed wind velocity at each node +"STVx" - x-component of structural translational velocity at each node +"STVy" - y-component of structural translational velocity at each node +"STVz" - z-component of structural translational velocity at each node +"VRel" - Relvative wind speed at each node +"DynP" - Dynamic pressure at each node +"Re" - Reynolds number (in millions) at each node +"M" - Mach number at each node +"Vindx" - Axial induced wind velocity at each node +"Vindy" - Tangential induced wind velocity at each node +"AxInd" - Axial induction factor at each node +"TnInd" - Tangential induction factor at each node +"Alpha" - Angle of attack at each node +"Theta" - Pitch+Twist angle at each node +"Phi" - Inflow angle at each node +"Curve" - Curvature angle at each node +"Cl" - Lift force coefficient at each node +"Cd" - Drag force coefficient at each node +"Cm" - Pitching moment coefficient at each node +"Cx" - Normal force (to plane) coefficient at each node +"Cy" - Tangential force (to plane) coefficient at each node +"Cn" - Normal force (to chord) coefficient at each node +"Ct" - Tangential force (to chord) coefficient at each node +"Fl" - Lift force per unit length at each node +"Fd" - Drag force per unit length at each node +"Mm" - Pitching moment per unit length at each node +"Fx" - Normal force (to plane) per unit length at each node +"Fy" - Tangential force (to plane) per unit length at each node +"Fn" - Normal force (to chord) per unit length at each node +"Ft" - Tangential force (to chord) per unit length at each node +"Clrnc" - Tower clearance at each node (based on the absolute distance to the nearest point in the tower from blade node B#N# minus the local tower radius, in the deflected configuration); please note that this clearance is only approximate because the calculation assumes that the blade is a line with no volume (however, the calculation does use the local tower radius); when blade node B#N# is above the tower top (or below the tower base), the absolute distance to the tower top (or base) minus the local tower radius, in the deflected configuration, is output +"Vx" - Local axial velocity +"Vy" - Local tangential velocity +"GeomPhi" - Geometric phi? If phi was solved using normal BEMT equations, GeomPhi = 1; otherwise, if it was solved geometrically, GeomPhi = 0. +"Chi" - Skew angle (used in skewed wake correction) -- not available for OLAF +"UA_Flag" - Flag indicating if UA is turned on for this node. -- not available for OLAF +"CpMin" - Pressure coefficient +"SgCav" - Cavitation number +"SigCr" - Critical cavitation number +"Gam" - Gamma -- circulation on blade +"Cl_Static" - Static portion of lift force coefficient at each node, without unsteady effects -- not available for BEMT/DBEMT +"Cd_Static" - Static portion of drag force coefficient at each node, without unsteady effects -- not available for BEMT/DBEMT +"Cm_Static" - Static portion of pitching moment coefficient at each node, without unsteady effects -- not available for BEMT/DBEMT +"Uin" - Axial induced velocity in rotating hub coordinates. Axial aligned with hub axis. rotor plane polar hub rotating coordinates +"Uit" - Tangential induced velocity in rotating hub coordinates. Tangential to the rotation plane. Perpendicular to blade aziumth. rotor plane polar hub rotating coordinates +"Uir" - Radial induced velocity in rotating hub coordinates. Radial outwards in rotation plane. Aligned with blade azimuth. rotor plane polar hub rotating coordinates END of input file (the word "END" must appear in the first 3 columns of this last OutList line) --------------------------------------------------------------------------------------- diff --git a/docs/source/user/api_change.rst b/docs/source/user/api_change.rst index 8babd2852b..0c9f94b037 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -25,6 +25,8 @@ OpenFAST 47 TrimGain 0.001 TrimGain - Proportional gain f OpenFAST 48 Twr_Kdmp 0 Twr_Kdmp - Damping factor for the tower [used only if CalcSteady=True] (N/(m/s)) OpenFAST 49 Bld_Kdmp 0 Bld_Kdmp - Damping factor for the blades [used only if CalcSteady=True] (N/(m/s)) InflowWind 48 InitPosition(x) 0.0 InitPosition(x) - Initial offset in +x direction (shift of wind box) [Only used with WindType = 5] (m) +AeroDyn 33 [separator line] ====== OLAF -- cOnvecting LAgrangian Filaments (Free Vortex Wake) Theory Options ================== [used only when WakeMod=3] +AeroDyn 34 OLAFInputFileName "Elliptic_OLAF.dat" OLAFInputFileName - Input file for OLAF [used only when WakeMod=3] ============== ==== ================== ============================================================================================================================================================================= Additional nodal output channels added for :ref:`AeroDyn15`, diff --git a/docs/source/user/beamdyn/future_work.rst b/docs/source/user/beamdyn/future_work.rst index 495994fc44..5caef1945f 100644 --- a/docs/source/user/beamdyn/future_work.rst +++ b/docs/source/user/beamdyn/future_work.rst @@ -1,4 +1,4 @@ -.. _future-work: +.. _bd-future-work: Future Work =========== diff --git a/docs/source/user/beamdyn/input_files.rst b/docs/source/user/beamdyn/input_files.rst index b9c2cd7779..f5802607ef 100644 --- a/docs/source/user/beamdyn/input_files.rst +++ b/docs/source/user/beamdyn/input_files.rst @@ -1,4 +1,4 @@ -.. _input-files: +.. _bd-input-files: Input Files =========== diff --git a/docs/source/user/beamdyn/introduction.rst b/docs/source/user/beamdyn/introduction.rst index 3f6b8b5d30..95e54cfc36 100644 --- a/docs/source/user/beamdyn/introduction.rst +++ b/docs/source/user/beamdyn/introduction.rst @@ -103,9 +103,9 @@ independent between BeamDyn and AeroDyn. This document is organized as follows. Section :ref:`running-beamdyn` details how to obtain the BeamDyn and FAST software archives and run either the stand-alone version of BeamDyn or BeamDyn coupled to FAST. -Section :ref:`input-files` describes the BeamDyn input files. -Section :ref:`output-files` discusses the output files generated by +Section :ref:`bd-input-files` describes the BeamDyn input files. +Section :ref:`bd-output-files` discusses the output files generated by BeamDyn. Section :ref:`beamdyn-theory` summarizes the BeamDyn theory. -Section :ref:`future-work` outlines potential future work. Example input +Section :ref:`bd-future-work` outlines potential future work. Example input files are shown in Appendix :numref:`bd_input_files`. A summary of available output channels is found in Appendix :ref:`app-output-channel`. diff --git a/docs/source/user/beamdyn/output_files.rst b/docs/source/user/beamdyn/output_files.rst index dfbf5b2e87..82a13535fd 100644 --- a/docs/source/user/beamdyn/output_files.rst +++ b/docs/source/user/beamdyn/output_files.rst @@ -1,4 +1,4 @@ -.. _output-files: +.. _bd-output-files: Output Files ============ diff --git a/docs/source/user/beamdyn/running_bd.rst b/docs/source/user/beamdyn/running_bd.rst index 0f3d93cfc6..a2885315fc 100644 --- a/docs/source/user/beamdyn/running_bd.rst +++ b/docs/source/user/beamdyn/running_bd.rst @@ -62,7 +62,7 @@ use of a driver file in addition to the primary and blade BeamDyn input files. This driver file specifies inputs normally provided to BeamDyn by FAST, including motions of the blade root and externally applied loads. Both the BeamDyn summary file and the results output file are available -when using the stand-alone BeamDyn (see Section :ref:`output-files` for +when using the stand-alone BeamDyn (see Section :ref:`bd-output-files` for more information regarding the BeamDyn output files). Run the stand-alone BeamDyn software from a DOS command prompt by diff --git a/docs/source/user/beamdyn/theory.rst b/docs/source/user/beamdyn/theory.rst index 390ad0b03d..15ccb380b3 100644 --- a/docs/source/user/beamdyn/theory.rst +++ b/docs/source/user/beamdyn/theory.rst @@ -18,7 +18,7 @@ underlines only denote the dimension of the corresponding matrix. Coordinate Systems ------------------ -:numref:`blade-geometry` (in :numref:`input-files`) and +:numref:`blade-geometry` (in :numref:`bd-input-files`) and :numref:`bd-frame` show the coordinate system used in BeamDyn. .. _bd-frame: diff --git a/docs/source/user/index.rst b/docs/source/user/index.rst index fe619b8749..71baff0e24 100644 --- a/docs/source/user/index.rst +++ b/docs/source/user/index.rst @@ -14,6 +14,7 @@ Details on the transition from FAST v8 to OpenFAST may be found in :numref:`fast api_change.rst aerodyn/index.rst + aerodyn-olaf/index.rst beamdyn/index.rst elastodyn/index.rst fast_to_openfast.rst diff --git a/modules/aerodyn/CMakeLists.txt b/modules/aerodyn/CMakeLists.txt index ea3acc5ce0..030ac0e474 100644 --- a/modules/aerodyn/CMakeLists.txt +++ b/modules/aerodyn/CMakeLists.txt @@ -21,6 +21,7 @@ if (GENERATE_TYPES) generate_f90_types(src/DBEMT_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/DBEMT_Types.f90) generate_f90_types(src/UnsteadyAero_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/UnsteadyAero_Types.f90) generate_f90_types(src/AeroDyn_Driver_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/AeroDyn_Driver_Types.f90 -noextrap) + generate_f90_types(src/FVW_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/FVW_Types.f90) endif() # AeroDyn lib @@ -28,21 +29,54 @@ set(AD_LIBS_SOURCES src/AeroDyn.f90 src/AeroDyn_IO.f90 src/AeroDyn_AllBldNdOuts_IO.f90 - src/AirfoilInfo.f90 src/BEMT.f90 src/DBEMT.f90 src/BEMTUncoupled.f90 - src/UnsteadyAero.f90 src/mod_root1dim.f90 src/AeroDyn_Types.f90 - src/AirfoilInfo_Types.f90 src/BEMT_Types.f90 src/DBEMT_Types.f90 +) + +# UnsteadyAero lib +set(UA_LIBS_SOURCES + src/UnsteadyAero.f90 src/UnsteadyAero_Types.f90 ) +# AirFoil Info lib +set(AFINFO_LIBS_SOURCES + src/AirfoilInfo.f90 + src/AirfoilInfo_Types.f90 +) + +# FVW lib +set(FVW_LIBS_SOURCES + src/FVW.f90 + src/FVW_IO.f90 + src/FVW_VortexTools.f90 + src/FVW_Wings.f90 + src/FVW_Subs.f90 + src/FVW_BiotSavart.f90 + src/FVW_Tests.f90 + src/FVW_Types.f90 + src/FVW_VTK.f90 +) + +# UnsteadyAero lib +add_library(uaaerolib ${UA_LIBS_SOURCES}) +target_link_libraries(uaaerolib afinfolib nwtclibs) + +# AirfoilInfo lib +add_library(afinfolib ${AFINFO_LIBS_SOURCES}) +target_link_libraries(afinfolib nwtclibs) + +# this lib is only for the ctest +add_library(fvwlib ${FVW_LIBS_SOURCES}) +target_link_libraries(fvwlib uaaerolib afinfolib nwtclibs) + add_library(aerodynlib ${AD_LIBS_SOURCES}) -target_link_libraries(aerodynlib nwtclibs) +target_link_libraries(aerodynlib fvwlib uaaerolib afinfolib nwtclibs) # AeroDyn driver set(AD_DRIVER_SOURCES @@ -52,7 +86,7 @@ set(AD_DRIVER_SOURCES ) add_executable(aerodyn_driver ${AD_DRIVER_SOURCES}) -target_link_libraries(aerodyn_driver aerodynlib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) +target_link_libraries(aerodyn_driver aerodynlib fvwlib uaaerolib afinfolib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) # UnsteadyAero driver set(UA_DRIVER_SOURCES @@ -60,9 +94,9 @@ set(UA_DRIVER_SOURCES src/UA_Dvr_Subs.f90 ) add_executable(unsteadyaero_driver ${UA_DRIVER_SOURCES}) -target_link_libraries(unsteadyaero_driver aerodynlib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) +target_link_libraries(unsteadyaero_driver aerodynlib fvwlib uaaerolib afinfolib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) -install(TARGETS unsteadyaero_driver aerodyn_driver aerodynlib +install(TARGETS unsteadyaero_driver aerodyn_driver aerodynlib fvwlib uaaerolib afinfolib EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 6e19482989..8e950f85d1 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -28,6 +28,8 @@ module AeroDyn use AirfoilInfo use NWTC_LAPACK use UnsteadyAero + use FVW + use FVW_Subs, only: FVW_AeroOuts implicit none @@ -59,7 +61,6 @@ module AeroDyn ! states(z) PUBLIC :: AD_GetOP !< Routine to pack the operating point values (for linearization) into arrays - contains !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets the initialization output data structure, which contains data to be returned to the calling program (e.g., @@ -82,8 +83,8 @@ subroutine AD_SetInitOut(p, InputFileData, InitOut, errStat, errMsg) integer(IntKi) :: i, j, k, f integer(IntKi) :: NumCoords - ! Initialize variables for this routine + ! Initialize variables for this routine errStat = ErrID_None errMsg = "" @@ -307,18 +308,43 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! initialize BEMT after setting parameters and inputs because we are going to use the already- ! calculated node positions from the input meshes - call Init_BEMTmodule( InputFileData, u, m%BEMT_u(1), p, x%BEMT, xd%BEMT, z%BEMT, & - OtherState%BEMT, m%BEMT_y, m%BEMT, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if - - call BEMT_CopyInput( m%BEMT_u(1), m%BEMT_u(2), MESH_NEWCOPY, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - - + if (p%WakeMod /= WakeMod_FVW) then + call Init_BEMTmodule( InputFileData, u, m%BEMT_u(1), p, x%BEMT, xd%BEMT, z%BEMT, & + OtherState%BEMT, m%BEMT_y, m%BEMT, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if + + call BEMT_CopyInput( m%BEMT_u(1), m%BEMT_u(2), MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + endif + + !------------------------------------------------------------------------------------------------- + ! Initialize FVW module if it is used + !------------------------------------------------------------------------------------------------- + ! Unfortunately we do not know the interpolation order used by OpenFAST glue code at this point, + ! so we can't size things exactly. This means that we either must size too big here, or we must + ! resize in the FVW code at the first CalcOutput call. This is a bit problematic for efficiency + ! but not a complete deal-breaker. + if (p%WakeMod == WakeMod_FVW) then + if (.not. allocated(m%FVW_u)) Allocate(m%FVW_u(3)) !size(u))) + call Init_FVWmodule( InputFileData, u, m%FVW_u(1), p, x%FVW, xd%FVW, z%FVW, & + OtherState%FVW, m%FVW_y, m%FVW, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if + ! populate the rest of the FVW_u so that extrap-interp will work + do i=2,3 !size(u) + call FVW_CopyInput( m%FVW_u(1), m%FVW_u(i), MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + enddo + endif + + !............................................................................................ ! Define outputs here !............................................................................................ @@ -339,6 +365,13 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call Init_MiscVars(m, p, u, y, errStat2, errMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !............................................................................................ + ! Initialize other states + !............................................................................................ + ! The wake from FVW is stored in other states. This may not be the best place to put it! + call Init_OtherStates(m, p, OtherState, errStat2, errMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !............................................................................................ ! Define initialization output here !............................................................................................ @@ -420,9 +453,10 @@ subroutine AD_ReInit(p, x, xd, z, OtherState, m, Interval, ErrStat, ErrMsg ) ! 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 - - call BEMT_ReInit(p%BEMT,x%BEMT,xd%BEMT,z%BEMT,OtherState%BEMT,m%BEMT,p%AFI) - + + if (p%WakeMod /= WakeMod_FVW) & + call BEMT_ReInit(p%BEMT,x%BEMT,xd%BEMT,z%BEMT,OtherState%BEMT,m%BEMT,p%AFI) + end subroutine AD_ReInit !---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes (allocates) the misc variables for use during the simulation. @@ -439,7 +473,7 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) integer(intKi) :: k integer(intKi) :: ErrStat2 ! temporary Error status character(ErrMsgLen) :: ErrMsg2 ! temporary Error message - character(*), parameter :: RoutineName = 'Init_OtherStates' + character(*), parameter :: RoutineName = 'Init_MiscVars' ! Initialize variables for this routine @@ -522,6 +556,28 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) end subroutine Init_MiscVars !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine initializes (allocates) the misc variables for use during the simulation. +subroutine Init_OtherStates(m, p, OtherState, errStat, errMsg) + type(AD_MiscVarType), intent(in ) :: m !< misc/optimization data (not defined in submodules) + type(AD_ParameterType), intent(in ) :: p !< Parameters + type(AD_OtherStateType), intent(inout) :: OtherState !< Discrete states + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(intKi) :: ErrStat2 ! temporary Error status + character(ErrMsgLen) :: ErrMsg2 ! temporary Error message + character(*), parameter :: RoutineName = 'Init_OtherStates' + + errStat = ErrID_None + errMsg = "" + ! store Wake positions in otherstates. This may not be the best location + if (allocated(m%FVW%r_wind)) then + call AllocAry( OtherState%WakeLocationPoints, 3_IntKi, size(m%FVW%r_wind,DIM=2), ' OtherState%WakeLocationPoints', ErrStat2, ErrMsg2 ) ! must be same size as m%r_wind from FVW + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + OtherState%WakeLocationPoints = m%FVW%r_wind + endif +end subroutine Init_OtherStates +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes AeroDyn meshes and output array variables for use during the simulation. subroutine Init_y(y, u, p, errStat, errMsg) type(AD_OutputType), intent( out) :: y !< Module outputs @@ -944,8 +1000,10 @@ subroutine AD_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) ErrMsg = "" - ! Place any last minute operations or calculations here: - + ! End the FVW submodule + if (p%WakeMod == WakeMod_FVW ) then + call FVW_End( m%FVW_u, p%FVW, x%FVW, xd%FVW, z%FVW, OtherState%FVW, m%FVW_y, m%FVW, ErrStat, ErrMsg ) + endif ! Close files here: @@ -1018,6 +1076,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) call AD_Input_ExtrapInterp(u,utimes,uInterp,t+p%DT, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1025,6 +1084,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) ! 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) @@ -1032,11 +1092,28 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat call SetInputs(p, uInterp, m, 1, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - - ! Call into the BEMT update states NOTE: This is a non-standard framework interface!!!!! GJH - 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) - + + 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 + 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) + + else ! Call the FVW sub module + ! This needs to extract the inputs from the AD data types (mesh) and copy pieces for the FVW module + call SetInputsForFVW(p, u, m, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! Note: the setup is handled above in the SetInputs routine + call FVW_UpdateStates( t, n, m%FVW_u, utimes, p%FVW, x%FVW, xd%FVW, z%FVW, OtherState%FVW, p%AFI, m%FVW, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! The wind points are passed out as other states. These really correspond to the propogation of the vortex to the next wind position. + if (allocated(OtherState%WakeLocationPoints)) then + OtherState%WakeLocationPoints = m%FVW%r_wind + endif + ! UA TODO + !call UA_UpdateState_Wrapper(p%AFI, n, p%FVW, x%FVW, xd%FVW, OtherState%FVW, m%FVW, ErrStat2, ErrMsg2) + ! call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif call Cleanup() @@ -1071,6 +1148,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 integer, parameter :: indx = 1 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt integer(intKi) :: i integer(intKi) :: j @@ -1084,6 +1162,12 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, ErrStat = ErrID_None ErrMsg = "" +#ifdef UA_OUTS + ! if ( mod(REAL(t,ReKi),.1) < p%dt) then + if (allocated(m%FVW%y_UA%WriteOutput)) m%FVW%y_UA%WriteOutput = 0.0 !reset to zero in case UA shuts off mid-simulation + ! endif +#endif + if (present(NeedWriteOutput)) then CalcWriteOutput = NeedWriteOutput else @@ -1094,14 +1178,28 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, call SetInputs(p, u, m, indx, errStat2, errMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - ! Call the BEMT module CalcOutput. Notice that the BEMT outputs are purposely attached to AeroDyn's MiscVar structure to - ! avoid issues with the coupling code - - call BEMT_CalcOutput(t, m%BEMT_u(indx), p%BEMT, x%BEMT, xd%BEMT, z%BEMT, OtherState%BEMT, p%AFI, m%BEMT_y, m%BEMT, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - - call SetOutputsFromBEMT(p, m, y ) - + + if (p%WakeMod /= WakeMod_FVW) then + ! Call the BEMT module CalcOutput. Notice that the BEMT outputs are purposely attached to AeroDyn's MiscVar structure to + ! avoid issues with the coupling code + + call BEMT_CalcOutput(t, m%BEMT_u(indx), p%BEMT, x%BEMT, xd%BEMT, z%BEMT, OtherState%BEMT, p%AFI, m%BEMT_y, m%BEMT, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + call SetOutputsFromBEMT(p, m, y ) + + else !(p%WakeMod == WakeMod_FVW) + ! This needs to extract the inputs from the AD data types (mesh) and copy pieces for the FVW module + call SetInputsForFVW(p, (/u/), m, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + ! Calculate Outputs at time t + 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 SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif + if ( p%TwrAero ) then call ADTwr_CalcOutput(p, u, m, y, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1135,7 +1233,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, !------------------------------------------------------- if (CalcWriteOutput) then if (p%NumOuts > 0) then - call Calc_WriteOutput( p, u, m, y, OtherState, indx, ErrStat2, ErrMsg2 ) + call Calc_WriteOutput( p, u, m, y, OtherState, xd, indx, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) !............................................................................................................................... @@ -1156,6 +1254,12 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, end if +#ifdef UA_OUTS + ! if ( mod(REAL(t,ReKi),.1) < p%dt) then + if (allocated(m%FVW%y_UA%WriteOutput)) & + WRITE (69, '(F20.6,'//trim(num2lstr(size(m%FVW%y_UA%WriteOutput)))//'(:,1x,ES19.5E3))') t, ( m%FVW%y_UA%WriteOutput(i), i=1,size(m%FVW%y_UA%WriteOutput)) + ! end if +#endif end subroutine AD_CalcOutput @@ -1233,12 +1337,14 @@ subroutine SetInputs(p, u, m, indx, errStat, errMsg) else m%DisturbedInflow = u%InflowOnBlade end if - - ! This needs to extract the inputs from the AD data types (mesh) and massage them for the BEMT module - call SetInputsForBEMT(p, u, m, indx, errStat2, errMsg2) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - - + + if (p%WakeMod /= WakeMod_FVW) then + ! This needs to extract the inputs from the AD data types (mesh) and massage them for the BEMT module + call SetInputsForBEMT(p, u, m, indx, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif + + end subroutine SetInputs !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets m%BEMT_u(indx). @@ -1254,15 +1360,13 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) ! local variables real(ReKi) :: x_hat(3) real(ReKi) :: y_hat(3) - real(ReKi) :: z_hat(3) real(ReKi) :: x_hat_disk(3) real(ReKi) :: y_hat_disk(3) real(ReKi) :: z_hat_disk(3) real(ReKi) :: tmp(3) - real(R8Ki) :: theta(3) - real(R8Ki) :: orientation(3,3) - real(R8Ki) :: orientation_nopitch(3,3) real(ReKi) :: tmp_sz, tmp_sz_y + real(R8Ki) :: thetaBladeNds(p%NumBlNds,p%NumBlades) + real(R8Ki) :: Azimuth(p%NumBlades) integer(intKi) :: j ! loop counter for nodes integer(intKi) :: k ! loop counter for blades @@ -1271,34 +1375,13 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) character(*), parameter :: RoutineName = 'SetInputsForBEMT' - ErrStat = ErrID_None - ErrMsg = "" - - - ! calculate disk-averaged relative wind speed, V_DiskAvg - m%V_diskAvg = 0.0_ReKi - do k=1,p%NumBlades - do j=1,p%NumBlNds - tmp = m%DisturbedInflow(:,j,k) - u%BladeMotion(k)%TranslationVel(:,j) - m%V_diskAvg = m%V_diskAvg + tmp - end do - end do - m%V_diskAvg = m%V_diskAvg / real( p%NumBlades * p%NumBlNds, ReKi ) - - ! orientation vectors: - x_hat_disk = u%HubMotion%Orientation(1,:,1) !actually also x_hat_hub - - m%V_dot_x = dot_product( m%V_diskAvg, x_hat_disk ) + ! 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) + if (ErrStat >= AbortErrLev) return + + ! Velocity in disk normal m%BEMT_u(indx)%Un_disk = m%V_dot_x - tmp = m%V_dot_x * x_hat_disk - m%V_diskAvg - tmp_sz = TwoNorm(tmp) - if ( EqualRealNos( tmp_sz, 0.0_ReKi ) ) then - y_hat_disk = u%HubMotion%Orientation(2,:,1) - z_hat_disk = u%HubMotion%Orientation(3,:,1) - else - y_hat_disk = tmp / tmp_sz - z_hat_disk = cross_product( m%V_diskAvg, x_hat_disk ) / tmp_sz - end if ! "Angular velocity of rotor" rad/s m%BEMT_u(indx)%omega = dot_product( u%HubMotion%RotationVel(:,1), x_hat_disk ) @@ -1317,52 +1400,15 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) end if ! "Azimuth angle" rad - do k=1,p%NumBlades - z_hat = u%BladeRootMotion(k)%Orientation(3,:,1) - tmp_sz_y = -1.0*dot_product(z_hat,y_hat_disk) - tmp_sz = dot_product(z_hat,z_hat_disk) - if ( EqualRealNos(tmp_sz_y,0.0_ReKi) .and. EqualRealNos(tmp_sz,0.0_ReKi) ) then - m%BEMT_u(indx)%psi(k) = 0.0_ReKi - else - m%BEMT_u(indx)%psi(k) = atan2( tmp_sz_y, tmp_sz ) - end if - end do - + m%bemt_u(indx)%psi = Azimuth + ! theta, "Twist angle (includes all sources of twist)" rad ! Vx, "Local axial velocity at node" m/s ! Vy, "Local tangential velocity at node" m/s do k=1,p%NumBlades - - ! construct system equivalent to u%BladeRootMotion(k)%Orientation, but without the blade-pitch angle: - - !orientation = matmul( u%BladeRootMotion(k)%Orientation(:,:,1), transpose(u%HubMotion%Orientation(:,:,1)) ) - call LAPACK_gemm( 'n', 't', 1.0_R8Ki, u%BladeRootMotion(k)%Orientation(:,:,1), u%HubMotion%Orientation(:,:,1), 0.0_R8Ki, orientation, errStat2, errMsg2) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - theta = EulerExtract( orientation ) !hub_theta_root(k) - m%AllOuts( BPitch( k) ) = -theta(3)*R2D ! save this value of pitch for potential output - theta(3) = 0.0_ReKi - m%hub_theta_x_root(k) = theta(1) ! save this value for FAST.Farm - - orientation = EulerConstruct( theta ) - orientation_nopitch = matmul( orientation, u%HubMotion%Orientation(:,:,1) ) ! withoutPitch_theta_Root(k) - do j=1,p%NumBlNds - ! form coordinate system equivalent to u%BladeMotion(k)%Orientation(:,:,j) but without live sweep (due to in-plane - ! deflection), blade-pitch and twist (aerodynamic + elastic) angles: - - ! orientation = matmul( u%BladeMotion(k)%Orientation(:,:,j), transpose(orientation_nopitch) ) - call LAPACK_gemm( 'n', 't', 1.0_R8Ki, u%BladeMotion(k)%Orientation(:,:,j), orientation_nopitch, 0.0_R8Ki, orientation, errStat2, errMsg2) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - theta = EulerExtract( orientation ) !root(k)WithoutPitch_theta(j)_blade(k) - - m%BEMT_u(indx)%theta(j,k) = -theta(3) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade - - - theta(1) = 0.0_ReKi - theta(3) = 0.0_ReKi - m%Curve(j,k) = theta(2) ! save value for possible output later - m%WithoutSweepPitchTwist(:,:,j,k) = matmul( EulerConstruct( theta ), orientation_nopitch ) ! WithoutSweepPitch+Twist_theta(j)_Blade(k) + m%BEMT_u(indx)%theta(j,k) = thetaBladeNds(j,k) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade x_hat = m%WithoutSweepPitchTwist(1,:,j,k) y_hat = m%WithoutSweepPitchTwist(2,:,j,k) @@ -1395,6 +1441,172 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%BEMT_u(indx)%UserProp = u%UserProp 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) :: Azimuth(p%NumBlades) + real(ReKi) :: z_hat(3) + real(ReKi) :: tmp(3) + real(ReKi) :: tmp_sz, tmp_sz_y + integer(intKi) :: j ! loop counter for nodes + integer(intKi) :: k ! loop counter for blades + + ! calculate disk-averaged relative wind speed, V_DiskAvg + m%V_diskAvg = 0.0_ReKi + do k=1,p%NumBlades + do j=1,p%NumBlNds + tmp = m%DisturbedInflow(:,j,k) - u%BladeMotion(k)%TranslationVel(:,j) + m%V_diskAvg = m%V_diskAvg + tmp + end do + end do + m%V_diskAvg = m%V_diskAvg / real( p%NumBlades * p%NumBlNds, ReKi ) + + ! orientation vectors: + x_hat_disk = u%HubMotion%Orientation(1,:,1) !actually also x_hat_hub + + m%V_dot_x = dot_product( m%V_diskAvg, x_hat_disk ) + tmp = m%V_dot_x * x_hat_disk - m%V_diskAvg + tmp_sz = TwoNorm(tmp) + if ( EqualRealNos( tmp_sz, 0.0_ReKi ) ) then + y_hat_disk = u%HubMotion%Orientation(2,:,1) + z_hat_disk = u%HubMotion%Orientation(3,:,1) + else + y_hat_disk = tmp / tmp_sz + z_hat_disk = cross_product( m%V_diskAvg, x_hat_disk ) / tmp_sz + end if + + ! "Azimuth angle" rad + do k=1,p%NumBlades + z_hat = u%BladeRootMotion(k)%Orientation(3,:,1) + tmp_sz_y = -1.0*dot_product(z_hat,y_hat_disk) + tmp_sz = dot_product(z_hat,z_hat_disk) + if ( EqualRealNos(tmp_sz_y,0.0_ReKi) .and. EqualRealNos(tmp_sz,0.0_ReKi) ) then + Azimuth(k) = 0.0_ReKi + else + Azimuth(k) = atan2( tmp_sz_y, tmp_sz ) + 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 + type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables + real(R8Ki), intent( out) :: thetaBladeNds(p%NumBlNds,p%NumBlades) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(R8Ki) :: theta(3) + real(R8Ki) :: orientation(3,3) + real(R8Ki) :: orientation_nopitch(3,3) + + integer(intKi) :: j ! loop counter for nodes + integer(intKi) :: k ! loop counter for blades + integer(intKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'GeomWithoutSweepPitchTwist' + + ErrStat = ErrID_None + ErrMsg = "" + + ! theta, "Twist angle (includes all sources of twist)" rad + ! Vx, "Local axial velocity at node" m/s + ! Vy, "Local tangential velocity at node" m/s + do k=1,p%NumBlades + + ! construct system equivalent to u%BladeRootMotion(k)%Orientation, but without the blade-pitch angle: + + call LAPACK_gemm( 'n', 't', 1.0_R8Ki, u%BladeRootMotion(k)%Orientation(:,:,1), u%HubMotion%Orientation(:,:,1), 0.0_R8Ki, orientation, errStat2, errMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + theta = EulerExtract( orientation ) !hub_theta_root(k) + m%AllOuts( BPitch( k) ) = -theta(3)*R2D ! save this value of pitch for potential output + theta(3) = 0.0_ReKi + m%hub_theta_x_root(k) = theta(1) ! save this value for FAST.Farm + + orientation = EulerConstruct( theta ) + orientation_nopitch = matmul( orientation, u%HubMotion%Orientation(:,:,1) ) ! withoutPitch_theta_Root(k) + + do j=1,p%NumBlNds + + ! form coordinate system equivalent to u%BladeMotion(k)%Orientation(:,:,j) but without live sweep (due to in-plane + ! deflection), blade-pitch and twist (aerodynamic + elastic) angles: + + ! orientation = matmul( u%BladeMotion(k)%Orientation(:,:,j), transpose(orientation_nopitch) ) + call LAPACK_gemm( 'n', 't', 1.0_R8Ki, u%BladeMotion(k)%Orientation(:,:,j), orientation_nopitch, 0.0_R8Ki, orientation, errStat2, errMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + theta = EulerExtract( orientation ) !root(k)WithoutPitch_theta(j)_blade(k) + + thetaBladeNds(j,k) = -theta(3) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade + + + theta(1) = 0.0_ReKi + theta(3) = 0.0_ReKi + m%Curve(j,k) = theta(2) ! save value for possible output later + m%WithoutSweepPitchTwist(:,:,j,k) = matmul( EulerConstruct( theta ), orientation_nopitch ) ! WithoutSweepPitch+Twist_theta(j)_Blade(k) + + end do !j=nodes + end do !k=blades +end subroutine GeomWithoutSweepPitchTwist +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine sets m%FVW_u(indx). +subroutine SetInputsForFVW(p, u, m, errStat, errMsg) + + 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 + 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) :: thetaBladeNds(p%NumBlNds,p%NumBlades) + real(R8Ki) :: Azimuth(p%NumBlades) + + integer(intKi) :: tIndx + integer(intKi) :: k ! loop counter for blades + character(*), parameter :: RoutineName = 'SetInputsForFVW' + + do tIndx=1,size(u) + ! Get disk average values and orientations + ! NOTE: needed because it sets m%V_diskAvg and m%V_dot_x, needed by CalcOutput.. + call DiskAvgValues(p, u(tIndx), m, x_hat_disk, y_hat_disk, z_hat_disk, Azimuth) + call GeomWithoutSweepPitchTwist(p,u(tIndx),m,thetaBladeNds,ErrStat,ErrMsg) + if (ErrStat >= AbortErrLev) return + + ! Rather than use a meshcopy, we will just copy what we need to the WingsMesh + ! NOTE: MeshCopy requires the source mesh to be INOUT intent + ! NOTE2: If we change the WingsMesh to not be identical to the BladeMotion mesh, add the mapping stuff here. + do k=1,p%NumBlades + if ( u(tIndx)%BladeMotion(k)%nNodes /= m%FVW_u(tIndx)%WingsMesh(k)%nNodes ) then + ErrStat = ErrID_Fatal + ErrMsg = RoutineName//": WingsMesh contains different number of nodes than the BladeMotion mesh" + return + endif + m%FVW%PitchAndTwist(:,k) = thetaBladeNds(:,k) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade + m%FVW_u(tIndx)%WingsMesh(k)%TranslationDisp = u(tIndx)%BladeMotion(k)%TranslationDisp + m%FVW_u(tIndx)%WingsMesh(k)%Orientation = u(tIndx)%BladeMotion(k)%Orientation + m%FVW_u(tIndx)%WingsMesh(k)%TranslationVel = u(tIndx)%BladeMotion(k)%TranslationVel + m%FVW_u(tIndx)%HubPosition = u(tIndx)%HubMotion%Position(:,1) + u(tIndx)%HubMotion%TranslationDisp(:,1) + m%FVW_u(tIndx)%HubOrientation = u(tIndx)%HubMotion%Orientation(:,:,1) + enddo + if (ALLOCATED(m%FVW_u(tIndx)%V_wind)) then + m%FVW_u(tIndx)%V_wind = u(tIndx)%InflowWakeVel + ! Applying tower shadow to V_wind based on r_wind positions + ! NOTE: m%DisturbedInflow also contains tower shadow and we need it for CalcOutput + if (p%TwrPotent /= TwrPotent_none .or. p%TwrShadow) then + if (p%FVW%TwrShadowOnWake) then + call TwrInflArray( p, u(tIndx), m, m%FVW%r_wind, m%FVW_u(tIndx)%V_wind, ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) return + endif + end if + endif + enddo + m%FVW%Vwnd_ND = m%DisturbedInflow ! Nasty transfer for UA, but this is temporary, waiting for AeroDyn to handle UA +end subroutine SetInputsForFVW !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine converts outputs from BEMT (stored in m%BEMT_y) into values on the AeroDyn BladeLoad output mesh. subroutine SetOutputsFromBEMT(p, m, y ) @@ -1438,6 +1650,126 @@ subroutine SetOutputsFromBEMT(p, m, y ) 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 + 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_DiscreteStateType),intent(in ) :: xd !< Discrete states + type(AD_OutputType), intent(inout) :: y !< AD outputs + type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + integer(intKi) :: j ! loop counter for nodes + integer(intKi) :: k ! loop counter for blades + real(reki) :: force(3) + real(reki) :: moment(3) + real(reki) :: q + REAL(ReKi) :: cp, sp ! cosine, sine of phi + + ! Local vars for readability + real(ReKi) :: Vind(3) + real(ReKi) :: Vstr(3) + real(ReKi) :: Vwnd(3) + real(ReKi) :: theta + ! Local variables that we store in misc for nodal outputs + real(ReKi) :: AxInd, TanInd, Vrel, phi, alpha, Re + + type(AFI_OutputType) :: AFI_interp ! Resulting values from lookup table + real(ReKi) :: UrelWind_s(3) ! Relative wind (wind+str) in section coords + real(ReKi) :: Cx, Cy + real(ReKi) :: Cl_Static, Cd_Static, Cm_Static + real(ReKi) :: Cl_dyn, Cd_dyn, Cm_dyn + + integer(intKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat2 = 0 + ErrMsg2 = "" + + ! zero forces + force(3) = 0.0_ReKi + moment(1:2) = 0.0_ReKi + + ! set all blade outputs for all nodes (needed in nodal outputs) + ! This loop is separated from below in case we want to move it later. + do k=1,p%numBlades + do j=1,p%NumBlNds + ! --- Computing main aero variables from induction - setting local variables + Vind = m%FVW_y%Vind(1:3,j,k) + Vstr = u%BladeMotion(k)%TranslationVel(1:3,j) + Vwnd = m%DisturbedInflow(1:3,j,k) ! NOTE: contains tower shadow + theta = m%FVW%PitchAndTwist(j,k) + call FVW_AeroOuts( m%WithoutSweepPitchTwist(1:3,1:3,j,k), u%BladeMotion(k)%Orientation(1:3,1:3,j), & ! inputs + theta, Vstr(1:3), Vind(1:3), VWnd(1:3), p%KinVisc, p%FVW%Chord(j,k), & ! inputs + AxInd, TanInd, Vrel, phi, alpha, Re, UrelWind_s(1:3), ErrStat2, ErrMsg2 ) ! outputs + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'SetOutputsFromFVW') + + ! Compute steady Airfoil Coefs no matter what.. + call AFI_ComputeAirfoilCoefs( alpha, Re, 0.0_ReKi, p%AFI(p%FVW%AFindx(j,k)), AFI_interp, ErrStat, ErrMsg ) + Cl_Static = AFI_interp%Cl + 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 + + cp = cos(phi) + sp = sin(phi) + Cx = Cl_dyn*cp + Cd_dyn*sp + Cy = Cl_dyn*sp - Cd_dyn*cp + + q = 0.5 * p%airDens * Vrel**2 ! dynamic pressure of the jth node in the kth blade + force(1) = Cx * q * p%FVW%Chord(j,k) ! X = normal force per unit length (normal to the plane, not chord) of the jth node in the kth blade + force(2) = -Cy * q * p%FVW%Chord(j,k) ! Y = tangential force per unit length (tangential to the plane, not chord) of the jth node in the kth blade + moment(3)= Cm_dyn * q * p%FVW%Chord(j,k)**2 ! M = pitching moment per unit length of the jth node in the kth blade + + ! save these values for possible output later: + m%X(j,k) = force(1) + m%Y(j,k) = force(2) + m%M(j,k) = moment(3) + + ! note: because force and moment are 1-d arrays, I'm calculating the transpose of the force and moment outputs + ! so that I don't have to take the transpose of WithoutSweepPitchTwist(:,:,j,k) + y%BladeLoad(k)%Force(:,j) = matmul( force, m%WithoutSweepPitchTwist(:,:,j,k) ) ! force per unit length of the jth node in the kth blade + y%BladeLoad(k)%Moment(:,j) = matmul( moment, m%WithoutSweepPitchTwist(:,:,j,k) ) ! moment per unit length of the jth node in the kth blade + + ! Save results for outputs so we don't have to recalculate them all when we write outputs + m%FVW%BN_AxInd(j,k) = AxInd + m%FVW%BN_TanInd(j,k) = TanInd + m%FVW%BN_Vrel(j,k) = Vrel + m%FVW%BN_alpha(j,k) = alpha + m%FVW%BN_phi(j,k) = phi + m%FVW%BN_Re(j,k) = Re + m%FVW%BN_UrelWind_s(1:3,j,k) = UrelWind_s(1:3) + m%FVW%BN_Cl_Static(j,k) = Cl_Static + m%FVW%BN_Cd_Static(j,k) = Cd_Static + m%FVW%BN_Cm_Static(j,k) = Cm_Static + m%FVW%BN_Cl(j,k) = Cl_dyn + m%FVW%BN_Cd(j,k) = Cd_dyn + m%FVW%BN_Cm(j,k) = Cm_dyn + m%FVW%BN_Cx(j,k) = Cx + m%FVW%BN_Cy(j,k) = Cy + end do !j=nodes + end do !k=blades + + +end subroutine SetOutputsFromFVW !---------------------------------------------------------------------------------------------------------------------------------- !> This routine validates the inputs from the AeroDyn input files. SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) @@ -1463,9 +1795,9 @@ 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) then - call SetErrStat ( ErrID_Fatal, 'WakeMod must '//trim(num2lstr(WakeMod_None))//' (none), '//trim(num2lstr(WakeMod_BEMT))//' (BEMT),'// & - 'or '//trim(num2lstr(WakeMod_DBEMT))//' (DBEMT).', 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), '// & + trim(num2lstr(WakeMod_DBEMT))//' (DBEMT), or '//trim(num2lstr(WakeMod_FVW))//' (FVW).',ErrStat, ErrMsg, RoutineName ) end if if (InputFileData%AFAeroMod /= AFAeroMod_Steady .and. InputFileData%AFAeroMod /= AFAeroMod_BL_unsteady) then @@ -1487,7 +1819,7 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) ! BEMT/DBEMT inputs ! bjj: these checks should probably go into BEMT where they are used... - if (InputFileData%WakeMod /= WakeMod_none) then + if (InputFileData%WakeMod /= WakeMod_none .and. InputFileData%WakeMod /= WakeMod_FVW) then if ( InputFileData%MaxIter < 1 ) call SetErrStat( ErrID_Fatal, 'MaxIter must be greater than 0.', ErrStat, ErrMsg, RoutineName ) if ( InputFileData%IndToler < 0.0 .or. EqualRealNos(InputFileData%IndToler, 0.0_ReKi) ) & @@ -1618,8 +1950,8 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) call SetErrStat( ErrID_Fatal, 'Steady blade airfoil aerodynamics must be used for linearization. Set AFAeroMod=1.', ErrStat, ErrMsg, RoutineName ) end if - if (InputFileData%WakeMod == WakeMod_DBEMT) then - call SetErrStat( ErrID_Fatal, 'DBEMT cannot currently be used for linearization. Set WakeMod=0 or WakeMod=1.', ErrStat, ErrMsg, RoutineName ) + 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 ) end if end if @@ -1803,6 +2135,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. 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) ) @@ -1865,8 +2198,169 @@ subroutine Cleanup() call BEMT_DestroyInitInput( InitInp, ErrStat2, ErrMsg2 ) call BEMT_DestroyInitOutput( InitOut, ErrStat2, ErrMsg2 ) end subroutine Cleanup - END SUBROUTINE Init_BEMTmodule + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine initializes the FVW module from within AeroDyn. +SUBROUTINE Init_FVWmodule( InputFileData, u_AD, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + type(AD_InputFile), intent(in ) :: InputFileData !< All the data in the AeroDyn input file + type(AD_InputType), intent(inout) :: u_AD !< AD inputs - used for input mesh node positions (intent out for meshcopy) + type(FVW_InputType), intent( out) :: u !< An initial guess for the input; input mesh must be defined + type(AD_ParameterType), intent(inout) :: p !< Parameters ! intent out b/c we set the FVW parameters here + type(FVW_ContinuousStateType), intent( out) :: x !< Initial continuous states + type(FVW_DiscreteStateType), intent( out) :: xd !< Initial discrete states + type(FVW_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states + type(FVW_OtherStateType), intent( out) :: OtherState !< Initial other states + type(FVW_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated; + !! only the output mesh is initialized) + type(FVW_MiscVarType), intent( out) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + + + ! Local variables + real(DbKi) :: Interval ! Coupling interval in seconds: the rate that + ! (1) FVW_UpdateStates() is called in loose coupling & + ! (2) FVW_UpdateDiscState() is called in tight coupling. + ! Input is the suggested time from the glue code; + ! Output is the actual coupling interval that will be used + ! by the glue code. + type(FVW_InitInputType) :: InitInp ! Input data for initialization routine + type(FVW_InitOutputType) :: InitOut ! Output for initialization routine + + integer(intKi) :: j ! node index + integer(intKi) :: IB ! blade index + real(ReKi) :: tmp(3), tmp_sz_y, tmp_sz + real(ReKi) :: y_hat_disk(3) + real(ReKi) :: z_hat_disk(3) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Init_FVWmodule' + + ! note here that each blade is required to have the same number of nodes + + ErrStat = ErrID_None + ErrMsg = "" + + ! set initialization data here: + InitInp%FVWFileName = InputFileData%FVWFileName + InitInp%numBlades = p%numBlades + InitInp%numBladeNodes = p%numBlNds + InitInp%DTaero = p%DT ! NOTE: FVW can run a lower timestep internally + InitInp%KinVisc = p%KinVisc + InitInp%RootName = p%RootName(1:len_trim(p%RootName)-2) ! Removing "AD" + + ! NOTE: The following are not meshes + ! It's just the spanwise location. + ! Also, it is off compared to the initial position of the blade + ! Also, it's centered on the hub, but that's fine for now + call AllocAry(InitInp%Chord, InitInp%numBladeNodes,InitInp%numBlades,'chord', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(InitInp%AFindx,InitInp%numBladeNodes,InitInp%numBlades,'AFindx',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(InitInp%zHub, InitInp%numBlades,'zHub', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(InitInp%zLocal,InitInp%numBladeNodes,InitInp%numBlades,'zLocal',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(InitInp%rLocal,InitInp%numBladeNodes,InitInp%numBlades,'rLocal',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call AllocAry(InitInp%zTip, InitInp%numBlades,'zTip', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + if ( ErrStat >= AbortErrLev ) then + call Cleanup() + return + end if + + + ! Hub + do IB=1,p%numBlades + InitInp%zHub(IB) = TwoNorm( u_AD%BladeRootMotion(IB)%Position(:,1) - u_AD%HubMotion%Position(:,1) ) + if (EqualRealNos(InitInp%zHub(IB),0.0_ReKi) ) & + call SetErrStat( ErrID_Fatal, "zHub for blade "//trim(num2lstr(IB))//" is zero.", ErrStat, ErrMsg, RoutineName) + enddo + if (ErrStat >= AbortErrLev) then + call CleanUp() + RETURN + endif + + ! Distance along blade curve -- NOTE: this is an approximation. + do IB=1,p%numBlades + InitInp%zLocal(1,IB) = InitInp%zHub(IB) + TwoNorm( u_AD%BladeMotion(IB)%Position(:,1) - u_AD%BladeRootMotion(IB)%Position(:,1) ) + do j=2,p%NumBlNds + InitInp%zLocal(j,IB) = InitInp%zLocal(j-1,IB) + TwoNorm( u_AD%BladeMotion(IB)%Position(:,j) - u_AD%BladeMotion(IB)%Position(:,j-1) ) + end do !j=nodes + end do !IB=blades + + ! Blade tip curve distance + do IB=1,p%numBlades + InitInp%zTip(IB) = InitInp%zLocal(p%NumBlNds,IB) + end do !IB=blades + + ! Distance from blade to hub axis (includes hub radius) + y_hat_disk = u_AD%HubMotion%Orientation(2,:,1) + z_hat_disk = u_AD%HubMotion%Orientation(3,:,1) + do IB=1,p%numBlades + do j=1,p%NumBlNds + ! displaced position of the jth node in the kth blade relative to the hub: + tmp = u_AD%BladeMotion(IB)%Position(:,j) - u_AD%HubMotion%Position(:,1) + ! local radius (normalized distance from rotor centerline) + tmp_sz_y = dot_product( tmp, y_hat_disk )**2 + tmp_sz = dot_product( tmp, z_hat_disk )**2 + InitInp%rLocal(j,IB) = sqrt( tmp_sz + tmp_sz_y ) + end do !j=nodes + end do !IB=blades + + + ! Copy over chord information + do IB=1,p%numBlades + do j=1,p%NumBlNds + InitInp%Chord (j,IB) = InputFileData%BladeProps(IB)%BlChord(j) + InitInp%AFindx(j,IB) = InputFileData%BladeProps(IB)%BlAFID(j) + end do + end do + + ! Unsteady Aero Data + InitInp%UA_Flag = InputFileData%AFAeroMod == AFAeroMod_BL_unsteady + InitInp%UAMod = InputFileData%UAMod + InitInp%Flookup = InputFileData%Flookup + InitInp%a_s = InputFileData%SpdSound + + ! Copy the mesh over for InitInp to FVW. We would not need to copy this if we decided to break the Framework + ! by passing u_AD%BladeMotion directly into FVW_Init, but nothing is really gained by doing that. + ALLOCATE( InitInp%WingsMesh(p%NumBlades), STAT = ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat ( ErrID_Fatal, 'Could not allocate InitInp%WingsMesh (meshes)', ErrStat,ErrMsg,RoutineName ) + RETURN + END IF + DO IB = 1, p%NumBlades + CALL MeshCopy ( SrcMesh = u_AD%BladeMotion(IB) & + ,DestMesh = InitInp%WingsMesh(IB) & + ,CtrlCode = MESH_COUSIN & + ,Orientation = .TRUE. & + ,TranslationVel = .TRUE. & + ,RotationVel = .TRUE. & + ,ErrStat = ErrStat2 & + ,ErrMess = ErrMsg2 ) + CALL SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ) + IF (ErrStat >= AbortErrLev) RETURN + ENDDO + + ! NOTE: not passing p%AFI at present. We are not storing it in FVW's parameters. + call FVW_Init(p%AFI, InitInp, u, p%FVW, x, xd, z, OtherState, y, m, Interval, InitOut, ErrStat2, ErrMsg2 ) + CALL SetErrStat ( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! set the size of the input and xd arrays for passing wind info to FVW. + if (ALLOCATED(m%r_wind)) then + call AllocAry(u_AD%InflowWakeVel, 3, size(m%r_wind,DIM=2), 'InflowWakeVel', ErrStat2,ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + endif + + if (.not. equalRealNos(Interval, p%DT) ) & + call SetErrStat( ErrID_Fatal, "DTAero was changed in Init_FVWmodule(); this is not allowed yet.", ErrStat2, ErrMsg2, RoutineName) + +contains + subroutine Cleanup() + call FVW_DestroyInitInput( InitInp, ErrStat2, ErrMsg2 ) + call FVW_DestroyInitOutput( InitOut, ErrStat2, ErrMsg2 ) + end subroutine Cleanup +END SUBROUTINE Init_FVWmodule !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine calculates the tower loads for the AeroDyn TowerLoad output mesh. SUBROUTINE ADTwr_CalcOutput(p, u, m, y, ErrStat, ErrMsg ) @@ -2065,6 +2559,110 @@ SUBROUTINE TwrInfl( p, u, m, ErrStat, ErrMsg ) END SUBROUTINE TwrInfl !---------------------------------------------------------------------------------------------------------------------------------- +!> Calculate the tower influence on a array of points `Positions` (3xn) +!! The subroutine has side effecs and modifies the inflow +!! Relies heavily (i.e. unfortunate copy pasting), on TwrInfl +SUBROUTINE TwrInflArray( p, u, m, Positions, Inflow, ErrStat, ErrMsg ) + TYPE(AD_InputType), INTENT(IN ) :: u !< Inputs at Time t + TYPE(AD_ParameterType), INTENT(IN ) :: p !< Parameters + type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables + real(ReKi), dimension(:,:), INTENT(IN ) :: Positions !< Positions where tower influence is to be computed + real(ReKi), dimension(:,:), INTENT(INOUT) :: Inflow !< Undisturbed inflow (in) -> disturbed inflow (out) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! local variables + real(ReKi) :: xbar ! local x^ component of r_TowerBlade (distance from tower to blade) normalized by tower radius + real(ReKi) :: ybar ! local y^ component of r_TowerBlade (distance from tower to blade) normalized by tower radius + real(ReKi) :: zbar ! local z^ component of r_TowerBlade (distance from tower to blade) normalized by tower radius + real(ReKi) :: theta_tower_trans(3,3) ! transpose of local tower orientation expressed as a DCM + real(ReKi) :: TwrCd ! local tower drag coefficient + real(ReKi) :: W_tower ! local relative wind speed normal to the tower + real(ReKi) :: Pos(3) ! current point + real(ReKi) :: u_TwrShadow ! axial velocity deficit fraction from tower shadow + real(ReKi) :: u_TwrPotent ! axial velocity deficit fraction from tower potential flow + real(ReKi) :: v_TwrPotent ! transverse velocity deficit fraction from tower potential flow + real(ReKi) :: denom ! denominator + real(ReKi) :: v(3) ! temp vector + integer(IntKi) :: i ! loop counters for points + real(ReKi) :: TwrClrnc ! local tower clearance + real(ReKi) :: r_TowerBlade(3) ! distance vector from tower to blade + real(ReKi) :: TwrDiam ! local tower diameter + logical :: found + integer(intKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'TwrInflArray' + ErrStat = ErrID_None + ErrMsg = "" + + ! these models are valid for only small tower deflections; check for potential division-by-zero errors: + call CheckTwrInfl( u, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ); if (ErrStat >= AbortErrLev) return + + !$OMP PARALLEL default(shared) + !$OMP do private(i,Pos,r_TowerBlade,theta_tower_trans,W_tower,xbar,ybar,zbar,TwrCd,TwrClrnc,TwrDiam,found,denom,u_TwrPotent,v_TwrPotent,u_TwrShadow,v) schedule(runtime) + do i = 1, size(Positions,2) + Pos=Positions(1:3,i) + + ! Find nearest line2 element or node of the tower (see getLocalTowerProps) + ! values are found for the deflected tower, returning theta_tower, W_tower, xbar, ybar, zbar, and TowerCd: + ! option 1: nearest line2 element + call TwrInfl_NearestLine2Element(p, u, Pos, r_TowerBlade, theta_tower_trans, W_tower, xbar, ybar, zbar, TwrCd, TwrDiam, found) + if ( .not. found) then + ! option 2: nearest node + call TwrInfl_NearestPoint(p, u, Pos, r_TowerBlade, theta_tower_trans, W_tower, xbar, ybar, zbar, TwrCd, TwrDiam) + end if + TwrClrnc = TwoNorm(r_TowerBlade) - 0.5_ReKi*TwrDiam + + if ( TwrClrnc>20*TwrDiam) then + ! Far away, we skip the computation and keep undisturbed inflow + elseif ( TwrClrnc<=0.01_ReKi*TwrDiam) then + ! Inside the tower, or very close, (will happen for vortex elements) we keep undisturbed inflow + ! We don't want to reach the stagnation points + else + ! calculate tower influence: + if ( abs(zbar) < 1.0_ReKi .and. p%TwrPotent /= TwrPotent_none ) then + + if ( p%TwrPotent == TwrPotent_baseline ) then + denom = (xbar**2 + ybar**2)**2 + u_TwrPotent = ( -1.0*xbar**2 + ybar**2 ) / denom + v_TwrPotent = ( -2.0*xbar * ybar ) / denom + + elseif (p%TwrPotent == TwrPotent_Bak) then + xbar = xbar + 0.1 + denom = (xbar**2 + ybar**2)**2 + u_TwrPotent = ( -1.0*xbar**2 + ybar**2 ) / denom + v_TwrPotent = ( -2.0*xbar * ybar ) / denom + denom = TwoPi*(xbar**2 + ybar**2) + u_TwrPotent = u_TwrPotent + TwrCd*xbar / denom + v_TwrPotent = v_TwrPotent + TwrCd*ybar / denom + + end if + else + u_TwrPotent = 0.0_ReKi + v_TwrPotent = 0.0_ReKi + end if + + if ( p%TwrShadow .and. xbar > 0.0_ReKi .and. abs(zbar) < 1.0_ReKi) then + denom = sqrt( sqrt( xbar**2 + ybar**2 ) ) + if ( abs(ybar) < denom ) then + u_TwrShadow = -TwrCd / denom * cos( PiBy2*ybar / denom )**2 + else + u_TwrShadow = 0.0_ReKi + end if + else + u_TwrShadow = 0.0_ReKi + end if + + v(1) = (u_TwrPotent + u_TwrShadow)*W_tower + v(2) = v_TwrPotent*W_tower + v(3) = 0.0_ReKi + + Inflow(1:3,i) = Inflow(1:3,i) + matmul( theta_tower_trans, v ) + endif ! Check if point far away or in tower + enddo ! loop on points + !$OMP END DO + !$OMP END PARALLEL +END SUBROUTINE TwrInflArray +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine returns the tower constants necessary to compute the tower influence. !! if u%TowerMotion does not have any nodes there will be serious problems. I assume that has been checked earlier. SUBROUTINE getLocalTowerProps(p, u, BladeNodePosition, theta_tower_trans, W_tower, xbar, ybar, zbar, TwrCd, TwrClrnc, ErrStat, ErrMsg) diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index 78571099d2..fc4c73684c 100644 --- a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 @@ -27,7 +27,7 @@ MODULE AeroDyn_AllBldNdOuts_IO ! 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 12-Dec-2017 22:02:25. +! This code was generated by Write_ChckOutLst.m at 02-Jul-2020 11:33:13. ! NOTES: @@ -36,50 +36,61 @@ MODULE AeroDyn_AllBldNdOuts_IO ! Blade: - INTEGER(IntKi), PARAMETER :: BldNd_VUndx = 1 - INTEGER(IntKi), PARAMETER :: BldNd_VUndy = 2 - INTEGER(IntKi), PARAMETER :: BldNd_VUndz = 3 - INTEGER(IntKi), PARAMETER :: BldNd_VDisx = 4 - INTEGER(IntKi), PARAMETER :: BldNd_VDisy = 5 - INTEGER(IntKi), PARAMETER :: BldNd_VDisz = 6 - INTEGER(IntKi), PARAMETER :: BldNd_STVx = 7 - INTEGER(IntKi), PARAMETER :: BldNd_STVy = 8 - INTEGER(IntKi), PARAMETER :: BldNd_STVz = 9 - INTEGER(IntKi), PARAMETER :: BldNd_VRel = 10 - INTEGER(IntKi), PARAMETER :: BldNd_DynP = 11 - INTEGER(IntKi), PARAMETER :: BldNd_Re = 12 - INTEGER(IntKi), PARAMETER :: BldNd_M = 13 - INTEGER(IntKi), PARAMETER :: BldNd_Vindx = 14 - INTEGER(IntKi), PARAMETER :: BldNd_Vindy = 15 - INTEGER(IntKi), PARAMETER :: BldNd_AxInd = 16 - INTEGER(IntKi), PARAMETER :: BldNd_TnInd = 17 - INTEGER(IntKi), PARAMETER :: BldNd_Alpha = 18 - INTEGER(IntKi), PARAMETER :: BldNd_Theta = 19 - INTEGER(IntKi), PARAMETER :: BldNd_Phi = 20 - INTEGER(IntKi), PARAMETER :: BldNd_Curve = 21 - INTEGER(IntKi), PARAMETER :: BldNd_Cl = 22 - INTEGER(IntKi), PARAMETER :: BldNd_Cd = 23 - INTEGER(IntKi), PARAMETER :: BldNd_Cm = 24 - INTEGER(IntKi), PARAMETER :: BldNd_Cx = 25 - INTEGER(IntKi), PARAMETER :: BldNd_Cy = 26 - INTEGER(IntKi), PARAMETER :: BldNd_Cn = 27 - INTEGER(IntKi), PARAMETER :: BldNd_Ct = 28 - INTEGER(IntKi), PARAMETER :: BldNd_Fl = 29 - INTEGER(IntKi), PARAMETER :: BldNd_Fd = 30 - INTEGER(IntKi), PARAMETER :: BldNd_Mm = 31 - INTEGER(IntKi), PARAMETER :: BldNd_Fx = 32 - INTEGER(IntKi), PARAMETER :: BldNd_Fy = 33 - INTEGER(IntKi), PARAMETER :: BldNd_Fn = 34 - INTEGER(IntKi), PARAMETER :: BldNd_Ft = 35 - INTEGER(IntKi), PARAMETER :: BldNd_Clrnc = 36 - INTEGER(IntKi), PARAMETER :: BldNd_Vx = 37 - INTEGER(IntKi), PARAMETER :: BldNd_Vy = 38 - INTEGER(IntKi), PARAMETER :: BldNd_GeomPhi = 39 - INTEGER(IntKi), PARAMETER :: BldNd_Chi = 40 - INTEGER(IntKi), PARAMETER :: BldNd_UA_Flag = 41 + INTEGER(IntKi), PARAMETER :: BldNd_VUndx = 1 + INTEGER(IntKi), PARAMETER :: BldNd_VUndy = 2 + INTEGER(IntKi), PARAMETER :: BldNd_VUndz = 3 + INTEGER(IntKi), PARAMETER :: BldNd_VDisx = 4 + INTEGER(IntKi), PARAMETER :: BldNd_VDisy = 5 + INTEGER(IntKi), PARAMETER :: BldNd_VDisz = 6 + INTEGER(IntKi), PARAMETER :: BldNd_STVx = 7 + INTEGER(IntKi), PARAMETER :: BldNd_STVy = 8 + INTEGER(IntKi), PARAMETER :: BldNd_STVz = 9 + INTEGER(IntKi), PARAMETER :: BldNd_VRel = 10 + INTEGER(IntKi), PARAMETER :: BldNd_DynP = 11 + INTEGER(IntKi), PARAMETER :: BldNd_Re = 12 + INTEGER(IntKi), PARAMETER :: BldNd_M = 13 + INTEGER(IntKi), PARAMETER :: BldNd_Vindx = 14 + INTEGER(IntKi), PARAMETER :: BldNd_Vindy = 15 + INTEGER(IntKi), PARAMETER :: BldNd_AxInd = 16 + INTEGER(IntKi), PARAMETER :: BldNd_TnInd = 17 + INTEGER(IntKi), PARAMETER :: BldNd_Alpha = 18 + INTEGER(IntKi), PARAMETER :: BldNd_Theta = 19 + INTEGER(IntKi), PARAMETER :: BldNd_Phi = 20 + INTEGER(IntKi), PARAMETER :: BldNd_Curve = 21 + INTEGER(IntKi), PARAMETER :: BldNd_Cl = 22 + INTEGER(IntKi), PARAMETER :: BldNd_Cd = 23 + INTEGER(IntKi), PARAMETER :: BldNd_Cm = 24 + INTEGER(IntKi), PARAMETER :: BldNd_Cx = 25 + INTEGER(IntKi), PARAMETER :: BldNd_Cy = 26 + INTEGER(IntKi), PARAMETER :: BldNd_Cn = 27 + INTEGER(IntKi), PARAMETER :: BldNd_Ct = 28 + INTEGER(IntKi), PARAMETER :: BldNd_Fl = 29 + INTEGER(IntKi), PARAMETER :: BldNd_Fd = 30 + INTEGER(IntKi), PARAMETER :: BldNd_Mm = 31 + INTEGER(IntKi), PARAMETER :: BldNd_Fx = 32 + INTEGER(IntKi), PARAMETER :: BldNd_Fy = 33 + INTEGER(IntKi), PARAMETER :: BldNd_Fn = 34 + INTEGER(IntKi), PARAMETER :: BldNd_Ft = 35 + INTEGER(IntKi), PARAMETER :: BldNd_Clrnc = 36 + INTEGER(IntKi), PARAMETER :: BldNd_Vx = 37 + INTEGER(IntKi), PARAMETER :: BldNd_Vy = 38 + INTEGER(IntKi), PARAMETER :: BldNd_GeomPhi = 39 + INTEGER(IntKi), PARAMETER :: BldNd_Chi = 40 + INTEGER(IntKi), PARAMETER :: BldNd_UA_Flag = 41 + INTEGER(IntKi), PARAMETER :: BldNd_CpMin = 42 + INTEGER(IntKi), PARAMETER :: BldNd_SgCav = 43 + INTEGER(IntKi), PARAMETER :: BldNd_SigCr = 44 + INTEGER(IntKi), PARAMETER :: BldNd_Gam = 45 + INTEGER(IntKi), PARAMETER :: BldNd_Cl_Static = 46 + INTEGER(IntKi), PARAMETER :: BldNd_Cd_Static = 47 + INTEGER(IntKi), PARAMETER :: BldNd_Cm_Static = 48 + INTEGER(IntKi), PARAMETER :: BldNd_Uin = 49 + INTEGER(IntKi), PARAMETER :: BldNd_Uit = 50 + INTEGER(IntKi), PARAMETER :: BldNd_Uir = 51 + ! The maximum number of output channels which can be output by the code. - INTEGER(IntKi), PARAMETER, PUBLIC :: BldNd_MaxOutPts = 41 + INTEGER(IntKi), PARAMETER, PUBLIC :: BldNd_MaxOutPts = 51 !End of code generated by Matlab script ! =================================================================================================== @@ -119,6 +130,7 @@ SUBROUTINE AllBldNdOuts_InitOut( InitOut, p, InputFileData, ErrStat, ErrMsg ) ! Populate the header an unit lines for all blades and nodes ! First set a counter so we know where in the output array we are in + ! NOTE: we populate invalid names as well (some names are not valid outputs for certain configurations). That means we will have zeros in those values. INDX = p%NumOuts + 1 ! p%NumOuts is the number of outputs from the normal AeroDyn output. The WriteOutput array is sized to p%NumOuts + num(AllBldNdOuts) DO IdxChan=1,p%BldNd_NumOuts @@ -167,13 +179,28 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM INTEGER(IntKi) :: IdxNode ! Counter to the blade node we ae on INTEGER(IntKi) :: IdxChan ! Counter to the channel we are outputting. CHARACTER(*), PARAMETER :: RoutineName = 'Calc_WriteAllBldNdOutput' - REAL(ReKi) :: ct, st ! cosine, sine of theta - REAL(ReKi) :: cp, sp ! cosine, sine of phi + REAL(ReKi) :: ct, st ! cosine, sine of theta + REAL(ReKi) :: cp, sp ! cosine, sine of phi + real(ReKi) :: M_ph(3,3) ! Transformation from hub to "blade-rotor-plane": n,t,r (not the same as AeroDyn) + real(ReKi) :: M_pg(3,3,p%NumBlades) ! Transformation from global to "blade-rotor-plane" (n,t,r), with same x at hub coordinate system + real(ReKi) :: psi_hub ! Azimuth wrt hub + real(ReKi) :: Vind_g(3) ! Induced velocity vector in global coordinates + real(ReKi) :: Vind_s(3) ! Induced velocity vector in section coordinates (AeroDyn "x-y") + ! Initialize some things ErrMsg = '' ErrStat = ErrID_None + ! Precalculate the M_ph matrix -- no reason to recalculate for each output + DO IdxBlade=1,p%NumBlades + psi_hub = TwoPi*(real(IdxBlade-1,ReKi))/real(p%NumBlades,ReKi) + M_ph(1,1:3) = (/ 1.0_ReKi, 0.0_ReKi , 0.0_ReKi /) + M_ph(2,1:3) = (/ 0.0_ReKi, cos(psi_hub), sin(psi_hub) /) + M_ph(3,1:3) = (/ 0.0_ReKi,-sin(psi_hub), cos(psi_hub) /) + M_pg(1:3,1:3,IdxBlade) = matmul(M_ph, u%HubMotion%Orientation(1:3,1:3,1) ) + ENDDO + ! Populate the header an unit lines for all blades and nodes ! First set a counter so we know where in the output array we are in @@ -186,44 +213,37 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM SELECT CASE( p%BldNd_OutParam(IdxChan)%Indx ) ! Indx contains the information on what channel should be output CASE (0) ! Invalid channel + ! We still have headers for invalid channels. Need to account for that + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + END DO + END DO CYCLE - ! ***** Undisturbed wind velocity in local blade coord system ***** + + ! ***** Undisturbed wind velocity in local blade coord system ***** CASE ( BldNd_VUndx ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(1) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(1,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO CASE ( BldNd_VUndy ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(2) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(2,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO CASE ( BldNd_VUndz ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(3) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(3,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO @@ -234,37 +254,23 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM CASE ( BldNd_VDisx ) DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(1) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(1,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO CASE ( BldNd_VDisy ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(2) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(2,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO CASE ( BldNd_VDisz ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - !y%WriteOutput( OutIdx ) = Tmp3(3) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(3,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 END DO END DO @@ -272,22 +278,16 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM ! ***** Structural translational velocity in the local blade coordinate system ***** CASE ( BldNd_STVx ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - !y%WriteOutput( OutIdx ) = Tmp3(1) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(1,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) OutIdx = OutIdx + 1 END DO END DO CASE ( BldNd_STVy ) - DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - !y%WriteOutput( OutIdx ) = Tmp3(2) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(2,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) OutIdx = OutIdx + 1 END DO @@ -296,8 +296,6 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM CASE ( BldNd_STVz ) DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - !Tmp3 = matmul( m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - !y%WriteOutput( OutIdx ) = Tmp3(3) y%WriteOutput( OutIdx ) = dot_product( m%WithoutSweepPitchTwist(3,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) OutIdx = OutIdx + 1 END DO @@ -306,195 +304,394 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM ! Relative wind speed CASE ( BldNd_VRel ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Vrel(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Dynamic pressure CASE ( BldNd_DynP ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.5 * p%airDens * m%BEMT_y%Vrel(IdxNode,IdxBlade)**2 - OutIdx = OutIdx + 1 - END DO - END DO + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = 0.5 * p%airDens * m%BEMT_y%Vrel(IdxNode,IdxBlade)**2 + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = 0.5 * p%airDens * m%FVW%BN_Vrel(IdxNode,IdxBlade)**2 + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Reynolds number (in millions) CASE ( BldNd_Re ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = p%BEMT%chord(IdxNode,IdxBlade) * m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%KinVisc / 1.0E6 - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = p%BEMT%chord(IdxNode,IdxBlade) * m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%KinVisc / 1.0E6 + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Re(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Mach number CASE ( BldNd_M ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%SpdSound - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%SpdSound + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Vrel(IdxNode,IdxBlade) / p%SpdSound + OutIdx = OutIdx + 1 + END DO + END DO + endif + ! Axial and tangential induced wind velocity CASE ( BldNd_Vindx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = - m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) * m%BEMT_y%axInduction( IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = - m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) * m%BEMT_y%axInduction( IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = -m%FVW%BN_UrelWind_s(1,IdxNode,IdxBlade) * m%FVW%BN_AxInd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Vindy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) * m%BEMT_y%tanInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) * m%BEMT_y%tanInduction(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_UrelWind_s(2,IdxNode,IdxBlade) * m%FVW%BN_TanInd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Axial and tangential induction factors CASE ( BldNd_AxInd ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%axInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%axInduction(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_AxInd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_TnInd ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%tanInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%tanInduction(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_TanInd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif ! AoA, pitch+twist angle, inflow angle, and curvature angle CASE ( BldNd_Alpha ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = Rad2M180to180Deg( m%BEMT_y%phi(IdxNode,IdxBlade) - m%BEMT_u(Indx)%theta(IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = Rad2M180to180Deg( m%BEMT_y%phi(IdxNode,IdxBlade) - m%BEMT_u(Indx)%theta(IdxNode,IdxBlade) ) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_alpha(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Theta ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%PitchAndTwist(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Phi ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%phi(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%phi(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) =m%FVW%BN_phi(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Curve ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%Curve(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%Curve(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds +!NOT available in FVW yet + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Lift force, drag force, pitching moment coefficients CASE ( BldNd_Cl ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cl(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Cl(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Cl(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Cd ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cd(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Cd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Cd(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Cm ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cm(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Cm(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Cm(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif ! Normal force (to plane), tangential force (to plane) coefficients CASE ( BldNd_Cx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Cx(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif CASE ( BldNd_Cy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cy(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%Cy(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_Cy(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif ! Normal force (to chord), and tangential force (to chord) coefficients CASE ( BldNd_Cn ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade)*ct + m%BEMT_y%Cy(IdxNode,IdxBlade)*st - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade)*ct + m%BEMT_y%Cy(IdxNode,IdxBlade)*st + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! cos(theta) + st=sin(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! sin(theta) + y%WriteOutput( OutIdx ) = m%FVW%BN_Cx(IdxNode,IdxBlade)*ct + m%FVW%BN_Cy(IdxNode,IdxBlade)*st + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif CASE ( BldNd_Ct ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = -m%BEMT_y%Cx(IdxNode,IdxBlade)*st + m%BEMT_y%Cy(IdxNode,IdxBlade)*ct - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = -m%BEMT_y%Cx(IdxNode,IdxBlade)*st + m%BEMT_y%Cy(IdxNode,IdxBlade)*ct + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! cos(theta) + st=sin(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! sin(theta) + y%WriteOutput( OutIdx ) = -m%FVW%BN_Cx(IdxNode,IdxBlade)*st + m%FVW%BN_Cy(IdxNode,IdxBlade)*ct + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif ! Lift force, drag force, pitching moment CASE ( BldNd_Fl ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) - sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*cp - m%Y(IdxNode,IdxBlade)*sp - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) + sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*cp - m%Y(IdxNode,IdxBlade)*sp + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + cp=cos(m%FVW%BN_phi(IdxNode,IdxBlade)) + sp=sin(m%FVW%BN_phi(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*cp - m%Y(IdxNode,IdxBlade)*sp + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif CASE ( BldNd_Fd ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) - sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*sp + m%Y(IdxNode,IdxBlade)*cp - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) + sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*sp + m%Y(IdxNode,IdxBlade)*cp + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + cp=cos(m%FVW%BN_phi(IdxNode,IdxBlade)) + sp=sin(m%FVW%BN_phi(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*sp + m%Y(IdxNode,IdxBlade)*cp + OutIdx = OutIdx + 1 + END DO END DO - END DO + endif CASE ( BldNd_Mm ) DO IdxBlade=1,p%BldNd_BladesOut @@ -523,24 +720,46 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM ! Normal force (to chord), and tangential force (to chord) per unit length CASE ( BldNd_Fn ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*ct - m%Y(IdxNode,IdxBlade)*st - OutIdx = OutIdx + 1 - END DO - END DO + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*ct - m%Y(IdxNode,IdxBlade)*st + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! cos(theta) + st=sin(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! sin(theta) + y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*ct - m%Y(IdxNode,IdxBlade)*st + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Ft ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = -m%X(IdxNode,IdxBlade)*st - m%Y(IdxNode,IdxBlade)*ct - OutIdx = OutIdx + 1 - END DO - END DO + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = -m%X(IdxNode,IdxBlade)*st - m%Y(IdxNode,IdxBlade)*ct + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + ct=cos(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! cos(theta) + st=sin(m%FVW%PitchAndTwist(IdxNode,IdxBlade)) ! sin(theta) + y%WriteOutput( OutIdx ) = -m%X(IdxNode,IdxBlade)*st - m%Y(IdxNode,IdxBlade)*ct + OutIdx = OutIdx + 1 + END DO + END DO + endif ! Tower clearance (requires tower influence calculation): CASE ( BldNd_Clrnc ) @@ -562,62 +781,290 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, u, m, y, OtherState, Indx, ErrStat, ErrM CASE ( BldNd_Vx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = -m%FVW%BN_UrelWind_s(1,IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_Vy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + END DO END DO - END DO - - CASE ( BldNd_GeomPhi ) - if (allocated(OtherState%BEMT%ValidPhi)) then + else DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - if (OtherState%BEMT%ValidPhi(IdxNode,IdxBlade)) then - y%WriteOutput( OutIdx ) = 0.0_ReKi - else - y%WriteOutput( OutIdx ) = 1.0_ReKi - end if + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%FVW%BN_UrelWind_s(2,IdxNode,IdxBlade) OutIdx = OutIdx + 1 END DO - END DO + END DO + endif + + CASE ( BldNd_GeomPhi ) + if (p%WakeMod /= WakeMod_FVW) then + if (allocated(OtherState%BEMT%ValidPhi)) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + if (OtherState%BEMT%ValidPhi(IdxNode,IdxBlade)) then + y%WriteOutput( OutIdx ) = 0.0_ReKi + else + y%WriteOutput( OutIdx ) = 1.0_ReKi + end if + OutIdx = OutIdx + 1 + END DO + END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = 1.0_ReKi + OutIdx = OutIdx + 1 + END DO + END DO + end if else DO IdxBlade=1,p%BldNd_BladesOut DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 1.0_ReKi + y%WriteOutput( OutIdx ) = 0.0_ReKi ! Not valid for FVW OutIdx = OutIdx + 1 END DO END DO - end if + endif CASE ( BldNd_chi ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%chi(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds + y%WriteOutput( OutIdx ) = m%BEMT_y%chi(IdxNode,IdxBlade)*R2D + OutIdx = OutIdx + 1 + END DO END DO - END DO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,p%NumBlNds +!NOT available in FVW yet + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + END DO + END DO + endif CASE ( BldNd_UA_Flag ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes ! Note p%node_total is total number of nodes including all elements - IF ( OtherState%BEMT%UA_Flag(IdxNode, IdxBlade) ) THEN - y%WriteOutput( OutIdx ) = 1.0_ReKi - ELSE + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + IF ( OtherState%BEMT%UA_Flag(IdxNode, IdxBlade) ) THEN + y%WriteOutput( OutIdx ) = 1.0_ReKi + ELSE + y%WriteOutput( OutIdx ) = 0.0_ReKi + ENDIF + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + IF ( OtherState%FVW%UA_Flag(IdxNode, IdxBlade) ) THEN + y%WriteOutput( OutIdx ) = 1.0_ReKi + ELSE + y%WriteOutput( OutIdx ) = 0.0_ReKi + ENDIF + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! CpMin + CASE ( BldNd_CpMin ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%BEMT_y%Cpmin(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes +!NOT available in FVW yet y%WriteOutput( OutIdx ) = 0.0_ReKi - ENDIF + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! Cavitation + CASE ( BldNd_SgCav ) + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%SigmaCavit(IdxNode,IdxBlade) OutIdx = OutIdx + 1 ENDDO ENDDO - + + CASE ( BldNd_SigCr ) + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%SigmaCavitCrit(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + ENDDO + ENDDO + + ! circulation on blade + CASE ( BldNd_Gam ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = 0.5_ReKi * p%BEMT%chord(IdxNode,IdxBlade) * m%BEMT_y%Vrel(IdxNode,IdxBlade) * m%BEMT_y%Cl(IdxNode,IdxBlade) ! "Gam" [m^2/s] + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = 0.5_ReKi * p%FVW%Chord(IdxNode,IdxBlade) * m%FVW%BN_Vrel(IdxNode,IdxBlade) * m%FVW%BN_Cl(IdxNode,IdxBlade) ! "Gam" [m^2/s] + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + + !================================================ + ! Static portion of Cl, Cd, Cm (ignoring unsteady effects) + ! Cl_Static + CASE ( BldNd_Cl_Static ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes +!NOT available in BEMT/DBEMT yet + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%FVW%BN_Cl_Static(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! Cd_Static + CASE ( BldNd_Cd_Static ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes +!NOT available in BEMT/DBEMT yet + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%FVW%BN_Cd_Static(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! Cm_Static + CASE ( BldNd_Cm_Static ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes +!NOT available in BEMT/DBEMT yet + y%WriteOutput( OutIdx ) = 0.0_ReKi + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = m%FVW%BN_Cm_Static(IdxNode,IdxBlade) + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + + + !================================================ + ! Inductions in polar rotating hub coordinates + ! Axial induction, polar rotating hub coordinates + CASE ( BldNd_Uin ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) + Vind_g = matmul(Vind_s, m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = dot_product(M_pg(1,1:3,IdxBlade), Vind_g(1:3) ) ! Uihn, hub normal + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = dot_product(M_pg(1,1:3,IdxBlade), m%FVW_y%Vind(1:3,IdxNode,IdxBlade) ) ! Uihn, hub normal + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! Tangential induction, polar rotating hub coordinates + CASE ( BldNd_Uit ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) + Vind_g = matmul(Vind_s, m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = dot_product(M_pg(2,1:3,IdxBlade), Vind_g(1:3) ) ! Uiht, hub tangential + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = dot_product(M_pg(2,1:3,IdxBlade), m%FVW_y%Vind(1:3,IdxNode,IdxBlade) ) ! Uiht, hub tangential + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + + ! Radial induction, polar rotating hub coordinates + CASE ( BldNd_Uir ) + if (p%WakeMod /= WakeMod_FVW) then + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) + Vind_g = matmul(Vind_s, m%WithoutSweepPitchTwist(:,:,IdxNode,IdxBlade)) + y%WriteOutput( OutIdx ) = dot_product(M_pg(3,1:3,IdxBlade), Vind_g(1:3) ) ! Uihr, hub radial + OutIdx = OutIdx + 1 + ENDDO + ENDDO + else + DO IdxBlade=1,p%BldNd_BladesOut + DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + y%WriteOutput( OutIdx ) = dot_product(M_pg(3,1:3,IdxBlade), m%FVW_y%Vind(1:3,IdxNode,IdxBlade) ) ! Uihr, hub radial + OutIdx = OutIdx + 1 + ENDDO + ENDDO + endif + END SELECT @@ -718,7 +1165,7 @@ END SUBROUTINE AllBldNdOuts_SetParameters !! the sign is set to 0 if the channel is invalid. !! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here. !! -!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 12-Dec-2017 22:08:06. +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 02-Jul-2020 11:33:13. SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, ErrStat, ErrMsg ) !.................................................................................................................................. @@ -726,7 +1173,7 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, ErrStat, ErrMsg ) ! Passed variables - CHARACTER(ChanLen), INTENT(IN) :: BldNd_OutList(:) !< The list out user-requested outputs + CHARACTER(ChanLen), INTENT(IN) :: BldNd_OutList(:) !< The list out user-requested outputs TYPE(AD_ParameterType), INTENT(INOUT) :: p !< The module parameters INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status code CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if an error occurred @@ -742,30 +1189,30 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, ErrStat, ErrMsg ) CHARACTER(ChanLen) :: OutListTmp ! A string to temporarily hold OutList(I) CHARACTER(*), PARAMETER :: RoutineName = "BldNdOuts_SetOutParam" - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(41) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically - "ALPHA ","AXIND ","CD ","CHI ", & - "CL ","CLRNC ","CM ","CN ","CT ","CURVE ","CX ","CY ","DYNP ", & - "FD ","FL ","FN ","FT ","FX ","FY ","GEOMPHI ","M ","MM ", & - "PHI ","RE ","STVX ", & - "STVY ","STVZ ","THETA ","TNIND ","UA_FLAG ", & - "VDISX ","VDISY ","VDISZ ","VINDX ","VINDY ","VREL ","VUNDX ","VUNDY ","VUNDZ ", & - "VX ","VY "/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(41) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) - BldNd_Alpha , BldNd_AxInd , BldNd_Cd , BldNd_Chi , & - BldNd_Cl , BldNd_Clrnc , BldNd_Cm , BldNd_Cn , BldNd_Ct , BldNd_Curve , BldNd_Cx , BldNd_Cy , BldNd_DynP , & - BldNd_Fd , BldNd_Fl , BldNd_Fn , BldNd_Ft , BldNd_Fx , BldNd_Fy , BldNd_GeomPhi , BldNd_M , BldNd_Mm , & - BldNd_Phi , BldNd_Re , BldNd_STVx , & - BldNd_STVy , BldNd_STVz , BldNd_Theta , BldNd_TnInd , BldNd_UA_Flag , & - BldNd_VDisx , BldNd_VDisy , BldNd_VDisz , BldNd_Vindx , BldNd_Vindy , BldNd_VRel , BldNd_VUndx , BldNd_VUndy , BldNd_VUndz , & - BldNd_Vx , BldNd_Vy /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(41) = (/ & ! 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) ","(1/0) ","(-) ","(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) ", & - "(m/s) ","(m/s) "/) + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(51) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "ALPHA ","AXIND ","CD ","CD_STATIC","CHI ","CL ","CLRNC ","CL_STATIC", & + "CM ","CM_STATIC","CN ","CPMIN ","CT ","CURVE ","CX ","CY ", & + "DYNP ","FD ","FL ","FN ","FT ","FX ","FY ","GAM ", & + "GEOMPHI ","M ","MM ","PHI ","RE ","SGCAV ","SIGCR ","STVX ", & + "STVY ","STVZ ","THETA ","TNIND ","UA_FLAG ","UIN ","UIR ","UIT ", & + "VDISX ","VDISY ","VDISZ ","VINDX ","VINDY ","VREL ","VUNDX ","VUNDY ", & + "VUNDZ ","VX ","VY "/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(51) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + BldNd_Alpha , BldNd_AxInd , BldNd_Cd , BldNd_Cd_Static , BldNd_Chi , BldNd_Cl , BldNd_Clrnc , BldNd_Cl_Static , & + BldNd_Cm , BldNd_Cm_Static , BldNd_Cn , BldNd_CpMin , BldNd_Ct , BldNd_Curve , BldNd_Cx , BldNd_Cy , & + BldNd_DynP , BldNd_Fd , BldNd_Fl , BldNd_Fn , BldNd_Ft , BldNd_Fx , BldNd_Fy , BldNd_Gam , & + BldNd_GeomPhi , BldNd_M , BldNd_Mm , BldNd_Phi , BldNd_Re , BldNd_SgCav , BldNd_SigCr , BldNd_STVx , & + BldNd_STVy , BldNd_STVz , BldNd_Theta , BldNd_TnInd , BldNd_UA_Flag , BldNd_Uin , BldNd_Uir , BldNd_Uit , & + BldNd_VDisx , BldNd_VDisy , BldNd_VDisz , BldNd_Vindx , BldNd_Vindy , BldNd_VRel , BldNd_VUndx , BldNd_VUndy , & + BldNd_VUndz , BldNd_Vx , BldNd_Vy /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(51) = (/ & ! 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)", & + "(1/0) ","(-) ","(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) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) "/) ! Initialize values @@ -776,6 +1223,18 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, ErrStat, ErrMsg ) ! ..... Developer must add checking for invalid inputs here: ..... + ! The following are valid only for BEMT/DBEMT + if (p%WakeMod /= WakeMod_FVW) then + InvalidOutput( BldNd_Cl_Static ) = .true. + InvalidOutput( BldNd_Cd_Static ) = .true. + InvalidOutput( BldNd_Cm_Static ) = .true. + else + ! The following are invalid for free vortex wake + InvalidOutput( BldNd_Chi ) = .true. + InvalidOutput( BldNd_Curve ) = .true. + InvalidOutput( BldNd_CpMin ) = .true. + endif + ! ................. End of validity checking ................. @@ -829,5 +1288,4 @@ END SUBROUTINE BldNdOuts_SetOutParam !---------------------------------------------------------------------------------------------------------------------------------- !End of code generated by Matlab script !********************************************************************************************************************************** - END MODULE AeroDyn_AllBldNdOuts_IO diff --git a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 index a8ea597818..5b0ed59818 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 @@ -35,6 +35,7 @@ MODULE AeroDyn_Driver_Types USE UnsteadyAero_Types USE DBEMT_Types USE BEMT_Types +USE FVW_Types USE AeroDyn_Types USE NWTC_Library IMPLICIT NONE diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 1e471bded2..928597e43b 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -23,6 +23,8 @@ MODULE AeroDyn_IO use NWTC_Library use AeroDyn_Types use BEMTUncoupled, only : SkewMod_Uncoupled, SkewMod_PittPeters, VelocityIsZero + use AirFoilInfo, only : AFI_ComputeAirfoilCoefs + use FVW_Subs, only : FVW_AeroOuts USE AeroDyn_AllBldNdOuts_IO @@ -31,12 +33,13 @@ MODULE AeroDyn_IO type(ProgDesc), parameter :: AD_Ver = ProgDesc( 'AeroDyn', '', '' ) character(*), parameter :: AD_Nickname = 'AD' + ! =================================================================================================== ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" -! using the parameters listed in the "OutListParameters_RMurray.xlsx" Excel file. Any changes to these +! 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 16-Feb-2017 15:50:51. +! This code was generated by Write_ChckOutLst.m at 05-May-2020 06:44:07. ! Parameters related to output length (number of characters allowed in the output data headers): @@ -1227,31 +1230,58 @@ MODULE AeroDyn_IO INTEGER(IntKi), PARAMETER :: B3N7SgCav = 1165 INTEGER(IntKi), PARAMETER :: B3N8SgCav = 1166 INTEGER(IntKi), PARAMETER :: B3N9SgCav = 1167 + INTEGER(IntKi), PARAMETER :: B1N1Gam = 1168 + INTEGER(IntKi), PARAMETER :: B1N2Gam = 1169 + INTEGER(IntKi), PARAMETER :: B1N3Gam = 1170 + INTEGER(IntKi), PARAMETER :: B1N4Gam = 1171 + INTEGER(IntKi), PARAMETER :: B1N5Gam = 1172 + INTEGER(IntKi), PARAMETER :: B1N6Gam = 1173 + INTEGER(IntKi), PARAMETER :: B1N7Gam = 1174 + INTEGER(IntKi), PARAMETER :: B1N8Gam = 1175 + INTEGER(IntKi), PARAMETER :: B1N9Gam = 1176 + INTEGER(IntKi), PARAMETER :: B2N1Gam = 1177 + INTEGER(IntKi), PARAMETER :: B2N2Gam = 1178 + INTEGER(IntKi), PARAMETER :: B2N3Gam = 1179 + INTEGER(IntKi), PARAMETER :: B2N4Gam = 1180 + INTEGER(IntKi), PARAMETER :: B2N5Gam = 1181 + INTEGER(IntKi), PARAMETER :: B2N6Gam = 1182 + INTEGER(IntKi), PARAMETER :: B2N7Gam = 1183 + INTEGER(IntKi), PARAMETER :: B2N8Gam = 1184 + INTEGER(IntKi), PARAMETER :: B2N9Gam = 1185 + INTEGER(IntKi), PARAMETER :: B3N1Gam = 1186 + INTEGER(IntKi), PARAMETER :: B3N2Gam = 1187 + INTEGER(IntKi), PARAMETER :: B3N3Gam = 1188 + INTEGER(IntKi), PARAMETER :: B3N4Gam = 1189 + INTEGER(IntKi), PARAMETER :: B3N5Gam = 1190 + INTEGER(IntKi), PARAMETER :: B3N6Gam = 1191 + INTEGER(IntKi), PARAMETER :: B3N7Gam = 1192 + INTEGER(IntKi), PARAMETER :: B3N8Gam = 1193 + INTEGER(IntKi), PARAMETER :: B3N9Gam = 1194 ! Rotor: - INTEGER(IntKi), PARAMETER :: RtSpeed = 1168 - INTEGER(IntKi), PARAMETER :: RtTSR = 1169 - INTEGER(IntKi), PARAMETER :: RtVAvgxh = 1170 - INTEGER(IntKi), PARAMETER :: RtVAvgyh = 1171 - INTEGER(IntKi), PARAMETER :: RtVAvgzh = 1172 - INTEGER(IntKi), PARAMETER :: RtSkew = 1173 - INTEGER(IntKi), PARAMETER :: RtAeroFxh = 1174 - INTEGER(IntKi), PARAMETER :: RtAeroFyh = 1175 - INTEGER(IntKi), PARAMETER :: RtAeroFzh = 1176 - INTEGER(IntKi), PARAMETER :: RtAeroMxh = 1177 - INTEGER(IntKi), PARAMETER :: RtAeroMyh = 1178 - INTEGER(IntKi), PARAMETER :: RtAeroMzh = 1179 - INTEGER(IntKi), PARAMETER :: RtAeroPwr = 1180 - INTEGER(IntKi), PARAMETER :: RtArea = 1181 - INTEGER(IntKi), PARAMETER :: RtAeroCp = 1182 - INTEGER(IntKi), PARAMETER :: RtAeroCq = 1183 - INTEGER(IntKi), PARAMETER :: RtAeroCt = 1184 + INTEGER(IntKi), PARAMETER :: RtSpeed = 1195 + INTEGER(IntKi), PARAMETER :: RtTSR = 1196 + INTEGER(IntKi), PARAMETER :: RtVAvgxh = 1197 + INTEGER(IntKi), PARAMETER :: RtVAvgyh = 1198 + INTEGER(IntKi), PARAMETER :: RtVAvgzh = 1199 + INTEGER(IntKi), PARAMETER :: RtSkew = 1200 + INTEGER(IntKi), PARAMETER :: RtAeroFxh = 1201 + INTEGER(IntKi), PARAMETER :: RtAeroFyh = 1202 + INTEGER(IntKi), PARAMETER :: RtAeroFzh = 1203 + INTEGER(IntKi), PARAMETER :: RtAeroMxh = 1204 + INTEGER(IntKi), PARAMETER :: RtAeroMyh = 1205 + INTEGER(IntKi), PARAMETER :: RtAeroMzh = 1206 + INTEGER(IntKi), PARAMETER :: RtAeroPwr = 1207 + INTEGER(IntKi), PARAMETER :: RtArea = 1208 + INTEGER(IntKi), PARAMETER :: RtAeroCp = 1209 + INTEGER(IntKi), PARAMETER :: RtAeroCq = 1210 + INTEGER(IntKi), PARAMETER :: RtAeroCt = 1211 ! The maximum number of output channels which can be output by the code. - INTEGER(IntKi), PARAMETER :: MaxOutPts = 1184 + INTEGER(IntKi), PARAMETER :: MaxOutPts = 1211 !End of code generated by Matlab script ! =================================================================================================== @@ -1413,19 +1443,19 @@ MODULE AeroDyn_IO B3N1Cm,B3N2Cm,B3N3Cm,B3N4Cm,B3N5Cm,B3N6Cm,B3N7Cm,B3N8Cm,B3N9Cm & /), (/9, 3/) ) - INTEGER, PARAMETER :: BNCpmin(9, 3) = RESHAPE( (/ & ! pressure coefficient + INTEGER, PARAMETER :: BNCpmin(9, 3) = RESHAPE( (/ & ! pressure coefficient B1N1Cpmin,B1N2Cpmin,B1N3Cpmin,B1N4Cpmin,B1N5Cpmin,B1N6Cpmin,B1N7Cpmin,B1N8Cpmin,B1N9Cpmin, & B2N1Cpmin,B2N2Cpmin,B2N3Cpmin,B2N4Cpmin,B2N5Cpmin,B2N6Cpmin,B2N7Cpmin,B2N8Cpmin,B2N9Cpmin, & B3N1Cpmin,B3N2Cpmin,B3N3Cpmin,B3N4Cpmin,B3N5Cpmin,B3N6Cpmin,B3N7Cpmin,B3N8Cpmin,B3N9Cpmin & /), (/9, 3/) ) - INTEGER, PARAMETER :: BNSigCr(9, 3) = RESHAPE( (/ & ! Critical cavitation number + INTEGER, PARAMETER :: BNSigCr(9, 3) = RESHAPE( (/ & ! Critical cavitation number B1N1SigCr,B1N2SigCr,B1N3SigCr,B1N4SigCr,B1N5SigCr,B1N6SigCr,B1N7SigCr,B1N8SigCr,B1N9SigCr, & B2N1SigCr,B2N2SigCr,B2N3SigCr,B2N4SigCr,B2N5SigCr,B2N6SigCr,B2N7SigCr,B2N8SigCr,B2N9SigCr, & B3N1SigCr,B3N2SigCr,B3N3SigCr,B3N4SigCr,B3N5SigCr,B3N6SigCr,B3N7SigCr,B3N8SigCr,B3N9SigCr & /), (/9, 3/) ) - INTEGER, PARAMETER :: BNSgCav(9, 3) = RESHAPE( (/ & ! Cavitation number + INTEGER, PARAMETER :: BNSgCav(9, 3) = RESHAPE( (/ & ! Cavitation number B1N1SgCav,B1N2SgCav,B1N3SgCav,B1N4SgCav,B1N5SgCav,B1N6SgCav,B1N7SgCav,B1N8SgCav,B1N9SgCav, & B2N1SgCav,B2N2SgCav,B2N3SgCav,B2N4SgCav,B2N5SgCav,B2N6SgCav,B2N7SgCav,B2N8SgCav,B2N9SgCav, & B3N1SgCav,B3N2SgCav,B3N3SgCav,B3N4SgCav,B3N5SgCav,B3N6SgCav,B3N7SgCav,B3N8SgCav,B3N9SgCav & @@ -1491,35 +1521,71 @@ MODULE AeroDyn_IO B2N1Clrnc,B2N2Clrnc,B2N3Clrnc,B2N4Clrnc,B2N5Clrnc,B2N6Clrnc,B2N7Clrnc,B2N8Clrnc,B2N9Clrnc, & B3N1Clrnc,B3N2Clrnc,B3N3Clrnc,B3N4Clrnc,B3N5Clrnc,B3N6Clrnc,B3N7Clrnc,B3N8Clrnc,B3N9Clrnc & /), (/9, 3/) ) - + INTEGER, PARAMETER :: BNGam(9,3) = RESHAPE( (/ & ! Vorticity gamma + B1N1Gam,B1N2Gam,B1N3Gam,B1N4Gam,B1N5Gam,B1N6Gam,B1N7Gam,B1N8Gam,B1N9Gam, & + B2N1Gam,B2N2Gam,B2N3Gam,B2N4Gam,B2N5Gam,B2N6Gam,B2N7Gam,B2N8Gam,B2N9Gam, & + B3N1Gam,B3N2Gam,B3N3Gam,B3N4Gam,B3N5Gam,B3N6Gam,B3N7Gam,B3N8Gam,B3N9Gam & + /), (/9,3/) ) + INTEGER(IntKi), PARAMETER :: MaxBl = 3 ! Maximum number of blades allowed in simulation - ! model identifiers - integer(intKi), parameter :: ModelUnknown = -1 - - integer(intKi), parameter :: WakeMod_none = 0 - integer(intKi), parameter :: WakeMod_BEMT = 1 - integer(intKi), parameter :: WakeMod_DBEMT = 2 - - integer(intKi), parameter :: AFAeroMod_steady = 1 ! steady model - integer(intKi), parameter :: AFAeroMod_BL_unsteady = 2 ! Beddoes-Leishman unsteady model - - integer(intKi), parameter :: TwrPotent_none = 0 ! none - integer(intKi), parameter :: TwrPotent_baseline = 1 ! baseline potential flow - integer(intKi), parameter :: TwrPotent_Bak = 2 ! potential flow with Bak correction - + contains - +!> Compute maximum radius over all blades (contains hub radius), in "projected rotor plane" +!! Solely based on AD inputs, needed for FVW since rLocal is not stored +PURE REAL(ReKi) FUNCTION Calc_MaxRadius(p, u) result(rmax) + implicit none + TYPE(AD_ParameterType), INTENT(IN ) :: p !< The module parameters + TYPE(AD_InputType), INTENT(IN ) :: u !< Inputs + real(ReKi) :: y_hat_disk(3), z_hat_disk(3), dr_gl(3), rLocal + integer(IntKi) :: iB, j + y_hat_disk = u%HubMotion%Orientation(2,:,1) + z_hat_disk = u%HubMotion%Orientation(3,:,1) + rmax = 0.0_ReKi + do iB=1,p%numBlades + do j=1,p%NumBlNds + dr_gl = u%BladeMotion(iB)%Position(:,j) - u%HubMotion%Position(:,1) ! vector hub center to node j in global coord + rLocal = sqrt( dot_product(dr_gl, y_hat_disk)**2 + dot_product(dr_gl, z_hat_disk)**2 ) + rmax = max(rmax, rLocal) + end do !j=nodes + end do !iB=blades +END FUNCTION Calc_MaxRadius + +!> Rotor speed +PURE REAL(ReKi) FUNCTION Calc_Omega(u) + TYPE(AD_InputType), INTENT(IN ) :: u !< Inputs + Calc_Omega = dot_product(u%HubMotion%RotationVel(:,1), u%HubMotion%Orientation(1,:,1)) +END FUNCTION Calc_Omega + +!> Mean skew angle +REAL(ReKi) FUNCTION Calc_Chi0(V_diskAvg, V_dot_x) + implicit none + REAL(ReKi), INTENT(IN ) :: V_diskAvg(3) + REAL(ReKi), INTENT(IN ) :: V_dot_x + REAL(ReKi) :: V_norm, sy + V_norm = TwoNorm( V_diskAvg ) + if ( EqualRealNos( V_norm, 0.0_ReKi ) ) then + Calc_Chi0 = 0.0_ReKi + else + ! make sure we don't have numerical issues that make the ratio outside +/-1 + sy = min( 1.0_ReKi, V_dot_x / V_norm ) + sy = max( -1.0_ReKi, sy ) + Calc_Chi0 = acos( sy ) + end if +END FUNCTION Calc_Chi0 + + !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE Calc_WriteOutput( p, u, m, y, OtherState, indx, ErrStat, ErrMsg ) +SUBROUTINE Calc_WriteOutput( p, u, m, y, OtherState, xd, indx, ErrStat, ErrMsg ) TYPE(AD_ParameterType), INTENT(IN ) :: p ! The module parameters TYPE(AD_InputType), INTENT(IN ) :: u ! inputs TYPE(AD_MiscVarType), INTENT(INOUT) :: m ! misc variables TYPE(AD_OutputType), INTENT(IN ) :: y ! outputs - TYPE(AD_OtherStateType), INTENT(IN ) :: OtherState ! other states at t (for DBEMT debugging) + TYPE(AD_OtherStateType), INTENT(IN ) :: OtherState ! other states at t (for DBEMT and UA) + TYPE(AD_DiscreteStateType),INTENT(IN ) :: xd ! Discrete states integer, intent(in ) :: indx ! index into m%BEMT_u(indx) array; 1=t and 2=t+dt (but not checked here) INTEGER(IntKi), INTENT( OUT) :: ErrStat ! The error status code CHARACTER(*), INTENT( OUT) :: ErrMsg ! The error message, if an error occurred @@ -1561,79 +1627,14 @@ SUBROUTINE Calc_WriteOutput( p, u, m, y, OtherState, indx, ErrStat, ErrMsg ) m%AllOuts( TwNFdy( beta) ) = m%Y_Twr(j) end do ! out nodes - - ! blade outputs - do k=1,p%numBlades - m%AllOuts( BAzimuth(k) ) = m%BEMT_u(indx)%psi(k)*R2D - ! m%AllOuts( BPitch( k) ) = calculated in SetInputsForBEMT - - do beta=1,p%NBlOuts - - j=p%BlOutNd(beta) - - - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%InflowOnBlade(:,j,k) ) - m%AllOuts( BNVUndx(beta,k) ) = tmp(1) - m%AllOuts( BNVUndy(beta,k) ) = tmp(2) - m%AllOuts( BNVUndz(beta,k) ) = tmp(3) - - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), m%DisturbedInflow(:,j,k) ) - m%AllOuts( BNVDisx(beta,k) ) = tmp(1) - m%AllOuts( BNVDisy(beta,k) ) = tmp(2) - m%AllOuts( BNVDisz(beta,k) ) = tmp(3) - - tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%BladeMotion(k)%TranslationVel(:,j) ) - m%AllOuts( BNSTVx( beta,k) ) = tmp(1) - m%AllOuts( BNSTVy( beta,k) ) = tmp(2) - m%AllOuts( BNSTVz( beta,k) ) = tmp(3) - - m%AllOuts( BNVrel( beta,k) ) = m%BEMT_y%Vrel(j,k) - m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m%BEMT_y%Vrel(j,k)**2 - m%AllOuts( BNRe( beta,k) ) = p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) / p%KinVisc / 1.0E6 - m%AllOuts( BNM( beta,k) ) = m%BEMT_y%Vrel(j,k) / p%SpdSound - m%AllOuts( BNVIndx(beta,k) ) = - m%BEMT_u(indx)%Vx(j,k) * m%BEMT_y%axInduction( j,k) - m%AllOuts( BNVIndy(beta,k) ) = m%BEMT_u(indx)%Vy(j,k) * m%BEMT_y%tanInduction(j,k) - - m%AllOuts( BNAxInd(beta,k) ) = m%BEMT_y%axInduction(j,k) - m%AllOuts( BNTnInd(beta,k) ) = m%BEMT_y%tanInduction(j,k) + if (p%WakeMod /= WakeMod_FVW) then + call Calc_WriteOutput_BEMT + else + call Calc_WriteOutput_FVW + endif + - m%AllOuts( BNAlpha(beta,k) ) = Rad2M180to180Deg( m%BEMT_y%phi(j,k) - m%BEMT_u(indx)%theta(j,k) ) - m%AllOuts( BNTheta(beta,k) ) = m%BEMT_u(indx)%theta(j,k)*R2D - m%AllOuts( BNPhi( beta,k) ) = m%BEMT_y%phi(j,k)*R2D - m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D - - !m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cl(j,k) - !m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cd(j,k) - - m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(j,k) - m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) - m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) - - cp=cos(m%BEMT_y%phi(j,k)) - sp=sin(m%BEMT_y%phi(j,k)) - m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cx(j,k)*cp + m%BEMT_y%Cy(j,k)*sp - m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cx(j,k)*sp - m%BEMT_y%Cy(j,k)*cp - m%AllOuts( BNCm( beta,k) ) = m%BEMT_y%Cm(j,k) - m%AllOuts( BNCx( beta,k) ) = m%BEMT_y%Cx(j,k) - m%AllOuts( BNCy( beta,k) ) = m%BEMT_y%Cy(j,k) - - ct=cos(m%BEMT_u(indx)%theta(j,k)) - st=sin(m%BEMT_u(indx)%theta(j,k)) - m%AllOuts( BNCn( beta,k) ) = m%BEMT_y%Cx(j,k)*ct + m%BEMT_y%Cy(j,k)*st - m%AllOuts( BNCt( beta,k) ) =-m%BEMT_y%Cx(j,k)*st + m%BEMT_y%Cy(j,k)*ct - - m%AllOuts( BNFl( beta,k) ) = m%X(j,k)*cp - m%Y(j,k)*sp - m%AllOuts( BNFd( beta,k) ) = m%X(j,k)*sp + m%Y(j,k)*cp - m%AllOuts( BNMm( beta,k) ) = m%M(j,k) - m%AllOuts( BNFx( beta,k) ) = m%X(j,k) - m%AllOuts( BNFy( beta,k) ) = -m%Y(j,k) - m%AllOuts( BNFn( beta,k) ) = m%X(j,k)*ct - m%Y(j,k)*st - m%AllOuts( BNFt( beta,k) ) = -m%X(j,k)*st - m%Y(j,k)*ct - - end do ! nodes - end do ! blades - ! blade node tower clearance (requires tower influence calculation): if (p%TwrPotent /= TwrPotent_none .or. p%TwrShadow) then do k=1,p%numBlades @@ -1644,61 +1645,258 @@ SUBROUTINE Calc_WriteOutput( p, u, m, y, OtherState, indx, ErrStat, ErrMsg ) end do end if - ! rotor outputs: - rmax = 0.0_ReKi - do k=1,p%NumBlades - do j=1,p%NumBlNds - rmax = max(rmax, m%BEMT_u(indx)%rLocal(j,k) ) - end do !j=nodes - end do !k=blades - - m%AllOuts( RtSpeed ) = m%BEMT_u(indx)%omega*RPS2RPM - m%AllOuts( RtArea ) = pi*rmax**2 - - tmp = matmul( u%HubMotion%Orientation(:,:,1), m%V_DiskAvg ) - m%AllOuts( RtVAvgxh ) = tmp(1) - m%AllOuts( RtVAvgyh ) = tmp(2) - m%AllOuts( RtVAvgzh ) = tmp(3) - - m%AllOuts( RtSkew ) = m%BEMT_u(indx)%chi0*R2D - - ! integrate force/moments over blades by performing mesh transfer to hub point: - force = 0.0_ReKi - moment = 0.0_ReKi - do k=1,p%NumBlades - call Transfer_Line2_to_Point( y%BladeLoad(k), m%HubLoad, m%B_L_2_H_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%HubMotion ) - force = force + m%HubLoad%force( :,1) - moment = moment + m%HubLoad%moment(:,1) - end do - tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) - m%AllOuts( RtAeroFxh ) = tmp(1) - m%AllOuts( RtAeroFyh ) = tmp(2) - m%AllOuts( RtAeroFzh ) = tmp(3) - - tmp = matmul( u%HubMotion%Orientation(:,:,1), moment ) - m%AllOuts( RtAeroMxh ) = tmp(1) - m%AllOuts( RtAeroMyh ) = tmp(2) - m%AllOuts( RtAeroMzh ) = tmp(3) - - m%AllOuts( RtAeroPwr ) = m%BEMT_u(indx)%omega * m%AllOuts( RtAeroMxh ) - - - if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then - m%AllOuts( RtTSR ) = 0.0_ReKi - m%AllOuts( RtAeroCp ) = 0.0_ReKi - m%AllOuts( RtAeroCq ) = 0.0_ReKi - m%AllOuts( RtAeroCt ) = 0.0_ReKi - else - denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 - m%AllOuts( RtTSR ) = m%BEMT_u(indx)%omega * rmax / m%V_dot_x - - m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) - m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) - m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom - end if - !m%AllOuts( 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( BPitch( k) ) = calculated in SetInputsForBEMT + + do beta=1,p%NBlOuts + + j=p%BlOutNd(beta) + + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%InflowOnBlade(:,j,k) ) + m%AllOuts( BNVUndx(beta,k) ) = tmp(1) + m%AllOuts( BNVUndy(beta,k) ) = tmp(2) + m%AllOuts( BNVUndz(beta,k) ) = tmp(3) + + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), m%DisturbedInflow(:,j,k) ) + m%AllOuts( BNVDisx(beta,k) ) = tmp(1) + m%AllOuts( BNVDisy(beta,k) ) = tmp(2) + m%AllOuts( BNVDisz(beta,k) ) = tmp(3) + + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%BladeMotion(k)%TranslationVel(:,j) ) + m%AllOuts( BNSTVx( beta,k) ) = tmp(1) + m%AllOuts( BNSTVy( beta,k) ) = tmp(2) + m%AllOuts( BNSTVz( beta,k) ) = tmp(3) + + m%AllOuts( BNVrel( beta,k) ) = m%BEMT_y%Vrel(j,k) + m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m%BEMT_y%Vrel(j,k)**2 + m%AllOuts( BNRe( beta,k) ) = p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) / p%KinVisc / 1.0E6 + m%AllOuts( BNM( beta,k) ) = m%BEMT_y%Vrel(j,k) / p%SpdSound + + m%AllOuts( BNVIndx(beta,k) ) = - m%BEMT_u(indx)%Vx(j,k) * m%BEMT_y%axInduction( j,k) + m%AllOuts( BNVIndy(beta,k) ) = m%BEMT_u(indx)%Vy(j,k) * m%BEMT_y%tanInduction(j,k) + + m%AllOuts( BNAxInd(beta,k) ) = m%BEMT_y%axInduction(j,k) + m%AllOuts( BNTnInd(beta,k) ) = m%BEMT_y%tanInduction(j,k) + + m%AllOuts( BNAlpha(beta,k) ) = Rad2M180to180Deg( m%BEMT_y%phi(j,k) - m%BEMT_u(indx)%theta(j,k) ) + m%AllOuts( BNTheta(beta,k) ) = m%BEMT_u(indx)%theta(j,k)*R2D + m%AllOuts( BNPhi( beta,k) ) = m%BEMT_y%phi(j,k)*R2D + m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D + + !m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cl(j,k) + !m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cd(j,k) + + m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(j,k) + m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) + m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) + + cp=cos(m%BEMT_y%phi(j,k)) + sp=sin(m%BEMT_y%phi(j,k)) + m%AllOuts( BNCl( beta,k) ) = m%BEMT_y%Cx(j,k)*cp + m%BEMT_y%Cy(j,k)*sp + m%AllOuts( BNCd( beta,k) ) = m%BEMT_y%Cx(j,k)*sp - m%BEMT_y%Cy(j,k)*cp + m%AllOuts( BNCm( beta,k) ) = m%BEMT_y%Cm(j,k) + m%AllOuts( BNCx( beta,k) ) = m%BEMT_y%Cx(j,k) + m%AllOuts( BNCy( beta,k) ) = m%BEMT_y%Cy(j,k) + + ct=cos(m%BEMT_u(indx)%theta(j,k)) + st=sin(m%BEMT_u(indx)%theta(j,k)) + m%AllOuts( BNCn( beta,k) ) = m%BEMT_y%Cx(j,k)*ct + m%BEMT_y%Cy(j,k)*st + m%AllOuts( BNCt( beta,k) ) =-m%BEMT_y%Cx(j,k)*st + m%BEMT_y%Cy(j,k)*ct + + m%AllOuts( BNFl( beta,k) ) = m%X(j,k)*cp - m%Y(j,k)*sp + m%AllOuts( BNFd( beta,k) ) = m%X(j,k)*sp + m%Y(j,k)*cp + m%AllOuts( BNMm( beta,k) ) = m%M(j,k) + m%AllOuts( BNFx( beta,k) ) = m%X(j,k) + m%AllOuts( BNFy( beta,k) ) = -m%Y(j,k) + m%AllOuts( BNFn( beta,k) ) = m%X(j,k)*ct - m%Y(j,k)*st + m%AllOuts( BNFt( beta,k) ) = -m%X(j,k)*st - m%Y(j,k)*ct + + m%AllOuts( BNGam( beta,k) ) = 0.5_ReKi * p%BEMT%chord(j,k) * m%BEMT_y%Vrel(j,k) * m%BEMT_y%Cl(j,k) ! "Gam" [m^2/s] + end do ! nodes + end do ! blades + + ! rotor outputs: + rmax = 0.0_ReKi + do k=1,p%NumBlades + do j=1,p%NumBlNds + rmax = max(rmax, m%BEMT_u(indx)%rLocal(j,k) ) + end do !j=nodes + end do !k=blades + + m%AllOuts( RtSpeed ) = m%BEMT_u(indx)%omega*RPS2RPM + m%AllOuts( RtArea ) = pi*rmax**2 + + tmp = matmul( u%HubMotion%Orientation(:,:,1), m%V_DiskAvg ) + m%AllOuts( RtVAvgxh ) = tmp(1) + m%AllOuts( RtVAvgyh ) = tmp(2) + m%AllOuts( RtVAvgzh ) = tmp(3) + + m%AllOuts( RtSkew ) = m%BEMT_u(indx)%chi0*R2D + + ! integrate force/moments over blades by performing mesh transfer to hub point: + force = 0.0_ReKi + moment = 0.0_ReKi + do k=1,p%NumBlades + call Transfer_Line2_to_Point( y%BladeLoad(k), m%HubLoad, m%B_L_2_H_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%HubMotion ) + force = force + m%HubLoad%force( :,1) + moment = moment + m%HubLoad%moment(:,1) + end do + tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) + m%AllOuts( RtAeroFxh ) = tmp(1) + m%AllOuts( RtAeroFyh ) = tmp(2) + m%AllOuts( RtAeroFzh ) = tmp(3) + + tmp = matmul( u%HubMotion%Orientation(:,:,1), moment ) + m%AllOuts( RtAeroMxh ) = tmp(1) + m%AllOuts( RtAeroMyh ) = tmp(2) + m%AllOuts( RtAeroMzh ) = tmp(3) + + m%AllOuts( RtAeroPwr ) = m%BEMT_u(indx)%omega * m%AllOuts( RtAeroMxh ) + + + if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then + m%AllOuts( RtTSR ) = 0.0_ReKi + m%AllOuts( RtAeroCp ) = 0.0_ReKi + m%AllOuts( RtAeroCq ) = 0.0_ReKi + m%AllOuts( RtAeroCt ) = 0.0_ReKi + else + denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 + m%AllOuts( RtTSR ) = m%BEMT_u(indx)%omega * rmax / m%V_dot_x + + m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) + m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) + m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom + end if + 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) + !! Make sure these are set! + subroutine Calc_WriteOutput_FVW + + real(ReKi) :: rmax, omega + + ! blade outputs + do k=1,p%numBlades + do beta=1,p%NBlOuts + j=p%BlOutNd(beta) + + ! --- Setting AD outputs + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%InflowOnBlade(:,j,k) ) + m%AllOuts( BNVUndx(beta,k) ) = tmp(1) + m%AllOuts( BNVUndy(beta,k) ) = tmp(2) + m%AllOuts( BNVUndz(beta,k) ) = tmp(3) + + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), m%DisturbedInflow(:,j,k) ) + m%AllOuts( BNVDisx(beta,k) ) = tmp(1) + m%AllOuts( BNVDisy(beta,k) ) = tmp(2) + m%AllOuts( BNVDisz(beta,k) ) = tmp(3) + + tmp = matmul( m%WithoutSweepPitchTwist(:,:,j,k), u%BladeMotion(k)%TranslationVel(:,j) ) + m%AllOuts( BNSTVx( beta,k) ) = tmp(1) + m%AllOuts( BNSTVy( beta,k) ) = tmp(2) + m%AllOuts( BNSTVz( beta,k) ) = tmp(3) + + m%AllOuts( BNVrel( beta,k) ) = m%FVW%BN_Vrel(j,k) + m%AllOuts( BNDynP( beta,k) ) = 0.5 * p%airDens * m%FVW%BN_Vrel(j,k)**2 + m%AllOuts( BNRe( beta,k) ) = m%FVW%BN_Re(j,k) + m%AllOuts( BNM( beta,k) ) = m%FVW%BN_Vrel(j,k) / p%SpdSound + + m%AllOuts( BNVIndx(beta,k) ) = -m%FVW%BN_UrelWind_s(1,j,k) * m%FVW%BN_AxInd(j,k) + m%AllOuts( BNVIndy(beta,k) ) = m%FVW%BN_UrelWind_s(2,j,k) * m%FVW%BN_TanInd(j,k) + + m%AllOuts( BNAxInd(beta,k) ) = m%FVW%BN_AxInd(j,k) + m%AllOuts( BNTnInd(beta,k) ) = m%FVW%BN_TanInd(j,k) + + m%AllOuts( BNAlpha(beta,k) ) = m%FVW%BN_alpha(j,k)*R2D + m%AllOuts( BNTheta(beta,k) ) = m%FVW%PitchAndTwist(j,k)*R2D + m%AllOuts( BNPhi( beta,k) ) = m%FVW%BN_phi(j,k)*R2D +! m%AllOuts( BNCurve(beta,k) ) = m%Curve(j,k)*R2D ! TODO + +! m%AllOuts( BNCpmin( beta,k) ) = m%BEMT_y%Cpmin(j,k) ! TODO + m%AllOuts( BNSigCr( beta,k) ) = m%SigmaCavitCrit(j,k) + m%AllOuts( BNSgCav( beta,k) ) = m%SigmaCavit(j,k) + + m%AllOuts( BNCl( beta,k) ) = m%FVW%BN_Cl(j,k) + m%AllOuts( BNCd( beta,k) ) = m%FVW%BN_Cd(j,k) + m%AllOuts( BNCm( beta,k) ) = m%FVW%BN_Cm(j,k) + m%AllOuts( BNCx( beta,k) ) = m%FVW%BN_Cx(j,k) + m%AllOuts( BNCy( beta,k) ) = m%FVW%BN_Cy(j,k) + + ct=cos(m%FVW%PitchAndTwist(j,k)) ! cos(theta) + st=sin(m%FVW%PitchAndTwist(j,k)) ! sin(theta) + m%AllOuts( BNCn( beta,k) ) = m%FVW%BN_Cx(j,k)*ct + m%FVW%BN_Cy(j,k)*st + m%AllOuts( BNCt( beta,k) ) =-m%FVW%BN_Cx(j,k)*st + m%FVW%BN_Cy(j,k)*ct + + cp=cos(m%FVW%BN_phi(j,k)) + sp=sin(m%FVW%BN_phi(j,k)) + m%AllOuts( BNFl( beta,k) ) = m%X(j,k)*cp - m%Y(j,k)*sp + m%AllOuts( BNFd( beta,k) ) = m%X(j,k)*sp + m%Y(j,k)*cp + m%AllOuts( BNMm( beta,k) ) = m%M(j,k) + m%AllOuts( BNFx( beta,k) ) = m%X(j,k) + m%AllOuts( BNFy( beta,k) ) = -m%Y(j,k) + m%AllOuts( BNFn( beta,k) ) = m%X(j,k)*ct - m%Y(j,k)*st + m%AllOuts( BNFt( beta,k) ) = -m%X(j,k)*st - m%Y(j,k)*ct + + m%AllOuts( BNGam( beta,k) ) = 0.5_ReKi * p%FVW%Chord(j,k) * m%FVW%BN_Vrel(j,k) * m%FVW%BN_Cl(j,k) ! "Gam" [m^2/s] + end do ! nodes + end do ! blades + + ! Compute max radius and rotor speed + rmax = Calc_MaxRadius(p, u) + omega = Calc_Omega(u) + + m%AllOuts( RtSpeed ) = omega*RPS2RPM + m%AllOuts( RtArea ) = pi*rmax**2 + + tmp = matmul( u%HubMotion%Orientation(:,:,1), m%V_DiskAvg ) + m%AllOuts( RtVAvgxh ) = tmp(1) + m%AllOuts( RtVAvgyh ) = tmp(2) + m%AllOuts( RtVAvgzh ) = tmp(3) + + m%AllOuts( RtSkew ) = Calc_Chi0(m%V_diskAvg, m%V_dot_x) * R2D + + ! integrate force/moments over blades by performing mesh transfer to hub point: + force = 0.0_ReKi + moment = 0.0_ReKi + do k=1,p%NumBlades + call Transfer_Line2_to_Point( y%BladeLoad(k), m%HubLoad, m%B_L_2_H_P(k), ErrStat2, ErrMsg2, u%BladeMotion(k), u%HubMotion ) + force = force + m%HubLoad%force( :,1) + moment = moment + m%HubLoad%moment(:,1) + end do + tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) + m%AllOuts( RtAeroFxh ) = tmp(1) + m%AllOuts( RtAeroFyh ) = tmp(2) + m%AllOuts( RtAeroFzh ) = tmp(3) + + tmp = matmul( u%HubMotion%Orientation(:,:,1), moment ) + m%AllOuts( RtAeroMxh ) = tmp(1) + m%AllOuts( RtAeroMyh ) = tmp(2) + m%AllOuts( RtAeroMzh ) = tmp(3) + + m%AllOuts( RtAeroPwr ) = omega * m%AllOuts( RtAeroMxh ) + + if ( EqualRealNos( m%V_dot_x, 0.0_ReKi ) ) then + m%AllOuts( RtTSR ) = 0.0_ReKi + m%AllOuts( RtAeroCp ) = 0.0_ReKi + m%AllOuts( RtAeroCq ) = 0.0_ReKi + m%AllOuts( RtAeroCt ) = 0.0_ReKi + else + denom = 0.5*p%AirDens*m%AllOuts( RtArea )*m%V_dot_x**2 + m%AllOuts( RtTSR ) = omega * rmax / m%V_dot_x + m%AllOuts( RtAeroCp ) = m%AllOuts( RtAeroPwr ) / (denom * m%V_dot_x) + m%AllOuts( RtAeroCq ) = m%AllOuts( RtAeroMxh ) / (denom * rmax) + m%AllOuts( RtAeroCt ) = m%AllOuts( RtAeroFxh ) / denom + end if + + end subroutine Calc_WriteOutput_FVW END SUBROUTINE Calc_WriteOutput !---------------------------------------------------------------------------------------------------------------------------------- @@ -1921,8 +2119,8 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF - ! WakeMod - Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT} (-): - CALL ReadVar( UnIn, InputFile, InputFileData%WakeMod, "WakeMod", "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT} (-)", ErrStat2, ErrMsg2, UnEc) + ! WakeMod - Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW} (-): + CALL ReadVar( UnIn, InputFile, InputFileData%WakeMod, "WakeMod", "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW} (-)", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! AFAeroMod - Type of airfoil aerodynamics model {1=steady model, 2=Beddoes-Leishman unsteady model} (-): @@ -2002,11 +2200,11 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE CALL ReadCom( UnIn, InputFile, 'Section Header: Blade-Element/Momentum Theory Options', ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! SkewMod - Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} (-) [unused when WakeMod=0]: - CALL ReadVar( UnIn, InputFile, InputFileData%SkewMod, "SkewMod", "Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} (-) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! SkewMod - Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} (-) [unused when WakeMod={0|3}]: + CALL ReadVar( UnIn, InputFile, InputFileData%SkewMod, "SkewMod", "Type of skewed-wake correction model {1=uncoupled, 2=Pitt/Peters, 3=coupled} (-) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! SkewModFactor - Constant used in Pitt/Peters skewed wake model {or default is 15/32*pi} (-) [used only when WakeMod/=0 and SkewMod=2]: + ! SkewModFactor - Constant used in Pitt/Peters skewed wake model {or default is 15/32*pi} (-) [used only when WakeMod/={0|3} and SkewMod=2]: Line = "" CALL ReadVar( UnIn, InputFile, Line, "SkewModFactor", "Constant used in Pitt/Peters skewed wake model {or default} (-)", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -2021,29 +2219,29 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE END IF - ! TipLoss - Use the Prandtl tip-loss model? (flag) [unused when WakeMod=0]: - CALL ReadVar( UnIn, InputFile, InputFileData%TipLoss, "TipLoss", "Use the Prandtl tip-loss model? (flag) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! TipLoss - Use the Prandtl tip-loss model? (flag) [unused when WakeMod={0|3}]: + CALL ReadVar( UnIn, InputFile, InputFileData%TipLoss, "TipLoss", "Use the Prandtl tip-loss model? (flag) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! HubLoss - Use the Prandtl hub-loss model? (flag) [unused when WakeMod=0]: - CALL ReadVar( UnIn, InputFile, InputFileData%HubLoss, "HubLoss", "Use the Prandtl hub-loss model? (flag) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! HubLoss - Use the Prandtl hub-loss model? (flag) [unused when WakeMod={0|3}]: + CALL ReadVar( UnIn, InputFile, InputFileData%HubLoss, "HubLoss", "Use the Prandtl hub-loss model? (flag) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! TanInd - Include tangential induction in BEMT calculations? (flag) [unused when WakeMod=0]: - CALL ReadVar( UnIn, InputFile, InputFileData%TanInd, "TanInd", "Include tangential induction in BEMT calculations? (flag) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! TanInd - Include tangential induction in BEMT calculations? (flag) [unused when WakeMod={0|3}]: + CALL ReadVar( UnIn, InputFile, InputFileData%TanInd, "TanInd", "Include tangential induction in BEMT calculations? (flag) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! AIDrag - Include the drag term in the axial-induction calculation? (flag) [unused when WakeMod=0]: - CALL ReadVar( UnIn, InputFile, InputFileData%AIDrag, "AIDrag", "Include the drag term in the axial-induction calculation? (flag) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! AIDrag - Include the drag term in the axial-induction calculation? (flag) [unused when WakeMod={0|3}]: + CALL ReadVar( UnIn, InputFile, InputFileData%AIDrag, "AIDrag", "Include the drag term in the axial-induction calculation? (flag) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! TIDrag - Include the drag term in the tangential-induction calculation? (flag) [unused when WakeMod=0 or TanInd=FALSE]: - CALL ReadVar( UnIn, InputFile, InputFileData%TIDrag, "TIDrag", "Include the drag term in the tangential-induction calculation? (flag) [unused when WakeMod=0 or TanInd=FALSE]", ErrStat2, ErrMsg2, UnEc) + ! TIDrag - Include the drag term in the tangential-induction calculation? (flag) [unused when WakeMod={0|3} or TanInd=FALSE]: + CALL ReadVar( UnIn, InputFile, InputFileData%TIDrag, "TIDrag", "Include the drag term in the tangential-induction calculation? (flag) [unused when WakeMod={0|3} or TanInd=FALSE]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! IndToler - Convergence tolerance for BEM induction factors (or "default"] (-) [unused when WakeMod=0]: + ! IndToler - Convergence tolerance for BEM induction factors (or "default"] (-) [unused when WakeMod={0|3}]: Line = "" - CALL ReadVar( UnIn, InputFile, Line, "IndToler", "Convergence tolerance for BEM induction factors (-) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + CALL ReadVar( UnIn, InputFile, Line, "IndToler", "Convergence tolerance for BEM induction factors (-) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL Conv2UC( Line ) @@ -2060,8 +2258,8 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE END IF - ! MaxIter - Maximum number of iteration steps [unused when WakeMod=0] (-): - CALL ReadVar( UnIn, InputFile, InputFileData%MaxIter, "MaxIter", "Maximum number of iteration steps (-) [unused when WakeMod=0]", ErrStat2, ErrMsg2, UnEc) + ! MaxIter - Maximum number of iteration steps [unused when WakeMod={0|3}] (-): + CALL ReadVar( UnIn, InputFile, InputFileData%MaxIter, "MaxIter", "Maximum number of iteration steps (-) [unused when WakeMod={0|3}]", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! Return on error at end of section @@ -2084,6 +2282,15 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, ADBlFile, OutFileRoot, UnE CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !----------- FREE VORTEX WAKE (FVW) THEORY OPTIONS ------------------------------ + CALL ReadCom( UnIn, InputFile, 'Section Header: Free Vortex Wake (FVW) Theory Options', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + CALL ReadVar ( UnIn, InputFile, InputFileData%FVWFileName, 'FVWFile', 'FVW input file name', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( PathIsRelative( InputFileData%FVWFileName ) ) InputFileData%FVWFileName = TRIM(PriPath)//TRIM(InputFileData%FVWFileName) + + !----------- BEDDOES-LEISHMAN UNSTEADY AIRFOIL AERODYNAMICS OPTIONS ------------- CALL ReadCom( UnIn, InputFile, 'Section Header: Beddoes-Leishman Unsteady Airfoil Aerodynamics Options', ErrStat2, ErrMsg2, UnEc ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -2557,6 +2764,8 @@ SUBROUTINE AD_PrintSum( InputFileData, p, u, y, ErrStat, ErrMsg ) Msg = 'Blade-Element/Momentum Theory' case (WakeMod_DBEMT) Msg = 'Dynamic Blade-Element/Momentum Theory' + case (WakeMod_FVW) + Msg = 'Free Vortex Wake Theory' case (WakeMod_None) Msg = 'steady' case default @@ -2782,7 +2991,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 16-Feb-2017 15:50:51. +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 05-May-2020 06:44:07. SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) !.................................................................................................................................. @@ -2807,503 +3016,518 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) CHARACTER(ChanLen) :: OutListTmp ! A string to temporarily hold OutList(I) CHARACTER(*), PARAMETER :: RoutineName = "SetOutParam" - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1184) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + 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 ","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 ","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 ", & - "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 ","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 ","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 ","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 ","B1N7M ","B1N7MM ","B1N7PHI ","B1N7RE ","B1N7SGCAV", & + "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 ","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 ","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 ","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 ","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 ","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 ", & - "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 ","B2N5M ","B2N5MM ","B2N5PHI ", & + "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 ","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 ","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 ","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 ","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 ","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 ","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 ","B3N3M ", & + "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 ","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 ", & - "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 ","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 ","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 ","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 ","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(1184) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + "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 , 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 , 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 , & - 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 , 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 , 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 , 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 , B1N7M , B1N7Mm , B1N7Phi , B1N7Re , B1N7SgCav , & + 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 , 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 , 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 , 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 , 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 , 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 , & - 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 , B2N5M , B2N5Mm , B2N5Phi , & + 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 , 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 , 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 , 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 , 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 , 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 , 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 , B3N3M , & + 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 , 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 , & - 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 , 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 , 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 , 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 , 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(1184) = (/ & ! This lists the units corresponding to the allowed parameters + 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) ","(-) ", & - "(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) ","(-) ","(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) ", & + "(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) ","(-) ","(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) ","(-) ","(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) ","(-) ","(N-m/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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & + "(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) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ", & + "(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) ","(-) ","(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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & + "(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) ","(-) ", & - "(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) ","(-) ","(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) ", & + "(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) ","(-) ","(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) ","(-) ","(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) ","(-) ","(N-m/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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & + "(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) ","(-) ", & - "(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) ","(-) ","(N-m/m) ", & + "(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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & + "(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) ","(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ", & - "(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) ","(-) ","(N-m/m) ","(deg) ","(-) ", & + "(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) ", & - "(-) ","(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) ","(-) ","(N-m/m) ","(deg) ", & + "(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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ","(m/s) ", & + "(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) ", & - "(deg) ","(-) ","(-) ","(-) ","(m) ","(-) ","(-) ", & - "(-) ","(-) ","(deg) ","(-) ","(-) ","(Pa) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ","(N-m/m) ", & + "(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) ","(-) ","(N-m/m) ","(deg) ","(-) ","(-) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(m/s) ", & + "(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) ", & - "(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) ", & + "(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) ", & @@ -3313,13 +3537,7 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) "(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) "/) + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) "/) ! Initialize values @@ -3397,6 +3615,10 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) InvalidOutput( BNFn( :,i) ) = .true. InvalidOutput( BNFt( :,i) ) = .true. InvalidOutput( BNClrnc(:,i) ) = .true. + InvalidOutput( BNGam( :,i) ) = .true. + InvalidOutput( BNSgCav(:,i) ) = .true. + InvalidOutput( BNSigCr(:,i) ) = .true. + InvalidOutput( BNCpMin(:,i) ) = .true. END DO @@ -3438,6 +3660,10 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) InvalidOutput( BNFn( i,:) ) = .true. InvalidOutput( BNFt( i,:) ) = .true. InvalidOutput( BNClrnc(i,:) ) = .true. + InvalidOutput( BNGam( i,:) ) = .true. + InvalidOutput( BNSgCav(i,:) ) = .true. + InvalidOutput( BNSigCr(i,:) ) = .true. + InvalidOutput( BNCpMin(i,:) ) = .true. END DO diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index eef99eb9c4..842a3511d1 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -13,8 +13,21 @@ include Registry_NWTC_Library.txt usefrom AirfoilInfo_Registry.txt usefrom BEMT_Registry.txt +usefrom FVW_Registry.txt usefrom UnsteadyAero_Registry.txt +param AeroDyn/AD - IntKi ModelUnknown - -1 - "" - +param ^ - IntKi WakeMod_none - 0 - "Wake model - none" - +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" - + + # ..... Initialization data ....................................................................................................... # Define inputs that the initialization routine may need here: typedef AeroDyn/AD InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - @@ -61,7 +74,7 @@ typedef ^ InitOutputType ReKi TwrDiam {:} - - "Diameter of tower at node" m # ..... Primary Input file data ................................................................................................... typedef ^ AD_InputFile DbKi DTAero - - - "Time interval for aerodynamic calculations {or "default"}" s -typedef ^ AD_InputFile IntKi WakeMod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT}" - +typedef ^ AD_InputFile IntKi WakeMod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW}" - typedef ^ AD_InputFile IntKi AFAeroMod - - - "Type of blade airfoil aerodynamics model {1=steady model, 2=Beddoes-Leishman unsteady model}" - typedef ^ AD_InputFile IntKi TwrPotent - - - "Type tower influence on wind based on potential flow around the tower {0=none, 1=baseline potential flow, 2=potential flow with Bak correction}" - typedef ^ AD_InputFile LOGICAL TwrShadow - - - "Calculate tower influence on wind based on downstream tower shadow?" - @@ -92,6 +105,7 @@ typedef ^ AD_InputFile ReKi InCol_Cm - - - "The column in the airfoil tables tha typedef ^ AD_InputFile ReKi InCol_Cpmin - - - "The column in the airfoil tables that contains the drag coefficient; use zero if there is no Cpmin column" - typedef ^ AD_InputFile 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 ^ AD_InputFile IntKi NumAFfiles - - - "Number of airfoil files used" - +typedef ^ AD_InputFile CHARACTER(1024) FVWFileName - - - "FVW input filename" "quoted string" typedef ^ AD_InputFile CHARACTER(1024) AFNames {:} - - "Airfoil file names (NumAF lines)" "quoted strings" typedef ^ AD_InputFile LOGICAL UseBlCm - - - "Include aerodynamic pitching moment in calculations?" flag #typedef ^ AD_InputFile IntKi NumBlNds - - - "Number of blade nodes used in the analysis" - @@ -119,20 +133,28 @@ typedef ^ AD_InputFile IntKi BldNd_BladesOut - - - "The blades to output (AD # ..... States .................................................................................................................... # Define continuous (differentiable) states here: typedef ^ ContinuousStateType BEMT_ContinuousStateType BEMT - - - "Continuous states from the BEMT module" - +typedef ^ ContinuousStateType FVW_ContinuousStateType FVW - - - "Continuous states from the FVW module" - # Define discrete (nondifferentiable) states here: typedef ^ DiscreteStateType BEMT_DiscreteStateType BEMT - - - "Discrete states from the BEMT module" - +typedef ^ DiscreteStateType FVW_DiscreteStateType FVW - - - "Discrete states from the FVW module" - # Define constraint states here: typedef ^ ConstraintStateType BEMT_ConstraintStateType BEMT - - - "Constraint states from the BEMT module" - +typedef ^ ConstraintStateType FVW_ConstraintStateType FVW - - - "Constraint states from the FVW module" - # Define "other" states here: typedef ^ OtherStateType BEMT_OtherStateType BEMT - - - "OtherStates from the BEMT module" - +typedef ^ OtherStateType FVW_OtherStateType FVW - - - "OtherStates from the FVW module" - +typedef ^ OtherStateType ReKi WakeLocationPoints {:}{:} - - "wake points velocity" m/s # Define misc/optimization variables (any data that are not considered actual states) here: typedef ^ MiscVarType BEMT_MiscVarType BEMT - - - "MiscVars from the BEMT module" - typedef ^ MiscVarType BEMT_OutputType BEMT_y - - - "Outputs from the BEMT module" - typedef ^ MiscVarType BEMT_InputType BEMT_u 2 - - "Inputs to the BEMT module" - +typedef ^ MiscVarType FVW_MiscVarType FVW - - - "MiscVars from the FVW module" - +typedef ^ MiscVarType FVW_OutputType FVW_y - - - "Outputs from the FVW module" - +typedef ^ MiscVarType FVW_InputType FVW_u : - - "Inputs to the FVW module" - typedef ^ MiscVarType ReKi DisturbedInflow {:}{:}{:} - - "InflowOnBlade values modified by tower influence" m/s typedef ^ MiscVarType ReKi WithoutSweepPitchTwist {:}{:}{:}{:} - - "Coordinate system equivalent to BladeMotion Orientation, but without live sweep, blade-pitch, and twist angles" - typedef ^ MiscVarType ReKi AllOuts {:} - - "An array holding the value of all of the calculated (not only selected) output channels" - @@ -157,7 +179,7 @@ typedef ^ MiscVarType Logical CavitWarnSet {:}{:} - - "cavitation warning issu # 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 WakeMod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT}" - +typedef ^ ParameterType IntKi WakeMod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW}" - typedef ^ ParameterType IntKi TwrPotent - - - "Type tower influence on wind based on potential flow around the tower {0=none, 1=baseline potential flow, 2=potential flow with Bak correction}" - typedef ^ ParameterType LOGICAL TwrShadow - - - "Calculate tower influence on wind based on downstream tower shadow?" - typedef ^ ParameterType LOGICAL TwrAero - - - "Calculate tower aerodynamic loads?" flag @@ -177,6 +199,7 @@ typedef ^ ParameterType ReKi Pvap - - - "Vapour pressure" Pa typedef ^ ParameterType ReKi FluidDepth - - - "Submerged hub height" m typedef ^ ParameterType AFI_ParameterType AFI {:} - - "AirfoilInfo parameters" typedef ^ ParameterType BEMT_ParameterType BEMT - - - "Parameters for BEMT module" +typedef ^ ParameterType FVW_ParameterType FVW - - - "Parameters for FVW module" # parameters for output typedef ^ ParameterType IntKi NumOuts - - - "Number of parameters in the output list (number of outputs requested)" - typedef ^ ParameterType CHARACTER(1024) RootName - - - "RootName for writing output files" - @@ -207,6 +230,7 @@ typedef ^ InputType MeshType BladeMotion {:} - - "motion on each blade" - typedef ^ InputType ReKi InflowOnBlade {:}{:}{:} - - "U,V,W at nodes on each blade (note if we change the requirement that NumNodes is the same for each blade, this will need to change)" m/s typedef ^ InputType ReKi InflowOnTower {:}{:} - - "U,V,W at nodes on the tower" m/s typedef ^ InputType ReKi UserProp {:}{:} - - "Optional user property for interpolating airfoils (per element per blade)" - +typedef ^ InputType ReKi InflowWakeVel {:}{:} - - "U,V,W at wake points" m/s # ..... Outputs ................................................................................................................... # Define outputs that are contained on the mesh here: diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 1c921c6754..38e27319f5 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -35,8 +35,19 @@ MODULE AeroDyn_Types USE UnsteadyAero_Types USE DBEMT_Types USE BEMT_Types +USE FVW_Types USE NWTC_Library IMPLICIT NONE + INTEGER(IntKi), PUBLIC, PARAMETER :: ModelUnknown = -1 ! [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: WakeMod_none = 0 ! Wake model - none [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: WakeMod_BEMT = 1 ! Wake model - BEMT (blade elememnt momentum theory) [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: WakeMod_DBEMT = 2 ! Wake model - DBEMT (dynamic elememnt momentum theory) [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: WakeMod_FVW = 3 ! Wake model - FVW (free vortex wake, OLAF) [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: AFAeroMod_steady = 1 ! steady model [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: AFAeroMod_BL_unsteady = 2 ! Beddoes-Leishman unsteady model [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: TwrPotent_none = 0 ! no tower potential flow [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: TwrPotent_baseline = 1 ! baseline tower potential flow [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: TwrPotent_Bak = 2 ! tower potential flow with Bak correction [-] ! ========= AD_InitInputType ======= TYPE, PUBLIC :: AD_InitInputType CHARACTER(1024) :: InputFile !< Name of the input file [-] @@ -89,7 +100,7 @@ MODULE AeroDyn_Types ! ========= AD_InputFile ======= TYPE, PUBLIC :: AD_InputFile REAL(DbKi) :: DTAero !< Time interval for aerodynamic calculations {or "default"} [s] - INTEGER(IntKi) :: WakeMod !< Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT} [-] + INTEGER(IntKi) :: WakeMod !< Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW} [-] INTEGER(IntKi) :: AFAeroMod !< Type of blade airfoil aerodynamics model {1=steady model, 2=Beddoes-Leishman unsteady model} [-] INTEGER(IntKi) :: TwrPotent !< Type tower influence on wind based on potential flow around the tower {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} [-] LOGICAL :: TwrShadow !< Calculate tower influence on wind based on downstream tower shadow? [-] @@ -120,6 +131,7 @@ MODULE AeroDyn_Types REAL(ReKi) :: InCol_Cpmin !< The column in the airfoil tables that contains the drag coefficient; use zero if there is no Cpmin column [-] 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} [-] INTEGER(IntKi) :: NumAFfiles !< Number of airfoil files used [-] + CHARACTER(1024) :: FVWFileName !< FVW input filename [quoted string] CHARACTER(1024) , DIMENSION(:), ALLOCATABLE :: AFNames !< Airfoil file names (NumAF lines) [quoted strings] LOGICAL :: UseBlCm !< Include aerodynamic pitching moment in calculations? [flag] TYPE(AD_BladePropsType) , DIMENSION(:), ALLOCATABLE :: BladeProps !< blade property information from blade input files [-] @@ -145,21 +157,26 @@ MODULE AeroDyn_Types ! ========= AD_ContinuousStateType ======= TYPE, PUBLIC :: AD_ContinuousStateType TYPE(BEMT_ContinuousStateType) :: BEMT !< Continuous states from the BEMT module [-] + TYPE(FVW_ContinuousStateType) :: FVW !< Continuous states from the FVW module [-] END TYPE AD_ContinuousStateType ! ======================= ! ========= AD_DiscreteStateType ======= TYPE, PUBLIC :: AD_DiscreteStateType TYPE(BEMT_DiscreteStateType) :: BEMT !< Discrete states from the BEMT module [-] + TYPE(FVW_DiscreteStateType) :: FVW !< Discrete states from the FVW module [-] END TYPE AD_DiscreteStateType ! ======================= ! ========= AD_ConstraintStateType ======= TYPE, PUBLIC :: AD_ConstraintStateType TYPE(BEMT_ConstraintStateType) :: BEMT !< Constraint states from the BEMT module [-] + TYPE(FVW_ConstraintStateType) :: FVW !< Constraint states from the FVW module [-] END TYPE AD_ConstraintStateType ! ======================= ! ========= AD_OtherStateType ======= TYPE, PUBLIC :: AD_OtherStateType TYPE(BEMT_OtherStateType) :: BEMT !< OtherStates from the BEMT module [-] + TYPE(FVW_OtherStateType) :: FVW !< OtherStates from the FVW module [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: WakeLocationPoints !< wake points velocity [m/s] END TYPE AD_OtherStateType ! ======================= ! ========= AD_MiscVarType ======= @@ -167,6 +184,9 @@ MODULE AeroDyn_Types TYPE(BEMT_MiscVarType) :: BEMT !< MiscVars from the BEMT module [-] TYPE(BEMT_OutputType) :: BEMT_y !< Outputs from the BEMT module [-] TYPE(BEMT_InputType) , DIMENSION(1:2) :: BEMT_u !< Inputs to the BEMT module [-] + TYPE(FVW_MiscVarType) :: FVW !< MiscVars from the FVW module [-] + TYPE(FVW_OutputType) :: FVW_y !< Outputs from the FVW module [-] + TYPE(FVW_InputType) , DIMENSION(:), ALLOCATABLE :: FVW_u !< Inputs to the FVW module [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: DisturbedInflow !< InflowOnBlade values modified by tower influence [m/s] REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: WithoutSweepPitchTwist !< Coordinate system equivalent to BladeMotion Orientation, but without live sweep, blade-pitch, and twist angles [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: AllOuts !< An array holding the value of all of the calculated (not only selected) output channels [-] @@ -191,7 +211,7 @@ MODULE AeroDyn_Types ! ========= AD_ParameterType ======= TYPE, PUBLIC :: AD_ParameterType REAL(DbKi) :: DT !< Time step for continuous state integration & discrete state update [seconds] - INTEGER(IntKi) :: WakeMod !< Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT} [-] + INTEGER(IntKi) :: WakeMod !< Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW} [-] INTEGER(IntKi) :: TwrPotent !< Type tower influence on wind based on potential flow around the tower {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} [-] LOGICAL :: TwrShadow !< Calculate tower influence on wind based on downstream tower shadow? [-] LOGICAL :: TwrAero !< Calculate tower aerodynamic loads? [flag] @@ -211,6 +231,7 @@ MODULE AeroDyn_Types REAL(ReKi) :: FluidDepth !< Submerged hub height [m] TYPE(AFI_ParameterType) , DIMENSION(:), ALLOCATABLE :: AFI !< AirfoilInfo parameters [-] TYPE(BEMT_ParameterType) :: BEMT !< Parameters for BEMT module [-] + TYPE(FVW_ParameterType) :: FVW !< Parameters for FVW module [-] INTEGER(IntKi) :: NumOuts !< Number of parameters in the output list (number of outputs requested) [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: OutParam !< Names and units (and other characteristics) of all requested output parameters [-] @@ -237,6 +258,7 @@ MODULE AeroDyn_Types REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: InflowOnBlade !< U,V,W at nodes on each blade (note if we change the requirement that NumNodes is the same for each blade, this will need to change) [m/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: InflowOnTower !< U,V,W at nodes on the tower [m/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: UserProp !< Optional user property for interpolating airfoils (per element per blade) [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: InflowWakeVel !< U,V,W at wake points [m/s] END TYPE AD_InputType ! ======================= ! ========= AD_OutputType ======= @@ -2435,6 +2457,7 @@ SUBROUTINE AD_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrSt DstInputFileData%InCol_Cpmin = SrcInputFileData%InCol_Cpmin DstInputFileData%AFTabMod = SrcInputFileData%AFTabMod DstInputFileData%NumAFfiles = SrcInputFileData%NumAFfiles + DstInputFileData%FVWFileName = SrcInputFileData%FVWFileName IF (ALLOCATED(SrcInputFileData%AFNames)) THEN i1_l = LBOUND(SrcInputFileData%AFNames,1) i1_u = UBOUND(SrcInputFileData%AFNames,1) @@ -2640,6 +2663,7 @@ SUBROUTINE AD_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Re_BufSz = Re_BufSz + 1 ! InCol_Cpmin Int_BufSz = Int_BufSz + 1 ! AFTabMod Int_BufSz = Int_BufSz + 1 ! NumAFfiles + Int_BufSz = Int_BufSz + 1*LEN(InData%FVWFileName) ! FVWFileName Int_BufSz = Int_BufSz + 1 ! AFNames allocated yes/no IF ( ALLOCATED(InData%AFNames) ) THEN Int_BufSz = Int_BufSz + 2*1 ! AFNames upper/lower bounds for each dimension @@ -2798,6 +2822,10 @@ SUBROUTINE AD_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%NumAFfiles Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(InData%FVWFileName) + IntKiBuf(Int_Xferred) = ICHAR(InData%FVWFileName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I IF ( .NOT. ALLOCATED(InData%AFNames) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -3060,6 +3088,10 @@ SUBROUTINE AD_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err Int_Xferred = Int_Xferred + 1 OutData%NumAFfiles = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(OutData%FVWFileName) + OutData%FVWFileName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! AFNames not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -3285,6 +3317,9 @@ SUBROUTINE AD_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrSt CALL BEMT_CopyContState( SrcContStateData%BEMT, DstContStateData%BEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyContState( SrcContStateData%FVW, DstContStateData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE AD_CopyContState SUBROUTINE AD_DestroyContState( ContStateData, ErrStat, ErrMsg ) @@ -3297,6 +3332,7 @@ SUBROUTINE AD_DestroyContState( ContStateData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" CALL BEMT_DestroyContState( ContStateData%BEMT, ErrStat, ErrMsg ) + CALL FVW_DestroyContState( ContStateData%FVW, ErrStat, ErrMsg ) END SUBROUTINE AD_DestroyContState SUBROUTINE AD_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3352,6 +3388,23 @@ SUBROUTINE AD_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + 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 @@ -3407,6 +3460,34 @@ SUBROUTINE AD_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL FVW_PackContState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + 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 AD_PackContState SUBROUTINE AD_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -3475,6 +3556,46 @@ SUBROUTINE AD_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err 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 FVW_UnpackContState( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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 AD_UnPackContState SUBROUTINE AD_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) @@ -3494,6 +3615,9 @@ SUBROUTINE AD_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrSt CALL BEMT_CopyDiscState( SrcDiscStateData%BEMT, DstDiscStateData%BEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyDiscState( SrcDiscStateData%FVW, DstDiscStateData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE AD_CopyDiscState SUBROUTINE AD_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) @@ -3506,6 +3630,7 @@ SUBROUTINE AD_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" CALL BEMT_DestroyDiscState( DiscStateData%BEMT, ErrStat, ErrMsg ) + CALL FVW_DestroyDiscState( DiscStateData%FVW, ErrStat, ErrMsg ) END SUBROUTINE AD_DestroyDiscState SUBROUTINE AD_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3561,6 +3686,23 @@ SUBROUTINE AD_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackDiscState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + 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 @@ -3616,6 +3758,34 @@ SUBROUTINE AD_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL FVW_PackDiscState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + 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 AD_PackDiscState SUBROUTINE AD_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -3684,6 +3854,46 @@ SUBROUTINE AD_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err 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 FVW_UnpackDiscState( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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 AD_UnPackDiscState SUBROUTINE AD_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) @@ -3703,6 +3913,9 @@ SUBROUTINE AD_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, CALL BEMT_CopyConstrState( SrcConstrStateData%BEMT, DstConstrStateData%BEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyConstrState( SrcConstrStateData%FVW, DstConstrStateData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE AD_CopyConstrState SUBROUTINE AD_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) @@ -3715,6 +3928,7 @@ SUBROUTINE AD_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" CALL BEMT_DestroyConstrState( ConstrStateData%BEMT, ErrStat, ErrMsg ) + CALL FVW_DestroyConstrState( ConstrStateData%FVW, ErrStat, ErrMsg ) END SUBROUTINE AD_DestroyConstrState SUBROUTINE AD_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3770,6 +3984,23 @@ SUBROUTINE AD_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackConstrState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + 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 @@ -3825,6 +4056,34 @@ SUBROUTINE AD_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL FVW_PackConstrState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + 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 AD_PackConstrState SUBROUTINE AD_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -3893,6 +4152,46 @@ SUBROUTINE AD_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL FVW_UnpackConstrState( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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 AD_UnPackConstrState SUBROUTINE AD_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) @@ -3903,6 +4202,8 @@ SUBROUTINE AD_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, Er 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 = 'AD_CopyOtherState' @@ -3912,6 +4213,23 @@ SUBROUTINE AD_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, Er CALL BEMT_CopyOtherState( SrcOtherStateData%BEMT, DstOtherStateData%BEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyOtherState( SrcOtherStateData%FVW, DstOtherStateData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcOtherStateData%WakeLocationPoints)) THEN + i1_l = LBOUND(SrcOtherStateData%WakeLocationPoints,1) + i1_u = UBOUND(SrcOtherStateData%WakeLocationPoints,1) + i2_l = LBOUND(SrcOtherStateData%WakeLocationPoints,2) + i2_u = UBOUND(SrcOtherStateData%WakeLocationPoints,2) + IF (.NOT. ALLOCATED(DstOtherStateData%WakeLocationPoints)) THEN + ALLOCATE(DstOtherStateData%WakeLocationPoints(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOtherStateData%WakeLocationPoints.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOtherStateData%WakeLocationPoints = SrcOtherStateData%WakeLocationPoints +ENDIF END SUBROUTINE AD_CopyOtherState SUBROUTINE AD_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) @@ -3924,6 +4242,10 @@ SUBROUTINE AD_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" CALL BEMT_DestroyOtherState( OtherStateData%BEMT, ErrStat, ErrMsg ) + CALL FVW_DestroyOtherState( OtherStateData%FVW, ErrStat, ErrMsg ) +IF (ALLOCATED(OtherStateData%WakeLocationPoints)) THEN + DEALLOCATE(OtherStateData%WakeLocationPoints) +ENDIF END SUBROUTINE AD_DestroyOtherState SUBROUTINE AD_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -3979,6 +4301,28 @@ SUBROUTINE AD_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackOtherState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! WakeLocationPoints allocated yes/no + IF ( ALLOCATED(InData%WakeLocationPoints) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! WakeLocationPoints upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WakeLocationPoints) ! WakeLocationPoints + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4034,6 +4378,54 @@ SUBROUTINE AD_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL FVW_PackOtherState( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF ( .NOT. ALLOCATED(InData%WakeLocationPoints) ) 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%WakeLocationPoints,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WakeLocationPoints,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WakeLocationPoints,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WakeLocationPoints,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%WakeLocationPoints,2), UBOUND(InData%WakeLocationPoints,2) + DO i1 = LBOUND(InData%WakeLocationPoints,1), UBOUND(InData%WakeLocationPoints,1) + ReKiBuf(Re_Xferred) = InData%WakeLocationPoints(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD_PackOtherState SUBROUTINE AD_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -4049,6 +4441,8 @@ SUBROUTINE AD_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er 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 = 'AD_UnPackOtherState' @@ -4102,6 +4496,69 @@ SUBROUTINE AD_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er 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 FVW_UnpackOtherState( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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 ! WakeLocationPoints 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%WakeLocationPoints)) DEALLOCATE(OutData%WakeLocationPoints) + ALLOCATE(OutData%WakeLocationPoints(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WakeLocationPoints.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%WakeLocationPoints,2), UBOUND(OutData%WakeLocationPoints,2) + DO i1 = LBOUND(OutData%WakeLocationPoints,1), UBOUND(OutData%WakeLocationPoints,1) + OutData%WakeLocationPoints(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD_UnPackOtherState SUBROUTINE AD_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) @@ -4133,6 +4590,28 @@ SUBROUTINE AD_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN ENDDO + CALL FVW_CopyMisc( SrcMiscData%FVW, DstMiscData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyOutput( SrcMiscData%FVW_y, DstMiscData%FVW_y, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcMiscData%FVW_u)) THEN + i1_l = LBOUND(SrcMiscData%FVW_u,1) + i1_u = UBOUND(SrcMiscData%FVW_u,1) + IF (.NOT. ALLOCATED(DstMiscData%FVW_u)) THEN + ALLOCATE(DstMiscData%FVW_u(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%FVW_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcMiscData%FVW_u,1), UBOUND(SrcMiscData%FVW_u,1) + CALL FVW_CopyInput( SrcMiscData%FVW_u(i1), DstMiscData%FVW_u(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF IF (ALLOCATED(SrcMiscData%DisturbedInflow)) THEN i1_l = LBOUND(SrcMiscData%DisturbedInflow,1) i1_u = UBOUND(SrcMiscData%DisturbedInflow,1) @@ -4365,6 +4844,14 @@ SUBROUTINE AD_DestroyMisc( MiscData, ErrStat, ErrMsg ) DO i1 = LBOUND(MiscData%BEMT_u,1), UBOUND(MiscData%BEMT_u,1) CALL BEMT_DestroyInput( MiscData%BEMT_u(i1), ErrStat, ErrMsg ) ENDDO + CALL FVW_DestroyMisc( MiscData%FVW, ErrStat, ErrMsg ) + CALL FVW_DestroyOutput( MiscData%FVW_y, ErrStat, ErrMsg ) +IF (ALLOCATED(MiscData%FVW_u)) THEN +DO i1 = LBOUND(MiscData%FVW_u,1), UBOUND(MiscData%FVW_u,1) + CALL FVW_DestroyInput( MiscData%FVW_u(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(MiscData%FVW_u) +ENDIF IF (ALLOCATED(MiscData%DisturbedInflow)) THEN DEALLOCATE(MiscData%DisturbedInflow) ENDIF @@ -4505,6 +4992,63 @@ SUBROUTINE AD_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Siz DEALLOCATE(Int_Buf) END IF END DO + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! FVW_y: size of buffers for each call to pack subtype + CALL FVW_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%FVW_y, ErrStat2, ErrMsg2, .TRUE. ) ! FVW_y + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW_y + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW_y + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW_y + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! FVW_u allocated yes/no + IF ( ALLOCATED(InData%FVW_u) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! FVW_u upper/lower bounds for each dimension + DO i1 = LBOUND(InData%FVW_u,1), UBOUND(InData%FVW_u,1) + Int_BufSz = Int_BufSz + 3 ! FVW_u: size of buffers for each call to pack subtype + CALL FVW_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%FVW_u(i1), ErrStat2, ErrMsg2, .TRUE. ) ! FVW_u + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW_u + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW_u + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW_u + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF Int_BufSz = Int_BufSz + 1 ! DisturbedInflow allocated yes/no IF ( ALLOCATED(InData%DisturbedInflow) ) THEN Int_BufSz = Int_BufSz + 2*3 ! DisturbedInflow upper/lower bounds for each dimension @@ -4731,6 +5275,103 @@ SUBROUTINE AD_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Siz IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF END DO + CALL FVW_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + 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 FVW_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%FVW_y, ErrStat2, ErrMsg2, OnlySize ) ! FVW_y + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF ( .NOT. ALLOCATED(InData%FVW_u) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%FVW_u,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%FVW_u,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%FVW_u,1), UBOUND(InData%FVW_u,1) + CALL FVW_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%FVW_u(i1), ErrStat2, ErrMsg2, OnlySize ) ! FVW_u + 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%DisturbedInflow) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -5241,6 +5882,142 @@ SUBROUTINE AD_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END DO + 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 FVW_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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 FVW_UnpackOutput( Re_Buf, Db_Buf, Int_Buf, OutData%FVW_y, ErrStat2, ErrMsg2 ) ! FVW_y + 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 ! FVW_u not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%FVW_u)) DEALLOCATE(OutData%FVW_u) + ALLOCATE(OutData%FVW_u(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%FVW_u.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%FVW_u,1), UBOUND(OutData%FVW_u,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 FVW_UnpackInput( Re_Buf, Db_Buf, Int_Buf, OutData%FVW_u(i1), ErrStat2, ErrMsg2 ) ! FVW_u + 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 ! DisturbedInflow not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -5746,6 +6523,9 @@ SUBROUTINE AD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) CALL BEMT_CopyParam( SrcParamData%BEMT, DstParamData%BEMT, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL FVW_CopyParam( SrcParamData%FVW, DstParamData%FVW, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN DstParamData%NumOuts = SrcParamData%NumOuts DstParamData%RootName = SrcParamData%RootName IF (ALLOCATED(SrcParamData%OutParam)) THEN @@ -5850,6 +6630,7 @@ SUBROUTINE AD_DestroyParam( ParamData, ErrStat, ErrMsg ) DEALLOCATE(ParamData%AFI) ENDIF CALL BEMT_DestroyParam( ParamData%BEMT, ErrStat, ErrMsg ) + CALL FVW_DestroyParam( ParamData%FVW, ErrStat, ErrMsg ) IF (ALLOCATED(ParamData%OutParam)) THEN DO i1 = LBOUND(ParamData%OutParam,1), UBOUND(ParamData%OutParam,1) CALL NWTC_Library_Destroyoutparmtype( ParamData%OutParam(i1), ErrStat, ErrMsg ) @@ -5976,6 +6757,23 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! FVW: size of buffers for each call to pack subtype + CALL FVW_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, .TRUE. ) ! FVW + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! FVW + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FVW + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FVW + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF Int_BufSz = Int_BufSz + 1 ! NumOuts Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName Int_BufSz = Int_BufSz + 1 ! OutParam allocated yes/no @@ -6207,6 +7005,34 @@ SUBROUTINE AD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL FVW_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FVW, ErrStat2, ErrMsg2, OnlySize ) ! FVW + 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) = InData%NumOuts Int_Xferred = Int_Xferred + 1 DO I = 1, LEN(InData%RootName) @@ -6561,6 +7387,46 @@ SUBROUTINE AD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg 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 FVW_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%FVW, ErrStat2, ErrMsg2 ) ! FVW + 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%NumOuts = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 DO I = 1, LEN(OutData%RootName) @@ -6862,6 +7728,20 @@ SUBROUTINE AD_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) END IF END IF DstInputData%UserProp = SrcInputData%UserProp +ENDIF +IF (ALLOCATED(SrcInputData%InflowWakeVel)) THEN + i1_l = LBOUND(SrcInputData%InflowWakeVel,1) + i1_u = UBOUND(SrcInputData%InflowWakeVel,1) + i2_l = LBOUND(SrcInputData%InflowWakeVel,2) + i2_u = UBOUND(SrcInputData%InflowWakeVel,2) + IF (.NOT. ALLOCATED(DstInputData%InflowWakeVel)) THEN + ALLOCATE(DstInputData%InflowWakeVel(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%InflowWakeVel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%InflowWakeVel = SrcInputData%InflowWakeVel ENDIF END SUBROUTINE AD_CopyInput @@ -6896,6 +7776,9 @@ SUBROUTINE AD_DestroyInput( InputData, ErrStat, ErrMsg ) ENDIF IF (ALLOCATED(InputData%UserProp)) THEN DEALLOCATE(InputData%UserProp) +ENDIF +IF (ALLOCATED(InputData%InflowWakeVel)) THEN + DEALLOCATE(InputData%InflowWakeVel) ENDIF END SUBROUTINE AD_DestroyInput @@ -7030,6 +7913,11 @@ SUBROUTINE AD_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Int_BufSz = Int_BufSz + 2*2 ! UserProp upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%UserProp) ! UserProp END IF + Int_BufSz = Int_BufSz + 1 ! InflowWakeVel allocated yes/no + IF ( ALLOCATED(InData%InflowWakeVel) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! InflowWakeVel upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%InflowWakeVel) ! InflowWakeVel + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -7260,6 +8148,26 @@ SUBROUTINE AD_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si END DO END DO END IF + IF ( .NOT. ALLOCATED(InData%InflowWakeVel) ) 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%InflowWakeVel,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%InflowWakeVel,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%InflowWakeVel,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%InflowWakeVel,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%InflowWakeVel,2), UBOUND(InData%InflowWakeVel,2) + DO i1 = LBOUND(InData%InflowWakeVel,1), UBOUND(InData%InflowWakeVel,1) + ReKiBuf(Re_Xferred) = InData%InflowWakeVel(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD_PackInput SUBROUTINE AD_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -7557,6 +8465,29 @@ SUBROUTINE AD_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg END DO END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! InflowWakeVel 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%InflowWakeVel)) DEALLOCATE(OutData%InflowWakeVel) + ALLOCATE(OutData%InflowWakeVel(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%InflowWakeVel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%InflowWakeVel,2), UBOUND(OutData%InflowWakeVel,2) + DO i1 = LBOUND(OutData%InflowWakeVel,1), UBOUND(OutData%InflowWakeVel,1) + OutData%InflowWakeVel(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD_UnPackInput SUBROUTINE AD_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) @@ -8105,6 +9036,14 @@ SUBROUTINE AD_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) u_out%UserProp(i1,i2) = u1%UserProp(i1,i2) + b * ScaleFactor END DO END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%InflowWakeVel) .AND. ALLOCATED(u1%InflowWakeVel)) THEN + DO i2 = LBOUND(u_out%InflowWakeVel,2),UBOUND(u_out%InflowWakeVel,2) + DO i1 = LBOUND(u_out%InflowWakeVel,1),UBOUND(u_out%InflowWakeVel,1) + b = -(u1%InflowWakeVel(i1,i2) - u2%InflowWakeVel(i1,i2)) + u_out%InflowWakeVel(i1,i2) = u1%InflowWakeVel(i1,i2) + b * ScaleFactor + END DO + END DO END IF ! check if allocated END SUBROUTINE AD_Input_ExtrapInterp1 @@ -8211,6 +9150,15 @@ SUBROUTINE AD_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrM u_out%UserProp(i1,i2) = u1%UserProp(i1,i2) + b + c * t_out END DO END DO +END IF ! check if allocated +IF (ALLOCATED(u_out%InflowWakeVel) .AND. ALLOCATED(u1%InflowWakeVel)) THEN + DO i2 = LBOUND(u_out%InflowWakeVel,2),UBOUND(u_out%InflowWakeVel,2) + DO i1 = LBOUND(u_out%InflowWakeVel,1),UBOUND(u_out%InflowWakeVel,1) + b = (t(3)**2*(u1%InflowWakeVel(i1,i2) - u2%InflowWakeVel(i1,i2)) + t(2)**2*(-u1%InflowWakeVel(i1,i2) + u3%InflowWakeVel(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%InflowWakeVel(i1,i2) + t(3)*u2%InflowWakeVel(i1,i2) - t(2)*u3%InflowWakeVel(i1,i2) ) * scaleFactor + u_out%InflowWakeVel(i1,i2) = u1%InflowWakeVel(i1,i2) + b + c * t_out + END DO + END DO END IF ! check if allocated END SUBROUTINE AD_Input_ExtrapInterp2 diff --git a/modules/aerodyn/src/BEMT.f90 b/modules/aerodyn/src/BEMT.f90 index 5ae4ffcf9d..8f9efbd62c 100644 --- a/modules/aerodyn/src/BEMT.f90 +++ b/modules/aerodyn/src/BEMT.f90 @@ -553,6 +553,8 @@ subroutine BEMT_Init( InitInp, u, p, x, xd, z, OtherState, AFInfo, y, misc, Inte call cleanup() return end if + 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 ) @@ -2048,4 +2050,4 @@ function NodeText(i,j) end function NodeText end module BEMT - \ No newline at end of file + diff --git a/modules/aerodyn/src/FVW.f90 b/modules/aerodyn/src/FVW.f90 new file mode 100644 index 0000000000..0782068e39 --- /dev/null +++ b/modules/aerodyn/src/FVW.f90 @@ -0,0 +1,1165 @@ +!> +!! +!! Abbreviations: +!! - FVW: Free Vortex Wake +!! - LL : Lifting Line +!! - CP : Control point +!! - NW : Near Wake +!! - FW : Far Wake +!! +module FVW + use NWTC_Library + use FVW_Types + use FVW_Subs + use FVW_IO + use FVW_Wings + use FVW_BiotSavart + use FVW_Tests + use AirFoilInfo + + IMPLICIT NONE + + PRIVATE + + type(ProgDesc), parameter :: FVW_Ver = ProgDesc( 'FVW', '', '' ) + + public :: FVW_Init ! Initialization routine + public :: FVW_End + + public :: FVW_CalcOutput + public :: FVW_UpdateStates + + ! parameter for deciding if enough time has elapsed (Wake calculation, and vtk output) + real(DbKi), parameter :: OneMinusEpsilon = 1 - 10000*EPSILON(1.0_DbKi) + +contains + +!---------------------------------------------------------------------------------------------------------------------------------- +!> 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. +!! The initial states and initial guess for the input are defined. +subroutine FVW_Init(AFInfo, InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut, ErrStat, ErrMsg ) + use OMP_LIB ! wrap with #ifdef _OPENMP if this causes an issue + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data, temporary, for UA.. + type(FVW_InitInputType), intent(inout) :: InitInp !< Input data for initialization routine (inout so we can use MOVE_ALLOC) + type(FVW_InputType), intent( out) :: u !< An initial guess for the input; input mesh must be defined + type(FVW_ParameterType), intent( out) :: p !< Parameters + type(FVW_ContinuousStateType), intent( out) :: x !< Initial continuous states + type(FVW_DiscreteStateType), intent( out) :: xd !< Initial discrete states + type(FVW_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states + type(FVW_OtherStateType), intent( out) :: OtherState !< Initial other states + type(FVW_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated; + !! only the output mesh is initialized) + type(FVW_MiscVarType), intent( out) :: m !< Initial misc/optimization variables + real(DbKi), intent(inout) :: interval !< Coupling interval in seconds: the rate that + !! (1) FVW_UpdateStates() is called in loose coupling & + !! (2) FVW_UpdateDiscState() is called in tight coupling. + !! Input is the suggested time from the glue code; + !! Output is the actual coupling interval that will be used + !! by the glue code. + type(FVW_InitOutputType), intent( out) :: InitOut !< Output for initialization routine + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + integer(IntKi) :: UnEcho ! Unit number for the echo file + character(*), parameter :: RoutineName = 'FVW_Init' + type(FVW_InputFile) :: InputFileData !< Data stored in the module's input file + character(len=1054) :: DirName + + ! Initialize variables for this routine + ErrStat = ErrID_None + ErrMsg = "" + UnEcho = -1 + + ! Initialize the NWTC Subroutine Library + call NWTC_Init( EchoLibVer=.FALSE. ) + + ! Display the module information + call DispNVD( FVW_Ver ) + ! Display convenient info to screen, until this is one day displayed by OpenFAST + call getcwd(DirName) + call WrScr(' - Directory: '//trim(DirName)) + call WrScr(' - RootName: '//trim(InitInp%RootName)) +#ifdef _OPENMP + call WrScr(' - Compiled with OpenMP') + !$OMP PARALLEL default(shared) + if (omp_get_thread_num()==0) then + call WrScr(' Number of threads: '//trim(Num2LStr(omp_get_num_threads()))//'/'//trim(Num2LStr(omp_get_max_threads()))) + endif + !$OMP END PARALLEL +#else + call WrScr(' - No OpenMP support') +#endif + if (DEV_VERSION) then + CALL FVW_RunTests(ErrStat2, ErrMsg2); if (Failed()) return + endif + + ! Set Parameters and *Misc* from inputs + CALL FVW_SetParametersFromInputs(InitInp, p, ErrStat2, ErrMsg2); if(Failed()) return + + ! Read and parse the input file here to get other parameters and info + CALL FVW_ReadInputFile(InitInp%FVWFileName, p, InputFileData, ErrStat2, ErrMsg2); if(Failed()) return + + ! Trigger required before allocations + p%nNWMax = max(InputFileData%nNWPanels,0)+1 ! +1 since LL panel included in NW + p%nFWMax = max(InputFileData%nFWPanels,0) + p%nFWFree = max(InputFileData%nFWPanelsFree,0) + p%DTfvw = InputFileData%DTfvw + p%DTvtk = InputFileData%DTvtk + + ! Initialize Misc Vars (may depend on input file) + CALL FVW_InitMiscVars( p, m, ErrStat2, ErrMsg2 ); if(Failed()) return + + ! Move the InitInp%WingsMesh to u + CALL MOVE_ALLOC( InitInp%WingsMesh, u%WingsMesh ) ! Move from InitInp to u + +!NOTE: We do not have the windspeed until after the FVW initialization (IfW is not initialized until after AD15) + ! Wind Speed hack, TODO temporary NOTE: it is still needed? + m%Vwnd_LL(:,:,:) = 0 + m%Vwnd_NW(:,:,:,:) = 0 + m%Vwnd_FW(:,:,:,:) = 0 + + ! This mesh is passed in as a cousin of the BladeMotion mesh. + CALL Wings_Panelling_Init(u%WingsMesh, p, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! Set parameters from InputFileData (need Misc allocated) + CALL FVW_SetParametersFromInputFile(InputFileData, p, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! Initialize Misc Vars (after input file params) + CALL FVW_InitMiscVarsPostParam( p, m, ErrStat2, ErrMsg2 ); if(Failed()) return + + ! Initialize States Vars + CALL FVW_InitStates( x, p, ErrStat2, ErrMsg2 ); if(Failed()) return + + ! Initialize Constraints Vars + CALL FVW_InitConstraint( z, p, m, ErrStat2, ErrMsg2 ); if(Failed()) return + + ! Panelling wings based on initial input mesh provided + ! This mesh is now a cousin of the BladeMotion mesh from AD. + CALL Wings_Panelling (u%WingsMesh, p, m, ErrStat2, ErrMsg2); if(Failed()) return + CALL FVW_InitRegularization(p, m, ErrStat2, ErrMsg2); if(Failed()) return + CALL FVW_ToString(p, m) ! Print to screen + + ! Mapping NW and FW (purely for esthetics, and maybe wind) ! TODO, just points + call Map_LL_NW(p, m, z, x, 1.0_ReKi, ErrStat2, ErrMsg2); if(Failed()) return + call Map_NW_FW(p, m, z, x, ErrStat2, ErrMsg2); if(Failed()) return + + ! Initialize output + CALL FVW_Init_Y( p, u, y, ErrStat2, ErrMsg2); if(Failed()) return + + ! Returned guessed locations where wind will be required + CALL SetRequestedWindPoints(m%r_wind, x, p, m ) + ! Return anything in FVW_InitOutput that should be passed back to the calling code here + + + ! --- UA + ! NOTE: quick and dirty since this should belong to AD + interval = InitInp%DTAero ! important, UA, needs proper interval + call UA_Init_Wrapper(AFInfo, InitInp, interval, p, x, xd, OtherState, m, ErrStat2, ErrMsg2); if (Failed()) return + + ! Framework types unused + Interval = InitInp%DTAero + OtherState%NULL = 0 + xd%NULL = 0 + InitOut%NULL = 0 +CONTAINS + + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_Init') + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +end subroutine FVW_Init + +! ============================================================================== +subroutine FVW_InitMiscVars( p, m, ErrStat, ErrMsg ) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: nMax ! Total number of wind points possible + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + character(*), parameter :: RoutineName = 'FVW_InitMiscVars' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + m%FirstCall = .True. + m%nNW = iNWStart-1 ! Number of active nearwake panels + m%nFW = 0 ! Number of active farwake panels + m%iStep = 0 ! Current step number + m%VTKStep = -1 ! Counter of VTK outputs + m%VTKlastTime = -HUGE(1.0_DbKi) + m%tSpent = 0 + + call AllocAry( m%LE , 3 , p%nSpan+1 , p%nWings, 'Leading Edge Points', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%LE = -999999_ReKi; + call AllocAry( m%TE , 3 , p%nSpan+1 , p%nWings, 'TrailingEdge Points', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%TE = -999999_ReKi; + call AllocAry( m%s_LL , p%nSpan+1 , p%nWings, 'Spanwise coord LL ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%s_LL= -999999_ReKi; + call AllocAry( m%chord_LL , p%nSpan+1 , p%nWings, 'Chord on LL ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%chord_LL= -999999_ReKi; + call AllocAry( m%PitchAndTwist , p%nSpan+1 , p%nWings, 'Pitch and twist ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%PitchAndTwist= -999999_ReKi; + call AllocAry( m%alpha_LL, p%nSpan , p%nWings, 'Wind on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%alpha_LL= -999999_ReKi; + call AllocAry( m%Vreln_LL, p%nSpan , p%nWings, 'Wind on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vreln_LL = -999999_ReKi; + ! Variables at control points/elements + call AllocAry( m%Gamma_LL, p%nSpan , p%nWings, 'Lifting line Circulation', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Gamma_LL = -999999_ReKi; + call AllocAry( m%chord_CP_LL , p%nSpan , p%nWings, 'Chord on CP LL ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%chord_CP_LL= -999999_ReKi; + call AllocAry( m%s_CP_LL , p%nSpan , p%nWings, 'Spanwise coord CPll', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%s_CP_LL= -999999_ReKi; + call AllocAry( m%CP_LL , 3 , p%nSpan , p%nWings, 'Control points LL ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%CP_LL= -999999_ReKi; + call AllocAry( m%Tang , 3 , p%nSpan , p%nWings, 'Tangential vector ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Tang= -999999_ReKi; + call AllocAry( m%Norm , 3 , p%nSpan , p%nWings, 'Normal vector ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Norm= -999999_ReKi; + call AllocAry( m%Orth , 3 , p%nSpan , p%nWings, 'Orthogonal vector ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Orth= -999999_ReKi; + call AllocAry( m%dl , 3 , p%nSpan , p%nWings, 'Orthogonal vector ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%dl= -999999_ReKi; + call AllocAry( m%Area , p%nSpan , p%nWings, 'LL Panel area ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Area = -999999_ReKi; + call AllocAry( m%diag_LL , p%nSpan , p%nWings, 'LL Panel diagonals ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%diag_LL = -999999_ReKi; + call AllocAry( m%Vind_LL , 3 , p%nSpan , p%nWings, 'Vind on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vind_LL= -999999_ReKi; + call AllocAry( m%Vtot_LL , 3 , p%nSpan , p%nWings, 'Vtot on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vtot_LL= -999999_ReKi; + call AllocAry( m%Vstr_LL , 3 , p%nSpan , p%nWings, 'Vstr on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vstr_LL= -999999_ReKi; + call AllocAry( m%Vwnd_LL , 3 , p%nSpan , p%nWings, 'Wind on CP ll ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vwnd_LL= -999999_ReKi; + ! Variables at panels points + call AllocAry( m%r_LL , 3 , p%nSpan+1 , 2 , p%nWings, 'Lifting Line Panels', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%r_LL= -999999_ReKi; + call AllocAry( m%Vwnd_NW , 3 , p%nSpan+1 ,p%nNWMax+1, p%nWings, 'Wind on NW ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vwnd_NW= -999_ReKi; + call AllocAry( m%Vwnd_FW , 3 , FWnSpan+1 ,p%nFWMax+1, p%nWings, 'Wind on FW ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vwnd_FW= -999_ReKi; + call AllocAry( m%Vind_NW , 3 , p%nSpan+1 ,p%nNWMax+1, p%nWings, 'Vind on NW ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vind_NW= -999_ReKi; + call AllocAry( m%Vind_FW , 3 , FWnSpan+1 ,p%nFWMax+1, p%nWings, 'Vind on FW ', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%Vind_FW= -999_ReKi; + call AllocAry( m%dxdt_NW , 3 , p%nSpan+1 , p%nNWMax+1, p%nWings, 'NW dxdt' , ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%dxdt_NW = -999999_ReKi; + call AllocAry( m%dxdt_FW , 3 , FWnSpan+1 , p%nFWMax+1, p%nWings, 'FW dxdt' , ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%dxdt_FW = -999999_ReKi; + ! Variables for optimizing outputs at blade nodes + call AllocAry( m%BN_UrelWind_s, 3, p%nSpan+1 , p%nWings, 'Relative wind in section coordinates', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_UrelWind_s= -999999_ReKi; + call AllocAry( m%BN_AxInd , p%nSpan+1 , p%nWings, 'Axial induction', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_AxInd = -999999_ReKi; + call AllocAry( m%BN_TanInd , p%nSpan+1 , p%nWings, 'Tangential induction', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_TanInd = -999999_ReKi; + call AllocAry( m%BN_Vrel , p%nSpan+1 , p%nWings, 'Relative velocity', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Vrel = -999999_ReKi; + call AllocAry( m%BN_alpha , p%nSpan+1 , p%nWings, 'Angle of attack', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_alpha = -999999_ReKi; + call AllocAry( m%BN_phi , p%nSpan+1 , p%nWings, 'angle between the plane local wind dir', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_phi = -999999_ReKi; + call AllocAry( m%BN_Re , p%nSpan+1 , p%nWings, 'Reynolds number', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Re = -999999_ReKi; + call AllocAry( m%BN_Cl_Static , p%nSpan+1 , p%nWings, 'Coefficient lift - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cl_Static = -999999_ReKi; + call AllocAry( m%BN_Cd_Static , p%nSpan+1 , p%nWings, 'Coefficient drag - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cd_Static = -999999_ReKi; + call AllocAry( m%BN_Cm_Static , p%nSpan+1 , p%nWings, 'Coefficient moment - no UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cm_Static = -999999_ReKi; + call AllocAry( m%BN_Cl , p%nSpan+1 , p%nWings, 'Coefficient lift - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cl = -999999_ReKi; + call AllocAry( m%BN_Cd , p%nSpan+1 , p%nWings, 'Coefficient drag - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cd = -999999_ReKi; + call AllocAry( m%BN_Cm , p%nSpan+1 , p%nWings, 'Coefficient moment - with UA', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cm = -999999_ReKi; + call AllocAry( m%BN_Cx , p%nSpan+1 , p%nWings, 'Coefficient normal (to plane)', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cx = -999999_ReKi; + call AllocAry( m%BN_Cy , p%nSpan+1 , p%nWings, 'Coefficient tangential (to plane)', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%BN_Cy = -999999_ReKi; + + + ! Wind request points + nMax = 0 + nMax = nMax + p%nSpan * p%nWings ! Lifting line Control Points + nMax = nMax + (p%nSpan+1) * (p%nNWMax+1) * p%nWings ! Nearwake points + nMax = nMax + (FWnSpan+1) * (p%nFWMax+1) * p%nWings ! Far wake points + call AllocAry( m%r_wind, 3, nMax, 'Requested wind points', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ) + m%r_wind = 0.0_ReKi ! set to zero so InflowWind can shortcut calculations + m%OldWakeTime = -HUGE(1.0_DbKi) + ! Temporary UA + call AllocAry( m%Vwnd_ND, 3, p%nSpan+1, p%nWings, 'Vwnd_ND', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ); m%TE = -999999_ReKi; + +end subroutine FVW_InitMiscVars +! ============================================================================== +subroutine FVW_InitMiscVarsPostParam( p, m, ErrStat, ErrMsg ) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + character(*), parameter :: RoutineName = 'FVW_InitMiscVarsPostParam' + integer(IntKi) :: nSeg, nSegP, nSegNW !< Total number of segments after packing + integer(IntKi) :: nCPs !< Total number of control points + logical :: bMirror + ErrStat = ErrID_None + ErrMsg = "" + ! --- Counting maximum number of segments and Control Points expected for the whole simulation + call CountSegments(p, p%nNWMax, p%nFWMax, 1, nSeg, nSegP, nSegNW) + nCPs = CountCPs(p, p%nNWMax, p%nFWFree) + + bMirror = p%ShearModel==idShearMirror ! Whether or not we mirror the vorticity wrt ground + if (bMirror) then + nSeg = nSeg*2 + nSegP = nSegP*2 + endif + call AllocAry( m%SegConnct, 4, nSeg , 'SegConnct' , ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%SegConnct = -999; + call AllocAry( m%SegPoints, 3, nSegP, 'SegPoints' , ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%SegPoints = -999999_ReKi; + call AllocAry( m%SegGamma , nSeg, 'SegGamma' , ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%SegGamma = -999999_ReKi; + call AllocAry( m%SegEpsilon, nSeg, 'SegEpsilon', ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%SegEpsilon= -999999_ReKi; + + call AllocAry( m%CPs , 3, nCPs, 'CPs' , ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%CPs= -999999_ReKi; + call AllocAry( m%Uind , 3, nCPs, 'Uind' , ErrStat2, ErrMsg2 );call SetErrStat(ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName); m%Uind= -999999_ReKi; + +end subroutine FVW_InitMiscVarsPostParam +! ============================================================================== +subroutine FVW_InitStates( x, p, ErrStat, ErrMsg ) + type(FVW_ContinuousStateType), intent( out) :: x !< States + type(FVW_ParameterType), intent(in ) :: p !< Parameters + 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 of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + character(*), parameter :: RoutineName = 'FVW_InitMiscVars' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + call AllocAry( x%Gamma_NW, p%nSpan , p%nNWMax , p%nWings, 'NW Panels Circulation', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_InitStates' ); + call AllocAry( x%Gamma_FW, FWnSpan , p%nFWMax , p%nWings, 'FW Panels Circulation', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_InitStates' ); + ! set x%r_NW and x%r_FW to (0,0,0) so that InflowWind can shortcut the calculations + call AllocAry( x%r_NW , 3, p%nSpan+1 , p%nNWMax+1, p%nWings, 'NW Panels Points' , ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_InitStates' ); + call AllocAry( x%r_FW , 3, FWnSpan+1 , p%nFWMax+1, p%nWings, 'FW Panels Points' , ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_InitStates' ); + !if (DEV_VERSION) then + ! x%r_NW = -9999999_ReKi; + ! x%r_FW = -9999999_ReKi; + ! x%Gamma_NW = -999999_ReKi; + ! x%Gamma_FW = -999999_ReKi; + !else + x%r_NW = 0.0_ReKi + x%r_FW = 0.0_ReKi + x%Gamma_NW = 0.0_ReKi ! First call of calcoutput, states might not be set + x%Gamma_FW = 0.0_ReKi ! NOTE, these values might be mapped from z%Gamma_LL at init + !endif + if (ErrStat >= AbortErrLev) return +end subroutine FVW_InitStates +! ============================================================================== +subroutine FVW_InitConstraint( z, p, m, ErrStat, ErrMsg ) + type(FVW_ConstraintStateType), intent( out) :: z !< Constraints + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + character(*), parameter :: RoutineName = 'FVW_InitMiscVars' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! + call AllocAry( z%Gamma_LL, p%nSpan, p%nWings, 'Lifting line Circulation', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_InitConstraint' ); + !z%Gamma_LL = -999999_ReKi + z%Gamma_LL = 0.0_ReKi + + if (ErrStat >= AbortErrLev) return + if(.false.) print*,m%nNW ! unused var for now +end subroutine FVW_InitConstraint +! ============================================================================== +subroutine FVW_Init_Y( p, u, y, ErrStat, ErrMsg ) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_InputType), intent(inout) :: u !< An initial guess for the input; input mesh must be defined + type(FVW_OutputType), intent( out) :: y !< Constraints + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: nMax ! Total number of wind points possible + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + character(*), parameter :: RoutineName = 'FVW_Init_Y' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! + nMax = 0 + nMax = nMax + p%nSpan * p%nWings ! Lifting line Control Points + nMax = nMax + (p%nSpan+1) * (p%nNWMax+1) * p%nWings ! Nearwake points + nMax = nMax + (FWnSpan+1) * (p%nFWMax+1) * p%nWings ! Far wake points + + call AllocAry( u%V_wind, 3, nMax, 'Wind Velocity at points', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ) + call AllocAry( y%Vind , 3, p%nSpan+1, p%nWings, 'Induced velocity vector', ErrStat2, ErrMsg2 ); ! TODO potentially nSpan+1 for AD15 + !call AllocAry( y%Cl_KJ , 1, 1, 'Lift coefficient from circulation (Kutta-Joukowski)', ErrStat2, ErrMsg2 );call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,RoutineName ) + if (ErrStat >= AbortErrLev) return + y%Vind = 0.0_ReKi + return +end subroutine FVW_Init_Y + + +! ============================================================================== +!> Setting parameters *and misc* from module inputs +SUBROUTINE FVW_SetParametersFromInputs( InitInp, p, ErrStat, ErrMsg ) + type(FVW_InitInputType), intent(inout) :: InitInp !< Input data for initialization routine (inout so we can use MOVE_ALLOC) + type(FVW_ParameterType), intent(inout) :: p !< Parameters + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + !integer(IntKi) :: ErrStat2 + !character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'FVW_SetParametersFromInputs' + ErrStat = ErrID_None + ErrMsg = "" + ! + p%nWings = InitInp%NumBlades + p%nSpan = InitInp%numBladeNodes-1 ! NOTE: temporary limitation, all wings have the same nspan + p%DTaero = InitInp%DTaero ! AeroDyn Time step + p%KinVisc = InitInp%KinVisc ! Kinematic air viscosity + p%RootName = InitInp%RootName ! Rootname for outputs + ! 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 + + ! Set the Chord values + call move_alloc(InitInp%Chord, p%Chord) + +end subroutine FVW_SetParametersFromInputs +! ============================================================================== +!> +SUBROUTINE FVW_SetParametersFromInputFile( InputFileData, p, m, ErrStat, ErrMsg ) + type(FVW_InputFile), intent(in ) :: InputFileData !< Data stored in the module's input file + type(FVW_ParameterType), intent(inout) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Misc + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + ErrStat = ErrID_None + ErrMsg = "" + + ! Set parameters from input file + p%IntMethod = InputFileData%IntMethod + p%CirculationMethod = InputFileData%CirculationMethod + p%CircSolvConvCrit = InputFileData%CircSolvConvCrit + p%CircSolvRelaxation = InputFileData%CircSolvRelaxation + p%CircSolvMaxIter = InputFileData%CircSolvMaxIter + p%FreeWakeStart = InputFileData%FreeWakeStart + p%CircSolvPolar = InputFileData%CircSolvPolar + p%FullCirculationStart = InputFileData%FullCirculationStart + p%FWShedVorticity = InputFileData%FWShedVorticity + p%DiffusionMethod = InputFileData%DiffusionMethod + p%RegFunction = InputFileData%RegFunction + p%RegDeterMethod = InputFileData%RegDeterMethod + p%WakeRegMethod = InputFileData%WakeRegMethod + p%WakeRegParam = InputFileData%WakeRegParam + p%WingRegParam = InputFileData%WingRegParam + p%CoreSpreadEddyVisc = InputFileData%CoreSpreadEddyVisc + p%ShearModel = InputFileData%ShearModel + p%TwrShadowOnWake = InputFileData%TwrShadowOnWake + p%VelocityMethod = InputFileData%VelocityMethod + p%TreeBranchFactor = InputFileData%TreeBranchFactor + p%PartPerSegment = InputFileData%PartPerSegment + p%WrVTK = InputFileData%WrVTK + p%VTKBlades = min(InputFileData%VTKBlades,p%nWings) ! Note: allowing it to be negative for temporary hack + p%VTKCoord = InputFileData%VTKCoord + + if (allocated(p%PrescribedCirculation)) deallocate(p%PrescribedCirculation) + if (InputFileData%CirculationMethod==idCircPrescribed) then + call AllocAry( p%PrescribedCirculation, p%nSpan, 'Prescribed Circulation', ErrStat2, ErrMsg2 ); call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_SetParameters' ); p%PrescribedCirculation = -999999_ReKi; + if (.not. allocated(m%s_CP_LL)) then + ErrMsg = 'Spanwise coordinate not allocated.' + ErrStat = ErrID_Fatal + return + endif + call ReadAndInterpGamma(trim(InputFileData%CirculationFile), m%s_CP_LL(1:p%nSpan,1), m%s_LL(p%nSpan+1,1), p%PrescribedCirculation, ErrStat2, ErrMsg2) + call SetErrStat ( ErrStat2, ErrMsg2, ErrStat,ErrMsg,'FVW_SetParameters' ); + endif + +end subroutine FVW_SetParametersFromInputFile + +subroutine FVW_ToString(p,m) + type(FVW_ParameterType), intent(in) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Misc + if (DEV_VERSION) then + print*,'-----------------------------------------------------------------------------------------' + if(.false.) print*,m%nNW ! unused var for now + endif +end subroutine FVW_ToString + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine is called at the end of the simulation. +subroutine FVW_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) + + type(FVW_InputType), intent(inout) :: u(:) !< System inputs + type(FVW_ParameterType), intent(inout) :: p !< Parameters + type(FVW_ContinuousStateType), intent(inout) :: x !< Continuous states + type(FVW_DiscreteStateType), intent(inout) :: xd !< Discrete states + type(FVW_ConstraintStateType), intent(inout) :: z !< Constraint states + type(FVW_OtherStateType), intent(inout) :: OtherState !< Other states + type(FVW_OutputType), intent(inout) :: y !< System outputs + type(FVW_MiscVarType), intent(inout) :: m !< Misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + integer(IntKi) :: i + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! Place any last minute operations or calculations here: + ! Close files here: + ! Destroy the input data: + do i=1,size(u) + call FVW_DestroyInput( u(i), ErrStat, ErrMsg ) + enddo + + ! Destroy the parameter data: + call FVW_DestroyParam( p, ErrStat, ErrMsg ) + + ! Destroy the state data: + call FVW_DestroyContState( x, ErrStat, ErrMsg ) + call FVW_DestroyDiscState( xd, ErrStat, ErrMsg ) + call FVW_DestroyConstrState( z, ErrStat, ErrMsg ) + call FVW_DestroyOtherState( OtherState, ErrStat, ErrMsg ) + call FVW_DestroyMisc( m, ErrStat, ErrMsg ) + + ! Destroy the output data: + call FVW_DestroyOutput( y, ErrStat, ErrMsg ) + +#ifdef UA_OUTS + CLOSE(69) +#endif +end subroutine FVW_End + + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> 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 FVW_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, AFInfo, m, errStat, errMsg ) +!.................................................................................................................................. + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< Current simulation time step n = 0,1,... + type(FVW_InputType), intent(inout) :: u(:) !< Inputs at utimes (out only for mesh record-keeping in ExtrapInterp routine) + real(DbKi), intent(in ) :: utimes(:) !< Times associated with u(:), in seconds + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; Output: at t+DTaero + type(FVW_DiscreteStateType), intent(inout) :: xd !< Input: Discrete states at t; Output: at t+DTaero + type(FVW_ConstraintStateType), intent(inout) :: z !< Input: Constraint states at t; Output: at t+DTaero + type(FVW_OtherStateType), intent(inout) :: OtherState !< Input: Other states at t; Output: at t+DTaero + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data + type(FVW_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(FVW_InputType) :: uInterp ! Interpolated/Extrapolated input + integer(IntKi) :: ErrStat2 ! temporary Error status + character(ErrMsgLen) :: ErrMsg2 ! temporary Error message + type(FVW_ConstraintStateType) :: z_guess ! < + integer(IntKi) :: nP, nFWEff + integer, dimension(8) :: time1, time2, time_diff + real(ReKi) :: ShedScale !< Scaling factor for shed vorticity (for sub-cycling), 1 if no subcycling + logical :: bReevaluation + + ErrStat = ErrID_None + ErrMsg = "" + + + ! --- Handling of time step, and time compared to previous call + m%iStep = n + ! Reevaluation: two repetitive calls starting from the same time, we will roll back the wake emission + bReevaluation=.False. + if (abs(t-m%OldWakeTime)<0.25_ReKi* p%DTaero) then + bReevaluation=.True. + endif + ! Compute Induced wake effects only if time since last compute is > DTfvw + if ( (( t - m%OldWakeTime ) >= p%DTfvw*OneMinusEpsilon) ) then + m%OldWakeTime = t + m%ComputeWakeInduced = .TRUE. ! It's time to update the induced velocities from wake + else + m%ComputeWakeInduced = .FALSE. + endif + if (bReevaluation) then + print*,'[INFO] FVW: Update States: reevaluation at the same starting time' + call RollBackPreviousTimeStep() ! Cancel wake emission done in previous call + m%ComputeWakeInduced = .TRUE. + endif + if (m%ComputeWakeInduced) then + call date_and_time(values=time1) + endif + + + nP = p%nWings * ( (p%nSpan+1)*(m%nNW-1+2) +(FWnSpan+1)*(m%nFW+1) ) + nFWEff = min(m%nFW, p%nFWFree) + ! --- Display some status to screen +!FIXME: this conflicts with the SimStatus WrOver from the FAST_Subs.f90. Leaving out for now. +! Ideally we put this into a log file. +! if (mod(n,10)==0) print'(A,F10.3,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,F7.2,A)','FVW status - t:',t,' n:',n,' nNW:',m%nNW-1,'/',p%nNWMax-1,' nFW:',nFWEff, '+',m%nFW-nFWEff,'=',m%nFW,'/',p%nFWMax,' nP:',nP,' spent:', m%tSpent, 's' + if (DEV_VERSION) print'(A,F10.3,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,F7.2,A,L1)','FVW status - t:',t,' n:',n,' nNW:',m%nNW-1,'/',p%nNWMax-1,' nFW:',nFWEff, '+',m%nFW-nFWEff,'=',m%nFW,'/',p%nFWMax,' nP:',nP,' spent:', m%tSpent, 's Comp:',m%ComputeWakeInduced + + ! --- Evaluation at t + ! Inputs at t + call FVW_CopyInput( u(2), uInterp, MESH_NEWCOPY, ErrStat2, ErrMsg2); if(Failed()) return + call FVW_Input_ExtrapInterp(u(1:size(utimes)),utimes(:),uInterp,t, ErrStat2, ErrMsg2); if(Failed()) return + call Wings_Panelling(uInterp%WingsMesh, p, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! Distribute the Wind we requested to Inflow wind to storage Misc arrays + CALL DistributeRequestedWind(u(1)%V_wind, p, m) + + ! --- Solve for circulation at t + ! Returns: z%Gamma_LL (at t) + call AllocAry( z_guess%Gamma_LL, p%nSpan, p%nWings, 'Lifting line Circulation', ErrStat, ErrMsg ); + 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 + + ! Map circulation and positions between LL and NW and then NW and FW + ! Changes: x only + ShedScale = 1.0_ReKi + call Map_LL_NW(p, m, z, x, ShedScale, ErrStat2, ErrMsg2); if(Failed()) return + call Map_NW_FW(p, m, z, x, ErrStat2, ErrMsg2); if(Failed()) return + !call print_x_NW_FW(p, m, x,'Map_') + + ! --- Integration between t and t+DTaero + ! NOTE: when sub-cycling, the previous convection velocity is used + ! If dtfvw = n dtaero, we assume xdot_local dtaero = xdot_stored * dtfvw/n + if (p%IntMethod .eq. idEuler1) then + call FVW_Euler1( t, uInterp, p, x, xd, z, OtherState, m, ErrStat2, ErrMsg2); if(Failed()) return + !elseif (p%IntMethod .eq. idRK4) then + ! call FVW_RK4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + !elseif (p%IntMethod .eq. idAB4) then + ! call FVW_AB4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + !elseif (p%IntMethod .eq. idABM4) then + ! call FVW_ABM4( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + else + call SetErrStat(ErrID_Fatal,'Invalid time integration method:'//Num2LStr(p%IntMethod),ErrStat,ErrMsg,'FVW_UpdateState') + end IF + !call print_x_NW_FW(p, m, x,'Conv') + + if (m%ComputeWakeInduced) then + ! We extend the wake length, i.e. we emit a new panel of vorticity at the TE + ! NOTE: this will be rolled back if UpdateState is called at the same starting time again + call PrepareNextTimeStep() + ! --- t+DTaero + ! Propagation/creation of new layer of panels + call PropagateWake(p, m, z, x, ErrStat2, ErrMsg2); if(Failed()) return + !call print_x_NW_FW(p, m, x,'Prop_') + endif + + ! Inputs at t+DTaero + call FVW_Input_ExtrapInterp(u(1:size(utimes)),utimes,uInterp,t+p%DTaero, ErrStat2, ErrMsg2); if(Failed()) return + + ! Panelling wings based on input mesh at t+p%DTaero + call Wings_Panelling(uInterp%WingsMesh, p, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! Updating positions of first NW and FW panels (Circulation also updated but irrelevant) + ! Changes: x only + ShedScale = (t+p%DTaero - m%OldWakeTime)/p%DTfvw + call Map_LL_NW(p, m, z, x, ShedScale, ErrStat2, ErrMsg2); if(Failed()) return + call Map_NW_FW(p, m, z, x, ErrStat2, ErrMsg2); if(Failed()) return + + !call print_x_NW_FW(p, m, x,'Map2') + + ! --- Solve for circulation at t+p%DTaero + ! Returns: z%Gamma_LL (at t+p%DTaero) + z_guess%Gamma_LL = z%Gamma_LL ! We use as guess the circulation from the previous time step (see above) + call FVW_CalcConstrStateResidual(t+p%DTaero, uInterp, p, x, xd, z_guess, OtherState, m, z, AFInfo, ErrStat2, ErrMsg2, 2); if(Failed()) return +! print*,'US: z_Gamma',x%Gamma_NW(1,1,1) +! print*,'US: x_Gamma',z%Gamma_LL(1,1) + + ! Updating circulation of near wake panel (and position but irrelevant) + ! Changes: x only + call Map_LL_NW(p, m, z, x, ShedScale, ErrStat2, ErrMsg2); if(Failed()) return + call Map_NW_FW(p, m, z, x, ErrStat2, ErrMsg2); if(Failed()) return + !call print_x_NW_FW(p, m, x,'Map3') + + ! --- Fake handling of ground effect + call FakeGroundEffect(p, x, m, ErrStat, ErrMsg) + + ! set the wind points required for t+p%DTaero timestep + CALL SetRequestedWindPoints(m%r_wind, x, p, m) + + if (m%FirstCall) then + m%FirstCall=.False. + endif + if (m%ComputeWakeInduced) then + ! Profiling of expensive time step + call date_and_time(values=time2) + time_diff=time2-time1 + m%tSpent = time_diff(5)*3600+time_diff(6)*60 +time_diff(7)+0.001*time_diff(8) + endif + call FVW_DestroyConstrState(z_guess, ErrStat2, ErrMsg2); if(Failed()) return + +contains + subroutine PrepareNextTimeStep() + ! --- Increase wake length if maximum not reached + if (m%nNW==p%nNWMax) then ! a far wake exist + m%nFW=min(m%nFW+1, p%nFWMax) + endif + m%nNW=min(m%nNW+1, p%nNWMax) + end subroutine PrepareNextTimeStep + + subroutine RollBackPreviousTimeStep() + ! --- Decrease wake length if maximum not reached + if (m%nNW==p%nNWMax) then ! a far wake exist + m%nFW=max(m%nFW-1, 0) + endif + m%nNW=max(m%nNW-1, 0) + end subroutine RollBackPreviousTimeStep + + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_UpdateStates') + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +end subroutine FVW_UpdateStates + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a tight coupling routine for computing derivatives of continuous states. +subroutine FVW_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(FVW_InputType), intent(in ) :: u !< Inputs at t + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(FVW_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(FVW_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(FVW_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(FVW_ContinuousStateType), intent( out) :: dxdt !< Continuous state derivatives at t + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + integer(IntKi) :: nFWEff ! Number of farwake panels that are free at current time step + integer(IntKi) :: i,j,k + real(ReKi), dimension(3) :: VmeanFW, VmeanNW ! Mean velocity of the near wake and far wake + + ErrStat = ErrID_None + ErrMsg = "" + + call AllocAry( dxdt%r_NW , 3 , p%nSpan+1 ,p%nNWMax+1, p%nWings, 'Wind on NW ', ErrStat2, ErrMsg2); dxdt%r_NW= -999999_ReKi; + call AllocAry( dxdt%r_FW , 3 , FWnSpan+1 ,p%nFWMax+1, p%nWings, 'Wind on FW ', ErrStat2, ErrMsg2); dxdt%r_FW= -999999_ReKi; + if(Failed()) return + + ! Only calculate freewake after start time and if on a timestep when it should be calculated. + if ((t>= p%FreeWakeStart)) then + nFWEff = min(m%nFW, p%nFWFree) + + ! --- Compute Induced velocities on the Near wake and far wake based on the marker postions: + ! (expensive N^2 call) + ! In : x%r_NW, r%r_FW + ! Out: m%Vind_NW, m%Vind_FW + call WakeInducedVelocities(p, x, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! --- Mean induced velocity over the near wake (NW) + VmeanNW(1:3)=0 + if (m%nNW >1) then + do i=1,size(m%Vind_NW,4); do j=2,m%nNW+1; do k=1,size(m%Vind_NW,2); + VmeanNW(1:3) = VmeanNW(1:3) + m%Vind_NW(1:3, k, j, i) + enddo; enddo; enddo; + VmeanNW(1:3) = VmeanNW(1:3) / (size(m%Vind_NW,4)*m%nNW*size(m%Vind_NW,2)) + endif + ! --- Induced velocity over the free far wake (FWEff) + VmeanFW(1:3)=0 + if (nFWEff >0) then + do i=1,size(m%Vind_FW,4); do j=1,nFWEff; do k=1,size(m%Vind_FW,2); + VmeanFW(1:3) = VmeanFW(1:3) + m%Vind_FW(1:3, k, j, i) + enddo; enddo; enddo; + VmeanFW(1:3) = VmeanFW(1:3) / (size(m%Vind_FW,4)*nFWEff*size(m%Vind_FW,2)) + else + VmeanFW=VmeanNW + ! Since we convect the first FW point, we need a reasonable velocity there + ! NOTE: mostly needed for sub-cycling and when no NW + m%Vind_FW(1, 1:FWnSpan+1, 1, 1:p%nWings) = VmeanFW(1) + m%Vind_FW(2, 1:FWnSpan+1, 1, 1:p%nWings) = VmeanFW(2) + m%Vind_FW(3, 1:FWnSpan+1, 1, 1:p%nWings) = VmeanFW(3) + endif + + ! --- Convecting non-free FW with a constant induced velocity (and free stream) + m%Vind_FW(1, 1:FWnSpan+1, p%nFWFree+1:p%nFWMax+1, 1:p%nWings) = VmeanFW(1) ! + m%Vind_FW(2, 1:FWnSpan+1, p%nFWFree+1:p%nFWMax+1, 1:p%nWings) = VmeanFW(2) ! + m%Vind_FW(3, 1:FWnSpan+1, p%nFWFree+1:p%nFWMax+1, 1:p%nWings) = VmeanFW(3) ! + + if (DEV_VERSION) then + call print_mean_4d( m%Vind_NW(:,:, 1:m%nNW+1,:), 'Mean induced vel. NW') + if (nFWEff>0) then + call print_mean_4d( m%Vind_FW(:,:, 1:nFWEff ,:), 'Mean induced vel. FW') + endif + print'(A25,3F12.4)','MeanFW (non free)',VmeanFW + call print_mean_4d( m%Vwnd_NW(:,:, 1:m%nNW+1,:), 'Mean wind vel. NW') + call print_mean_4d( m%Vwnd_FW(:,:, 1:nFWEff+1,:), 'Mean wind vel. FWEff') + call print_mean_4d( m%Vwnd_FW(:,:, (p%nFWFree+1):m%nFW+1,:), 'Mean wind vel. FWNF') + call print_mean_4d( m%Vwnd_FW(:,:, 1:m%nFW+1,:), 'Mean wind vel. FW') + endif + + ! --- Vortex points are convected with the free stream and induced velocity + dxdt%r_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) = m%Vwnd_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) + m%Vind_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) + dxdt%r_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) = m%Vwnd_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) + m%Vind_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) + else + if(DEV_VERSION) then + call print_mean_4d( m%Vwnd_NW(:,:,1:m%nNW+1,:), 'Mean wind vel. NW') + !call print_mean_4d( m%Vwnd_FW(:,:,1:m%nFW+1,:), 'Mean wind vel. FW') + endif + + ! --- Vortex points are convected with the free stream + dxdt%r_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) = m%Vwnd_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) + dxdt%r_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) = m%Vwnd_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) + endif + ! First NW point does not convect (bound to LL) + dxdt%r_NW(1:3, :, 1:iNWStart-1, :)=0 + ! First FW point always convects (even if bound to NW) + ! This is done for subcycling + !dxdt%r_FW(1:3, :, 1, :)=0 +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_CalcContStateDeriv') + Failed = ErrStat >= AbortErrLev + end function Failed +end subroutine FVW_CalcContStateDeriv + +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine FVW_Euler1( t, u, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(FVW_InputType), intent(in ) :: u !< Input at t + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(inout) :: x !< Continuous states at t on input at t + dt on output + type(FVW_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraint states at t (possibly a guess) + type(FVW_OtherStateType), intent(inout) :: OtherState !< Other states at t on input at t + dt on output + type(FVW_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(FVW_ContinuousStateType) :: dxdt ! time derivatives of continuous states + real(ReKi) :: dt + integer(IntKi) :: ErrStat2 ! temporary error status of the operation + character(ErrMsgLen) :: ErrMsg2 ! temporary error message + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + dt = real(p%DTaero,ReKi) ! NOTE: this is DTaero not DTfvw since we integrate at each sub time step + ! Compute "right hand side" + if (m%ComputeWakeInduced) then + CALL FVW_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat2, ErrMsg2); if (Failed()) return + ! Storage of convection velocity, purely for sub-cycling for now + ! Since Euler1 is linear we use partial increments of dtaero0) then + if (any(m%dxdt_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings)<-999)) then + call print_x_NW_FW(p, m, x, 'STP') + print*,'FVW_Euler1: Attempting to convect FW with a wrong velocity' + STOP + endif + endif + endif + + ! Update of positions + x%r_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) = x%r_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) + dt * m%dxdt_NW(1:3, 1:p%nSpan+1, 1:m%nNW+1, 1:p%nWings) + if ( m%nFW>0) then + x%r_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) = x%r_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) + dt * m%dxdt_FW(1:3, 1:FWnSpan+1, 1:m%nFW+1, 1:p%nWings) + endif + ! Update of Gamma + ! TODO, viscous diffusion, stretching + + call FVW_DestroyContState(dxdt, ErrStat2, ErrMsg2); if(Failed()) return +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_Euler1') + Failed = ErrStat >= AbortErrLev + end function Failed +end subroutine FVW_Euler1 +!---------------------------------------------------------------------------------------------------------------------------------- + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a tight coupling routine for solving for the residual of the constraint state functions. +subroutine FVW_CalcConstrStateResidual( t, u, p, x, xd, z_guess, OtherState, m, z_out, AFInfo, ErrStat, ErrMsg, iLabel) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(FVW_InputType), intent(in ) :: u !< Inputs at t + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(FVW_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(FVW_ConstraintStateType), intent(in ) :: z_guess !< Constraint states at t (possibly a guess) + type(FVW_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(FVW_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(FVW_ConstraintStateType), intent( out) :: z_out !< Residual of the constraint state functions using + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data + integer(IntKi), intent(in ) :: iLabel + integer(IntKi), intent( OUT) :: ErrStat !< Error status of the operation + character(*), intent( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! Solve for the residual of the constraint state functions here: + !z%residual = 0.0_ReKi + !z%Gamma_LL = 0.0_ReKi + call AllocAry( z_out%Gamma_LL, p%nSpan, p%nWings, 'Lifting line Circulation', ErrStat, ErrMsg ); + z_out%Gamma_LL = -999999_ReKi; + + CALL Wings_ComputeCirculation(t, z_out%Gamma_LL, z_guess%Gamma_LL, u, p, x, m, AFInfo, ErrStat, ErrMsg, iLabel) + +end subroutine FVW_CalcConstrStateResidual + +!---------------------------------------------------------------------------------------------------------------------------------- +!> Routine for computing outputs, used in both loose and tight coupling. +!! This subroutine is used to compute the output channels (motions and loads) and place them in the WriteOutput() array. +!! The descriptions of the output channels are not given here. Please see the included OutListParameters.xlsx sheet for +!! for a complete description of each output parameter. +! NOTE: no matter how many channels are selected for output, all of the outputs are calculated +! All of the calculated output channels are placed into the m%AllOuts(:), while the channels selected for outputs are +! placed in the y%WriteOutput(:) array. +subroutine FVW_CalcOutput( t, u, p, x, xd, z, OtherState, AFInfo, y, m, ErrStat, ErrMsg ) + use FVW_VTK, only: set_vtk_coordinate_transform + use FVW_VortexTools, only: interpextrap_cp2node + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(FVW_InputType), intent(in ) :: u !< Inputs at Time t + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(FVW_DiscreteStateType), intent(in ) :: xd !< Discrete states at t +!FIXME:TODO: AD15_CalcOutput has constraint states as intent(in) only. This is forcing me to store z in the AD15 miscvars for now. + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(FVW_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data + type(FVW_OutputType), intent(inout) :: y !< Outputs computed at t (Input only so that mesh con- + !! nectivity information does not have to be recalculated) + type(FVW_MiscVarType), intent(inout) :: m !< Misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: iW, n, i0, i1, i2 + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'FVW_CalcOutput' + + ErrStat = ErrID_None + ErrMsg = "" + + if (DEV_VERSION) then + print'(A,F10.3,A,L1,A,I0,A,I0)','CalcOutput t:',t,' ',m%FirstCall,' nNW:',m%nNW,' nFW:',m%nFW + endif + + ! Set the wind velocity at vortex + CALL DistributeRequestedWind(u%V_wind, p, m) + + ! if we are on a correction step, CalcOutput may be called again with different inputs + ! Compute m%Gamma_LL + CALL Wings_ComputeCirculation(t, m%Gamma_LL, z%Gamma_LL, u, p, x, m, AFInfo, ErrStat2, ErrMsg2, 0); if(Failed()) return ! For plotting only + + + ! Induction on the lifting line control point + ! Set m%Vind_LL + m%Vind_LL=-9999.0_ReKi + call LiftingLineInducedVelocities(p, x, 1, m, ErrStat2, ErrMsg2); if(Failed()) return + + ! Induction on the mesh points (AeroDyn nodes) + n=p%nSpan + y%Vind(1:3,:,:) = 0.0_ReKi + do iW=1,p%nWings + ! --- Linear interpolation for interior points and extrapolations at boundaries + call interpextrap_cp2node(m%s_CP_LL(:,iW), m%Vind_LL(1,:,iW), m%s_LL(:,iW), y%Vind(1,:,iW)) + call interpextrap_cp2node(m%s_CP_LL(:,iW), m%Vind_LL(2,:,iW), m%s_LL(:,iW), y%Vind(2,:,iW)) + call interpextrap_cp2node(m%s_CP_LL(:,iW), m%Vind_LL(3,:,iW), m%s_LL(:,iW), y%Vind(3,:,iW)) + enddo + + ! For plotting only + m%Vtot_ll = m%Vind_LL + m%Vwnd_LL - m%Vstr_ll + if (DEV_VERSION) then + call print_mean_3d(m%Vind_LL,'Mean induced vel. LL') + call print_mean_3d(m%Vtot_LL,'Mean relativevel. LL') + endif + + ! --- Write to local VTK at fps requested + if (p%WrVTK==1) then + if (m%VTKStep==-1) then + m%VTKStep = 0 ! Has never been called, special handling for init + else + m%VTKStep = m%iStep+1 ! We use glue code step number for outputs + endif + if (m%FirstCall) then + call MKDIR('vtk_fvw') + 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., & + 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.) + endif + endif + endif + + +contains + + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_CalcOutput') + Failed = ErrStat >= AbortErrLev + end function Failed + +end subroutine FVW_CalcOutput +!---------------------------------------------------------------------------------------------------------------------------------- +! --- UA related, should be merged with AeroDyn +!---------------------------------------------------------------------------------------------------------------------------------- +subroutine UA_Init_Wrapper(AFInfo, InitInp, interval, p, x, xd, OtherState, m, ErrStat, ErrMsg ) + use UnsteadyAero, only: UA_Init, UA_TurnOff_param + type(AFI_ParameterType), intent(in ) :: AFInfo(:) !< The airfoil parameter data, temporary, for UA.. + type(FVW_InitInputType), intent(inout) :: InitInp !< Input data for initialization routine (inout so we can use MOVE_ALLOC) + real(DbKi), intent(inout) :: interval !< time interval + type(FVW_ParameterType), intent(inout) :: p !< Parameters + type(FVW_ContinuousStateType), intent(inout) :: x !< Initial continuous states + type(FVW_DiscreteStateType), intent(inout) :: xd !< Initial discrete states + type(FVW_OtherStateType), intent(inout) :: OtherState !< Initial other states + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! + type(UA_InitInputType) :: Init_UA_Data + type(UA_InputType) :: u_UA + type(UA_InitOutputType):: InitOutData_UA + integer :: i,j + integer(intKi) :: ErrStat2 ! temporary Error status + character(ErrMsgLen) :: ErrMsg2 + ErrStat = ErrID_None + ErrMsg = "" + + m%UA_Flag=InitInp%UA_Flag + ! --- Condensed version of BEMT_Init_Otherstate + allocate ( OtherState%UA_Flag( InitInp%numBladeNodes, InitInp%NumBlades ), STAT = ErrStat2 ) + OtherState%UA_Flag=m%UA_Flag + if ( m%UA_Flag ) then + ErrMsg2='Unsteady aerodynamic (`AFAeroMod>1`) cannot be used with the free wake code (`WakeMod=3`) for now.'; ErrStat2=ErrID_Fatal; + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'UA_Init_Wrapper'); return + + ! ---Condensed version of "BEMT_Set_UA_InitData" + allocate(Init_UA_Data%c(InitInp%numBladeNodes,InitInp%numBlades), STAT = errStat2) + do j = 1,InitInp%NumBlades; do i = 1,InitInp%numBladeNodes; + Init_UA_Data%c(i,j) = p%chord(i,j) ! NOTE: InitInp chord move-allocd to p + end do; end do + Init_UA_Data%dt = interval + Init_UA_Data%OutRootName = '' + Init_UA_Data%numBlades = InitInp%NumBlades + Init_UA_Data%nNodesPerBlade = InitInp%numBladeNodes + Init_UA_Data%NumOuts = 0 + Init_UA_Data%UAMod = InitInp%UAMod + 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 + 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) + 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. + end if + end do; end do; +#ifdef UA_OUTS + CALL OpenFOutFile ( 69, 'Debug.UA.out', errStat, errMsg ); IF (ErrStat >= AbortErrLev) RETURN + WRITE (69,'(/,A)') 'This output information was generated by FVW'// ' 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 + call UA_DestroyInput( u_UA, ErrStat2, ErrMsg2 ); if(Failed())return + call UA_DestroyInitInput( Init_UA_Data, ErrStat2, ErrMsg2 ); if(Failed())return + call UA_DestroyInitOutput( InitOutData_UA, ErrStat2, ErrMsg2 ); if(Failed())return + + ! --- FVW specific + if (p%CirculationMethod/=idCircPolarData) then + ErrMsg2='Unsteady aerodynamic (`AFAeroMod>1`) is only available with a circulation solving using profile data (`CircSolvingMethod=1`)'; ErrStat2=ErrID_Fatal; + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'UA_Init_Wrapper'); return + endif + endif +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'UA_Init_Wrapper') + Failed = ErrStat >= AbortErrLev + end function Failed +end subroutine UA_Init_Wrapper + +subroutine UA_UpdateState_Wrapper(AFInfo, 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.. + integer(IntKi), intent(in ) :: n !< time step + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_InputType), intent(in ) :: u !< Inputs + type(FVW_ContinuousStateType), intent(inout) :: x !< Initial continuous states + type(FVW_DiscreteStateType), intent(inout) :: xd !< Initial discrete states + type(FVW_OtherStateType), intent(inout) :: OtherState !< Initial other states + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + 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 + integer :: i,j + integer(intKi) :: ErrStat2 ! temporary Error status + character(ErrMsgLen) :: ErrMsg2 + real(ReKi), dimension(:,:), allocatable :: Vind_node + ErrStat = ErrID_None + ErrStat2 = ErrID_None + ErrMsg = "" + ErrMsg2 = "" + if (m%UA_Flag) then + + ! --- Induction on the lifting line control point + ! NOTE: this is expensive since it's an output for FVW but here we have to use it for UA + ! Set m%Vind_LL + m%Vind_LL=-9999.0_ReKi + call LiftingLineInducedVelocities(p, x, 1, m, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'UA_UpdateState_Wrapper'); if (ErrStat >= AbortErrLev) return + + allocate(Vind_node(3,1:p%nSpan+1)) + + ! --- Condensed version of BEMT_Update States + do j = 1,p%nWings + ! Induced velocity at Nodes (NOTE: we rely on storage done when computing Circulation) + if (m%nNW>1) then + call interpextrap_cp2node(m%s_CP_LL(:,j), m%Vind_LL(1,:,j), m%s_LL(:,j), Vind_node(1,:)) + call interpextrap_cp2node(m%s_CP_LL(:,j), m%Vind_LL(2,:,j), m%s_LL(:,j), Vind_node(2,:)) + call interpextrap_cp2node(m%s_CP_LL(:,j), m%Vind_LL(3,:,j), m%s_LL(:,j), Vind_node(3,:)) + else + Vind_node=0.0_ReKi + endif + + do i = 1,p%nSpan+1 + ! 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 + !! ....... 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 + !! ....... check inputs to UA ........... + call UA_TurnOff_input(AFInfo(p%AFIndx(i,j)), u_UA, 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 ) + if (ErrStat2 /= ErrID_None) then + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'UA_UpdateState_Wrapper'//trim(NodeText(i,j))) + call WrScr(trim(ErrMsg)) + if (ErrStat >= AbortErrLev) return + end if + end if + end if + end do + end do + call UA_DestroyInput( u_UA, ErrStat2, ErrMsg2 ); + deallocate(Vind_node) + endif + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'UA_UpdateState_Wrapper') +contains + function NodeText(i,j) + integer(IntKi), intent(in) :: i ! node number + integer(IntKi), intent(in) :: j ! blade number + character(25) :: NodeText + NodeText = '(nd:'//trim(num2lstr(i))//' bld:'//trim(num2lstr(j))//')' + end function NodeText +end subroutine UA_UpdateState_Wrapper + +end module FVW diff --git a/modules/aerodyn/src/FVW_BiotSavart.f90 b/modules/aerodyn/src/FVW_BiotSavart.f90 new file mode 100644 index 0000000000..cb15a379ea --- /dev/null +++ b/modules/aerodyn/src/FVW_BiotSavart.f90 @@ -0,0 +1,430 @@ +module FVW_BiotSavart + + use NWTC_Library, only: ReKi, IntKi + use OMP_LIB ! wrap with #ifdef _OPENMP if this causes an issue + + implicit none + + real(ReKi),parameter :: PRECISION_UI = epsilon(1.0_ReKi)/100 !< NOTE assuming problem of size 1 + real(ReKi),parameter :: MIN_EXP_VALUE=-10.0_ReKi + real(ReKi),parameter :: MINDENOM=0.0_ReKi +! real(ReKi),parameter :: MINDENOM=1e-15_ReKi + real(ReKi),parameter :: MINNORM=1e-4 + + integer(IntKi), parameter :: idRegNone = 0 + integer(IntKi), parameter :: idRegRankine = 1 + integer(IntKi), parameter :: idRegLambOseen = 2 + integer(IntKi), parameter :: idRegVatistas = 3 + integer(IntKi), parameter :: idRegOffset = 4 + integer(IntKi), parameter :: idRegExp = 1 + integer(IntKi), parameter :: idRegCompact = 2 + integer(IntKi), parameter, dimension(5) :: idRegVALID = (/idRegNone,idRegRankine,idRegLambOseen,idRegVatistas,idRegOffset/) + integer(IntKi), parameter, dimension(3) :: idRegPartVALID = (/idRegNone,idRegExp,idRegCompact/) + + real(ReKi),parameter :: fourpi_inv = 0.25_ReKi / ACOS(-1.0_Reki ) + +contains + + +!> Induced velocity from one segment at one control points +subroutine ui_seg_11(DeltaPa, DeltaPb, SegGamma, RegFunction, RegParam1, Uind) + ! Input/output arguments + real(ReKi), dimension(3), intent(in) :: DeltaPa !< 3 x 1 Pcp-P1 [m] + real(ReKi), dimension(3), intent(in) :: DeltaPb !< 3 x 1 Pcp-P2 [m] + real(ReKi), intent(in) :: SegGamma !< Circulation [m^2/s] + integer, intent(in) :: RegFunction!< Regularization model + real(ReKi), intent(in) :: RegParam1 !< Regularization parameter (core radius) [m] + real(ReKi), dimension(3),intent(out) :: Uind !< Induced velocity (no side effects) [m/s] + ! Variables declaration + real(ReKi),dimension(3) :: crossprod !< + real(ReKi) :: denominator !< + real(ReKi) :: r_bar2 !< (r/rc)^2 + real(ReKi) :: Kv !< + real(ReKi) :: norm_a, norm_b !< + real(ReKi) :: norm2_r0 !< Squared length of the segment + real(ReKi) :: norm2_orth !< Squared distance orthogonal to the segment + real(ReKi) :: xa, ya, za, xb, yb, zb !< Coordinates of X-Xa and X-Xb + real(ReKi) :: exp_value !< + ! + Uind(1:3)=0.0_ReKi + xa=DeltaPa(1); ya=DeltaPa(2); za=DeltaPa(3) + xb=DeltaPb(1); yb=DeltaPb(2); zb=DeltaPb(3) + norm_a = sqrt(xa*xa + ya*ya + za*za) + norm_b = sqrt(xb*xb + yb*yb + zb*zb) + denominator = norm_a*norm_b*(norm_a*norm_b + xa*xb+ya*yb+za*zb) ! |r1|*|r2|*(|r1|*|r2| + r1.r2) + if (denominator>PRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then ! segment of zero length + ! --- Far field TODO + ! --- Regularization (close field) + norm2_orth = norm2_orth/norm2_r0 ! d = (r1xr2)/r0 + select case (RegFunction) ! + case ( idRegNone ) ! No vortex core model + Kv=1.0_ReKi + case ( idRegRankine ) ! Rankine + r_bar2 = norm2_orth/ RegParam1**2 + if (r_bar2<1) then + Kv=r_bar2 + else + Kv=1.0_ReKi + end if + case ( idRegLambOseen ) ! Lamb-Oseen + r_bar2 = norm2_orth/ RegParam1**2 + exp_value = -1.25643_ReKi*r_bar2 + if(exp_value Induced velocity from a list of segments defined by Connectivity (SegConnct) and Points (SegPoints) +!! NOTE: this function has side effects and expects Uind_out to be initialized! +!! The function can compute the velocity on part of the segments and part of the control points. +!! This feature is useful if some parallelization is used, while common storage vectors are used. +subroutine ui_seg(iCPStart, iCPEnd, CPs, & + iSegStart, iSegEnd, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, & + RegFunction, RegParam, Uind_out) + real(ReKi), dimension(:,:), intent(in) :: CPs !< Control points (3 x nCPs++) + integer(IntKi), intent(in) :: iCPStart !< Index where we start in Control points array + integer(IntKi), intent(in) :: iCPEnd !< Index where we end in Control points array + real(ReKi), dimension(:,:), intent(in) :: SegPoints !< Segment points (3 x nSegPTot) + integer(IntKi), dimension(:,:), intent(in) :: SegConnct !< Connectivity, indices of segments points iSeg1, iSeg2, iDepth, iSpan + real(ReKi), dimension(:), intent(in) :: SegGamma !< Segment circulation (nSegTot) + integer(IntKi), intent(in) :: iSegStart !< Index in SegConnct, and SegGamma where we start + integer(IntKi), intent(in) :: iSegEnd !< Index in SegConnct, and SegGamma where we end + integer(IntKi), intent(in) :: nSegTot !< Total number of segments + integer(IntKi), intent(in) :: nSegPTot !< Total number of segment points + integer(IntKi), intent(in) :: RegFunction !< Regularization model + real(ReKi), dimension(:), intent(in) :: RegParam !< Regularization parameter (nSegTot) + real(ReKi), dimension(:,:) , intent(inout) :: Uind_out !< Induced velocity vector - Side effects!!! (3 x nCPs++) + ! Variables + integer(IntKi) :: icp, is + real(ReKi), dimension(3) :: Uind !< + real(ReKi), dimension(3) :: P1, P2 !< Extremities of a given segment + ! Variables declaration + real(ReKi),dimension(3) :: crossprod !< + real(ReKi) :: denominator !< + real(ReKi) :: r_bar2 !< (r/rc)^2 + real(ReKi) :: Kv !< + real(ReKi) :: norm_a, norm_b !< + real(ReKi) :: norm2_orth !< + real(ReKi) :: norm2_r0 !< Squared length of the segment d = (r1xr2)/r0 + real(ReKi) :: xa, ya, za, xb, yb, zb !< Coordinates of X-Xa and X-Xb + real(ReKi) :: exp_value !< + + ! Branching based on regularization model + ! NOTE: copy paste of code is done for optimization! + ! The only thing changing is the part labelled "regularization" + select case (RegFunction) + case ( idRegNone ) ! No vortex core + !$OMP PARALLEL default(shared) + !$OMP do private(icp,is,Uind,P1,P2,crossprod,denominator,Kv,norm_a,norm_b,norm2_r0,norm2_orth,xa,ya,za,xb,yb,zb) schedule(runtime) + do icp=iCPStart,iCPEnd ! loop on CPs + do is=iSegStart,iSegEnd ! loop on selected segments + Uind = 0.0_ReKi + P1 = SegPoints(1:3, SegConnct(1,is)) ! Segment extremity points + P2 = SegPoints(1:3, SegConnct(2,is)) + xa=CPs(1,icp)-P1(1); ya=CPs(2,icp)-P1(2); za=CPs(3,icp)-P1(3); + xb=CPs(1,icp)-P2(1); yb=CPs(2,icp)-P2(2); zb=CPs(3,icp)-P2(3); + norm_a = sqrt(xa*xa + ya*ya + za*za) + norm_b = sqrt(xb*xb + yb*yb + zb*zb) + denominator = norm_a*norm_b*(norm_a*norm_b + xa*xb+ya*yb+za*zb) + ! --- Far field TODO + if (denominator>PRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then + ! --- Far field TODO + ! --- NO Regularization (close field) + Kv = SegGamma(is)*fourpi_inv*(norm_a+norm_b)/(denominator + MINDENOM) + Uind(1:3) = Kv*crossprod(1:3) + end if + end if + end if + Uind_out(1:3,icp) = Uind_out(1:3,icp)+Uind(1:3) + end do ! Loop on segments + enddo ! Loop on control points + !$OMP END DO + !$OMP END PARALLEL + + case ( idRegRankine ) ! Rankine + !$OMP PARALLEL default(shared) + !$OMP do private(icp,is,Uind,P1,P2,crossprod,denominator,r_bar2,Kv,norm_a,norm_b,norm2_r0,norm2_orth,xa,ya,za,xb,yb,zb) schedule(runtime) + do icp=iCPStart,iCPEnd ! loop on CPs + do is=iSegStart,iSegEnd ! loop on selected segments + Uind = 0.0_ReKi + P1 = SegPoints(1:3, SegConnct(1,is)) ! Segment extremity points + P2 = SegPoints(1:3, SegConnct(2,is)) + xa=CPs(1,icp)-P1(1); ya=CPs(2,icp)-P1(2); za=CPs(3,icp)-P1(3); + xb=CPs(1,icp)-P2(1); yb=CPs(2,icp)-P2(2); zb=CPs(3,icp)-P2(3); + norm_a = sqrt(xa*xa + ya*ya + za*za) + norm_b = sqrt(xb*xb + yb*yb + zb*zb) + denominator = norm_a*norm_b*(norm_a*norm_b + xa*xb+ya*yb+za*zb) + if (denominator>PRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then + ! --- Far field TODO + ! --- Regularization (close field) --- Rankine + norm2_orth = norm2_orth/norm2_r0 ! d = (r1xr2)/r0 + r_bar2 = norm2_orth/ RegParam(is)**2 + if (r_bar2<1) then + Kv=r_bar2 + else + Kv=1.0_ReKi + end if + Kv = SegGamma(is)*fourpi_inv*Kv*(norm_a+norm_b)/(denominator + MINDENOM) + Uind(1:3) = Kv*crossprod(1:3) + end if + end if ! denominator size or distances too small + end if ! + Uind_out(1:3,icp) = Uind_out(1:3,icp)+Uind(1:3) + end do ! Loop on segments + enddo ! Loop on control points + !$OMP END DO + !$OMP END PARALLEL + + case ( idRegLambOseen ) ! LambOseen + !$OMP PARALLEL default(shared) + !$OMP do private(icp,is,Uind,P1,P2,crossprod,denominator,r_bar2,Kv,norm_a,norm_b,norm2_r0,norm2_orth,xa,ya,za,xb,yb,zb,exp_value) schedule(runtime) + do icp=iCPStart,iCPEnd ! loop on CPs + do is=iSegStart,iSegEnd ! loop on selected segments + Uind = 0.0_ReKi + P1 = SegPoints(1:3, SegConnct(1,is)) ! Segment extremity points + P2 = SegPoints(1:3, SegConnct(2,is)) + xa=CPs(1,icp)-P1(1); ya=CPs(2,icp)-P1(2); za=CPs(3,icp)-P1(3); + xb=CPs(1,icp)-P2(1); yb=CPs(2,icp)-P2(2); zb=CPs(3,icp)-P2(3); + norm_a = sqrt(xa*xa + ya*ya + za*za) + norm_b = sqrt(xb*xb + yb*yb + zb*zb) + denominator = norm_a*norm_b*(norm_a*norm_b + xa*xb+ya*yb+za*zb) + if (denominator>PRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then + ! --- Far field TODO + ! --- Regularization (close field) --- Lamb Oseen + norm2_orth = norm2_orth/norm2_r0 ! d = (r1xr2)/r0 + r_bar2 = norm2_orth/ RegParam(is)**2 + exp_value = -1.25643_ReKi*r_bar2 + if(exp_valuePRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then + ! --- Far field TODO + ! --- Regularization (close field) --- Vatistas + norm2_orth = norm2_orth/norm2_r0 ! d = (r1xr2)/r0 + r_bar2 = norm2_orth/RegParam(is)**2 + Kv = r_bar2/sqrt(1+r_bar2**2) + Kv = SegGamma(is)*fourpi_inv*Kv*(norm_a+norm_b)/(denominator + MINDENOM) + Uind(1:3) = Kv*crossprod(1:3) + end if + end if ! denominator size or distances too small + end if ! + Uind_out(1:3,icp) = Uind_out(1:3,icp)+Uind(1:3) + end do ! Loop on segments + enddo ! Loop on control points + !$OMP END DO + !$OMP END PARALLEL + + case ( idRegOffset ) ! Denominator offset + !$OMP PARALLEL default(shared) + !$OMP do private(icp,is,Uind,P1,P2,crossprod,denominator,r_bar2,Kv,norm_a,norm_b,norm2_r0,norm2_orth,xa,ya,za,xb,yb,zb) schedule(runtime) + do icp=iCPStart,iCPEnd ! loop on CPs + do is=iSegStart,iSegEnd ! loop on selected segments + Uind = 0.0_ReKi + P1 = SegPoints(1:3, SegConnct(1,is)) ! Segment extremity points + P2 = SegPoints(1:3, SegConnct(2,is)) + xa=CPs(1,icp)-P1(1); ya=CPs(2,icp)-P1(2); za=CPs(3,icp)-P1(3); + xb=CPs(1,icp)-P2(1); yb=CPs(2,icp)-P2(2); zb=CPs(3,icp)-P2(3); + norm_a = sqrt(xa*xa + ya*ya + za*za) + norm_b = sqrt(xb*xb + yb*yb + zb*zb) + denominator = norm_a*norm_b*(norm_a*norm_b + xa*xb+ya*yb+za*zb) + if (denominator>PRECISION_UI) then + crossprod(1) = ya*zb-za*yb; crossprod(2) = za*xb-xa*zb; crossprod(3) = xa*yb-ya*xb + norm2_orth = crossprod(1)**2 + crossprod(2)**2 + crossprod(3)**2 + if (norm2_orth>PRECISION_UI) then ! On the singularity, Uind(1:3)=0.0_ReKi + norm2_r0 = (xa-xb)*(xa-xb) + (ya-yb)*(ya-yb) +(za-zb)*(za-zb) + if (norm2_r0>PRECISION_UI) then + ! --- Far field TODO + ! --- Regularization (close field) -- Offset + denominator = denominator+RegParam(is)**2*norm2_r0 + Kv = SegGamma(is)*fourpi_inv*(norm_a+norm_b)/(denominator + MINDENOM) + Uind(1:3) = Kv*crossprod(1:3) + end if + end if ! denominator size or distances too small + end if ! + Uind_out(1:3,icp) = Uind_out(1:3,icp)+Uind(1:3) + end do ! Loop on segments + enddo ! Loop on control points + !$OMP END DO + !$OMP END PARALLEL + case default + print*,'[ERROR] Unknown RegFunction for segment',RegFunction + STOP + end select +end subroutine ui_seg + +!> Induced velocity from `nPart` particles at `nCPs` control points. The velocity gradient is not computed +subroutine ui_part_nograd(CPs, Part, Alpha, RegFunction, RegParam, UIout, nCPs, nPart) + integer(IntKi), intent(in) :: nCPs + integer(IntKi), intent(in) :: nPart + real(ReKi), dimension(:,:), intent(in) :: CPs !< Control points (3 x nCPs) + real(ReKi), dimension(:,:), intent(inout) :: UIout !< Induced velocity, with side effects! (3 x nCPs) + real(ReKi), dimension(:,:), intent(in) :: Part !< Particle positions (3 x nPart) + real(ReKi), dimension(:,:), intent(in) :: Alpha !< Particle intensity [m^3/s] (3 x nPart) omega dV= alpha + integer(IntKi), intent(in) :: RegFunction !< Regularization function + real(ReKi), dimension(:), intent(in) :: RegParam !< Regularization parameter (nPart) + real(ReKi), dimension(3) :: UItmp !< + real(ReKi), dimension(3) :: DP !< + integer :: icp,ip + ! TODO: inlining of regularization + !$OMP PARALLEL DEFAULT(SHARED) + !$OMP DO PRIVATE(icp,ip, DP, UItmp) schedule(runtime) + do icp=1,nCPs ! loop on CPs + do ip=1,nPart ! loop on particles + UItmp(1:3) = 0.0_ReKi + DP(1:3) = CPs(1:3,icp)-Part(1:3,ip) + call ui_part_nograd_11(DP, Alpha(1:3,ip), RegFunction , RegParam(ip), UItmp) + UIout(1:3,icp)=UIout(1:3,icp)+UItmp(1:3) + enddo! loop on particles + enddo ! loop CPs + !$OMP END DO + !$OMP END PARALLEL +end subroutine ui_part_nograd + +!> Induced velocity from 1 particle at 1 control point. The velocity gradient is not computed +subroutine ui_part_nograd_11(DeltaP, Alpha, RegFunction, RegParam, Ui) + real(ReKi), dimension(3), intent(out) :: Ui !< no side effects + real(ReKi), dimension(3), intent(in) :: DeltaP !< CP-PP "control point - particle point" + real(ReKi), dimension(3), intent(in) :: Alpha !< Particle intensity [m^2/s] alpha=om.dV + integer(IntKi), intent(in) :: RegFunction !< + real(ReKi), intent(in) :: RegParam !< + real(ReKi),dimension(3) :: C !< Cross product of Alpha and r + real(ReKi) :: E !< Exponential poart for the mollifider + real(ReKi) :: r3_inv !< + real(ReKi) :: rDeltaP !< norm , distance between point and particle + real(ReKi) :: ScalarPart !< the part containing the inverse of the distance, but not 4pi, Mollifier + rDeltaP=sqrt(DeltaP(1)**2+ DeltaP(2)**2+ DeltaP(3)**2)! norm + if (rDeltaP Velocity induced by one vortex quad on nCPs Control Points +subroutine ui_quad_n1(CPs, nCPs, P1, P2, P3, P4, Gamm, RegFunction, RegParam, Uind) + integer, intent(in) :: nCPs !< + real(ReKi), dimension(:,:), intent(in) :: CPs !< 3 x "nCPs"++ + real(ReKi), dimension(3), intent(in) :: P1,P2,P3,P4 !< Coordinates of vortex quadrilateral + real(ReKi), intent(in) :: Gamm + integer(IntKi) , intent(in) :: RegFunction !< Regularization model (e.g. LambOseen) + real(ReKi), intent(in) :: RegParam !< Regularization parameter [m] + real(ReKi), dimension(:,:), intent(inout) :: Uind !< side effects!!! 3 x "nCPs++" + real(ReKi), dimension(3) :: CP !< + real(ReKi), dimension(3) :: Uindtmp !< + real(ReKi), dimension(3) :: DP1 !< + real(ReKi), dimension(3) :: DP2 !< + integer :: icp + ! + !OMP PARALLEL DEFAULT(SHARED) + !OMP DO PRIVATE(icp,CP,Uindtmp,DP1,DP2) schedule(runtime) + do icp=1,nCPs + CP(1:3)=CPs(1:3,icp) + ! 1-2 segment + DP1=CP-P1; DP2=CP-P2; + call ui_seg_11 ( DP1, DP2, Gamm, RegFunction, RegParam, Uindtmp) + Uind(1:3,icp) = Uind(1:3,icp)+Uindtmp(1:3) + ! 3-4 segment + DP1=CP-P3; DP2=CP-P4; + call ui_seg_11 ( DP1, DP2, Gamm, RegFunction, RegParam, Uindtmp) + Uind(1:3,icp) = Uind(1:3,icp)+Uindtmp(1:3) + ! 2-3 segment + DP1=CP-P2; DP2=CP-P3; + call ui_seg_11 ( DP1, DP2, Gamm, RegFunction, RegParam, Uindtmp) + Uind(1:3,icp) = Uind(1:3,icp)+Uindtmp(1:3) + ! 4-1 segment + DP1=CP-P4; DP2=CP-P1; + call ui_seg_11 ( DP1, DP2, Gamm, RegFunction, RegParam, Uindtmp) + Uind(1:3,icp) = Uind(1:3,icp)+Uindtmp(1:3) + end do ! loop on CPs + !OMP END DO + !OMP END PARALLEL +end subroutine ui_quad_n1 + +end module FVW_BiotSavart diff --git a/modules/aerodyn/src/FVW_IO.f90 b/modules/aerodyn/src/FVW_IO.f90 new file mode 100644 index 0000000000..9dc0f23db9 --- /dev/null +++ b/modules/aerodyn/src/FVW_IO.f90 @@ -0,0 +1,411 @@ +module FVW_IO + + USE FVW_Types + USE FVW_Subs + use FVW_VortexTools + implicit none + +contains + +! ============================================================================== +!> Reads the input file for FVW +SUBROUTINE FVW_ReadInputFile( FileName, p, Inp, ErrStat, ErrMsg ) + character(len=*), intent(in) :: FileName !< Input file name for FVW + type( FVW_ParameterType ), intent(inout) :: p !< Parameters + type(FVW_InputFile), intent(out) :: Inp !< Data stored in the module's input file + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + character(1024) :: PriPath ! the path to the primary input file + character(1024) :: VTK_fps_line ! string to temporarially hold value of read line for VTK_fps + integer(IntKi) :: UnIn + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + ErrStat = ErrID_None + ErrMsg = "" + ! Open file + CALL GetNewUnit( UnIn ) + CALL OpenFInpfile(UnIn, TRIM(FileName), ErrStat2, ErrMsg2) + if (Check( ErrStat2 /= ErrID_None , 'Could not open input file')) return + CALL GetPath( FileName, PriPath ) ! Input files will be relative to the path where the primary input file is located. + !------------------------------------- HEADER --------------------------------------------------- + CALL ReadCom(UnIn, FileName, 'FVW input file header line 1', ErrStat2, ErrMsg2 ); if(Failed()) return + CALL ReadCom(UnIn, FileName, 'FVW input file header line 2', ErrStat2, ErrMsg2 ); if(Failed()) return + !------------------------ GENERAL OPTIONS ------------------------------------------- + CALL ReadCom (UnIn,FileName, '--- General option header' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%IntMethod ,'Integration method' ,'', idEuler1 , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%DTfvw ,'DTfvw' ,'', p%DTaero , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%FreeWakeStart ,'FreeWakeStart' ,'', 0.0_ReKi , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%FullCirculationStart,'FullCirculationStart','', real(20.0_ReKi*Inp%DTfvw,ReKi), ErrStat2,ErrMsg2); if(Failed())return + !------------------------ CIRCULATION SPECIFICATIONS ------------------------------------------- + CALL ReadCom(UnIn,FileName, '--- Circulation specification header' , ErrStat2, ErrMsg2 ); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%CirculationMethod ,'CirculationMethod' ,'', idCircPolarData, ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%CircSolvConvCrit ,'CircSolvConvCrit ' ,'', 0.001 , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%CircSolvRelaxation,'CircSolvRelaxation','', 0.1 , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%CircSolvMaxIter ,'CircSolvMaxIter' ,'', 30 , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVar(UnIn,FileName,Inp%CirculationFile ,'CirculationFile' ,'',ErrStat2,ErrMsg2); if(Failed())return + !------------------------ WAKE OPTIONS ------------------------------------------- + CALL ReadCom (UnIn,FileName, '=== Separator' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadCom (UnIn,FileName, '--- Wake options header' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadCom (UnIn,FileName, '--- Wake extent header' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVar (UnIn,FileName,Inp%nNWPanels ,'nNWPanels' ,'' , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVar (UnIn,FileName,Inp%nFWPanels ,'nFWPanels' ,'' , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%nFWPanelsFree ,'nFWPanelsFree' ,'', Inp%nFWPanels , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%FWShedVorticity ,'FWShedVorticity' ,'', .False. , ErrStat2,ErrMsg2); if(Failed())return + + CALL ReadCom (UnIn,FileName, '--- Wake regularization header' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%DiffusionMethod ,'DiffusionMethod' ,'',idDiffusionNone , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%RegDeterMethod ,'RegDeterMethod' ,'',idRegDeterManual, ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%RegFunction ,'RegFunction' ,'',idRegVatistas , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%WakeRegMethod ,'WakeRegMethod' ,'',idRegConstant , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVar (UnIn,FileName,Inp%WakeRegParam ,'WakeRegParam' ,'' , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVar (UnIn,FileName,Inp%WingRegParam ,'WingRegParam' ,'' , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%CoreSpreadEddyVisc ,'CoreSpreadEddyVisc','',100.0_ReKi , ErrStat2,ErrMsg2); if(Failed())return + + CALL ReadCom (UnIn,FileName, '--- Wake treatment header' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%TwrShadowOnWake ,'TwrShadowOnWake' ,'',.false. , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%ShearModel ,'ShearModel' ,'',idShearNone , ErrStat2,ErrMsg2); if(Failed())return + + CALL ReadCom (UnIn,FileName, '--- Speed up header ' , ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%VelocityMethod ,'VelocityMethod' ,'',idVelocityBasic , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%TreeBranchFactor ,'TreeBranchFactor' ,'',2.0_ReKi , ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%PartPerSegment ,'PartPerSegment' ,'', 1 , ErrStat2,ErrMsg2); if(Failed())return +! Inp%TwrShadowOnWake = .False. +! Inp%VelocityMethod = idVelocityBasic +! Inp%TreeBranchFactor = 3.0_ReKi +! Inp%PartPerSegment = 1 + !------------------------ OUTPUT OPTIONS ----------------------------------------- + CALL ReadCom (UnIn,FileName, '=== Separator' ,ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadCom (UnIn,FileName, '--- Output options header' ,ErrStat2,ErrMsg2); if(Failed()) return + CALL ReadVarWDefault(UnIn,FileName,Inp%WrVTK , 'WrVTK' ,'', 0 ,ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%VTKBlades , 'VTKBlades' ,'', 1 ,ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVarWDefault(UnIn,FileName,Inp%VTKCoord , 'VTKCoord' ,'', 1 ,ErrStat2,ErrMsg2); if(Failed())return + CALL ReadVar (UnIn,FileName,VTK_fps_line , 'VTK_fps' ,'' ,ErrStat2,ErrMsg2); if(Failed())return + + ! --- Validation of inputs + if (PathIsRelative(Inp%CirculationFile)) Inp%CirculationFile = TRIM(PriPath)//TRIM(Inp%CirculationFile) + + if (Check(.not.(ANY(idCircVALID ==Inp%CirculationMethod)), 'Circulation method (CircSolvingMethod) not implemented: '//trim(Num2LStr(Inp%CirculationMethod)))) return + if (Check(.not.(ANY(idIntMethodVALID==Inp%IntMethod )) , 'Time integration method (IntMethod) not yet implemented. Use Euler 1st order method for now.')) return + if (Check(.not.(ANY(idDiffusionVALID==Inp%DiffusionMethod)) , 'Diffusion method (DiffusionMethod) not implemented: '//trim(Num2LStr(Inp%DiffusionMethod)))) return + if (Check(.not.(ANY(idRegDeterVALID ==Inp%RegDeterMethod)) , 'Regularization determination method (RegDeterMethod) not yet implemented: '//trim(Num2LStr(Inp%RegDeterMethod)))) return + if (Check(.not.(ANY(idRegVALID ==Inp%RegFunction )), 'Regularization function (RegFunction) not implemented: '//trim(Num2LStr(Inp%RegFunction)))) return + if (Check(.not.(ANY(idRegMethodVALID==Inp%WakeRegMethod)), 'Wake regularization method (WakeRegMethod) not implemented: '//trim(Num2LStr(Inp%WakeRegMethod)))) return + if (Check(.not.(ANY(idShearVALID ==Inp%ShearModel )), 'Shear model (ShearModel) not valid: '//trim(Num2LStr(Inp%ShearModel)))) return + if (Check(.not.(ANY(idVelocityVALID ==Inp%VelocityMethod )), 'Velocity method (VelocityMethod) not valid: '//trim(Num2LStr(Inp%VelocityMethod)))) return + + if (Check( Inp%DTfvw < p%DTaero, 'DTfvw must be >= DTaero from AD15.')) return + if (abs(Inp%DTfvw-p%DTaero)>epsilon(1.0_ReKi)) then + ! subcycling + if (Check(Inp%IntMethod/=idEuler1 , 'Sub-cycling (DTfvw>DTaro) is only possible with Forward Euler `IntMethod`')) return + endif + if (Inp%CirculationMethod == idCircPolarData) then + if (Check( Inp%nNWPanels<1 , 'Number of near wake panels (`nNWPanels`) must be >=1 when using circulation solving with polar data (`CircSolvingMethod=1`)')) return + endif + + if (Check( Inp%nNWPanels<0 , 'Number of near wake panels must be >=0')) return + if (Check( Inp%nFWPanels<0 , 'Number of far wake panels must be >=0')) return + if (Check( Inp%nFWPanelsFree<0 , 'Number of free far wake panels must be >=0')) return + if (Check( Inp%nFWPanelsFree>Inp%nFWPanels , 'Number of free far wake panels must be <=Number of far wake panels')) return + + if (Check(Inp%WakeRegParam<0 , 'Wake regularization parameter (WakeRegParam) should be positive')) return + if (Check(Inp%WingRegParam<0 , 'Wing regularization parameter (WakeRegParam) should be positive')) return + if (Check(Inp%CoreSpreadEddyVisc<0 , 'Core spreading eddy viscosity (CoreSpreadEddyVisc) should be positive')) return + + ! Removing the shed vorticity is a dangerous option if this is done too close to the blades. + ! To be safe, we will no matter what ensure that the last segments of NW are 0 if FWShedVorticity is False (see PackPanelsToSegments) + ! Still we force the user to be responsible. + if (Check((.not.(Inp%FWShedVorticity)) .and. Inp%nNWPanels<30, '`FWShedVorticity` should be true if `nNWPanels`<30. Alternatively, use a larger number of NWPanels ')) return + + Inp%DTvtk = Get_DTvtk( VTK_fps_line, p%DTaero, Inp%DTfvw ) + + ! At least one NW panel if FW, this shoudln't be a problem since the LL is in NW, but safety for now + !if (Check( (Inp%nNWPanels<=0).and.(Inp%nFWPanels>0) , 'At least one near wake panel is required if the number of far wake panel is >0')) return + call CleanUp() + +CONTAINS + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'FVW_ReadInputFile') + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + + logical function Check(Condition, ErrMsg_in) + logical, intent(in) :: Condition + character(len=*), intent(in) :: ErrMsg_in + Check=Condition + if (Check) then + call SetErrStat(ErrID_Fatal, 'Error in file '//TRIM(FileName)//': '//trim(ErrMsg_in), ErrStat, ErrMsg, 'FVW_ReadInputFile'); + call CleanUp() + endif + end function Check + + subroutine CleanUp() + close( UnIn ) + end subroutine + + real(DbKi) function Get_DTvtk( VTK_fps_line, DTaero, DTfvw ) + character(len=*), intent(inout) :: VTK_fps_line + real(DbKi), intent(in ) :: DTaero + real(DbKi), intent(in ) :: DTfvw + real(DbKi) :: VTK_fps + integer(IntKi) :: IOS + integer(IntKi) :: TmpRate + real(DbKi) :: TmpTime + + call Conv2UC( VTK_fps_line ) + if ( index(VTK_fps_line, "DEFAULT" ) == 1 ) then ! at DTfvw frequency + Get_DTvtk = DTfvw + elseif ( index(VTK_fps_line, "ALL" ) == 1 ) then ! at DTaero frequency + Get_DTvtk = DTaero + else ! read a number. Calculate this later. {will use closest integer multiple of DT} + read( VTK_fps_line, *, IOSTAT=IOS) VTK_fps + CALL CheckIOS ( IOS, FileName, 'VTK_fps', NumType, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! convert frames-per-second to seconds per sample: + if ( EqualRealNos(VTK_fps, 0.0_DbKi) ) then + Get_DTvtk = HUGE(1.0_DbKi) + else + TmpTime = 1.0_DbKi / VTK_fps + TmpRate = max( NINT( TmpTime / DTaero ),1_IntKi ) ! Can't be smaller that DTaero + Get_DTvtk = TmpRate * DTaero + ! warn if DTvtk is not TmpTime + if (.not. EqualRealNos(Get_DTvtk, TmpTime)) then + call SetErrStat(ErrID_Info, '1/VTK_fps is not an integer multiple of DT. FVW will output VTK information at '//& + trim(num2lstr(1.0_DbKi/(TmpRate*DTaero)))//' fps, the closest rate possible.',ErrStat,ErrMsg,'FVW_ReadInputFile') + end if + end if + end if + end function Get_DTvtk + + +END SUBROUTINE FVW_ReadInputFile + +!================================================= +!> Export FVW variables to VTK +!! NOTE: when entering this function nNW and nFW has been incremented by 1 +subroutine WrVTK_FVW(p, x, z, m, FileRootName, VTKcount, Twidth, bladeFrame, HubOrientation, HubPosition) + use FVW_VTK ! for all the vtk_* functions + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< States + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraints + type(FVW_MiscVarType), intent(in ) :: m !< MiscVars + character(*), intent(in) :: FileRootName !< Name of the file to write the output in (excluding extension) + integer(IntKi), intent(in) :: VTKcount !< Indicates number for VTK output file (when 0, the routine will also write reference information) + integer(IntKi), intent(in) :: Twidth !< Number of digits in the maximum write-out step (used to pad the VTK write-out in the filename with zeros) + logical, intent(in ) :: bladeFrame !< Output in blade coordinate frame + real(ReKi),optional,dimension(3,3), intent(in) :: HubOrientation + real(ReKi),optional,dimension(3) , intent(in) :: HubPosition + + ! local variables + integer:: iW + character(1024) :: FileName + character(255) :: Label + character(Twidth) :: Tstr ! string for current VTK write-out step (padded with zeros) + character(1), dimension(3) :: I2ABC =(/'A','B','C'/) + integer(IntKi) :: nSeg, nSegP, nSegNW + logical :: bMirror + !integer(IntKi) :: ErrStat2 + !character(ErrMsgLen) :: ErrMsg2 + real(Reki), dimension(:,:,:), allocatable :: dxdt_0 !< + + type(FVW_VTK_Misc) :: mvtk + + call vtk_misc_init(mvtk) + + if (bladeFrame) then + if (present(HubOrientation) .and. present(HubPosition)) then + call set_vtk_coordinate_transform(HubOrientation,HubPosition,mvtk) + else + Call ProgAbort('Programming error in WrVTK_FVW call: Cannot use the WrVTK_FVW with bladeFrame==TRUE without the optional arguments of HubOrientation and HubPosition') + endif + endif + + if (DEV_VERSION) then + print*,'------------------------------------------------------------------------------' + print'(A,L1,A,I0,A,I0,A,I0)','VTK Output - First call ',m%FirstCall, ' nNW:',m%nNW,' nFW:',m%nFW,' i:',VTKCount + endif + ! + call set_vtk_binary_format(.false.,mvtk) ! TODO binary fails + + ! TimeStamp + write(Tstr, '(i' // trim(Num2LStr(Twidth)) //'.'// trim(Num2LStr(Twidth)) // ')') VTKcount + + ! --------------------------------------------------------------------------------} + ! --- Blade + ! --------------------------------------------------------------------------------{ + ! --- Blade Quarter chord points (AC) + do iW=1,p%VTKBlades + write(Label,'(A,A)') 'BldPointCP.Bld', i2ABC(iW) + Filename = TRIM(FileRootName)//'.'//trim(Label)//'.'//Tstr//'.vtk' + if ( vtk_new_ascii_file(trim(filename),Label,mvtk) ) then + call vtk_dataset_polydata(m%CP_LL(1:3,1:p%nSpan,iW),mvtk,bladeFrame) + call vtk_point_data_init(mvtk) + call vtk_point_data_scalar(m%Gamma_ll( 1:p%nSpan,iW),'Gamma_ll',mvtk) + call vtk_point_data_vector(m%Vind_ll (1:3,1:p%nSpan,iW),'Vind_ll',mvtk) + call vtk_point_data_vector(m%Vtot_ll (1:3,1:p%nSpan,iW),'Vtot_ll',mvtk) + call vtk_point_data_vector(m%Vstr_ll (1:3,1:p%nSpan,iW),'Vstr_ll',mvtk) + call vtk_point_data_vector(m%Vwnd_ll (1:3,1:p%nSpan,iW),'Vwnd_ll',mvtk) + call vtk_point_data_vector(m%Tang (1:3,1:p%nSpan,iW),'Tangent',mvtk) + call vtk_point_data_vector(m%Norm (1:3,1:p%nSpan,iW),'Normal',mvtk) + call vtk_point_data_vector(m%Orth (1:3,1:p%nSpan,iW),'Orth',mvtk) + call vtk_close_file(mvtk) + endif + enddo + ! --- Lifting line panels + do iW=1,p%VTKBlades + write(Label,'(A,A)') 'LL.Bld', i2ABC(iW) + Filename = TRIM(FileRootName)//'.'//trim(Label)//'.'//Tstr//'.vtk' + call WrVTK_Lattice(FileName, mvtk, m%r_LL(1:3,:,:,iW), m%Gamma_LL(:,iW:iW), bladeFrame=bladeFrame) + enddo + ! --------------------------------------------------------------------------------} + ! --- Near wake + ! --------------------------------------------------------------------------------{ + ! --- Near wake panels + do iW=1,p%VTKBlades + write(Label,'(A,A)') 'NW.Bld', i2ABC(iW) + Filename = TRIM(FileRootName)//'.'//trim(Label)//'.'//Tstr//'.vtk' + if (m%FirstCall) then ! Small Hack - At t=0, NW not set, but first NW panel is the LL panel + allocate(dxdt_0(3, size(m%dxdt_NW,2) , m%nNW+1)); dxdt_0=0.0_ReKi + call WrVTK_Lattice(FileName, mvtk, m%r_LL(1:3,:,1:2,iW), m%Gamma_LL(:,iW:iW),dxdt_0, bladeFrame=bladeFrame) + deallocate(dxdt_0) + else + call WrVTK_Lattice(FileName, mvtk, x%r_NW(1:3,:,1:m%nNW+1,iW), x%Gamma_NW(:,1:m%nNW,iW), m%dxdt_NW(:,:,1:m%nNW+1,iW), bladeFrame=bladeFrame) + endif + enddo + ! --------------------------------------------------------------------------------} + ! --- Far wake + ! --------------------------------------------------------------------------------{ + ! --- Far wake panels + do iW=1,p%VTKBlades + write(Label,'(A,A)') 'FW.Bld', i2ABC(iW) + Filename = TRIM(FileRootName)//'.'//trim(Label)//'.'//Tstr//'.vtk' + call WrVTK_Lattice(FileName, mvtk, x%r_FW(1:3,1:FWnSpan+1,1:m%nFW+1,iW), x%Gamma_FW(1:FWnSpan,1:m%nFW,iW),m%dxdt_FW(:,:,1:m%nFW+1,iW), bladeFrame=bladeFrame) + enddo + ! --------------------------------------------------------------------------------} + ! --- All Segments + ! --------------------------------------------------------------------------------{ + ! NOTE: now we rely on the fact that the segments in Misc are well set + ! These segments are correct after a call to CalcOutput + ! The alternative is to call PackPanelsToSegments as was done before + ! This would require to allocate some local SegPoints,SegConnct here. + ! False below is to avoid writing the mirrored vorticity, this could be an option though + bMirror= (p%ShearModel==idShearMirror) .and. (p%VTKBlades<0) ! NOTE: temporary hack to output mirrored vorticity + call CountSegments(p, m%nNW, m%nFW, 1, nSeg, nSegP, nSegNW) + if (bMirror) then + nSeg = 2*nSeg + nSegP = 2*nSegP + endif + Filename = TRIM(FileRootName)//'.AllSeg.'//Tstr//'.vtk' + CALL WrVTK_Segments(Filename, mvtk, m%SegPoints(:,1:nSegP), m%SegConnct(:,1:nSeg), m%SegGamma(1:nSeg), m%SegEpsilon(1:nSeg), bladeFrame) + + if(.false.) print*,z%Gamma_LL(1,1) ! unused var for now +end subroutine WrVTK_FVW + + +subroutine WrVTK_Segments(filename, mvtk, SegPoints, SegConnct, SegGamma, SegEpsilon, bladeFrame) + use FVW_VTK + character(len=*),intent(in) :: filename + type(FVW_VTK_Misc), intent(inout) :: mvtk !< miscvars for VTK output + real(ReKi), dimension(:,:), intent(in) :: SegPoints !< + integer(IntKi), dimension(:,:), intent(in) :: SegConnct !< + real(ReKi), dimension(:) , intent(in) :: SegGamma !< + real(ReKi), dimension(:) , intent(in) :: SegEpsilon !< + logical, intent(in ) :: bladeFrame !< Output in blade coordinate frame + if ( vtk_new_ascii_file(filename,'Sgmt',mvtk) ) then + call vtk_dataset_polydata(SegPoints(1:3,:),mvtk,bladeFrame) + call vtk_lines(SegConnct(1:2,:)-1,mvtk) ! NOTE: VTK indexing at 0 + call vtk_cell_data_init(mvtk) + call vtk_cell_data_scalar(SegGamma ,'Gamma',mvtk) + call vtk_cell_data_scalar(SegEpsilon,'Epsilon',mvtk) +! call vtk_cell_data_scalar(real(SegConnct(3,:), ReKi),'Age',mvtk) + !call vtk_cell_data_scalar(real(SegConnct(4,:), ReKi),'Span',mvtk) + call vtk_close_file(mvtk) + endif +end subroutine + +subroutine WrVTK_Lattice(filename, mvtk, LatticePoints, LatticeGamma, LatticeData3d, bladeFrame) + use FVW_VTK ! for all the vtk_* functions + character(len=*), intent(in) :: filename + type(FVW_VTK_Misc), intent(inout) :: mvtk !< miscvars for VTK output + real(Reki), dimension(:,:,:), intent(in ) :: LatticePoints !< Array of points 3 x nSpan x nDepth + real(Reki), dimension(:,:), intent(in ) :: LatticeGamma !< Array of nSpan x nDepth + real(Reki), dimension(:,:,:), intent(in ), optional :: LatticeData3d !< Array of n x nSpan x nDepth KEEP ME + logical, intent(in ) :: bladeFrame !< Output in blade coordinate frame + ! + integer(IntKi), dimension(:,:), allocatable :: Connectivity + real(ReKi), dimension(:,:), allocatable :: Points + + CALL LatticeToPanlConnectivity(LatticePoints, Connectivity, Points) + + if ( vtk_new_ascii_file(filename,'',mvtk)) then + call vtk_dataset_polydata(Points,mvtk,bladeFrame) + call vtk_quad(Connectivity,mvtk) + call vtk_cell_data_init(mvtk) + call vtk_cell_data_scalar(LatticeGamma,'Gamma',mvtk) + if (present(LatticeData3d)) then + call vtk_point_data_init(mvtk) + call vtk_point_data_vector(LatticeData3d,'Uconv',mvtk) + endif + call vtk_close_file(mvtk) + endif + +end subroutine WrVTK_Lattice + +subroutine LatticeToPanlConnectivity(LatticePoints, Connectivity, Points) + real(Reki), dimension(:,:,:), intent(in ) :: LatticePoints !< Array of points 3 x nSpan x nDepth + integer(IntKi), dimension(:,:), allocatable :: Connectivity + real(ReKi), dimension(:,:), allocatable :: Points + ! Local + integer(IntKi) :: nSpan, nDepth + integer(IntKi) :: iSpan, iDepth, k + nSpan = size(LatticePoints,2) + nDepth = size(LatticePoints,3) + + if (allocated(Connectivity)) deallocate(Connectivity) + allocate(Connectivity(1:4, 1:(nSpan-1)*(nDepth-1))) + if (allocated(Points)) deallocate(Points) + allocate(Points(1:3, 1:nSpan*nDepth)) + + k=1 + do iDepth=1,nDepth-1; do iSpan=1,nSpan-1 + Connectivity(1,k)=(iDepth-1)*nSpan+(iSpan-1) + Connectivity(2,k)=(iDepth-1)*nSpan+(iSpan ) + Connectivity(3,k)=(iDepth )*nSpan+(iSpan) + Connectivity(4,k)=(iDepth )*nSpan+(iSpan-1) + k=k+1 + enddo; enddo + + k=1 + do iDepth=1,nDepth; do iSpan=1,nSpan + Points(1:3,k) = LatticePoints(1:3,iSpan,iDepth) + k=k+1 + enddo; enddo + +! do iWing=1,p%NumBlades +! if ( vtk_new_ascii_file(trim(filename),Label,mvtk) ) then +! ! Buffer for points +! k=1; do iNW=1,nNW; do iSpan=1,nSpan +! Buffer(1:3,k) = Misc%NWake%r_nearj(1:3,iSpan,iNW,iWing) +! k=k+1 +! enddo; enddo +! call vtk_dataset_polydata(Buffer,mvtk) +! call vtk_quad(Connectivity) +! call vtk_cell_data_init() +! ! Buffer for Gammas m1 +! k=1; do iNW=1,(nNW-1); do iSpan=1,(nSpan-1) +! if (iSpan "" "" +################################################################################################################################## +include Registry_NWTC_Library.txt +usefrom AirfoilInfo_Registry.txt +usefrom UnsteadyAero_Registry.txt + + +##################### Registry for FVW ############### +# ..... PARAMETERS ............. +#FVW_ParameterType +typedef FVW/FVW ParameterType IntKi nWings - - - "Number of Wings" - +typedef ^ ^ IntKi nSpan - - - "TODO, should be defined per wing. Number of spanwise element" - +typedef ^ ^ IntKi AFindx :: - - "Index to the airfoils from AD15 [idx1= BladeNode, idx2=Blade number]" - +typedef ^ ^ ReKi Chord :: - - "Chord of each blade element from input file [idx1=BladeNode, idx2=Blade number]" - +typedef ^ ^ IntKi nNWMax - - - "Maximum number of nw panels, per wing" - +typedef ^ ^ IntKi nFWMax - - - "Maximum number of fw panels, per wing" - +typedef ^ ^ IntKi nFWFree - - - "Number of fw panels that are free, per wing" - +typedef ^ ^ Logical FWShedVorticity - - - "Include shed vorticity in the far wake" - +typedef ^ ^ IntKi IntMethod - - - "Integration Method (1=RK4, 2=AB4, 3=ABM4, 5=Euler1)" - +typedef ^ ^ ReKi FreeWakeStart - - - "Time when wake starts convecting (rolling up)" s +typedef ^ ^ ReKi FullCirculationStart - - - "Time when the circulation is full" s +typedef ^ ^ IntKi CirculationMethod - - - "Method to determine the circulation" - +typedef ^ ^ ReKi PrescribedCirculation : - - "Prescribed circulation on all lifting lines" "m/s" +typedef ^ ^ IntKi CircSolvMaxIter - - - "Maximum number of iterations for circulation solving" - +typedef ^ ^ ReKi CircSolvConvCrit - - - "Convergence criterion for circulation solving" - +typedef ^ ^ ReKi CircSolvRelaxation - - - "Relaxation factor for circulation solving" - +typedef ^ ^ IntKi CircSolvPolar - - - "(0=Use AD polars, 1=2PiAlpha, 2=sin(2pialpha)" - +typedef ^ ^ IntKi DiffusionMethod - - - "Diffusion method (None, CoreSpreading, PSE)" - +typedef ^ ^ ReKi CoreSpreadEddyVisc - - - "Eddy viscosity used in the core spreading method" +typedef ^ ^ IntKi RegDeterMethod - - - "Regularization determinatino method (manual, automatic)" - +typedef ^ ^ IntKi RegFunction - - - "Type of regularizaion function (LambOseen, Vatistas, see FVW_BiotSavart)" - +typedef ^ ^ IntKi WakeRegMethod - - - "Method for regularization (constant, stretching, age, etc.)" - +typedef ^ ^ ReKi WakeRegParam - - - "Initial value of the regularization parameter" +typedef ^ ^ ReKi WingRegParam - - - "Regularization parameter of the wing" +typedef ^ ^ IntKi ShearModel - - - "Option for shear modelling" +typedef ^ ^ Logical TwrShadowOnWake - - - "Include tower shadow effects on wake" +typedef ^ ^ IntKi VelocityMethod - - - "Velocity calculation method" +typedef ^ ^ ReKi TreeBranchFactor - - - "Factor used to determine if a point is far enough" +typedef ^ ^ IntKi PartPerSegment - - - "Number of particles per segment, e.g. for tree method" +typedef ^ ^ DbKi DTaero - - - "Time interval for calls calculations" s +typedef ^ ^ DbKi DTfvw - - - "Time interval for calculating wake induced velocities" s +typedef ^ ^ ReKi KinVisc - - - "Kinematic air viscosity" m^2/s +# Parametesr output options +typedef ^ ^ IntKi WrVTK - - - "Outputs VTK at each calcoutput call, even if main fst doesnt do it" - +typedef ^ ^ IntKi VTKBlades - - - "Outputs VTk for each blade 0=no blade, 1=Bld 1" - +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" - + +# ....... MiscVars ............ +# FVW_MiscVarType +typedef FVW/FVW MiscVarType Logical FirstCall - - - "True if this is the first call to update state (used in CalcOutput)" - +# Variables at wing extent +typedef ^ ^ ReKi LE ::: - - "Leading edge points" - +typedef ^ ^ ReKi TE ::: - - "Trailing edge points" - +typedef ^ ^ ReKi r_LL :::: - - "Position of the Lifting line panels" - +typedef ^ ^ ReKi s_LL :: - - "Spanwise coordinate of LL elements" m +typedef ^ ^ ReKi chord_LL :: - - "chord on LL nodes " m +# Variables at control point - Dimensions nSpan +typedef ^ ^ ReKi s_CP_LL :: - - "Spanwise coordinate of LL CP" m +typedef ^ ^ ReKi chord_CP_LL :: - - "chord on LL cp " m +typedef ^ ^ ReKi CP_LL ::: - - "Coordinates of LL CP" - +typedef ^ ^ ReKi Tang ::: - - "Unit Tangential vector on LL CP" - +typedef ^ ^ ReKi Norm ::: - - "Unit Normal vector on LL CP " - +typedef ^ ^ ReKi Orth ::: - - "Unit Orthogonal vector on LL CP" - +typedef ^ ^ ReKi dl ::: - - "Vector of elementary length along the LL" - +typedef ^ ^ ReKi Area :: - - "Area of each LL panel" - +typedef ^ ^ ReKi diag_LL :: - - "Diagonal length of each LL panel" - +typedef ^ ^ Reki Gamma_LL :: - - "Circulation on the wing lifting line (COPY of Constraint State)" - +typedef ^ ^ ReKi Vind_LL ::: - - "Induced velocity on lifting line control points" m/s +typedef ^ ^ ReKi Vtot_LL ::: - - "Total velocity on lifting line control points" m/s +typedef ^ ^ ReKi Vstr_LL ::: - - "Structural velocity on LL CP" m/s +typedef ^ ^ ReKi Vwnd_LL ::: - - "Wind on lifting line control points" m/s +typedef ^ ^ ReKi Vwnd_NW :::: - - "Wind on near wake panels" m/s +typedef ^ ^ ReKi Vwnd_FW :::: - - "Wind on far wake panels" m/s +typedef ^ ^ ReKi Vind_NW :::: - - "Induced velocity on near wake panels" m/s +typedef ^ ^ ReKi Vind_FW :::: - - "Induced velocity on far wake panels" m/s +typedef ^ ^ IntKi nNW - - - "Number of active near wake panels" - +typedef ^ ^ IntKi nFW - - - "Number of active far wake panels" - +typedef ^ ^ IntKi iStep - - - "Current step number used for update state" - +typedef ^ ^ IntKi VTKstep - - - "Current vtk output step number" - +typedef ^ ^ DbKi VTKlastTime - - - "Time the last VTK file set was written out" s +typedef ^ ^ ReKi r_wind :: - - "List of points where wind is requested for next time step" - +typedef ^ ^ ReKi PitchAndTwist :: - - "Twist angle (includes all sources of twist) [Array of size (NumBlNds,numBlades)]" rad +typedef ^ ^ Logical ComputeWakeInduced - - - "Compute induced velocities on this timestep" - +typedef ^ ^ DbKi OldWakeTime - - - "Time the wake induction velocities were last calculated" s +typedef ^ ^ ReKi tSpent - - - "Time spent in expensive Biot-Savart computation" s +typedef ^ ^ ReKi dxdt_NW :::: - - "State time derivatie, stored for subcylcing" - +typedef ^ ^ ReKi dxdt_FW :::: - - "State time derivatie, stored for subcylcing" - +# Convenient storage +typedef ^ ^ Reki alpha_LL :: - - "Angle of attack at lifting line CP, only computed with CircPolarData method" - +typedef ^ ^ Reki Vreln_LL :: - - "Norm of Vrel on the lifting line" - +# Segment storage (buffer) +typedef ^ ^ IntKi SegConnct :: - - "Connectivity of segments" - +typedef ^ ^ ReKi SegPoints :: - - "Points delimiting the segments" - +typedef ^ ^ ReKi SegGamma : - - "Segment circulations" - +typedef ^ ^ ReKi SegEpsilon : - - "Segment regularization parameter" - +# Wake rollup storage (buffer) +typedef ^ ^ ReKi CPs :: - - "Control points used for wake rollup computation" - +typedef ^ ^ ReKi Uind :: - - "Induced velocities obtained at control points" - +# for calculating outputs at blade nodes +typedef ^ ^ ReKi BN_AxInd :: - - "Axial induction [size: (NumBlNds,numBlades)]" - +typedef ^ ^ ReKi BN_TanInd :: - - "Tangential induction [size: (NumBlNds,numBlades)]" - +typedef ^ ^ ReKi BN_Vrel :: - - "Relative velocity [size: (NumBlNds,numBlades)]" m/s +typedef ^ ^ ReKi BN_alpha :: - - "Angle of attack [size: (NumBlNds,numBlades)]" rad +typedef ^ ^ ReKi BN_phi :: - - "angle between the plane of rotation and the direction of the local wind [size: (NumBlNds,numBlades)]" rad +typedef ^ ^ ReKi BN_Re :: - - "Reynolds number [size: (NumBlNds,numBlades)]" - +typedef ^ ^ ReKi BN_URelWind_s ::: - - "Relative wind velocity in section coordinates [size: (3,NumBlNds,numBlades)]" m/s +typedef ^ ^ ReKi BN_Cl_Static :: - - "Coefficient lift, excluding unsteady aero effects" - +typedef ^ ^ ReKi BN_Cd_Static :: - - "Coefficient drag. excluding unsteady aero effects" - +typedef ^ ^ ReKi BN_Cm_Static :: - - "Coefficient moment, excluding unsteady aero effects" - +typedef ^ ^ ReKi BN_Cl :: - - "Coefficient lift, including unsteady aero effects" - +typedef ^ ^ ReKi BN_Cd :: - - "Coefficient drag, including unsteady aero effects" - +typedef ^ ^ ReKi BN_Cm :: - - "Coefficient moment, including unsteady aero effects" - +typedef ^ ^ ReKi BN_Cx :: - - "normal force coefficient (normal to the plane, not chord) of the jth node in the kth blade" - +typedef ^ ^ ReKi BN_Cy :: - - "tangential force coefficient (tangential to the plane, not chord) of the jth node in the kth blade" - + +# TODO UA - Should be part of AeroDyn +typedef ^ ^ UA_MiscVarType m_UA - - - "misc vars for UnsteadyAero" - +typedef ^ ^ UA_OutputType y_UA - - - "outputs from UnsteadyAero" - +typedef ^ ^ UA_ParameterType p_UA - - - "parameters for UnsteadyAero" - +typedef ^ ^ LOGICAL UA_Flag - - - "logical flag indicating whether to use UnsteadyAero" - +typedef ^ ^ ReKi Vwnd_ND ::: - - "InflowOnBlade (at nodes) values modified by tower influence. ONLY for UA" m/s + +# ........ Input ............ +# FVW_InputType +typedef FVW/FVW InputType MeshType WingsMesh : - - "Input Mesh defining position and orientation of wings" +typedef ^ ^ ReKi V_wind :: - - "Wind at requested points (r_wind)" - +typedef ^ ^ ReKi HubOrientation {3}{3} - - "Orientation of hub coordinate system (for output only)" - +typedef ^ ^ ReKi HubPosition {3} - - "Origin of hub (for output only)" - + +# ........ Output ............ +# FVW_OutputType +typedef FVW/FVW OutputType ReKi Vind ::: - - "TODO mesh - Induced velocity vector. " - +typedef ^ ^ ReKi Cl_KJ :: - - "Lift coefficient from circulation (Kutta-Joukowski)" - + +#.......... ContinuousStateType ...... +# FVW_ContinuousStateType +typedef FVW/FVW ContinuousStateType ReKi Gamma_NW ::: - - "Circulation of the near wake panels" - +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" - + + +#.......... DiscreteStateType ...... +# FVW_DiscreteStateType +typedef FVW/FVW DiscreteStateType ReKi NULL - - - "Empty to satisfy framework" - +# TODO UA +typedef ^ ^ UA_DiscreteStateType UA - - - "states for UnsteadyAero" - + +#.......... ConstraintStateType ...... +# FVW_ConstraintStateType +typedef FVW/FVW ConstraintStateType Reki residual - - "Residual" - +typedef ^ ^ Reki Gamma_LL :: - - "Circulation on the wing lifting line" - + +# ....... OtherStateType ............ +# FVW_OtherStateType +typedef FVW/FVW OtherStateType IntKi NULL - - - "Number of active near wake panels" - +# TODO UA +typedef ^ ^ UA_OtherStateType UA - - - "other states for UnsteadyAero" - +typedef ^ ^ Logical UA_Flag {:}{:} - - "logical flag indicating whether to use UnsteadyAero" - + + +#.......... InitInputType ...... +# FVW_InitInputType +typedef FVW/FVW InitInputType CHARACTER(1024) FVWFileName - - - "Main FVW input file name" - +typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ ^ MeshType WingsMesh : - - "Input Mesh defining position and orientation of wings (nSpan+1) " - +typedef ^ ^ IntKi AFindx :: - - "Index to the airfoils from AD15 [idx1=BladeNode, idx2=Blade number]" - +typedef ^ ^ ReKi Chord :: - - "Chord of each blade element from input file [idx1=BladeNode, idx2=Blade number]" - +typedef ^ ^ ReKi RElm : - - "radius of center of each element" - +typedef ^ ^ ReKi zHub : - - "Distance to hub for each blade" m +typedef ^ ^ ReKi zLocal :: - - "Distance to blade node, measured along the blade" m +typedef ^ ^ ReKi zTip : - - "Distance to blade tip, measured along the blade" m +typedef ^ ^ ReKi rLocal :: - - "Radial distance to blade node from the center of rotation, measured in the rotor plane, needed for DBEMT" m +typedef ^ ^ IntKi NumBlades - - - "Number of blades" - +typedef ^ ^ IntKi NumBladeNodes - - - "Number of nodes on each blade" - +typedef ^ ^ DbKi DTaero - - - "Time interval for calls (from AD15)" s +typedef ^ ^ ReKi KinVisc - - - "Kinematic air viscosity" m^2/s +# TODO UA - Should be part of AeroDyn +typedef ^ ^ IntKi UAMod - - - "Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema]" - +typedef ^ ^ LOGICAL UA_Flag - - - "logical flag indicating whether to use UnsteadyAero" - +typedef ^ ^ LOGICAL Flookup - - - "Use table lookup for f' and f'' " - +typedef ^ ^ ReKi a_s - - - "speed of sound" m/s + +#.......... InputFileType ...... +# FVW_InputFile +typedef FVW/FVW FVW_InputFile IntKi CirculationMethod - - - "Method to determine the circulation" - +typedef ^ ^ CHARACTER(1024) CirculationFile - - - "Prescribed circulation file" - +typedef ^ ^ IntKi CircSolvMaxIter - - - "Maximum number of iterations for circulation solving" - +typedef ^ ^ ReKi CircSolvConvCrit - - - "Convergence criterion for circulation solving" - +typedef ^ ^ ReKi CircSolvRelaxation - - - "Relaxation factor for circulation solving" - + +typedef ^ ^ IntKi IntMethod - - - "Integration Method (1=RK4, 2=AB4, 3=ABM4, 5=Euler1, 7=Corrector/Predictor)" - +typedef ^ ^ LOGICAL FreeWake - - - "Disable roll up, wake convects with wind only (flag)" - +typedef ^ ^ ReKi FreeWakeStart - - - "Time when wake starts convecting (rolling up)" s +typedef ^ ^ ReKi FullCirculationStart - - - "Time when the circulation is full" s +typedef ^ ^ DbKi DTfvw - - - "Time interval for calculating wake induced velocities" s +typedef ^ ^ IntKi CircSolvPolar - - - "(0=Use AD polars, 1=2PiAlpha, 2=sin(2pialpha)" - +typedef ^ ^ IntKi nNWPanels - - - "Number of nw panels" - +typedef ^ ^ IntKi nFWPanels - - - "Number of fw panels" - +typedef ^ ^ IntKi nFWPanelsFree - - - "Number of fw panels that are free" - +typedef ^ ^ Logical FWShedVorticity - - - "Include shed vorticity in the far wake" - +typedef ^ ^ IntKi DiffusionMethod - - - "Diffusion method (None, CoreSpreading, PSE)" - +typedef ^ ^ ReKi CoreSpreadEddyVisc - - - "Eddy viscosity used in the core spreading method" +typedef ^ ^ IntKi RegDeterMethod - - - "Regularization determinatino method (manual, automatic)" - +typedef ^ ^ IntKi RegFunction - - - "Type of regularizaion function (LambOseen, Vatistas, see FVW_BiotSavart)" - +typedef ^ ^ IntKi WakeRegMethod - - - "Method for regularization (constant, stretching, age, etc.)" - +typedef ^ ^ ReKi WakeRegParam - - - "Factor used in the regularization " +typedef ^ ^ ReKi WingRegParam - - - "Factor used in the regularization " +typedef ^ ^ IntKi ShearModel - - - "Option for shear modelling" +typedef ^ ^ Logical TwrShadowOnWake - - - "Include tower shadow effects on wake" +typedef ^ ^ IntKi VelocityMethod - - - "Velocity calculation method" +typedef ^ ^ ReKi TreeBranchFactor - - - "Factor used to determine if a point is far enough" +typedef ^ ^ IntKi PartPerSegment - - - "Number of particles per segment, e.g. for tree method" +typedef ^ ^ IntKi WrVTK - - - "Outputs VTK at each calcoutput call, even if main fst doesnt do it" - +typedef ^ ^ IntKi VTKBlades - - - "Outputs VTk for each blade 0=no blade, 1=Bld 1" - +typedef ^ ^ DbKi DTvtk - - - "Requested timestep between VTK outputs (calculated from the VTK_fps read in)" s +typedef ^ ^ IntKi VTKCoord - - - "Switch for VTK outputs coordinate system" - + +#.......... InitOutputType ...... +# FVW_InitOutputType +typedef FVW/FVW InitOutputType IntKi Null - - - "Empty parameter to satisfy framework" - + + + diff --git a/modules/aerodyn/src/FVW_Subs.f90 b/modules/aerodyn/src/FVW_Subs.f90 new file mode 100644 index 0000000000..cdff226121 --- /dev/null +++ b/modules/aerodyn/src/FVW_Subs.f90 @@ -0,0 +1,1088 @@ +module FVW_SUBS + + use NWTC_LIBRARY + use FVW_TYPES + use FVW_VortexTools + use FVW_BiotSavart + + implicit none + + ! --- Module parameters + ! Circulation solving methods + integer(IntKi), parameter :: idCircPolarData = 1 + integer(IntKi), parameter :: idCircNoFlowThrough = 2 + integer(IntKi), parameter :: idCircPrescribed = 3 + integer(IntKi), parameter, dimension(2) :: idCircVALID = (/idCircPolarData, idCircPrescribed /) + ! Integration method + integer(IntKi), parameter :: idRK4 = 1 + integer(IntKi), parameter :: idAB4 = 2 + integer(IntKi), parameter :: idABM4 = 3 + integer(IntKi), parameter :: idPredictor= 4 + integer(IntKi), parameter :: idEuler1 = 5 + integer(IntKi), parameter, dimension(1) :: idIntMethodVALID = (/idEuler1 /) + ! Diffusion method + integer(IntKi), parameter :: idDiffusionNone = 0 + integer(IntKi), parameter :: idDiffusionCoreSpread = 1 + integer(IntKi), parameter :: idDiffusionPSE = 2 + integer(IntKi), parameter, dimension(1) :: idDiffusionVALID = (/idDiffusionNone /) + ! Regularization Method + integer(IntKi), parameter :: idRegConstant = 1 + integer(IntKi), parameter :: idRegStretching = 2 + integer(IntKi), parameter :: idRegAge = 3 + integer(IntKi), parameter, dimension(2) :: idRegMethodVALID = (/idRegConstant,idRegAge/) + ! Regularization determination method + integer(IntKi), parameter :: idRegDeterManual = 0 + integer(IntKi), parameter :: idRegDeterAuto = 1 + integer(IntKi), parameter, dimension(2) :: idRegDeterVALID = (/idRegDeterManual, idRegDeterAuto /) + ! Shear model + integer(IntKi), parameter :: idShearNone = 0 + integer(IntKi), parameter :: idShearMirror = 1 + integer(IntKi), parameter, dimension(2) :: idShearVALID = (/idShearNone, idShearMirror /) + ! Velocity calculation method + integer(IntKi), parameter :: idVelocityBasic = 1 + integer(IntKi), parameter :: idVelocityTree = 2 + integer(IntKi), parameter :: idVelocityPart = 3 + integer(IntKi), parameter, dimension(3) :: idVelocityVALID = (/idVelocityBasic, idVelocityTree, idVelocityPart /) + + real(ReKi), parameter :: CoreSpreadAlpha = 1.25643 + + ! Implementation + integer(IntKi), parameter :: iNWStart=2 !< Index in r%NW where the near wake start (if >1 then the Wing panels are included in r_NW) + integer(IntKi), parameter :: FWnSpan=1 !< Number of spanwise far wake panels ! TODO make it an input later + logical , parameter :: DEV_VERSION=.False. +contains + +!========================================================================== +!> Helper function for 1d interpolation (interp1d) +function interpolation_array( xvals, yvals, xi, nOut, nIn ) + integer nOut, nIn, arindx, ilo + real(ReKi), dimension( nOut ) :: interpolation_array, xi + real(ReKi), dimension( nIn ) :: xvals, yvals, tmp2, tmp3 + real(ReKi) :: tmp1 + ilo = 1 + DO arindx = 1, nOut + IF ( xi( arindx ) .LT. xvals( 1 )) THEN + interpolation_array( arindx ) = yvals( 1 ) + ( xi( arindx ) - xvals( 1 )) / & + & ( xvals( 2 ) - xvals( 1 )) * ( yvals( 2 ) - yvals( 1 )) + ELSE IF ( xi( arindx ) .GT. xvals( nIn )) THEN + interpolation_array( arindx ) = yvals( nIn - 1 ) + ( xi( arindx ) - & + & xvals( nIn - 1 )) / ( xvals( nIn ) - xvals( nIn - 1 )) * & + & ( yvals( nIn ) - yvals( nIn - 1 )) + ELSE + tmp1 = real( xi( arindx ), ReKi) + tmp2 = real( xvals , ReKi) + tmp3 = real( yvals , ReKi) + interpolation_array( arindx ) = InterpBinReal( tmp1, tmp2, tmp3, ilo, nIn ) + END IF + END DO +END FUNCTION interpolation_array +!========================================================================== + +! ===================================================================================== +!> Output blade circulation +subroutine Output_Gamma(CP, Gamma_LL, iWing, iStep, iLabel, iIter) + real( ReKi ), dimension( :, : ), intent(in ) :: CP !< Control Points + real( ReKi ), dimension( : ), intent(in ) :: Gamma_LL !< Circulation on the lifting line + integer( IntKi ), intent(in ) :: iWing !< Wing index + integer( IntKi ), intent(in ) :: iStep !< Call ID + integer( IntKi ), intent(in ) :: iLabel !< Call ID + integer( IntKi ), intent(in ) :: iIter !< Call ID + character(len=255) :: filename + integer :: i + integer :: iUnit + real(ReKi) :: norm + call GetNewUnit(iUnit) + ! TODO output folder + CALL MKDIR('Gamma') + write(filename,'(A,I0,A,I0,A,I0,A,I0,A)')'Gamma/Gamma_step',int(iStep),'_lab',iLabel,'_it',iIter,'_Wing',int(iWing),'.txt' + OPEN(unit = iUnit, file = trim(filename), status="unknown", action="write") + write(iUnit,'(A)') 'norm_[m],x_[m],y_[m],z_[m], Gamma_[m^2/s]' + do i=1,size(Gamma_LL) + norm=sqrt(CP(1,i)**2+CP(2,i)**2+CP(3,i)**2) + write(iUnit,'(E14.7,A,E14.7,A,E14.7,A,E14.7,A,E14.7)') norm,',', CP(1,i),',',CP(2,i),',',CP(3,i),',', Gamma_LL(i) + enddo + close(iUnit) +endsubroutine Output_Gamma +! ===================================================================================== +!> Read a delimited file containing a circulation and interpolate it on the requested Control Points +!! The input file is a delimited file with one line of header. +!! Each following line consists of two columns: r/R_[-] and Gamma_[m^2/s] +subroutine ReadAndInterpGamma(CirculationFileName, s_CP_LL, L, Gamma_CP_LL, ErrStat, ErrMsg) + character(len=*), intent(in ) :: CirculationFileName !< Input file to read + real(ReKi), dimension(:), intent(in ) :: s_CP_LL !< Spanwise location of the lifting CP [m] + real(ReKi), intent(in ) :: L !< Full span of lifting line + real(ReKi), dimension(:), intent(out ) :: Gamma_CP_LL !< Interpolated circulation of the LL CP + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local + integer(IntKi) :: nLines + integer(IntKi) :: i + integer(IntKi) :: iStat + integer(IntKi) :: iUnit + character(len=1054) :: line + real(ReKi), dimension(:), allocatable :: sPrescr, GammaPrescr !< Radius + ErrStat = ErrID_None + ErrMsg = '' + ! --- + call GetNewUnit(iUnit) + open(unit = iUnit, file = CirculationFileName) + nLines=line_count(iUnit)-1 + ! Read Header + read(iUnit,*, iostat=istat) line + ! Read table: s/L [-], GammaPresc [m^2/s] + allocate(sPrescr(1:nLines), GammaPrescr(1:nLines)) + do i=1,nLines + read(iUnit,*, iostat=istat) sPrescr(i), GammaPrescr(i) + sPrescr(i) = sPrescr(i) * L + GammaPrescr(i) = GammaPrescr(i) + enddo + close(iUnit) + if (istat/=0) then + ErrStat=ErrID_Fatal + ErrMsg='Error occured while reading Circulation file: '//trim(CirculationFileName) + return + endif + ! NOTE: TODO TODO TODO THIS ROUTINE PERFORMS NASTY EXTRAPOLATION, SHOULD BE PLATEAUED + Gamma_CP_LL = interpolation_array( sPrescr, GammaPrescr, s_CP_LL, size(s_CP_LL), nLines ) +contains + + !> Counts number of lines in a file + integer function line_count(iunit) + integer(IntKi), intent(in) :: iunit + character(len=1054) :: line + ! safety for infinite loop.. + integer(IntKi), parameter :: nline_max=100000000 ! 100 M + integer(IntKi) :: i + line_count=0 + do i=1,nline_max + line='' + read(iunit,'(A)',END=100)line + line_count=line_count+1 + enddo + if (line_count==nline_max) then + print*,'Error: maximum number of line exceeded' + endif + 100 if(len(trim(line))>0) then + line_count=line_count+1 + endif + rewind(iunit) + end function + +endsubroutine ReadAndInterpGamma +! ===================================================================================== + +! -------------------------------------------------------------------------------- +! --- Mapping functions +! -------------------------------------------------------------------------------- + +!> Make sure the First panel of the NW match the last panel of the Trailing edge +!! - Same position of points +!! - Same circulation +subroutine Map_LL_NW(p, m, z, x, ShedScale, ErrStat, ErrMsg ) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraints states + type(FVW_ContinuousStateType), intent(inout) :: x !< Continuous states + real(ReKi), intent(in) :: ShedScale !< Time scaling of shed vorticity + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(ReKi) :: Gamma_Prev, Gamma_new + ! Local + integer(IntKi) :: iSpan , iW + ErrStat = ErrID_None + ErrMsg = "" + + ! First panel of NW is the last lifting line panel + do iW = 1,p%nWings + do iSpan = 1,p%nSpan+1 + x%r_NW(1:3, iSpan, iNWStart-1, iW) = m%r_LL(1:3, iSpan, 1, iW) ! iAge=1 + x%r_NW(1:3, iSpan, iNWStart , iW) = m%r_LL(1:3, iSpan, 2, iW) ! iAge=2 + enddo + enddo + ! First panel of NW is the last lifting line panel + do iW = 1,p%nWings + do iSpan = 1,p%nSpan + x%Gamma_NW(iSpan, iNWStart-1, iW) = z%Gamma_LL(iSpan,iW) ! iAge=1 + enddo + enddo + ! Circulations are the same on both side of the TE + if (p%nNWMax>iNWStart-1) then + do iW = 1,p%nWings + do iSpan = 1,p%nSpan + x%Gamma_NW(iSpan, iNWStart , iW) = z%Gamma_LL(iSpan,iW) ! iAge=2 + enddo + enddo + endif + ! When subcycling, we make sure the new circulation progressively ramps up from the old one + ! NOTE: subcycling needs improvement. + ! Frequencies are introduced, even for prescribed circulation, when wake roll up is included + ! If the wake is not free, the convection velocity is constant and there is no issue. + ! As a test case, the elliptical wing with constant circulation can be used, with roll up + ! The error seems to be bigger near the tip/root for this case. + if(.false.) then + if ((ShedScale<1.0_ReKi) .and. (m%nNW>=3)) then + print*,'Scaling' + do iW = 1,p%nWings + do iSpan = 1,p%nSpan + Gamma_Prev = x%Gamma_NW(iSpan, iNWStart+1, iW) ! Previous circulation + Gamma_New = x%Gamma_NW(iSpan, iNWStart , iW) + x%Gamma_NW(iSpan, iNWStart , iW) = Gamma_New*ShedScale + (1.0_ReKi-ShedScale) * Gamma_Prev + enddo + enddo + endif + endif +end subroutine Map_LL_NW + +!> Map the last NW panel with the first FW panel +subroutine Map_NW_FW(p, m, z, x, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraints states + type(FVW_ContinuousStateType), intent(inout) :: x !< Continuous states + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: iW, iRoot + real(ReKi), dimension(p%nWings) :: FWGamma + integer(IntKi), parameter :: iAgeFW=1 !< we update the first FW panel + ErrStat = ErrID_None + ErrMsg = "" + + ! First Panel of Farwake has coordinates of last panel of near wake always + if (p%nFWMax>0) then + FWGamma(:)=0.0_ReKi + if (m%nNW==p%nNWMax) then + ! First circulation of Farwake is taken as the max circulation of last NW column + do iW=1,p%nWings + !FWGamma = sum(x%Gamma_NW(:,p%nNWMax,iW))/p%nSpan + FWGamma(iW) = maxval(x%Gamma_NW(:,p%nNWMax,iW)) + x%Gamma_FW(1:FWnSpan,iAgeFW,iW) = FWGamma(iW) + enddo + endif + + do iW=1,p%nWings + ! Find first point (in half span) where circulation is more than 0.1% of MaxGamma, call it the root + iRoot=1 + ! NOTE: this below won't work for a wing + ! Need to go from maxgamma location, and integrate spanwise position on both side to find location of tip and root vortex + !do while ((iRoot2)) then + ErrMsg='Error: FWnSpan>2 not implemented.' + ErrStat=ErrID_Fatal + return + endif + enddo + endif + if (.false.) print*,z%Gamma_LL(1,1) ! Just to avoid unused var warning +endsubroutine Map_NW_FW + +!> Propagate the positions and circulation one index forward (loop from end to start) +subroutine PropagateWake(p, m, z, x, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + type(FVW_ConstraintStateType), intent(in ) :: z !< Constraints states + type(FVW_ContinuousStateType), intent(inout) :: x !< Continuous states + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: iSpan, iAge, iW + ErrStat = ErrID_None + ErrMsg = "" + + ! -- Propagate far wake + do iW=1,p%nWings + do iAge=p%nFWMax+1,2,-1 ! + do iSpan=1,FWnSpan+1 + x%r_FW(1:3,iSpan,iAge,iW) = x%r_FW(1:3,iSpan,iAge-1,iW) + enddo + enddo + x%r_FW(1:3,1:FWnSpan+1,1,iW) = -999.9_ReKi ! Nullified + enddo + if (p%nFWMax>0) then + do iW=1,p%nWings + do iAge=p%nFWMax,2,-1 + do iSpan=1,FWnSpan + x%Gamma_FW(iSpan,iAge,iW) = x%Gamma_FW(iSpan,iAge-1,iW) + enddo + enddo + x%Gamma_FW(1,1:FWnSpan-1,iW) = -999.9_ReKi ! Nullified + enddo + endif + ! --- Propagate near wake + do iW=1,p%nWings + do iAge=p%nNWMax+1,iNWStart+1,-1 + do iSpan=1,p%nSpan+1 + x%r_NW(1:3,iSpan,iAge,iW) = x%r_NW(1:3,iSpan,iAge-1,iW) + enddo + enddo + x%r_NW(1:3,:,1:iNWStart,iW) = -999.9_ReKi ! Nullified + enddo + if (p%nNWMax>1) then + do iW=1,p%nWings + do iAge=p%nNWMax,iNWStart+1,-1 + do iSpan=1,p%nSpan + x%Gamma_NW(iSpan,iAge,iW) = x%Gamma_NW(iSpan,iAge-1,iW) + enddo + enddo + x%Gamma_NW(:,1:iNWStart,iW) = -999.9_ReKi ! Nullified + enddo + endif + + ! Temporary hack for sub-cycling since straight after wkae computation, the wake size will increase + ! So we do a "fake" propagation here + do iW=1,p%nWings + do iAge=p%nFWMax+1,2,-1 ! + do iSpan=1,FWnSpan+1 + m%dxdt_FW(1:3,iSpan,iAge,iW) = m%dxdt_FW(1:3,iSpan,iAge-1,iW) + enddo + enddo + !m%dxdt_FW(1:3,1:FWnSpan+1,1,iW) = -999999_ReKi ! Important not nullified. The best would be to map the last NW convection velocity for this first row. + enddo + do iW=1,p%nWings + do iAge=p%nNWMax+1,iNWStart+1,-1 + do iSpan=1,p%nSpan+1 + m%dxdt_NW(1:3,iSpan,iAge,iW) = m%dxdt_NW(1:3,iSpan,iAge-1,iW) + enddo + enddo + m%dxdt_NW(1:3,:,1:iNWStart,iW) = 0.0_ReKi ! Nullified, wing do no convect, handled by LL,NW mapping + enddo + + if (.false.) print*,m%nNW,z%Gamma_LL(1,1) ! Just to avoid unused var warning +end subroutine PropagateWake + + +subroutine print_x_NW_FW(p, m, x, label) + type(FVW_ParameterType), intent(in) :: p !< Parameters + type(FVW_MiscVarType), intent(in) :: m !< Initial misc/optimization variables + type(FVW_ContinuousStateType), intent(in) :: x !< Continuous states + character(len=*),intent(in) :: label + integer(IntKi) :: iAge + character(len=1):: flag + print*,'------------------------------------------------------------------' + print'(A,I0,A,I0)',' NW .....................iNWStart:',iNWStart,' nNW:',m%nNW + do iAge=1,p%nNWMax+1 + flag='X' + if ((iAge)<= m%nNW+1) flag='.' + print'(A,A,I0,A)',flag,'iAge ',iAge,' Root Tip' + print*,trim(label)//'x', x%r_NW(1, 1, iAge,1), x%r_NW(1, p%nSpan+1, iAge,1) + print*,trim(label)//'y', x%r_NW(2, 1, iAge,1), x%r_NW(2, p%nSpan+1, iAge,1) + print*,trim(label)//'z', x%r_NW(3, 1, iAge,1), x%r_NW(3, p%nSpan+1, iAge,1) + enddo + print'(A,I0)','FW <<<<<<<<<<<<<<<<<<<< nFW:',m%nFW + do iAge=1,p%nFWMax+1 + flag='X' + if ((iAge)<= m%nFW+1) flag='.' + print'(A,A,I0,A)',flag,'iAge ',iAge,' Root Tip' + print*,trim(label)//'x', x%r_FW(1, 1, iAge,1), x%r_FW(1, FWnSpan+1, iAge,1) + print*,trim(label)//'y', x%r_FW(2, 1, iAge,1), x%r_FW(2, FWnSpan+1, iAge,1) + print*,trim(label)//'z', x%r_FW(3, 1, iAge,1), x%r_FW(3, FWnSpan+1, iAge,1) + enddo + !print'(A,I0,A,I0)','dxdt NW .....................iNWStart:',iNWStart,' nNW:',m%nNW + !do iAge=1,p%nNWMax+1 + ! flag='X' + ! if ((iAge)<= m%nNW+1) flag='.' + ! print'(A,A,I0,A)',flag,'iAge ',iAge,' Root Tip' + ! print*,trim(label)//'x', m%dxdt_NW(1, 1, iAge,1), m%dxdt_NW(1, p%nSpan+1, iAge,1) + ! print*,trim(label)//'y', m%dxdt_NW(2, 1, iAge,1), m%dxdt_NW(2, p%nSpan+1, iAge,1) + ! print*,trim(label)//'z', m%dxdt_NW(3, 1, iAge,1), m%dxdt_NW(3, p%nSpan+1, iAge,1) + !enddo + !print'(A,I0)','dxdt FW <<<<<<<<<<<<<<<<<<<< nFW:',m%nFW + !do iAge=1,p%nFWMax+1 + ! flag='X' + ! if ((iAge)<= m%nFW+1) flag='.' + ! print'(A,A,I0,A)',flag,'iAge ',iAge,' Root Tip' + ! print*,trim(label)//'x', m%dxdt_FW(1, 1, iAge,1), m%dxdt_FW(1, FWnSpan+1, iAge,1) + ! print*,trim(label)//'y', m%dxdt_FW(2, 1, iAge,1), m%dxdt_FW(2, FWnSpan+1, iAge,1) + ! print*,trim(label)//'z', m%dxdt_FW(3, 1, iAge,1), m%dxdt_FW(3, FWnSpan+1, iAge,1) + !enddo +endsubroutine + + +! -------------------------------------------------------------------------------- +! --- PACKING/UNPACKING FUNCTIONS +! -------------------------------------------------------------------------------- +!> Establish the list of points where we will need the free stream +!! The r_wind array is allocated at initialization to the largest size possible. This is to +!! ensure that we do not violate requirements in the framework later for changing the size +!! of input and output arrays. +subroutine SetRequestedWindPoints(r_wind, x, p, m) + real(ReKi), dimension(:,:), allocatable, intent(inout) :: r_wind !< Position where wind is requested + type(FVW_ContinuousStateType), intent(inout) :: x !< States + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + integer(IntKi) :: iP_start,iP_end ! Current index of point, start and end of range + + ! Using array reshaping to ensure a given near or far wake point is always at the same location in the array. + ! NOTE: Maximum number of points are passed, whether they "exist" or not. + ! NOTE: InflowWind ignores points at (0,0,0) + !if (DEV_VERSION) then + ! ! Removing points that don't exist + ! !call print_x_NW_FW(p,m,x,'wind befr') + ! if (m%nNW<=p%nNWMax) then + ! x%r_NW(1:3, 1:p%nSpan+1, m%nNW+2:p%nNWMax+1, 1:p%nWings) = 0.0_ReKi + ! endif + ! if ( ((p%nNWMax<=1) .and. (m%nFW==0)) .or. ((m%nFW>0) .and. (m%nFW<=p%nFWMax))) then + ! x%r_FW(1:3, 1:FWnSpan+1, m%nFW+2:p%nFWMax+1, 1:p%nWings) = 0.0_ReKi + ! else + ! x%r_FW(1:3, 1:FWnSpan+1, m%nFW+1:p%nFWMax+1, 1:p%nWings) = 0.0_ReKi + ! endif + ! !call print_x_NW_FW(p,m,x,'wind after') + !endif + + ! --- LL CP + iP_start=1 + iP_end=p%nWings*p%nSpan + r_wind(1:3,iP_start:iP_end) = reshape( m%CP_LL(1:3,1:p%nSpan,1:p%nWings), (/ 3, p%nSpan*p%nWings /)) + ! --- NW points + iP_start=iP_end+1 + iP_end=iP_start-1+(p%nSpan+1)*(p%nNWMax+1)*p%nWings + r_wind(1:3,iP_start:iP_end) = reshape( x%r_NW(1:3,1:p%nSpan+1,1:p%nNWMax+1,1:p%nWings), (/ 3, (p%nSpan+1)*(p%nNWMax+1)*p%nWings /)) + ! --- FW points + if (p%nFWMax>0) then + iP_start=iP_end+1 + iP_end=iP_start-1+(FWnSpan+1)*(p%nFWMax+1)*p%nWings + r_wind(1:3,iP_start:iP_end) = reshape( x%r_FW(1:3,1:FWnSpan+1,1:p%nFWMax+1,1:p%nWings), (/ 3, (FWnSpan+1)*(p%nFWMax+1)*p%nWings /)) + endif + + !if (DEV_VERSION) then + ! ! Additional checks + ! if (any(r_wind(3,:)<=-99999_ReKi)) then + ! call print_x_NW_FW(p,m,x,'wind after') + ! print*,'Error in wind' + ! STOP + ! endif + ! ! Removing points that don't exist + ! if (m%nNW<=p%nNWMax) then + ! x%r_NW(1:3, 1:p%nSpan+1, m%nNW+2:p%nNWMax+1, 1:p%nWings) = -999999.0_ReKi + ! endif + ! if ( ((p%nNWMax<=1) .and. (m%nFW==0)) .or. ((m%nFW>0) .and. (m%nFW<=p%nFWMax))) then + ! x%r_FW(1:3, 1:FWnSpan+1, m%nFW+2:p%nFWMax+1, 1:p%nWings) =-999999.0_ReKi + ! else + ! x%r_FW(1:3, 1:FWnSpan+1, m%nFW+1:p%nFWMax+1, 1:p%nWings) =-999999.0_ReKi + ! endif + !endif + +end subroutine SetRequestedWindPoints + + +!> Set the requested wind into the correponding misc variables +subroutine DistributeRequestedWind(V_wind, p, m) + real(ReKi), dimension(:,:), intent(in ) :: V_wind !< Position where wind is requested + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi) :: iP_start,iP_end ! Current index of point, start and end of range + + ! Using array reshaping to ensure a given near or far wake point is always at the same location in the array. + ! NOTE: Maximum number of points are passed, whether they "exist" or not. + ! --- LL CP + iP_start=1 + iP_end=p%nWings*p%nSpan + m%Vwnd_LL(1:3,1:p%nSpan,1:p%nWings) = reshape( V_wind(1:3,iP_start:iP_end), (/ 3, p%nSpan, p%nWings /)) + ! --- NW points + iP_start=iP_end+1 + iP_end=iP_start-1+(p%nSpan+1)*(p%nNWMax+1)*p%nWings + m%Vwnd_NW(1:3,1:p%nSpan+1,1:p%nNWMax+1,1:p%nWings) = reshape( V_wind(1:3,iP_start:iP_end), (/ 3, p%nSpan+1, p%nNWMax+1, p%nWings/)) + ! --- FW points + if (p%nFWMax>0) then + iP_start=iP_end+1 + iP_end=iP_start-1+(FWnSpan+1)*(p%nFWMax+1)*p%nWings + m%Vwnd_FW(1:3,1:FWnSpan+1,1:p%nFWMax+1,1:p%nWings) = reshape( V_wind(1:3,iP_start:iP_end), (/ 3, FWnSpan+1, p%nFWMax+1, p%nWings /)) + endif + +end subroutine DistributeRequestedWind + + +!> Count how many segments are needed to represent the Near wake and far wakes, starting at a given depth +subroutine CountSegments(p, nNW, nFW, iDepthStart, nSeg, nSegP, nSegNW) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + integer(IntKi), intent(in ) :: nNW !< Number of NW panels + integer(IntKi), intent(in ) :: nFW !< Number of FW panels + integer(IntKi), intent(in ) :: iDepthStart !< Index where we start packing for NW panels + integer(IntKi), intent( out) :: nSeg !< Total number of segments after packing + integer(IntKi), intent( out) :: nSegP !< Total number of segments points after packing + integer(IntKi), intent( out) :: nSegNW !< Total number of segments points for the near wake only + logical :: LastNWShed + ! If the FW contains Shed vorticity, we include the last shed vorticity from the NW, otherwise, we don't! + ! It's important not to include it, otherwise a strong vortex will be present there with no compensating vorticity from the FW + LastNWShed = (p%FWShedVorticity ) .or. ((.not.p%FWShedVorticity) .and. (nNW=0) then + nSegP = p%nWings * ( (p%nSpan+1)*(nNW-iDepthStart+2) ) + nSegNW = p%nWings * (2*(p%nSpan+1)*(nNW-iDepthStart+2)-(p%nSpan+1)-(nNW-iDepthStart+1+1)) + if (.not.LastNWShed) then + nSegNW = nSegNW - p%nWings * (p%nSpan) ! Removing last set of shed segments + endif + endif + nSeg=nSegNW + ! FW segments + if (nFW>0) then + nSegP = nSegP + p%nWings * ( (FWnSpan+1)*(nFW+1) ) + if (p%FWShedVorticity) then + nSeg = nSeg + p%nWings * (2*(FWnSpan+1)*(nFW+1)-(FWnSpan+1)-(nFW+1)) + else + nSeg = nSeg + p%nWings * ( (FWnSpan+1)*(nFW) ) ! No Shed vorticity + endif + endif +end subroutine CountSegments + +!> Count how many control points are convecting (needed to compute the wake convection) +pure integer(IntKi) function CountCPs(p, nNW, nFWEff) result(nCPs) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + integer(IntKi), intent(in ) :: nNW !< Number of NW panels + integer(IntKi), intent(in ) :: nFWEff !< Number of effective (ie. convecting) FW panels + nCPs = p%nWings * ( (p%nSpan+1)*(nNW+1) ) + if (nFWEff>0) nCPs = nCPs + p%nWings * ((FWnSpan+1)*(nFWEff+1) ) +end function CountCPs + + +subroutine PackPanelsToSegments(p, m, x, iDepthStart, bMirror, SegConnct, SegPoints, SegGamma, nSeg, nSegP) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + type(FVW_ContinuousStateType), intent(in ) :: x !< States + integer(IntKi), intent(in ) :: iDepthStart !< Index where we start packing for NW panels + logical, intent(in ) :: bMirror !< Mirror the vorticity wrt the ground + integer(IntKi),dimension(:,:), intent(inout) :: SegConnct !< Segment connectivity + real(ReKi), dimension(:,:), intent(inout) :: SegPoints !< Segment Points + real(ReKi), dimension(:) , intent(inout) :: SegGamma !< Segment Circulation + integer(IntKi), intent(out) :: nSeg !< Total number of segments after packing + integer(IntKi), intent(out) :: nSegP !< Total number of segments points after packing + ! Local + integer(IntKi) :: iHeadC, iHeadP, nC, nCNW, nP, iW, iHeadC_bkp, i, iMirror + logical :: LastNWShed + + ! If the FW contains Shed vorticity, we include the last shed vorticity form the NW, orhtwerise, we don't! + ! It's important not to include it, otherwise a strong vortex will be present there with no compensating vorticity from the FW + LastNWShed = (p%FWShedVorticity ) .or. ((.not.p%FWShedVorticity) .and. (m%nNW0) then + ! Nullifying for safety + SegConnct=-1 + SegPoints=-1 + SegGamma =-1 + ! + iHeadP=1 + iHeadC=1 + if (nCNW>0) then + do iW=1,p%nWings + CALL LatticeToSegments(x%r_NW(1:3,:,1:m%nNW+1,iW), x%Gamma_NW(:,1:m%nNW,iW), iDepthStart, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC, .True., LastNWShed ) + enddo + endif + if (m%nFW>0) then + iHeadC_bkp = iHeadC + do iW=1,p%nWings + CALL LatticeToSegments(x%r_FW(1:3,:,1:m%nFW+1,iW), x%Gamma_FW(:,1:m%nFW,iW), 1, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC , p%FWShedVorticity, p%FWShedVorticity) + enddo + SegConnct(3,iHeadC_bkp:) = SegConnct(3,iHeadC_bkp:) + m%nNW ! Increasing iDepth (or age) to account for NW + endif + if (DEV_VERSION) then + ! Safety checks + if ((iHeadP-1)/=nP) then + print*,'PackPanelsToSegments: Number of points wrongly estimated',nP, iHeadP-1 + STOP ! Keep me. The check will be removed once the code is well established + endif + if ((iHeadC-1)/=nC) then + print*,'PackPanelsToSegments: Number of segments wrongly estimated',nC, iHeadC-1 + STOP ! Keep me. The check will be removed once the code is well established + endif + if (any(SegPoints(3,:)<-99._ReKi)) then + call print_x_NW_FW(p,m,x,'pack') + print*,'PackPanelsToSegments: some segments are NAN' + STOP ! Keep me. The check will be removed once the code is well established + endif + endif + nSeg = iHeadC-1 + nSegP = iHeadP-1 + + if (bMirror) then + ! Mirroring the segments directly + ! NOTE: an alternative is to handle this in the Biot-Savart law directly... + do i=1,nSeg + iMirror = i + nSeg + SegConnct(1:2, iMirror) = SegConnct(1:2, i) + nSegP ! Increased point indices + SegConnct(3:4, iMirror) = SegConnct(3:4, i) ! Span and age is copied + SegGamma(iMirror) = -SegGamma(i) ! Vorticity needs mirroring + enddo + do i=1,nSegP + iMirror = i + nSegP + SegPoints(1:2, iMirror) = SegPoints(1:2, i) ! Same x and y + SegPoints(3 , iMirror) = - SegPoints(3 , i) ! Mirror with respect to z=0 + enddo + ! We now have double the amount of segments and points + nSeg = nSeg*2 + nSegP = nSegP*2 + endif + else + nSeg = 0 + nSegP = 0 + endif +end subroutine PackPanelsToSegments + +!> Set up regularization parameter based on diffusion method and regularization method +!! NOTE: this should preferably be done at the "panel"/vortex sheet level +subroutine FVW_InitRegularization(p, m, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(inout) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + real(ReKi) :: ds_min, ds_max, ds_mean !< min,max and mean of spanwise sections + real(ReKi) :: c_min, c_max, c_mean !< min,max and mean of chord + real(ReKi) :: d_min, d_max, d_mean !< min,max and mean of panel diagonal + real(ReKi) :: RegParam + real(ReKi) :: Span !< "Blade span" + integer :: iW + ErrStat = ErrID_None + ErrMsg = "" + ! --- Compute min max and mean spanwise section lengths + iW =1 + ds_min = minval(m%s_ll(2:p%nSpan+1,iW)-m%s_ll(1:p%nSpan,iW)) + ds_max = maxval(m%s_ll(2:p%nSpan+1,iW)-m%s_ll(1:p%nSpan,iW)) + ds_mean = sum(m%s_ll(2:p%nSpan+1,iW)-m%s_ll(1:p%nSpan,iW))/(p%nSpan+1) + c_min = minval(m%chord_LL(:,iW)) + c_max = maxval(m%chord_LL(:,iW)) + c_mean = sum (m%chord_LL(:,iW))/(p%nSpan+1) + d_min = minval(m%diag_LL(:,iW)) + d_max = maxval(m%diag_LL(:,iW)) + d_mean = sum (m%diag_LL(:,iW))/(p%nSpan+1) + Span = m%s_ll(p%nSpan+1,iW)-m%s_ll(1,iW) + RegParam = ds_mean*2 + if (DEV_VERSION) then + write(*,'(A)')'-----------------------------------------------------------------------------------------' + write(*,'(A)')'Regularization Info' + write(*,'(A,1F8.4,A)') 'Span : ',Span + write(*,'(A,3F8.4,A)') 'Chord : ',c_min,c_mean,c_max,' (min, mean, max)' + write(*,'(A,3F8.4,A)') 'Spanwise discretization: ',ds_min,ds_mean,ds_max,' (min, mean, max)' + write(*,'(A,3F8.4,A)') 'Diagonal discretization: ',d_min,d_mean,d_max,' (min, mean, max)' + write(*,'(A,1F8.4)') 'RegParam (Recommended) : ',RegParam + write(*,'(A,1F8.4)') 'RegParam (Input ) : ',p%WakeRegParam + endif + if (p%RegDeterMethod==idRegDeterAuto) then + ! TODO this is beta + print*,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + print*,'!!! NOTE: using optmized wake regularization parameters is still a beta feature!' + print*,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + p%WakeRegMethod = idRegConstant + p%RegFunction = idRegVatistas + p%WakeRegParam = RegParam + p%WingRegParam = RegParam + p%CoreSpreadEddyVisc = 100 + write(*,'(A)' ) 'The following regularization parameters will be used:' + write(*,'(A,I0)' ) 'WakeRegMethod : ', p%WakeRegMethod + write(*,'(A,I0)' ) 'RegFunction : ', p%RegFunction + write(*,'(A,1F8.4)') 'WakeRegParam : ', p%WakeRegParam + write(*,'(A,1F8.4)') 'WingRegParam : ', p%WingRegParam + write(*,'(A,1F8.4)') 'CoreSpreadEddyVisc: ', p%CoreSpreadEddyVisc + endif + ! KEEP ME: potentially perform pre-computation here + !if (p%WakeRegMethod==idRegConstant) then + !else if (p%WakeRegMethod==idRegStretching) then + !else if (p%WakeRegMethod==idRegAge) then + !else + ! ErrStat = ErrID_Fatal + ! ErrMsg ='Regularization method not implemented' + !endif +end subroutine FVW_InitRegularization + + +!> Set up regularization parameter based on diffusion method and regularization method +!! NOTE: this should preferably be done at the "panel"/vortex sheet level +subroutine WakeRegularization(p, x, m, SegConnct, SegPoints, SegGamma, SegEpsilon, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< States + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + integer(IntKi),dimension(:,:) , intent(in ) :: SegConnct !< Segment connectivity + real(ReKi), dimension(:,:) , intent(in ) :: SegPoints !< Segment Points + real(ReKi), dimension(:) , intent(in ) :: SegGamma !< Segment Circulation + real(ReKi), dimension(:) , intent( out) :: SegEpsilon !< Segment regularization parameter + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: iSeg + real(ReKi) :: time + ErrStat = ErrID_None + ErrMsg = "" + + ! + if (p%WakeRegMethod==idRegConstant) then + SegEpsilon=p%WakeRegParam + + else if (p%WakeRegMethod==idRegStretching) then + ! TODO + ErrStat = ErrID_Fatal + ErrMsg ='Regularization method not implemented' + if (.false.) print*,m%nNW,x%r_NW(1,1,1,1),SegPoints(1,1),SegGamma(1) ! Needed in the future, Just to avoid unused var warning + + else if (p%WakeRegMethod==idRegAge) then + do iSeg=1,size(SegEpsilon,1) ! loop on segments + time = (SegConnct(3, iSeg)-1) * p%DTfvw ! column 3 contains "iDepth", or "iAge", from 1 to nSteps + SegEpsilon(iSeg) = sqrt( 4._ReKi * CoreSpreadAlpha * p%CoreSpreadEddyVisc * p%KinVisc* time + p%WakeRegParam**2 ) + enddo + + else + ErrStat = ErrID_Fatal + ErrMsg ='Regularization method not implemented' + endif + +end subroutine WakeRegularization + + +!> Compute induced velocities from all vortex elements onto all the vortex elements +!! In : x%r_NW, x%r_FW, x%Gamma_NW, x%Gamma_FW +!! Out: m%Vind_NW, m%Vind_FW +subroutine WakeInducedVelocities(p, x, m, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< States + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local variables + integer(IntKi) :: iW, nSeg, nSegP, nCPs, iHeadP + integer(IntKi) :: nFWEff ! Number of farwake panels that are free at current tmie step + logical :: bMirror ! True if we mirror the vorticity wrt ground + ! TODO new options + integer(IntKi) :: RegFunctionPart + integer(IntKi) :: nPart + real(ReKi) :: DistanceDirect ! Distance under which direct evaluation of the Biot-Savart should be done for tree + type(T_Tree) :: Tree + real(ReKi), dimension(:,:), allocatable :: PartPoints !< Particle points + real(ReKi), dimension(:,:), allocatable :: PartAlpha !< Particle circulation + real(ReKi), dimension(:) , allocatable :: PartEpsilon !< Regularization parameter + ErrStat= ErrID_None + ErrMsg ='' + + nFWEff = min(m%nFW, p%nFWFree) + bMirror = p%ShearModel==idShearMirror ! Whether or not we mirror the vorticity wrt ground + + m%Vind_NW = -9999._ReKi !< Safety + m%Vind_FW = -9999._ReKi !< Safety + + ! --- Packing all vortex elements into a list of segments + ! NOTE: modifies m%Seg* + call PackPanelsToSegments(p, m, x, 1, bMirror, m%SegConnct, m%SegPoints, m%SegGamma, nSeg, nSegP) + + ! --- Setting up regularization SegEpsilon + call WakeRegularization(p, x, m, m%SegConnct, m%SegPoints, m%SegGamma, m%SegEpsilon(1:nSeg), ErrStat, ErrMsg) + + ! --- Computing induced velocity + call PackConvectingPoints() + if (DEV_VERSION) then + print'(A,I0,A,I0,A,I0)','Convection - nSeg:',nSeg,' - nSegP:',nSegP, ' - nCPs:',nCPs + endif + + ! --- Converting to particles + if ((p%VelocityMethod==idVelocityTree) .or. (p%VelocityMethod==idVelocityPart)) then + iHeadP=1 + nPart = p%PartPerSegment * nSeg + allocate(PartPoints(3,nPart), PartAlpha(3,nPart), PartEpsilon(nPart)) + PartAlpha(:,:) = -99999.99_ReKi + PartPoints(:,:) = -99999.99_ReKi + PartEpsilon(:) = -99999.99_ReKi + call SegmentsToPart(m%SegPoints, m%SegConnct, m%SegGamma, m%SegEpsilon, 1, nSeg, p%PartPerSegment, PartPoints, PartAlpha, PartEpsilon, iHeadP) + if (p%RegFunction/=idRegNone) then + RegFunctionPart = idRegExp ! TODO need to find a good equivalence and potentially adapt Epsilon in SegmentsToPart + endif + if (any(PartEpsilon(:)<-9999.99_ReKi)) then + print*,'Error in Segment to part conversion' + STOP + endif + endif + + ! --- Getting induced velocity + m%Uind=0.0_ReKi ! very important due to side effects of ui_* methods + if (p%VelocityMethod==idVelocityBasic) then + call ui_seg( 1, nCPs, m%CPs, 1, nSeg, nSeg, nSegP, m%SegPoints, m%SegConnct, m%SegGamma, p%RegFunction, m%SegEpsilon, m%Uind) + + elseif (p%VelocityMethod==idVelocityTree) then + + DistanceDirect = 2*sum(PartEpsilon)/size(PartEpsilon) ! 2*mean(eps), below that distance eps has a strong effect + call grow_tree(Tree, PartPoints, PartAlpha, RegFunctionPart, PartEpsilon, 0) + !call print_tree(Tree) + call ui_tree(Tree, m%CPs, 0, 1, nCPs, p%TreeBranchFactor, DistanceDirect, m%Uind, ErrStat, ErrMsg) + call cut_tree(Tree) + deallocate(PartPoints, PartAlpha, PartEpsilon) + + elseif (p%VelocityMethod==idVelocityPart) then + call ui_part_nograd(m%CPs ,PartPoints, PartAlpha, RegFunctionPart, PartEpsilon, m%Uind, nCPs, nPart) + deallocate(PartPoints, PartAlpha, PartEpsilon) + endif + call UnPackInducedVelocity() + +contains + !> Pack all the points that convect + subroutine PackConvectingPoints() + ! Counting total number of control points that convects + nCPs = CountCPs(p, m%nNW, nFWEff) + m%CPs=-999.9_ReKi + ! Packing + iHeadP=1 + do iW=1,p%nWings + CALL LatticeToPoints(x%r_NW(1:3,:,1:m%nNW+1,iW), 1, m%CPs, iHeadP) + enddo + if (nFWEff>0) then + do iW=1,p%nWings + CALL LatticeToPoints(x%r_FW(1:3,:,1:nFWEff+1,iW), 1, m%CPs, iHeadP) + enddo + endif + if (DEV_VERSION) then + ! Additional checks + if (any(m%CPs(1,1:nCPs)<=-99)) then + call print_x_NW_FW(p,m,x,'pack') + ErrMsg='PackConvectingPoints: Problem in Control points'; ErrStat=ErrID_Fatal; return + endif + if ((iHeadP-1)/=nCPs) then + print*,'PackConvectingPoints: Number of points wrongly estimated',nCPs, iHeadP-1 + STOP ! Keep me. The check will be removed once the code is well established + ErrMsg='PackConvectingPoints: Number of points wrongly estimated '; ErrStat=ErrID_Fatal; return + endif + endif + end subroutine + !> Distribute the induced velocity to the proper location + subroutine UnPackInducedVelocity() + iHeadP=1 + do iW=1,p%nWings + CALL VecToLattice(m%Uind, 1, m%Vind_NW(:,:,1:m%nNW+1,iW), iHeadP) + enddo + if (nFWEff>0) then + do iW=1,p%nWings + CALL VecToLattice(m%Uind, 1, m%Vind_FW(1:3,1:FWnSpan+1,1:nFWEff+1,iW), iHeadP) + enddo + if (DEV_VERSION) then + if (any(m%Vind_FW(1:3,1:FWnSpan+1,1:nFWEff+1,:)<-99)) then + ErrMsg='UnPackInducedVelocity: Problem in FW induced velocity on FW points'; ErrStat=ErrID_Fatal; return + endif + endif + endif + if (DEV_VERSION) then + if ((iHeadP-1)/=nCPs) then + print*,'UnPackInducedVelocity: Number of points wrongly estimated',nCPs, iHeadP-1 + STOP ! Keep me. The check will be removed once the code is well established + ErrMsg='UnPackInducedVelocity: Number of points wrongly estimated'; ErrStat=ErrID_Fatal; return + endif + endif + end subroutine + +end subroutine + +!> Compute induced velocities from all vortex elements onto the lifting line control points +!! In : x%r_NW, x%r_FW, x%Gamma_NW, x%Gamma_FW +!! Out: m%Vind_LL +subroutine LiftingLineInducedVelocities(p, x, iDepthStart, m, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< States + integer(IntKi), intent(in ) :: iDepthStart !< Index where we start packing for NW panels + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + ! Local variables + integer(IntKi) :: iW, nSeg, nSegP, nCPs, iHeadP + real(ReKi), dimension(:,:), allocatable :: CPs !< ControlPoints + real(ReKi), dimension(:,:), allocatable :: Uind !< Induced velocity + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + logical :: bMirror + ErrStat = ErrID_None + ErrMsg = "" + m%Vind_LL = -9999._ReKi !< Safety + bMirror = p%ShearModel==idShearMirror ! Whether or not we mirror the vorticity wrt ground + + ! --- Packing all vortex elements into a list of segments + call PackPanelsToSegments(p, m, x, iDepthStart, bMirror, m%SegConnct, m%SegPoints, m%SegGamma, nSeg, nSegP) + + ! --- Computing induced velocity + if (nSegP==0) then + nCPs=0 + m%Vind_LL = 0.0_ReKi + if (DEV_VERSION) then + print'(A,I0,A,I0,A,I0,A)','Induction - nSeg:',nSeg,' - nSegP:',nSegP, ' - nCPs:',nCPs, ' -> No induction' + endif + else + ! --- Setting up regularization + call WakeRegularization(p, x, m, m%SegConnct(:,1:nSeg), m%SegPoints(:,1:nSegP), m%SegGamma(1:nSeg), m%SegEpsilon(1:nSeg), ErrStat, ErrMsg) + + nCPs=p%nWings * p%nSpan + allocate(CPs (1:3,1:nCPs)) ! NOTE: here we do allocate CPs and Uind insteadof using Misc + allocate(Uind(1:3,1:nCPs)) ! The size is reasonably small, and m%Uind then stay filled with "rollup velocities" (for export) + Uind=0.0_ReKi !< important due to side effects of ui_seg + ! --- + call PackLiftingLinePoints() + if (DEV_VERSION) then + print'(A,I0,A,I0,A,I0)','Induction - nSeg:',nSeg,' - nSegP:',nSegP, ' - nCPs:',nCPs + endif + call ui_seg( 1, nCPs, CPs, 1, nSeg, nSeg, nSegP, m%SegPoints, m%SegConnct, m%SegGamma, p%RegFunction, m%SegEpsilon, Uind) + call UnPackLiftingLineVelocities() + + deallocate(Uind) + deallocate(CPs) + endif +contains + !> Pack all the control points + subroutine PackLiftingLinePoints() + iHeadP=1 + do iW=1,p%nWings + CALL LatticeToPoints(m%CP_LL(1:3,:,iW:iW), 1, CPs, iHeadP) + enddo + if (DEV_VERSION) then + if ((iHeadP-1)/=size(CPs,2)) then + print*,'PackLLPoints: Number of points wrongly estimated',size(CPs,2), iHeadP-1 + STOP ! Keep me. The check will be removed once the code is well established + endif + endif + nCPs=iHeadP-1 + end subroutine + + !> Distribute the induced velocity to the proper location + subroutine UnPackLiftingLineVelocities() + iHeadP=1 + do iW=1,p%nWings + CALL VecToLattice(Uind, 1, m%Vind_LL(1:3,:,iW:iW), iHeadP) + enddo + if (DEV_VERSION) then + if ((iHeadP-1)/=size(Uind,2)) then + print*,'UnPackLiftingLineVelocities: Number of points wrongly estimated',size(Uind,2), iHeadP-1 + STOP ! Keep me. The check will be removed once the code is well established + endif + endif + end subroutine +end subroutine + +!> Fake ground effect handling to prevents vortices to enter the ground +!! For now a crude bounding is done, engineering models may follow +!! True account of the ground effect (using mirroring or panels) should be done elsewhere +!! This assumes that the ground is at z=0, in harmony with inflow wind +subroutine FakeGroundEffect(p, x, m, ErrStat, ErrMsg) + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(inout) :: x !< States + type(FVW_MiscVarType), intent(in ) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: iAge, iWing, iSpan + integer(IntKi) :: nBelow + real(ReKi), parameter:: GROUND = 1.e-4_ReKi + real(ReKi), parameter:: ABOVE_GROUND = 0.1_ReKi + ErrStat = ErrID_None + ErrMsg = "" + + nBelow=0 + do iWing = 1,p%nWings + do iAge = 1,m%nNW+1 + do iSpan = 1,p%nSpan+1 + if (x%r_NW(3, iSpan, iAge, iWing) < GROUND) then + x%r_NW(3, iSpan, iAge, iWing) = ABOVE_GROUND ! could use m%dxdt + nBelow=nBelow+1 + endif + enddo + enddo + enddo + if (m%nFW>0) then + do iWing = 1,p%nWings + do iAge = 1,m%nFW+1 + do iSpan = 1,FWnSpan + if (x%r_FW(3, iSpan, iAge, iWing) < GROUND) then + x%r_FW(3, iSpan, iAge, iWing) = ABOVE_GROUND ! could use m%dxdt + nBelow=nBelow+1 + endif + enddo + enddo + enddo + endif + if (nBelow>0) then + print*,'[WARN] Check the simulation, some vortices were found below the ground: ',nBelow + endif +end subroutine FakeGroundEffect + +!> Compute typical aerodynamic outputs based on: +!! - the lifting line velocities in global coordinates +!! - some transformation matrices +!! - M_ag : from global to airfoil (this is well defined, also called "n-t" system in AeroDyn) +!! - M_sg : from global to section (this is ill-defined), this coordinate is used to define the "axial" and "tangential" inductions +subroutine FVW_AeroOuts( M_sg, M_ag, PitchAndTwist, Vstr_g, Vind_g, Vwnd_g, KinVisc, Chord, & + AxInd, TanInd, Vrel_norm, phi, alpha, Re, Urel_s, ErrStat, ErrMsg ) + real(ReKi), intent(in ) :: M_sg(3,3) ! m%WithoutSweepPitchTwist global coord to "section" coord + real(R8Ki), intent(in ) :: M_ag(3,3) ! u%BladeMotion(k)%Orientation(1:3,1:3,j) global coord to airfoil coord + real(ReKi), intent(in ) :: PitchAndTwist ! Pitch and twist of section + real(ReKi), intent(in ) :: Vstr_g(3) ! Structural velocity global coord + real(ReKi), intent(in ) :: Vind_g(3) ! Induced wind velocity global coord + real(ReKi), intent(in ) :: Vwnd_g(3) ! Disturbed inflow global coord + real(ReKi), intent(in ) :: KinVisc ! Viscosity + real(ReKi), intent(in ) :: Chord ! chord length + real(ReKi), intent( out) :: AxInd ! axial induction + real(ReKi), intent( out) :: TanInd ! Tangential induction + real(ReKi), intent( out) :: Vrel_norm ! Relative velocity norm + real(Reki), intent( out) :: phi ! Flow angle + real(Reki), intent( out) :: alpha ! angle of attack + real(ReKi), intent( out) :: Re ! Reynolds number + real(ReKi), intent( out) :: Urel_s(3) ! Relative wind of the airfoil (Vwnd - Vstr) section coord + integer(IntKi), intent( out) :: ErrStat + character(ErrMsgLen), intent( out) :: ErrMsg + + ! Local vars + real(ReKi) :: Vstr_s(3) ! Struct Velocity, section coord + real(ReKi) :: Vind_s(3) ! Induced Velocity, section coord + real(ReKi) :: Vwnd_s(3) ! Disturbed wind velocity, section coord + real(ReKi) :: Vtot_g(3) ! Vector of total relative velocity section coord + real(ReKi) :: Vtot_a(3) ! Vector of total relative velocity global coord + real(ReKi) :: Vtot_s(3) ! Vector of total relative velocity global coord + ErrStat = ErrID_None + ErrMsg = "" + !real(DbKi), dimension(3,3) :: M_sa !< Transformation matrix from airfoil to section coord + !real(DbKi), dimension(3,3) :: M_sg2 !< Transformation matrix from global to section coord + ! --- Transformation from airfoil to section (KEEP ME) + !M_sa(1,1:3) = (/ cos(PitchAndTwist*1._DbKi), sin(PitchAndTwist*1._DbKi), 0.0_DbKi /) + !M_sa(2,1:3) = (/ -sin(PitchAndTwist*1._DbKi), cos(PitchAndTwist*1._DbKi), 0.0_DbKi /) + !M_sa(3,1:3) = (/ 0.0_DbKi, 0.0_DbKi, 1.0_DbKi /) + !M_sg= matmul(M_sa, M_ag ) + + ! --- Airfoil coordinates: used to define alpha, and Vrel, also called "n-t" system + Vtot_g = Vwnd_g - Vstr_g + Vind_g + Vtot_a = matmul(M_ag, Vtot_g) + alpha = atan2( Vtot_a(1), Vtot_a(2) ) + Vrel_norm = sqrt(Vtot_a(1)**2 + Vtot_a(2)**2) ! NOTE: z component shoudn't be used + Re = Chord * Vrel_norm / KinVisc / 1.0E6 + + ! Section coordinates: used to define axial induction andflow angle + Vstr_s = matmul(M_sg, Vstr_g) + Vind_s = matmul(M_sg, Vind_g) + Vwnd_s = matmul(M_sg, Vwnd_g) + Urel_s = Vwnd_s - Vstr_s ! relative wind + Vtot_s = Vwnd_s - Vstr_s + Vind_s + AxInd = -Vind_s(1)/Urel_s(1) + TanInd = Vind_s(2)/Urel_s(2) + phi = atan2( Vtot_s(1), Vtot_s(2) ) ! flow angle + + if(.false.) print*,PitchAndTwist ! just to avoid unused var for now +end subroutine FVW_AeroOuts + +!> Generic function to compute alpha, Vrel and Re based on global data +subroutine AlphaVrel_Generic(M_ag, Vstr_g, Vind_g, Vwnd_g, KinVisc, Chord, Vrel_norm, alpha, Re) + real(R8Ki), intent(in ) :: M_ag(3,3) ! u%BladeMotion(k)%Orientation(1:3,1:3,j) global coord to airfoil coord + real(ReKi), intent(in ) :: Vstr_g(3) ! Structural velocity global coord + real(ReKi), intent(in ) :: Vind_g(3) ! Induced wind velocity global coord + real(ReKi), intent(in ) :: Vwnd_g(3) ! Disturbed inflow global coord + real(ReKi), intent(in ) :: KinVisc ! Viscosity + real(ReKi), intent(in ) :: Chord ! chord length + real(ReKi), intent( out) :: Vrel_norm ! Relative velocity norm + real(Reki), intent( out) :: alpha ! angle of attack + real(ReKi), intent( out) :: Re ! Reynolds number + ! Local vars + real(ReKi) :: Vtot_g(3) ! Vector of total relative velocity section coord + real(ReKi) :: Vtot_a(3) ! Vector of total relative velocity global coord + ! --- Airfoil coordinates: used to define alpha, and Vrel, also called "n-t" system + Vtot_g = Vwnd_g - Vstr_g + Vind_g + Vtot_a = matmul(M_ag, Vtot_g) + alpha = atan2( Vtot_a(1), Vtot_a(2) ) + Vrel_norm = sqrt(Vtot_a(1)**2 + Vtot_a(2)**2) ! NOTE: z component shoudn't be used + Re = Chord * Vrel_norm / KinVisc / 1.0E6 +end subroutine AlphaVrel_Generic + + +end module FVW_Subs diff --git a/modules/aerodyn/src/FVW_Tests.f90 b/modules/aerodyn/src/FVW_Tests.f90 new file mode 100644 index 0000000000..03dc1c19cf --- /dev/null +++ b/modules/aerodyn/src/FVW_Tests.f90 @@ -0,0 +1,754 @@ +module FVW_Tests + + use NWTC_Library + + use FVW_Types + use FVW_Subs + use FVW_VortexTools + use FVW_Wings + use FVW_IO + use FVW_BiotSavart + use FVW_VTK, only : FVW_VTK_Misc + + implicit none + + public :: FVW_RunTests + private + + interface test_equal; module procedure & + test_equal_i1, & + test_equal_i0 + end interface + interface test_almost_equal; module procedure & + test_almost_equal_0, & + test_almost_equal_1, & + test_almost_equal_2 + end interface +contains + ! -------------------------------------------------------------------------------- + ! --- Helper functions (should be part of NWTC library) + ! -------------------------------------------------------------------------------- + subroutine test_success(testname,info,bPrint_in) + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: info + logical, intent(in), optional :: bPrint_in + if(present(bPrint_in)) then + if(bPrint_in) then + write(*,'(A)')'[ OK ] '//trim(testname)//': '//trim(Info) + endif + else + write(*,'(A)')'[ OK ] '//trim(testname)//': '//trim(Info) + endif + end subroutine + + subroutine test_fail(testname,info,bPrint_in,bStop_in) + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: info + logical, intent(in), optional :: bPrint_in + logical, intent(in), optional :: bStop_in + if(present(bPrint_in)) then + if(bPrint_in) then + write(*,'(A)')'[FAIL] '//trim(testname)//': '//trim(Info) + endif + else + write(*,'(A)')'[FAIL] '//trim(testname)//': '//trim(Info) + endif + if(present(bStop_in)) then + if(bStop_in) then + STOP + endif + else + STOP + endif + end subroutine + + subroutine test_equal_i0(testname,Var,iTry,iRef) + ! Arguments + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: Var + integer, intent(in) :: iTry !< + integer, intent(in) :: iRef !< + ! Variables + character(len=255) :: InfoAbs + if(iRef/=iTry) then + write(InfoAbs,'(A,I0,A,I0)') trim(Var),iRef,'/',iTry + call test_fail(testname,InfoAbs) + STOP + else + write(InfoAbs,'(A,A,I0)') trim(Var),' ok ',iRef + call test_success(testname,InfoAbs) + endif + end subroutine + + subroutine test_equal_i1(testname,Var,VecTry,VecRef,bTest,bPrintOnly,bPassed) + ! Arguments + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: Var + integer, dimension(:), intent(in) :: VecTry !< + integer, dimension(:), intent(in) :: VecRef !< + logical, intent(in) :: bTest + logical, intent(in) :: bPrintOnly + logical, intent(out),optional :: bPassed + ! Variables + character(len=255) :: InfoAbs + integer :: i,cpt + ! + cpt=0 + do i=1,size(VecRef) + if(VecRef(i)/=VecTry(i)) then + cpt=cpt+1 + endif + enddo + if(cpt>0) then + write(InfoAbs,'(A,I0)') trim(Var)//' Elements different: ',cpt + if(present(bPassed)) then + bPassed=.false. + endif + else + write(InfoAbs,'(A)') trim(Var)//' reproduced to identity' + if(present(bPassed)) then + bPassed=.true. + endif + endif + if(bPrintOnly) then + print'(A)',trim(InfoAbs) + endif + if(bTest) then + if(cpt>0) then + call test_fail(testname,InfoAbs) + STOP + else + call test_success(testname,InfoAbs) + endif + endif + end subroutine + + subroutine test_almost_equal_0(testname,Var,Ref,Try,MINNORM,bStop,bPrint,bPassed) + ! Arguments + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: Var + real(ReKi), intent(in) :: Ref !< + real(ReKi), intent(in) :: Try !< + real(ReKi), intent(in) :: MINNORM + logical, intent(in) :: bStop + logical, intent(in) :: bPrint + logical, intent(out),optional :: bPassed + ! Variables + character(len=255) :: InfoAbs + real(ReKi) :: delta + integer :: cpt + ! + cpt=0 + delta=abs(Ref-Try) + if(delta>MINNORM) then + write(InfoAbs,'(A,ES8.1E2,A,ES8.1E2,A,I0)') trim(Var)//' tol: ',MINNORM,', mean: ',delta,' - Failed:',cpt + call test_fail(testname,InfoAbs,bPrint,bStop) + else + write(InfoAbs,'(A,ES8.1E2,A,ES8.1E2)') trim(Var)//' tol: ',MINNORM,', mean: ',delta + call test_success(testname,InfoAbs,bPrint) + endif + if(present(bPassed)) then + bPassed=delta>MINNORM + endif + end subroutine + subroutine test_almost_equal_1(testname,Var,VecRef,VecTry,MINNORM,bStop,bPrint,bPassed) + ! Arguments + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: Var + real(ReKi), dimension(:), intent(in) :: VecRef !< + real(ReKi), dimension(:), intent(in) :: VecTry !< + real(ReKi), intent(in) :: MINNORM + logical, intent(in) :: bStop + logical, intent(in) :: bPrint + logical, intent(out),optional :: bPassed + ! Variables + character(len=255) :: InfoAbs + integer :: i,cpt + real(ReKi) :: delta + real(ReKi) :: delta_cum + ! + cpt=0 + delta_cum=0.0_ReKi + do i=1,size(VecRef,1) + delta=abs(VecRef(i)-VecTry(i)) + delta_cum=delta_cum+delta + if(delta>MINNORM) then + cpt=cpt+1 + endif + enddo + delta_cum=delta_cum/size(VecRef) + + if(cpt>0) then + write(InfoAbs,'(A,ES8.1E2,A,ES8.1E2,A,I0)') trim(Var)//' tol: ',MINNORM,', mean: ',delta_cum,' - Failed:',cpt + call test_fail(testname,InfoAbs,bPrint,bStop) + else + write(InfoAbs,'(A,ES8.1E2,A,ES8.1E2)') trim(Var)//' tol: ',MINNORM,', mean: ',delta_cum + call test_success(testname,InfoAbs,bPrint) + endif + if(present(bPassed)) then + bPassed=(cpt==0) + endif + end subroutine + subroutine test_almost_equal_2(testname,Var,VecRef,VecTry,MINNORM,bStop,bPrint,bPassed) + ! Arguments + character(len=*), intent(in) :: testname + character(len=*), intent(in) :: Var + real(ReKi), dimension(:,:), intent(in) :: VecRef !< + real(ReKi), dimension(:,:), intent(in) :: VecTry !< + real(ReKi), intent(in) :: MINNORM + logical, intent(in) :: bStop + logical, intent(in) :: bPrint + logical, intent(out),optional :: bPassed + ! Variables + real(ReKi), dimension(:),allocatable :: VecRef2 !< + real(ReKi), dimension(:),allocatable :: VecTry2 !< + integer :: p, i,j,n1,n2,nCPs + ! + n1 = size(VecRef,1); n2 = size(VecRef,2); nCPs=n1*n2 + allocate ( VecRef2 (n1*n2) ) ; allocate ( VecTry2 (n1*n2) ) + p=0 + do j=1,n2; do i=1,n1 + p=p+1 + VecRef2(p)=VecRef(i,j) + VecTry2(p)=VecTry(i,j) + enddo; enddo; + call test_almost_equal(testname,Var,VecRef2,VecTry2,MINNORM,bStop,bPrint,bPassed) + end subroutine + + ! --------------------------------------------------------------------------------} + ! --- Specific FVW tests + ! --------------------------------------------------------------------------------{ + !> + subroutine Test_BiotSavart_Sgmt(testname, ErrStat, ErrMsg) + character(len=*), intent(in) :: testname + integer(IntKi) , intent(out) :: ErrStat !< Error status of the operation + character(ErrMsgLen), intent(out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(ReKi), dimension(3) :: P1,P2,P3,CP + real(ReKi), dimension(3) :: U1 + real(ReKi) :: SegGamma1 !< Circulation [m^2/s] + real(ReKi) :: RegParam1 !< + integer(IntKi) :: i1,i2 + integer(IntKi) :: RegFunction + integer(IntKi), parameter :: nSegTot = 2 + integer(IntKi), parameter :: nSegPTot = 3 + integer(IntKi), parameter :: nCPsTot = 1 + real(ReKi), dimension(3,nCPsTot) :: CPs !< Control points + real(ReKi), dimension(3,nSegPTot) :: SegPoints !< Segment points + integer(IntKi), dimension(2,nSegTot) :: SegConnct !< Connectivity, indices of segments points iSeg1, iSeg2 + real(ReKi), dimension(nSegTot) :: SegGamma !< Segment circulation + real(ReKi), dimension(nSegTot) :: RegParam !< Regularization parameter + real(ReKi), dimension(3,nCPsTot) :: Uind_out !< Induced velocity vector - Side effects!!! + real(ReKi), dimension(3,4) :: CPs_test !< + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! --- Test that the two functions return the same values + P1=(/0. ,0.,-1./) + P2=(/0. ,0., 1./) + CPs_test(:,1) = (/ 0.0, 0., 0.0 /) ! Middle + CPs_test(:,2) = P1 ! Extremity + CPs_test(:,3) = (/ 0.05, 0., -0.5 /) ! Close + CPs_test(:,4) = (/ 10., 0., 0.0 /) ! Far + do i2 = 1, size(CPs_test,2) + ! Segment param + CP=CPs_test(:,i2) + SegGamma1=1 + RegParam1=0.5 + ! One segment param + SegConnct(:,1)=(/1,2/) + SegPoints(:,1) = P1 + SegPoints(:,2) = P2 + SegGamma(:) = SegGamma1 + RegParam(:) = RegParam1 + CPs (:,1) = CP + do i1=1,5 + RegFunction = idRegVALID(i1) + ! Method 1 + Uind_out =0.0_ReKi + call ui_seg(1, 1, CPs, & + 1, 1, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, & + RegFunction, RegParam, Uind_out) + ! Method 2 + call ui_seg_11(CP-P1, CP-P2, SegGamma1, RegFunction, RegParam1, U1) + ! Test + !print*,'Reg function', RegFunction, 'CP',CP + !print*,'Uind_out',Uind_out + !print*,'U1 ',U1 + call test_almost_equal(testname,'Uind method1/2', U1, Uind_out(:,1), 1e-4_ReKi, .true.,.true.) + !call test_almost_equal('Uind method1/2', U1, Uind_out(:,1), 1e-4, .false.,.true.) + enddo + enddo + + ! --- Test that the two segments or one segment returns the same value + P1=(/0. ,0.,-1./) + P2=(/0. ,0., 1./) + P3=(/0. ,0., 0./) + CPs_test(:,1) = (/ 0.0, 0., 0.0 /) ! Middle + CPs_test(:,2) = P1 ! Extremity + CPs_test(:,3) = (/ 0.05, 0., -0.5 /) ! Close + CPs_test(:,4) = (/ 100., 0., -0.5 /) ! Far + do i2 = 1,size(CPs_test,2) + ! Segment param + CP=CPs_test(:,i2) + SegGamma1=1 + RegParam1=0.5 + ! One segment param + SegConnct(:,1)=(/1,2/) + SegConnct(:,2)=(/2,3/) + SegPoints(:,1) = P1 + SegPoints(:,2) = P3 + SegPoints(:,3) = P2 + SegGamma(:) = SegGamma1 + RegParam(:) = RegParam1 + CPs (:,1) = CP + do i1=1,4 ! NOTE stopping at 4 since Offset is not linear + RegFunction = idRegVALID(i1) + ! Method 1 + Uind_out =0.0_ReKi + call ui_seg(1, 1, CPs, & + 1, 2, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, & + RegFunction, RegParam, Uind_out) + ! Method 2 + call ui_seg_11(CP-P1, CP-P2, SegGamma1, RegFunction, RegParam1, U1) + !print*,'Reg function', RegFunction, 'CP',CP + !print*,'Uind_out',Uind_out + !print*,'U1 ',U1 + call test_almost_equal(testname,'Uind 1seg/2seg', U1, Uind_out(:,1), 1e-4_ReKi, .true.,.true.) + enddo + enddo + end subroutine + + !> + subroutine Test_BiotSavart_Part(testname, ErrStat, ErrMsg) + character(len=*), intent(in) :: testname + integer(IntKi) , intent(out) :: ErrStat !< Error status of the operation + character(ErrMsgLen), intent(out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(ReKi), dimension(3) :: P1,CP + real(ReKi), dimension(3) :: U1 + real(ReKi), dimension(3) :: PartAlpha1 !< Particle intensity alpha=om.dV [m^3/s] + real(ReKi) :: RegParam1 !< + integer(IntKi) :: i1,i2 + integer(IntKi) :: RegFunction + integer(IntKi), parameter :: nPart = 1 + integer(IntKi), parameter :: nCPs = 1 + real(ReKi), dimension(3,nCPs) :: CPs !< Control points + real(ReKi), dimension(3,nPart):: PartPoints !< Particle points + real(ReKi), dimension(3,nPart):: PartAlpha !< Particle circulation + real(ReKi), dimension(nPart) :: RegParam !< Regularization parameter + real(ReKi), dimension(3,nCPs) :: Uind_out !< Induced velocity vector - Side effects!!! + real(ReKi), dimension(3,4) :: CPs_test !< + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! --- Test that the two functions return the same values + P1=(/0.0, 0.0, -1.0 /) + CPs_test(:,1) = (/ 0.0, 0., 0.0 /) ! Middle + CPs_test(:,2) = P1 ! Extremity + CPs_test(:,3) = (/ 0.01, 0.01, -0.9 /) ! Close + CPs_test(:,4) = (/ 10., 0., 0.0 /) ! Far + do i1=1,3 + do i2 = 1, size(CPs_test,2) + ! Segment param + CP = CPs_test(:,i2) + PartAlpha1(1:2) = 0 + PartAlpha1(3 ) = 2 + RegParam1 = 0.5 + ! One segment param + PartPoints(:,1) = P1 + PartAlpha(:,1) = PartAlpha1 + RegParam(:) = RegParam1 + CPs (:,1) = CP + RegFunction = idRegPartVALID(i1) + ! Method 1 + Uind_out =0.0_ReKi + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunction, RegParam, Uind_out, nCPs, nPart) + ! Method 2 + call ui_part_nograd_11(CP-P1, PartAlpha1, RegFunction, RegParam1, U1) + ! Test + !print*,'Reg function', RegFunction, 'CP',CP + !print*,'Uind_out',Uind_out + !print*,'U1 ',U1 + call test_almost_equal(testname,'Uind part method1/2', U1, Uind_out(:,1), 1e-4_ReKi, .true.,.true.) + enddo + enddo + end subroutine Test_BiotSavart_Part + + !> This test compares calls using the tree algorithm and the direct N^2 evaluation + subroutine Test_BiotSavart_PartTree(testname, ErrStat, ErrMsg) + character(len=*), intent(in) :: testname + integer(IntKi) , intent(out) :: ErrStat !< Error status of the operation + character(ErrMsgLen), intent(out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + type(T_Tree) :: Tree + real(ReKi), dimension(3) :: U_ref + integer(IntKi) :: i1,i2,i3,k, iCP + integer(IntKi) :: RegFunction + integer(IntKi) :: nPart = 1 + integer(IntKi) :: nCPs = 1 + real(ReKi), dimension(:,:), allocatable :: CPs !< Control points + real(ReKi), dimension(:,:), allocatable :: PartPoints !< Particle points + real(ReKi), dimension(:,:), allocatable :: PartAlpha !< Particle circulation + real(ReKi), dimension(:) , allocatable :: RegParam !< Regularization parameter + real(ReKi), dimension(:,:), allocatable :: Uind1 !< Induced velocity vector - Side effects!!! + real(ReKi), dimension(:,:), allocatable :: Uind2 !< Induced velocity vector - Side effects!!! + real(ReKi) :: BranchFactor, BranchSmall + real(ReKi), dimension(3,5) :: CPs_test !< + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + BranchFactor = 2.0_ReKi !< Should be above1 + BranchSmall = 0.0_ReKi + RegFunction = 1 + + ! --- Test with 0 particle + nPart=0; nCPs= 1 + call alloc(nPart,nCPs) + CPs(:,1) = (/0.0,0.0,0.0/) + Uind1 =0.0_ReKi + Uind2 =0.0_ReKi + U_ref =0.0_ReKi + call grow_tree(Tree, PartPoints, PartAlpha, RegFunction, RegParam, 0) + !call print_tree(Tree) + call ui_tree(Tree, CPs, 0, 1, nCPs, BranchFactor, BranchSmall, Uind2, ErrStat, ErrMsg) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunction, RegParam, Uind1, nCPs, nPart) + ! Test + call test_almost_equal(testname,'Uind tree 0 part', U_ref, Uind2(:,1), 1e-4_ReKi, .true.,.true.) + call cut_tree(Tree) + call dealloc() + + + ! --- Test with 1 particle + nPart=1; nCPs= 1 + call alloc(nPart,nCPs) + CPs(:,1) = (/0.0,0.0,0.0/) + PartPoints(1:3,1) = (/1.0,0.0,0.0/) + U_ref =0.0_ReKi + call grow_tree(Tree, PartPoints, PartAlpha, RegFunction, RegParam, 0) + !call print_tree(Tree) + call ui_tree(Tree, CPs, 0, 1, nCPs, BranchFactor, BranchSmall, Uind2, ErrStat, ErrMsg) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunction, RegParam, Uind1, nCPs, nPart) + ! Test + call test_almost_equal(testname,'Uind tree 1 part', Uind1, Uind2, 1e-4_ReKi, .true.,.true.) + call cut_tree(Tree) + !call print_tree(Tree) + call dealloc() + + ! --- Test with 81 particles on different CPs, inside and outside the distribution of particles + nPart=3*3**3; nCPs= 1 + call alloc(nPart,nCPs) + k=0 + do i1 = -1,1,1 + do i2 = -1,1,1 + do i3 = -1,1,1 + ! NOTE: here we purposely duplicate a point, since since is a challenging case + k=k+1; PartPoints(1:3,k) = (/ i1, i2, i3 /) + k=k+1; PartPoints(1:3,k) = (/ i1, i2, i3 /) + k=k+1; PartPoints(1:3,k) = (/ i1*1.2, i2*1.3, i3*1.1 /) + enddo + enddo + enddo + CPs_test(:,1) = (/ 0.0, 0., 0.0 /) ! Middle + CPs_test(:,2) = (/ 1.0, 1.0, 1.0 /) ! Close to a cell center + CPs_test(:,3) = PartPoints(:,5) ! On a particle point + CPs_test(:,4) = (/ 2.0, 2.0, 2.0 /) ! Starts to be far from most points + CPs_test(:,5) = (/ 10., 10., 10.0 /) ! Far from all + + call grow_tree(Tree, PartPoints, PartAlpha, RegFunction, RegParam, 0) + !call print_tree(Tree) + do iCP=1,4 + CPs(:,1) = CPs_test(:,icp) + Uind2=0.0_ReKi; Uind1=0.0_ReKi + call ui_tree(Tree, CPs, 0, 1, nCPs, BranchFactor, BranchSmall, Uind2, ErrStat, ErrMsg) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunction, RegParam, Uind1, nCPs, nPart) + !print*,'Uind',Uind1, Uind2 + ! Test + call test_almost_equal(testname,'Uind tree 81 part', Uind1, Uind2, 1e-2_ReKi, .true.,.true.) + enddo + call cut_tree(Tree) + ! --- Test that tree ui cannot be called after tree has been cut + call ui_tree(Tree, CPs, 0, 1, nCPs, BranchFactor, BranchSmall, Uind2, ErrStat, ErrMsg) + call test_equal(testname,'Err. stat tree cut',ErrStat,ErrID_Fatal) + call dealloc() + + contains + subroutine alloc(nPart, nCPs) + integer(IntKi) :: nPart, nCPs + allocate(PartPoints(3,nPart), PartAlpha(3,nPart), RegParam(nPart)) + allocate(CPs(3,nCPs), Uind1(3,nCPs), Uind2(3,nCPs)) + RegParam(:)=0.01 + PartAlpha(1,:) = 0.0 + PartAlpha(2,:) = 0.0 + PartAlpha(3,:) = 1.0 + Uind1 =0.0_ReKi + Uind2 =0.0_ReKi + end subroutine + subroutine dealloc() + deallocate(PartPoints, PartAlpha, RegParam) + deallocate(CPs, Uind1, Uind2) + end subroutine + end subroutine Test_BiotSavart_PartTree + + !> Compares the velocity field obtained from a segment and its convert to particle version + subroutine Test_SegmentsToPart(testname, ErrStat, ErrMsg) + character(len=*), intent(in) :: testname + integer(IntKi) , intent(out) :: ErrStat !< Error status of the operation + character(ErrMsgLen), intent(out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(ReKi), dimension(:,:), allocatable :: PartPoints !< Particle points + real(ReKi), dimension(:,:), allocatable :: PartAlpha !< Particle circulation + real(ReKi), dimension(:) , allocatable :: PartEpsilon !< Regularization parameter + integer(IntKi), parameter :: nSegTot = 2 + integer(IntKi), parameter :: nSegPTot = 3 + integer(IntKi), parameter :: nCPsTot = 10 + real(ReKi), dimension(3,nSegPTot) :: SegPoints !< Segment points + integer(IntKi), dimension(2,nSegTot) :: SegConnct !< Connectivity, indices of segments points iSeg1, iSeg2 + real(ReKi), dimension(nSegTot) :: SegGamma !< Segment circulation + real(ReKi), dimension(nSegTot) :: SegEpsilon !< Regularization parameter + real(ReKi), dimension(3,nCPsTot) :: CPs !< Control points + real(ReKi), dimension(3,nCPsTot) :: Uind1 !< Induced velocity vector - Side effects!!! + real(ReKi), dimension(3,nCPsTot) :: Uind2 !< Induced velocity vector - Side effects!!! + real(ReKi) :: RegParam1 !< + integer(IntKi) :: nPartPerSeg, nPart, iHeadP + integer(IntKi) :: RegFunctionPart, RegFunctionSeg + ErrStat = ErrID_None + ErrMsg = "" + RegParam1=1.0 + ! Creating two aligned segments + SegConnct(:,1)=(/1,2/) + SegConnct(:,2)=(/2,3/) + SegPoints(:,1) = (/0. ,0.,-1./) + SegPoints(:,2) = (/0. ,0., 0./) + SegPoints(:,3) = (/0. ,0., 1./) + SegGamma(:) =4 + SegEpsilon = RegParam1 + ! Points where velocity will be evaluated + CPs(:,1) = SegPoints(:,1) + CPs(:,2) = SegPoints(:,2) + CPs(:,3) = SegPoints(:,3) + CPs(:,4) = (/ 0.2, 0.2, 0.0/) + CPs(:,6) = (/ 0.5, 0.5, 0. /) + CPs(:,8) = (/ 1.0, 1.0, 0./) + CPs(:,9) = (/ 10.0, 10.0, 0./) + CPs(:,5) = (/ 0.2, 0.2, 0.5/) + CPs(:,7) = (/ 0.5, 0.5, 0.5/) + CPs(:,10) = (/ 1.0, 1.0, 1./) + + ! --- Test 1 - 10 particles, no regularization + RegFunctionSeg = idRegNone + RegFunctionPart = idRegNone + nPartPerSeg = 10 + + nPart = nPartPerSeg * nSegTot + call alloc(nPart) + iHeadP=1 + call SegmentsToPart(SegPoints, SegConnct, SegGamma, SegEpsilon, 1, nSegTot, nPartPerSeg, PartPoints, PartAlpha, PartEpsilon, iHeadP) + + Uind1 =0.0_ReKi; Uind2 =0.0_ReKi; + call ui_seg(1, nCPsTot, CPs, 1, nSegTot, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, RegFunctionSeg, SegEpsilon, Uind1) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunctionPart, PartEpsilon, Uind2, nCPsTot, nPart) + call test_almost_equal(testname,'Uind 10 part/sgmt no reg', Uind1, Uind2, 1e-3_ReKi, .true.,.true.) + call dealloc() + + ! --- Test 1 - 2 particles, no regularization + RegFunctionSeg = idRegNone + RegFunctionPart = idRegNone + nPartPerSeg = 2 + + nPart = nPartPerSeg * nSegTot + call alloc(nPart) + iHeadP=1 + call SegmentsToPart(SegPoints, SegConnct, SegGamma, SegEpsilon, 1, nSegTot, nPartPerSeg, PartPoints, PartAlpha, PartEpsilon, iHeadP) + + Uind1 =0.0_ReKi; Uind2 =0.0_ReKi; + call ui_seg(1, nCPsTot, CPs, 1, nSegTot, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, RegFunctionSeg, SegEpsilon, Uind1) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunctionPart, PartEpsilon, Uind2, nCPsTot, nPart) + call test_almost_equal(testname,'Uind 2 part/sgmt noreg', Uind1, Uind2, 3e-1_ReKi, .true.,.true.) + call dealloc() + + + ! --- Test 3 - 10 particles, regularization + ! NOTE: more work needed to match the regularization functions and parameters optimally + RegFunctionSeg = idRegLambOseen + RegFunctionPart = idRegExp + nPartPerSeg = 10 + + nPart = nPartPerSeg * nSegTot + call alloc(nPart) + iHeadP=1 + call SegmentsToPart(SegPoints, SegConnct, SegGamma, SegEpsilon, 1, nSegTot, nPartPerSeg, PartPoints, PartAlpha, PartEpsilon, iHeadP) + + Uind1 =0.0_ReKi; Uind2 =0.0_ReKi; + call ui_seg(1, nCPsTot, CPs, 1, nSegTot, nSegTot, nSegPTot, SegPoints, SegConnct, SegGamma, RegFunctionSeg, SegEpsilon, Uind1) + call ui_part_nograd(CPs,PartPoints, PartAlpha, RegFunctionPart, PartEpsilon, Uind2, nCPsTot, nPart) + !print'(A,10F7.3)','Uind1',Uind1(1,:) + !print'(A,10F7.3)','Uind2',Uind2(1,:) + !print'(A,10F7.3)','Uind1',Uind1(2,:) + !print'(A,10F7.3)','Uind2',Uind2(2,:) + !print'(A,10F7.3)','Uind1',Uind1(3,:) + !print'(A,10F7.3)','Uind2',Uind2(3,:) + call test_almost_equal(testname,'Uind 10 part/sgmt w.reg', Uind1, Uind2, 5e-2_ReKi, .true.,.true.) + call dealloc() + + contains + subroutine alloc(n) + integer(IntKi) :: n + allocate(PartPoints(3,n), PartAlpha(3,n), PartEpsilon(n)) + PartAlpha(:,:) = -99999.99_ReKi + PartPoints(:,:) = -99999.99_ReKi + PartEpsilon(:) = -99999.99_ReKi + end subroutine + subroutine dealloc() + deallocate(PartPoints, PartAlpha, PartEpsilon) + end subroutine + end subroutine Test_SegmentsToPart + + !> + subroutine Test_LatticeToSegment(mvtk,iStat) + type(FVW_VTK_Misc),intent(inout) :: mvtk !< miscvars for VTK output + integer(IntKi), intent( out) :: iStat !< Status for test + ! Local + integer(IntKi),dimension(:,:), allocatable :: SegConnct !< Segment connectivity + real(ReKi), dimension(:,:), allocatable :: SegPoints !< Segment Points + real(ReKi), dimension(:) , allocatable :: SegGamma !< Segment Circulation + real(ReKi), dimension(:), allocatable :: SegEpsilon !< + ! + real(ReKi), dimension(:,:,:), allocatable :: LatticePoints1 !< Lattice Points + real(ReKi), dimension(:,:,:), allocatable :: LatticePoints2 !< Lattice Points + real(ReKi), dimension(:,:), allocatable :: LatticeGamma1 !< Lattice Circulation + real(ReKi), dimension(:,:), allocatable :: LatticeGamma2 !< Lattice Circulation + real(ReKi), dimension(:,:), allocatable :: CPs !< ControlPoints + real(ReKi), dimension(:,:), allocatable :: Uind !< Induced velocity + integer(IntKi) :: iHeadC + integer(IntKi) :: iHeadP + integer(IntKi) :: i,j + integer(IntKi) :: nP + integer(IntKi) :: nC + integer(IntKi) :: nP1, nP2 + integer(IntKi) :: nC1, nC2 + integer(IntKi) :: nDepth, nSpan + integer(IntKi) :: SmoothModel + logical :: bladeFrame !< Output in blade frame instead of global coordinate frame + iStat=0 + bladeFrame=.FALSE. + + ! --- Creating two lattice + allocate(LatticePoints1(3,2,2)) + allocate(LatticePoints2(3,3,4)) + allocate(LatticeGamma1(1,1)) ; + allocate(LatticeGamma2(2,3)) ; + LatticeGamma1=1 + ! Test shed vorticity + LatticeGamma2(:,1)=1 + LatticeGamma2(:,2)=2 + LatticeGamma2(:,3)=3 + ! Test trailed vorticity +! LatticeGamma2(1,:)=1 +! LatticeGamma2(2,:)=2 + CALL MeshMe(LatticePoints1,(/0.,0.,0./)) + CALL MeshMe(LatticePoints2,(/0.,0.,1./)) + + CALL WrVTK_Lattice('Points1.vtk',mvtk,LatticePoints1, LatticeGamma1, bladeframe=bladeframe) + CALL WrVTK_Lattice('Points2.vtk',mvtk,LatticePoints2, LatticeGamma2, bladeframe=bladeframe) + + ! --- Convert lattice 1 to segments + nSpan = size(LatticePoints1,2) + nDepth = size(LatticePoints1,3) + nP1 = nSpan*nDepth + nC1 = 2*(nSpan*nDepth)-nSpan-nDepth + allocate(SegConnct(1:2,1:nC1)); SegConnct=-1 + allocate(SegPoints(1:3,1:nP1)); SegPoints=-1 + allocate(SegGamma (1:nC1) ); SegGamma=-999 + allocate(SegEpsilon(1:nC1) ); SegEpsilon=0.0_ReKi + + iHeadP=1 + iHeadC=1 + CALL LatticeToSegments(LatticePoints1, LatticeGamma1, 1, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC, .true., .true. ) + CALL printall() + CALL WrVTK_Segments('Points1_seg.vtk', mvtk, SegPoints, SegConnct, SegGamma, SegEpsilon, bladeFrame) + + allocate(Uind(1:3,1) ); Uind=0.0_ReKi + allocate(CPs (1:3,1) ); + CPs(1:3,1)=(/1.5,1.5,0./) + SegEpsilon=100.0_ReKi + SmoothModel=0 ! No smooth + CALL ui_seg(1, 1, CPs, & + 1, nC1, nC1, nP1, SegPoints, SegConnct, SegGamma, & + SmoothModel, SegEpsilon, Uind) + !print*,'Uind',Uind + + ! --- Convert lattice 2 to segments + nSpan = size(LatticePoints2,2) + nDepth = size(LatticePoints2,3) + nP2 = nSpan*nDepth + nC2 = 2*(nSpan*nDepth)-nSpan-nDepth + deallocate(SegConnct) + deallocate(SegPoints) + deallocate(SegGamma) + allocate(SegConnct(1:2,1:nC2)); SegConnct=-1 + allocate(SegPoints(1:3,1:nP2)); SegPoints=-1 + allocate(SegGamma (1:nC2) ); SegGamma=-9999 + iHeadP=1 + iHeadC=1 + CALL LatticeToSegments(LatticePoints2, LatticeGamma2, 1, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC , .true., .true.) + CALL printall() + CALL WrVTK_Segments('Points2_seg.vtk', mvtk, SegPoints, SegConnct, SegGamma, SegEpsilon, bladeFrame) + + ! --- Concatenate both + nP = nP1 + nP2 + nC = nC1 + nC2 + iHeadP=1 + iHeadC=1 + deallocate(SegConnct) + deallocate(SegPoints) + deallocate(SegGamma) + allocate(SegConnct(1:2,1:nC)); SegConnct=-1 + allocate(SegPoints(1:3,1:nP)); SegPoints=-1 + allocate(SegGamma (1:nC) ); SegGamma=-9999 + CALL LatticeToSegments(LatticePoints1, LatticeGamma1, 1, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC, .true. , .true.) + CALL LatticeToSegments(LatticePoints2, LatticeGamma2, 1, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC, .true. , .true.) + CALL printall() + CALL WrVTK_Segments('PointsBoth_seg.vtk', mvtk, SegPoints, SegConnct, SegGamma, SegEpsilon, bladeFrame) + + + contains + subroutine printall() + print*,'Points' + do i=1,size(SegPoints,2) + print*,'i',i,'Coords:', SegPoints(1:3,i) + enddo + print*,'Connectivity' + do i=1,size(SegConnct,2) + print*,'i',i,'Conn:', SegConnct(1:2,i),'Gam:', SegGamma(i) + enddo + print*,'-----------------------------' + endsubroutine + + subroutine MeshMe(M,offset) + real(ReKi), dimension(:,:,:), intent(inout) :: M + real(ReKi), dimension(3) , intent(in ):: offset + do j=1,size(M,3) + do i=1,size(M,2) + M(1,i,j)=i + offset(1) + M(2,i,j)=j + offset(2) + M(3,i,j)=0 + offset(3) + enddo + enddo + endsubroutine + endsubroutine Test_LatticeToSegment + + !> Main test function + subroutine FVW_RunTests(ErrStat,ErrMsg) + integer(IntKi) , intent(out) :: ErrStat !< Error status of the operation + character(ErrMsgLen), intent(out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(len=255) :: testname + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + testname='FVW' + call Test_BiotSavart_Sgmt(testname, ErrStat2, ErrMsg2) + call Test_BiotSavart_Part(testname, ErrStat2, ErrMsg2) + call Test_BiotSavart_PartTree(testname, ErrStat2, ErrMsg2) + call Test_SegmentsToPart(testname, ErrStat2, ErrMsg2) + end subroutine FVW_RunTests + +end module FVW_Tests diff --git a/modules/aerodyn/src/FVW_Types.f90 b/modules/aerodyn/src/FVW_Types.f90 new file mode 100644 index 0000000000..f5d4452578 --- /dev/null +++ b/modules/aerodyn/src/FVW_Types.f90 @@ -0,0 +1,8216 @@ +!STARTOFREGISTRYGENERATEDFILE 'FVW_Types.f90' +! +! WARNING This file is generated automatically by the FAST registry. +! Do not edit. Your changes to this file will be lost. +! +! FAST Registry +!********************************************************************************************************************************* +! FVW_Types +!................................................................................................................................. +! This file is part of FVW. +! +! Copyright (C) 2012-2016 National Renewable Energy Laboratory +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +! +! W A R N I N G : This file was automatically generated from the FAST registry. Changes made to this file may be lost. +! +!********************************************************************************************************************************* +!> This module contains the user-defined types needed in FVW. It also contains copy, destroy, pack, and +!! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. +MODULE FVW_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE AirfoilInfo_Types +USE UnsteadyAero_Types +USE NWTC_Library +IMPLICIT NONE +! ========= FVW_ParameterType ======= + TYPE, PUBLIC :: FVW_ParameterType + INTEGER(IntKi) :: nWings !< Number of Wings [-] + INTEGER(IntKi) :: nSpan !< TODO, should be defined per wing. Number of spanwise element [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: AFindx !< Index to the airfoils from AD15 [idx1= BladeNode, idx2=Blade number] [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Chord !< Chord of each blade element from input file [idx1=BladeNode, idx2=Blade number] [-] + INTEGER(IntKi) :: nNWMax !< Maximum number of nw panels, per wing [-] + INTEGER(IntKi) :: nFWMax !< Maximum number of fw panels, per wing [-] + INTEGER(IntKi) :: nFWFree !< Number of fw panels that are free, per wing [-] + LOGICAL :: FWShedVorticity !< Include shed vorticity in the far wake [-] + INTEGER(IntKi) :: IntMethod !< Integration Method (1=RK4, 2=AB4, 3=ABM4, 5=Euler1) [-] + REAL(ReKi) :: FreeWakeStart !< Time when wake starts convecting (rolling up) [s] + REAL(ReKi) :: FullCirculationStart !< Time when the circulation is full [s] + INTEGER(IntKi) :: CirculationMethod !< Method to determine the circulation [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: PrescribedCirculation !< Prescribed circulation on all lifting lines [m/s] + INTEGER(IntKi) :: CircSolvMaxIter !< Maximum number of iterations for circulation solving [-] + REAL(ReKi) :: CircSolvConvCrit !< Convergence criterion for circulation solving [-] + REAL(ReKi) :: CircSolvRelaxation !< Relaxation factor for circulation solving [-] + INTEGER(IntKi) :: CircSolvPolar !< (0=Use AD polars, 1=2PiAlpha, 2=sin(2pialpha) [-] + INTEGER(IntKi) :: DiffusionMethod !< Diffusion method (None, CoreSpreading, PSE) [-] + REAL(ReKi) :: CoreSpreadEddyVisc !< Eddy viscosity used in the core spreading method [-] + INTEGER(IntKi) :: RegDeterMethod !< Regularization determinatino method (manual, automatic) [-] + INTEGER(IntKi) :: RegFunction !< Type of regularizaion function (LambOseen, Vatistas, see FVW_BiotSavart) [-] + INTEGER(IntKi) :: WakeRegMethod !< Method for regularization (constant, stretching, age, etc.) [-] + REAL(ReKi) :: WakeRegParam !< Initial value of the regularization parameter [-] + REAL(ReKi) :: WingRegParam !< Regularization parameter of the wing [-] + INTEGER(IntKi) :: ShearModel !< Option for shear modelling [-] + LOGICAL :: TwrShadowOnWake !< Include tower shadow effects on wake [-] + INTEGER(IntKi) :: VelocityMethod !< Velocity calculation method [-] + REAL(ReKi) :: TreeBranchFactor !< Factor used to determine if a point is far enough [-] + INTEGER(IntKi) :: PartPerSegment !< Number of particles per segment, e.g. for tree method [-] + REAL(DbKi) :: DTaero !< Time interval for calls calculations [s] + REAL(DbKi) :: DTfvw !< Time interval for calculating wake induced velocities [s] + REAL(ReKi) :: KinVisc !< Kinematic air viscosity [m^2/s] + INTEGER(IntKi) :: WrVTK !< Outputs VTK at each calcoutput call, even if main fst doesnt do it [-] + INTEGER(IntKi) :: VTKBlades !< Outputs VTk for each blade 0=no blade, 1=Bld 1 [-] + 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 [-] + END TYPE FVW_ParameterType +! ======================= +! ========= FVW_MiscVarType ======= + TYPE, PUBLIC :: FVW_MiscVarType + LOGICAL :: FirstCall !< True if this is the first call to update state (used in CalcOutput) [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: LE !< Leading edge points [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: TE !< Trailing edge points [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: r_LL !< Position of the Lifting line panels [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: s_LL !< Spanwise coordinate of LL elements [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: chord_LL !< chord on LL nodes [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: s_CP_LL !< Spanwise coordinate of LL CP [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: chord_CP_LL !< chord on LL cp [m] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: CP_LL !< Coordinates of LL CP [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Tang !< Unit Tangential vector on LL CP [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Norm !< Unit Normal vector on LL CP [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Orth !< Unit Orthogonal vector on LL CP [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: dl !< Vector of elementary length along the LL [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Area !< Area of each LL panel [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: diag_LL !< Diagonal length of each LL panel [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Gamma_LL !< Circulation on the wing lifting line (COPY of Constraint State) [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vind_LL !< Induced velocity on lifting line control points [m/s] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vtot_LL !< Total velocity on lifting line control points [m/s] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vstr_LL !< Structural velocity on LL CP [m/s] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vwnd_LL !< Wind on lifting line control points [m/s] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: Vwnd_NW !< Wind on near wake panels [m/s] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: Vwnd_FW !< Wind on far wake panels [m/s] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: Vind_NW !< Induced velocity on near wake panels [m/s] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: Vind_FW !< Induced velocity on far wake panels [m/s] + INTEGER(IntKi) :: nNW !< Number of active near wake panels [-] + INTEGER(IntKi) :: nFW !< Number of active far wake panels [-] + INTEGER(IntKi) :: iStep !< Current step number used for update state [-] + INTEGER(IntKi) :: VTKstep !< Current vtk output step number [-] + REAL(DbKi) :: VTKlastTime !< Time the last VTK file set was written out [s] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: r_wind !< List of points where wind is requested for next time step [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PitchAndTwist !< Twist angle (includes all sources of twist) [Array of size (NumBlNds,numBlades)] [rad] + LOGICAL :: ComputeWakeInduced !< Compute induced velocities on this timestep [-] + REAL(DbKi) :: OldWakeTime !< Time the wake induction velocities were last calculated [s] + REAL(ReKi) :: tSpent !< Time spent in expensive Biot-Savart computation [s] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: dxdt_NW !< State time derivatie, stored for subcylcing [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: dxdt_FW !< State time derivatie, stored for subcylcing [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: alpha_LL !< Angle of attack at lifting line CP, only computed with CircPolarData method [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vreln_LL !< Norm of Vrel on the lifting line [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: SegConnct !< Connectivity of segments [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SegPoints !< Points delimiting the segments [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: SegGamma !< Segment circulations [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: SegEpsilon !< Segment regularization parameter [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: CPs !< Control points used for wake rollup computation [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Uind !< Induced velocities obtained at control points [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_AxInd !< Axial induction [size: (NumBlNds,numBlades)] [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_TanInd !< Tangential induction [size: (NumBlNds,numBlades)] [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Vrel !< Relative velocity [size: (NumBlNds,numBlades)] [m/s] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_alpha !< Angle of attack [size: (NumBlNds,numBlades)] [rad] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_phi !< angle between the plane of rotation and the direction of the local wind [size: (NumBlNds,numBlades)] [rad] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Re !< Reynolds number [size: (NumBlNds,numBlades)] [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: BN_URelWind_s !< Relative wind velocity in section coordinates [size: (3,NumBlNds,numBlades)] [m/s] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cl_Static !< Coefficient lift, excluding unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cd_Static !< Coefficient drag. excluding unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cm_Static !< Coefficient moment, excluding unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cl !< Coefficient lift, including unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cd !< Coefficient drag, including unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cm !< Coefficient moment, including unsteady aero effects [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cx !< normal force coefficient (normal to the plane, not chord) of the jth node in the kth blade [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BN_Cy !< tangential force coefficient (tangential to the plane, not chord) of the jth node in the kth blade [-] + TYPE(UA_MiscVarType) :: m_UA !< misc vars for UnsteadyAero [-] + TYPE(UA_OutputType) :: y_UA !< outputs from UnsteadyAero [-] + TYPE(UA_ParameterType) :: p_UA !< parameters for UnsteadyAero [-] + LOGICAL :: UA_Flag !< logical flag indicating whether to use UnsteadyAero [-] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vwnd_ND !< InflowOnBlade (at nodes) values modified by tower influence. ONLY for UA [m/s] + END TYPE FVW_MiscVarType +! ======================= +! ========= FVW_InputType ======= + TYPE, PUBLIC :: FVW_InputType + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: WingsMesh !< Input Mesh defining position and orientation of wings [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: V_wind !< Wind at requested points (r_wind) [-] + REAL(ReKi) , DIMENSION(1:3,1:3) :: HubOrientation !< Orientation of hub coordinate system (for output only) [-] + REAL(ReKi) , DIMENSION(1:3) :: HubPosition !< Origin of hub (for output only) [-] + END TYPE FVW_InputType +! ======================= +! ========= FVW_OutputType ======= + TYPE, PUBLIC :: FVW_OutputType + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vind !< TODO mesh - Induced velocity vector. [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Cl_KJ !< Lift coefficient from circulation (Kutta-Joukowski) [-] + END TYPE FVW_OutputType +! ======================= +! ========= FVW_ContinuousStateType ======= + TYPE, PUBLIC :: FVW_ContinuousStateType + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Gamma_NW !< Circulation of the near wake panels [-] + 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 [-] + END TYPE FVW_ContinuousStateType +! ======================= +! ========= FVW_DiscreteStateType ======= + TYPE, PUBLIC :: FVW_DiscreteStateType + REAL(ReKi) :: NULL !< Empty to satisfy framework [-] + TYPE(UA_DiscreteStateType) :: UA !< states for UnsteadyAero [-] + END TYPE FVW_DiscreteStateType +! ======================= +! ========= FVW_ConstraintStateType ======= + TYPE, PUBLIC :: FVW_ConstraintStateType + REAL(ReKi) :: residual + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Gamma_LL !< Circulation on the wing lifting line [-] + END TYPE FVW_ConstraintStateType +! ======================= +! ========= FVW_OtherStateType ======= + TYPE, PUBLIC :: FVW_OtherStateType + INTEGER(IntKi) :: NULL !< Number of active near wake panels [-] + TYPE(UA_OtherStateType) :: UA !< other states for UnsteadyAero [-] + LOGICAL , DIMENSION(:,:), ALLOCATABLE :: UA_Flag !< logical flag indicating whether to use UnsteadyAero [-] + END TYPE FVW_OtherStateType +! ======================= +! ========= FVW_InitInputType ======= + TYPE, PUBLIC :: FVW_InitInputType + CHARACTER(1024) :: FVWFileName !< Main FVW input file name [-] + CHARACTER(1024) :: RootName !< RootName for writing output files [-] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: WingsMesh !< Input Mesh defining position and orientation of wings (nSpan+1) [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: AFindx !< Index to the airfoils from AD15 [idx1=BladeNode, idx2=Blade number] [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Chord !< Chord of each blade element from input file [idx1=BladeNode, idx2=Blade number] [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RElm !< radius of center of each element [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: zHub !< Distance to hub for each blade [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: zLocal !< Distance to blade node, measured along the blade [m] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: zTip !< Distance to blade tip, measured along the blade [m] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: rLocal !< Radial distance to blade node from the center of rotation, measured in the rotor plane, needed for DBEMT [m] + INTEGER(IntKi) :: NumBlades !< Number of blades [-] + INTEGER(IntKi) :: NumBladeNodes !< Number of nodes on each blade [-] + REAL(DbKi) :: DTaero !< Time interval for calls (from AD15) [s] + REAL(ReKi) :: KinVisc !< Kinematic air viscosity [m^2/s] + INTEGER(IntKi) :: UAMod !< Model for the dynamic stall equations [1 = Leishman/Beddoes, 2 = Gonzalez, 3 = Minnema] [-] + LOGICAL :: UA_Flag !< logical flag indicating whether to use UnsteadyAero [-] + LOGICAL :: Flookup !< Use table lookup for f' and f'' [-] + REAL(ReKi) :: a_s !< speed of sound [m/s] + END TYPE FVW_InitInputType +! ======================= +! ========= FVW_InputFile ======= + TYPE, PUBLIC :: FVW_InputFile + INTEGER(IntKi) :: CirculationMethod !< Method to determine the circulation [-] + CHARACTER(1024) :: CirculationFile !< Prescribed circulation file [-] + INTEGER(IntKi) :: CircSolvMaxIter !< Maximum number of iterations for circulation solving [-] + REAL(ReKi) :: CircSolvConvCrit !< Convergence criterion for circulation solving [-] + REAL(ReKi) :: CircSolvRelaxation !< Relaxation factor for circulation solving [-] + INTEGER(IntKi) :: IntMethod !< Integration Method (1=RK4, 2=AB4, 3=ABM4, 5=Euler1, 7=Corrector/Predictor) [-] + LOGICAL :: FreeWake !< Disable roll up, wake convects with wind only (flag) [-] + REAL(ReKi) :: FreeWakeStart !< Time when wake starts convecting (rolling up) [s] + REAL(ReKi) :: FullCirculationStart !< Time when the circulation is full [s] + REAL(DbKi) :: DTfvw !< Time interval for calculating wake induced velocities [s] + INTEGER(IntKi) :: CircSolvPolar !< (0=Use AD polars, 1=2PiAlpha, 2=sin(2pialpha) [-] + INTEGER(IntKi) :: nNWPanels !< Number of nw panels [-] + INTEGER(IntKi) :: nFWPanels !< Number of fw panels [-] + INTEGER(IntKi) :: nFWPanelsFree !< Number of fw panels that are free [-] + LOGICAL :: FWShedVorticity !< Include shed vorticity in the far wake [-] + INTEGER(IntKi) :: DiffusionMethod !< Diffusion method (None, CoreSpreading, PSE) [-] + REAL(ReKi) :: CoreSpreadEddyVisc !< Eddy viscosity used in the core spreading method [-] + INTEGER(IntKi) :: RegDeterMethod !< Regularization determinatino method (manual, automatic) [-] + INTEGER(IntKi) :: RegFunction !< Type of regularizaion function (LambOseen, Vatistas, see FVW_BiotSavart) [-] + INTEGER(IntKi) :: WakeRegMethod !< Method for regularization (constant, stretching, age, etc.) [-] + REAL(ReKi) :: WakeRegParam !< Factor used in the regularization [-] + REAL(ReKi) :: WingRegParam !< Factor used in the regularization [-] + INTEGER(IntKi) :: ShearModel !< Option for shear modelling [-] + LOGICAL :: TwrShadowOnWake !< Include tower shadow effects on wake [-] + INTEGER(IntKi) :: VelocityMethod !< Velocity calculation method [-] + REAL(ReKi) :: TreeBranchFactor !< Factor used to determine if a point is far enough [-] + INTEGER(IntKi) :: PartPerSegment !< Number of particles per segment, e.g. for tree method [-] + INTEGER(IntKi) :: WrVTK !< Outputs VTK at each calcoutput call, even if main fst doesnt do it [-] + INTEGER(IntKi) :: VTKBlades !< Outputs VTk for each blade 0=no blade, 1=Bld 1 [-] + REAL(DbKi) :: DTvtk !< Requested timestep between VTK outputs (calculated from the VTK_fps read in) [s] + INTEGER(IntKi) :: VTKCoord !< Switch for VTK outputs coordinate system [-] + END TYPE FVW_InputFile +! ======================= +! ========= FVW_InitOutputType ======= + TYPE, PUBLIC :: FVW_InitOutputType + INTEGER(IntKi) :: Null !< Empty parameter to satisfy framework [-] + END TYPE FVW_InitOutputType +! ======================= +CONTAINS + SUBROUTINE FVW_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_ParameterType), INTENT(IN) :: SrcParamData + TYPE(FVW_ParameterType), INTENT(INOUT) :: DstParamData + 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) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_CopyParam' +! + ErrStat = ErrID_None + ErrMsg = "" + DstParamData%nWings = SrcParamData%nWings + DstParamData%nSpan = SrcParamData%nSpan +IF (ALLOCATED(SrcParamData%AFindx)) THEN + i1_l = LBOUND(SrcParamData%AFindx,1) + i1_u = UBOUND(SrcParamData%AFindx,1) + i2_l = LBOUND(SrcParamData%AFindx,2) + i2_u = UBOUND(SrcParamData%AFindx,2) + IF (.NOT. ALLOCATED(DstParamData%AFindx)) THEN + ALLOCATE(DstParamData%AFindx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%AFindx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%AFindx = SrcParamData%AFindx +ENDIF +IF (ALLOCATED(SrcParamData%Chord)) THEN + i1_l = LBOUND(SrcParamData%Chord,1) + i1_u = UBOUND(SrcParamData%Chord,1) + i2_l = LBOUND(SrcParamData%Chord,2) + i2_u = UBOUND(SrcParamData%Chord,2) + IF (.NOT. ALLOCATED(DstParamData%Chord)) THEN + ALLOCATE(DstParamData%Chord(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Chord.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Chord = SrcParamData%Chord +ENDIF + DstParamData%nNWMax = SrcParamData%nNWMax + DstParamData%nFWMax = SrcParamData%nFWMax + DstParamData%nFWFree = SrcParamData%nFWFree + DstParamData%FWShedVorticity = SrcParamData%FWShedVorticity + DstParamData%IntMethod = SrcParamData%IntMethod + DstParamData%FreeWakeStart = SrcParamData%FreeWakeStart + DstParamData%FullCirculationStart = SrcParamData%FullCirculationStart + DstParamData%CirculationMethod = SrcParamData%CirculationMethod +IF (ALLOCATED(SrcParamData%PrescribedCirculation)) THEN + i1_l = LBOUND(SrcParamData%PrescribedCirculation,1) + i1_u = UBOUND(SrcParamData%PrescribedCirculation,1) + IF (.NOT. ALLOCATED(DstParamData%PrescribedCirculation)) THEN + ALLOCATE(DstParamData%PrescribedCirculation(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%PrescribedCirculation.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%PrescribedCirculation = SrcParamData%PrescribedCirculation +ENDIF + DstParamData%CircSolvMaxIter = SrcParamData%CircSolvMaxIter + DstParamData%CircSolvConvCrit = SrcParamData%CircSolvConvCrit + DstParamData%CircSolvRelaxation = SrcParamData%CircSolvRelaxation + DstParamData%CircSolvPolar = SrcParamData%CircSolvPolar + DstParamData%DiffusionMethod = SrcParamData%DiffusionMethod + DstParamData%CoreSpreadEddyVisc = SrcParamData%CoreSpreadEddyVisc + DstParamData%RegDeterMethod = SrcParamData%RegDeterMethod + DstParamData%RegFunction = SrcParamData%RegFunction + DstParamData%WakeRegMethod = SrcParamData%WakeRegMethod + DstParamData%WakeRegParam = SrcParamData%WakeRegParam + DstParamData%WingRegParam = SrcParamData%WingRegParam + DstParamData%ShearModel = SrcParamData%ShearModel + DstParamData%TwrShadowOnWake = SrcParamData%TwrShadowOnWake + DstParamData%VelocityMethod = SrcParamData%VelocityMethod + DstParamData%TreeBranchFactor = SrcParamData%TreeBranchFactor + DstParamData%PartPerSegment = SrcParamData%PartPerSegment + DstParamData%DTaero = SrcParamData%DTaero + DstParamData%DTfvw = SrcParamData%DTfvw + DstParamData%KinVisc = SrcParamData%KinVisc + DstParamData%WrVTK = SrcParamData%WrVTK + DstParamData%VTKBlades = SrcParamData%VTKBlades + DstParamData%DTvtk = SrcParamData%DTvtk + DstParamData%VTKCoord = SrcParamData%VTKCoord + DstParamData%RootName = SrcParamData%RootName + END SUBROUTINE FVW_CopyParam + + SUBROUTINE FVW_DestroyParam( ParamData, ErrStat, ErrMsg ) + TYPE(FVW_ParameterType), INTENT(INOUT) :: ParamData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyParam' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ParamData%AFindx)) THEN + DEALLOCATE(ParamData%AFindx) +ENDIF +IF (ALLOCATED(ParamData%Chord)) THEN + DEALLOCATE(ParamData%Chord) +ENDIF +IF (ALLOCATED(ParamData%PrescribedCirculation)) THEN + DEALLOCATE(ParamData%PrescribedCirculation) +ENDIF + END SUBROUTINE FVW_DestroyParam + + SUBROUTINE FVW_PackParam( 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(FVW_ParameterType), 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 = 'FVW_PackParam' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! nWings + Int_BufSz = Int_BufSz + 1 ! nSpan + Int_BufSz = Int_BufSz + 1 ! AFindx allocated yes/no + IF ( ALLOCATED(InData%AFindx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! AFindx upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%AFindx) ! AFindx + END IF + Int_BufSz = Int_BufSz + 1 ! Chord allocated yes/no + IF ( ALLOCATED(InData%Chord) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Chord upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Chord) ! Chord + END IF + Int_BufSz = Int_BufSz + 1 ! nNWMax + Int_BufSz = Int_BufSz + 1 ! nFWMax + Int_BufSz = Int_BufSz + 1 ! nFWFree + Int_BufSz = Int_BufSz + 1 ! FWShedVorticity + Int_BufSz = Int_BufSz + 1 ! IntMethod + Re_BufSz = Re_BufSz + 1 ! FreeWakeStart + Re_BufSz = Re_BufSz + 1 ! FullCirculationStart + Int_BufSz = Int_BufSz + 1 ! CirculationMethod + Int_BufSz = Int_BufSz + 1 ! PrescribedCirculation allocated yes/no + IF ( ALLOCATED(InData%PrescribedCirculation) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! PrescribedCirculation upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%PrescribedCirculation) ! PrescribedCirculation + END IF + Int_BufSz = Int_BufSz + 1 ! CircSolvMaxIter + Re_BufSz = Re_BufSz + 1 ! CircSolvConvCrit + Re_BufSz = Re_BufSz + 1 ! CircSolvRelaxation + Int_BufSz = Int_BufSz + 1 ! CircSolvPolar + Int_BufSz = Int_BufSz + 1 ! DiffusionMethod + Re_BufSz = Re_BufSz + 1 ! CoreSpreadEddyVisc + Int_BufSz = Int_BufSz + 1 ! RegDeterMethod + Int_BufSz = Int_BufSz + 1 ! RegFunction + Int_BufSz = Int_BufSz + 1 ! WakeRegMethod + Re_BufSz = Re_BufSz + 1 ! WakeRegParam + Re_BufSz = Re_BufSz + 1 ! WingRegParam + Int_BufSz = Int_BufSz + 1 ! ShearModel + Int_BufSz = Int_BufSz + 1 ! TwrShadowOnWake + Int_BufSz = Int_BufSz + 1 ! VelocityMethod + Re_BufSz = Re_BufSz + 1 ! TreeBranchFactor + Int_BufSz = Int_BufSz + 1 ! PartPerSegment + Db_BufSz = Db_BufSz + 1 ! DTaero + Db_BufSz = Db_BufSz + 1 ! DTfvw + Re_BufSz = Re_BufSz + 1 ! KinVisc + Int_BufSz = Int_BufSz + 1 ! WrVTK + Int_BufSz = Int_BufSz + 1 ! VTKBlades + Db_BufSz = Db_BufSz + 1 ! DTvtk + Int_BufSz = Int_BufSz + 1 ! VTKCoord + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + 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 + + IntKiBuf(Int_Xferred) = InData%nWings + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nSpan + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%AFindx) ) 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%AFindx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AFindx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%AFindx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AFindx,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%AFindx,2), UBOUND(InData%AFindx,2) + DO i1 = LBOUND(InData%AFindx,1), UBOUND(InData%AFindx,1) + IntKiBuf(Int_Xferred) = InData%AFindx(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Chord) ) 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%Chord,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Chord,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Chord,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Chord,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Chord,2), UBOUND(InData%Chord,2) + DO i1 = LBOUND(InData%Chord,1), UBOUND(InData%Chord,1) + ReKiBuf(Re_Xferred) = InData%Chord(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IntKiBuf(Int_Xferred) = InData%nNWMax + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nFWMax + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nFWFree + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%FWShedVorticity, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%IntMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%FreeWakeStart + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%FullCirculationStart + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%CirculationMethod + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%PrescribedCirculation) ) 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%PrescribedCirculation,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PrescribedCirculation,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%PrescribedCirculation,1), UBOUND(InData%PrescribedCirculation,1) + ReKiBuf(Re_Xferred) = InData%PrescribedCirculation(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IntKiBuf(Int_Xferred) = InData%CircSolvMaxIter + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CircSolvConvCrit + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CircSolvRelaxation + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%CircSolvPolar + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%DiffusionMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CoreSpreadEddyVisc + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%RegDeterMethod + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%RegFunction + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%WakeRegMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%WakeRegParam + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%WingRegParam + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%ShearModel + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%TwrShadowOnWake, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VelocityMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TreeBranchFactor + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%PartPerSegment + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTaero + Db_Xferred = Db_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTfvw + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%KinVisc + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%WrVTK + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VTKBlades + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTvtk + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VTKCoord + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END SUBROUTINE FVW_PackParam + + SUBROUTINE FVW_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(FVW_ParameterType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_UnPackParam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%nWings = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nSpan = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! AFindx 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%AFindx)) DEALLOCATE(OutData%AFindx) + ALLOCATE(OutData%AFindx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%AFindx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%AFindx,2), UBOUND(OutData%AFindx,2) + DO i1 = LBOUND(OutData%AFindx,1), UBOUND(OutData%AFindx,1) + OutData%AFindx(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Chord 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%Chord)) DEALLOCATE(OutData%Chord) + ALLOCATE(OutData%Chord(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Chord.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Chord,2), UBOUND(OutData%Chord,2) + DO i1 = LBOUND(OutData%Chord,1), UBOUND(OutData%Chord,1) + OutData%Chord(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + OutData%nNWMax = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nFWMax = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nFWFree = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%FWShedVorticity = TRANSFER(IntKiBuf(Int_Xferred), OutData%FWShedVorticity) + Int_Xferred = Int_Xferred + 1 + OutData%IntMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%FreeWakeStart = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%FullCirculationStart = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%CirculationMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! PrescribedCirculation 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%PrescribedCirculation)) DEALLOCATE(OutData%PrescribedCirculation) + ALLOCATE(OutData%PrescribedCirculation(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%PrescribedCirculation.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%PrescribedCirculation,1), UBOUND(OutData%PrescribedCirculation,1) + OutData%PrescribedCirculation(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + OutData%CircSolvMaxIter = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%CircSolvConvCrit = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%CircSolvRelaxation = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%CircSolvPolar = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%DiffusionMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%CoreSpreadEddyVisc = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RegDeterMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%RegFunction = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%WakeRegMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%WakeRegParam = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%WingRegParam = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%ShearModel = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%TwrShadowOnWake = TRANSFER(IntKiBuf(Int_Xferred), OutData%TwrShadowOnWake) + Int_Xferred = Int_Xferred + 1 + OutData%VelocityMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%TreeBranchFactor = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%PartPerSegment = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%DTaero = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%DTfvw = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%KinVisc = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%WrVTK = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%VTKBlades = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%DTvtk = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%VTKCoord = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(OutData%RootName) + OutData%RootName(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 ) + TYPE(FVW_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(FVW_MiscVarType), INTENT(INOUT) :: DstMiscData + 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) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_CopyMisc' +! + ErrStat = ErrID_None + ErrMsg = "" + DstMiscData%FirstCall = SrcMiscData%FirstCall +IF (ALLOCATED(SrcMiscData%LE)) THEN + i1_l = LBOUND(SrcMiscData%LE,1) + i1_u = UBOUND(SrcMiscData%LE,1) + i2_l = LBOUND(SrcMiscData%LE,2) + i2_u = UBOUND(SrcMiscData%LE,2) + i3_l = LBOUND(SrcMiscData%LE,3) + i3_u = UBOUND(SrcMiscData%LE,3) + IF (.NOT. ALLOCATED(DstMiscData%LE)) THEN + ALLOCATE(DstMiscData%LE(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%LE.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%LE = SrcMiscData%LE +ENDIF +IF (ALLOCATED(SrcMiscData%TE)) THEN + i1_l = LBOUND(SrcMiscData%TE,1) + i1_u = UBOUND(SrcMiscData%TE,1) + i2_l = LBOUND(SrcMiscData%TE,2) + i2_u = UBOUND(SrcMiscData%TE,2) + i3_l = LBOUND(SrcMiscData%TE,3) + i3_u = UBOUND(SrcMiscData%TE,3) + IF (.NOT. ALLOCATED(DstMiscData%TE)) THEN + ALLOCATE(DstMiscData%TE(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%TE.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%TE = SrcMiscData%TE +ENDIF +IF (ALLOCATED(SrcMiscData%r_LL)) THEN + i1_l = LBOUND(SrcMiscData%r_LL,1) + i1_u = UBOUND(SrcMiscData%r_LL,1) + i2_l = LBOUND(SrcMiscData%r_LL,2) + i2_u = UBOUND(SrcMiscData%r_LL,2) + i3_l = LBOUND(SrcMiscData%r_LL,3) + i3_u = UBOUND(SrcMiscData%r_LL,3) + i4_l = LBOUND(SrcMiscData%r_LL,4) + i4_u = UBOUND(SrcMiscData%r_LL,4) + IF (.NOT. ALLOCATED(DstMiscData%r_LL)) THEN + ALLOCATE(DstMiscData%r_LL(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%r_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%r_LL = SrcMiscData%r_LL +ENDIF +IF (ALLOCATED(SrcMiscData%s_LL)) THEN + i1_l = LBOUND(SrcMiscData%s_LL,1) + i1_u = UBOUND(SrcMiscData%s_LL,1) + i2_l = LBOUND(SrcMiscData%s_LL,2) + i2_u = UBOUND(SrcMiscData%s_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%s_LL)) THEN + ALLOCATE(DstMiscData%s_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%s_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%s_LL = SrcMiscData%s_LL +ENDIF +IF (ALLOCATED(SrcMiscData%chord_LL)) THEN + i1_l = LBOUND(SrcMiscData%chord_LL,1) + i1_u = UBOUND(SrcMiscData%chord_LL,1) + i2_l = LBOUND(SrcMiscData%chord_LL,2) + i2_u = UBOUND(SrcMiscData%chord_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%chord_LL)) THEN + ALLOCATE(DstMiscData%chord_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%chord_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%chord_LL = SrcMiscData%chord_LL +ENDIF +IF (ALLOCATED(SrcMiscData%s_CP_LL)) THEN + i1_l = LBOUND(SrcMiscData%s_CP_LL,1) + i1_u = UBOUND(SrcMiscData%s_CP_LL,1) + i2_l = LBOUND(SrcMiscData%s_CP_LL,2) + i2_u = UBOUND(SrcMiscData%s_CP_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%s_CP_LL)) THEN + ALLOCATE(DstMiscData%s_CP_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%s_CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%s_CP_LL = SrcMiscData%s_CP_LL +ENDIF +IF (ALLOCATED(SrcMiscData%chord_CP_LL)) THEN + i1_l = LBOUND(SrcMiscData%chord_CP_LL,1) + i1_u = UBOUND(SrcMiscData%chord_CP_LL,1) + i2_l = LBOUND(SrcMiscData%chord_CP_LL,2) + i2_u = UBOUND(SrcMiscData%chord_CP_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%chord_CP_LL)) THEN + ALLOCATE(DstMiscData%chord_CP_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%chord_CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%chord_CP_LL = SrcMiscData%chord_CP_LL +ENDIF +IF (ALLOCATED(SrcMiscData%CP_LL)) THEN + i1_l = LBOUND(SrcMiscData%CP_LL,1) + i1_u = UBOUND(SrcMiscData%CP_LL,1) + i2_l = LBOUND(SrcMiscData%CP_LL,2) + i2_u = UBOUND(SrcMiscData%CP_LL,2) + i3_l = LBOUND(SrcMiscData%CP_LL,3) + i3_u = UBOUND(SrcMiscData%CP_LL,3) + IF (.NOT. ALLOCATED(DstMiscData%CP_LL)) THEN + ALLOCATE(DstMiscData%CP_LL(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%CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%CP_LL = SrcMiscData%CP_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Tang)) THEN + i1_l = LBOUND(SrcMiscData%Tang,1) + i1_u = UBOUND(SrcMiscData%Tang,1) + i2_l = LBOUND(SrcMiscData%Tang,2) + i2_u = UBOUND(SrcMiscData%Tang,2) + i3_l = LBOUND(SrcMiscData%Tang,3) + i3_u = UBOUND(SrcMiscData%Tang,3) + IF (.NOT. ALLOCATED(DstMiscData%Tang)) THEN + ALLOCATE(DstMiscData%Tang(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%Tang.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Tang = SrcMiscData%Tang +ENDIF +IF (ALLOCATED(SrcMiscData%Norm)) THEN + i1_l = LBOUND(SrcMiscData%Norm,1) + i1_u = UBOUND(SrcMiscData%Norm,1) + i2_l = LBOUND(SrcMiscData%Norm,2) + i2_u = UBOUND(SrcMiscData%Norm,2) + i3_l = LBOUND(SrcMiscData%Norm,3) + i3_u = UBOUND(SrcMiscData%Norm,3) + IF (.NOT. ALLOCATED(DstMiscData%Norm)) THEN + ALLOCATE(DstMiscData%Norm(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%Norm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Norm = SrcMiscData%Norm +ENDIF +IF (ALLOCATED(SrcMiscData%Orth)) THEN + i1_l = LBOUND(SrcMiscData%Orth,1) + i1_u = UBOUND(SrcMiscData%Orth,1) + i2_l = LBOUND(SrcMiscData%Orth,2) + i2_u = UBOUND(SrcMiscData%Orth,2) + i3_l = LBOUND(SrcMiscData%Orth,3) + i3_u = UBOUND(SrcMiscData%Orth,3) + IF (.NOT. ALLOCATED(DstMiscData%Orth)) THEN + ALLOCATE(DstMiscData%Orth(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%Orth.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Orth = SrcMiscData%Orth +ENDIF +IF (ALLOCATED(SrcMiscData%dl)) THEN + i1_l = LBOUND(SrcMiscData%dl,1) + i1_u = UBOUND(SrcMiscData%dl,1) + i2_l = LBOUND(SrcMiscData%dl,2) + i2_u = UBOUND(SrcMiscData%dl,2) + i3_l = LBOUND(SrcMiscData%dl,3) + i3_u = UBOUND(SrcMiscData%dl,3) + IF (.NOT. ALLOCATED(DstMiscData%dl)) THEN + ALLOCATE(DstMiscData%dl(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%dl.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%dl = SrcMiscData%dl +ENDIF +IF (ALLOCATED(SrcMiscData%Area)) THEN + i1_l = LBOUND(SrcMiscData%Area,1) + i1_u = UBOUND(SrcMiscData%Area,1) + i2_l = LBOUND(SrcMiscData%Area,2) + i2_u = UBOUND(SrcMiscData%Area,2) + IF (.NOT. ALLOCATED(DstMiscData%Area)) THEN + ALLOCATE(DstMiscData%Area(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Area.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Area = SrcMiscData%Area +ENDIF +IF (ALLOCATED(SrcMiscData%diag_LL)) THEN + i1_l = LBOUND(SrcMiscData%diag_LL,1) + i1_u = UBOUND(SrcMiscData%diag_LL,1) + i2_l = LBOUND(SrcMiscData%diag_LL,2) + i2_u = UBOUND(SrcMiscData%diag_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%diag_LL)) THEN + ALLOCATE(DstMiscData%diag_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%diag_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%diag_LL = SrcMiscData%diag_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Gamma_LL)) THEN + i1_l = LBOUND(SrcMiscData%Gamma_LL,1) + i1_u = UBOUND(SrcMiscData%Gamma_LL,1) + i2_l = LBOUND(SrcMiscData%Gamma_LL,2) + i2_u = UBOUND(SrcMiscData%Gamma_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%Gamma_LL)) THEN + ALLOCATE(DstMiscData%Gamma_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Gamma_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Gamma_LL = SrcMiscData%Gamma_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vind_LL)) THEN + i1_l = LBOUND(SrcMiscData%Vind_LL,1) + i1_u = UBOUND(SrcMiscData%Vind_LL,1) + i2_l = LBOUND(SrcMiscData%Vind_LL,2) + i2_u = UBOUND(SrcMiscData%Vind_LL,2) + i3_l = LBOUND(SrcMiscData%Vind_LL,3) + i3_u = UBOUND(SrcMiscData%Vind_LL,3) + IF (.NOT. ALLOCATED(DstMiscData%Vind_LL)) THEN + ALLOCATE(DstMiscData%Vind_LL(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%Vind_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vind_LL = SrcMiscData%Vind_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vtot_LL)) THEN + i1_l = LBOUND(SrcMiscData%Vtot_LL,1) + i1_u = UBOUND(SrcMiscData%Vtot_LL,1) + i2_l = LBOUND(SrcMiscData%Vtot_LL,2) + i2_u = UBOUND(SrcMiscData%Vtot_LL,2) + i3_l = LBOUND(SrcMiscData%Vtot_LL,3) + i3_u = UBOUND(SrcMiscData%Vtot_LL,3) + IF (.NOT. ALLOCATED(DstMiscData%Vtot_LL)) THEN + ALLOCATE(DstMiscData%Vtot_LL(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%Vtot_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vtot_LL = SrcMiscData%Vtot_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vstr_LL)) THEN + i1_l = LBOUND(SrcMiscData%Vstr_LL,1) + i1_u = UBOUND(SrcMiscData%Vstr_LL,1) + i2_l = LBOUND(SrcMiscData%Vstr_LL,2) + i2_u = UBOUND(SrcMiscData%Vstr_LL,2) + i3_l = LBOUND(SrcMiscData%Vstr_LL,3) + i3_u = UBOUND(SrcMiscData%Vstr_LL,3) + IF (.NOT. ALLOCATED(DstMiscData%Vstr_LL)) THEN + ALLOCATE(DstMiscData%Vstr_LL(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%Vstr_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vstr_LL = SrcMiscData%Vstr_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vwnd_LL)) THEN + i1_l = LBOUND(SrcMiscData%Vwnd_LL,1) + i1_u = UBOUND(SrcMiscData%Vwnd_LL,1) + i2_l = LBOUND(SrcMiscData%Vwnd_LL,2) + i2_u = UBOUND(SrcMiscData%Vwnd_LL,2) + i3_l = LBOUND(SrcMiscData%Vwnd_LL,3) + i3_u = UBOUND(SrcMiscData%Vwnd_LL,3) + IF (.NOT. ALLOCATED(DstMiscData%Vwnd_LL)) THEN + ALLOCATE(DstMiscData%Vwnd_LL(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%Vwnd_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vwnd_LL = SrcMiscData%Vwnd_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vwnd_NW)) THEN + i1_l = LBOUND(SrcMiscData%Vwnd_NW,1) + i1_u = UBOUND(SrcMiscData%Vwnd_NW,1) + i2_l = LBOUND(SrcMiscData%Vwnd_NW,2) + i2_u = UBOUND(SrcMiscData%Vwnd_NW,2) + i3_l = LBOUND(SrcMiscData%Vwnd_NW,3) + i3_u = UBOUND(SrcMiscData%Vwnd_NW,3) + i4_l = LBOUND(SrcMiscData%Vwnd_NW,4) + i4_u = UBOUND(SrcMiscData%Vwnd_NW,4) + IF (.NOT. ALLOCATED(DstMiscData%Vwnd_NW)) THEN + ALLOCATE(DstMiscData%Vwnd_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Vwnd_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vwnd_NW = SrcMiscData%Vwnd_NW +ENDIF +IF (ALLOCATED(SrcMiscData%Vwnd_FW)) THEN + i1_l = LBOUND(SrcMiscData%Vwnd_FW,1) + i1_u = UBOUND(SrcMiscData%Vwnd_FW,1) + i2_l = LBOUND(SrcMiscData%Vwnd_FW,2) + i2_u = UBOUND(SrcMiscData%Vwnd_FW,2) + i3_l = LBOUND(SrcMiscData%Vwnd_FW,3) + i3_u = UBOUND(SrcMiscData%Vwnd_FW,3) + i4_l = LBOUND(SrcMiscData%Vwnd_FW,4) + i4_u = UBOUND(SrcMiscData%Vwnd_FW,4) + IF (.NOT. ALLOCATED(DstMiscData%Vwnd_FW)) THEN + ALLOCATE(DstMiscData%Vwnd_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Vwnd_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vwnd_FW = SrcMiscData%Vwnd_FW +ENDIF +IF (ALLOCATED(SrcMiscData%Vind_NW)) THEN + i1_l = LBOUND(SrcMiscData%Vind_NW,1) + i1_u = UBOUND(SrcMiscData%Vind_NW,1) + i2_l = LBOUND(SrcMiscData%Vind_NW,2) + i2_u = UBOUND(SrcMiscData%Vind_NW,2) + i3_l = LBOUND(SrcMiscData%Vind_NW,3) + i3_u = UBOUND(SrcMiscData%Vind_NW,3) + i4_l = LBOUND(SrcMiscData%Vind_NW,4) + i4_u = UBOUND(SrcMiscData%Vind_NW,4) + IF (.NOT. ALLOCATED(DstMiscData%Vind_NW)) THEN + ALLOCATE(DstMiscData%Vind_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Vind_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vind_NW = SrcMiscData%Vind_NW +ENDIF +IF (ALLOCATED(SrcMiscData%Vind_FW)) THEN + i1_l = LBOUND(SrcMiscData%Vind_FW,1) + i1_u = UBOUND(SrcMiscData%Vind_FW,1) + i2_l = LBOUND(SrcMiscData%Vind_FW,2) + i2_u = UBOUND(SrcMiscData%Vind_FW,2) + i3_l = LBOUND(SrcMiscData%Vind_FW,3) + i3_u = UBOUND(SrcMiscData%Vind_FW,3) + i4_l = LBOUND(SrcMiscData%Vind_FW,4) + i4_u = UBOUND(SrcMiscData%Vind_FW,4) + IF (.NOT. ALLOCATED(DstMiscData%Vind_FW)) THEN + ALLOCATE(DstMiscData%Vind_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Vind_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vind_FW = SrcMiscData%Vind_FW +ENDIF + DstMiscData%nNW = SrcMiscData%nNW + DstMiscData%nFW = SrcMiscData%nFW + DstMiscData%iStep = SrcMiscData%iStep + DstMiscData%VTKstep = SrcMiscData%VTKstep + DstMiscData%VTKlastTime = SrcMiscData%VTKlastTime +IF (ALLOCATED(SrcMiscData%r_wind)) THEN + i1_l = LBOUND(SrcMiscData%r_wind,1) + i1_u = UBOUND(SrcMiscData%r_wind,1) + i2_l = LBOUND(SrcMiscData%r_wind,2) + i2_u = UBOUND(SrcMiscData%r_wind,2) + IF (.NOT. ALLOCATED(DstMiscData%r_wind)) THEN + ALLOCATE(DstMiscData%r_wind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%r_wind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%r_wind = SrcMiscData%r_wind +ENDIF +IF (ALLOCATED(SrcMiscData%PitchAndTwist)) THEN + i1_l = LBOUND(SrcMiscData%PitchAndTwist,1) + i1_u = UBOUND(SrcMiscData%PitchAndTwist,1) + i2_l = LBOUND(SrcMiscData%PitchAndTwist,2) + i2_u = UBOUND(SrcMiscData%PitchAndTwist,2) + IF (.NOT. ALLOCATED(DstMiscData%PitchAndTwist)) THEN + ALLOCATE(DstMiscData%PitchAndTwist(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%PitchAndTwist.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%PitchAndTwist = SrcMiscData%PitchAndTwist +ENDIF + DstMiscData%ComputeWakeInduced = SrcMiscData%ComputeWakeInduced + DstMiscData%OldWakeTime = SrcMiscData%OldWakeTime + DstMiscData%tSpent = SrcMiscData%tSpent +IF (ALLOCATED(SrcMiscData%dxdt_NW)) THEN + i1_l = LBOUND(SrcMiscData%dxdt_NW,1) + i1_u = UBOUND(SrcMiscData%dxdt_NW,1) + i2_l = LBOUND(SrcMiscData%dxdt_NW,2) + i2_u = UBOUND(SrcMiscData%dxdt_NW,2) + i3_l = LBOUND(SrcMiscData%dxdt_NW,3) + i3_u = UBOUND(SrcMiscData%dxdt_NW,3) + i4_l = LBOUND(SrcMiscData%dxdt_NW,4) + i4_u = UBOUND(SrcMiscData%dxdt_NW,4) + IF (.NOT. ALLOCATED(DstMiscData%dxdt_NW)) THEN + ALLOCATE(DstMiscData%dxdt_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%dxdt_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%dxdt_NW = SrcMiscData%dxdt_NW +ENDIF +IF (ALLOCATED(SrcMiscData%dxdt_FW)) THEN + i1_l = LBOUND(SrcMiscData%dxdt_FW,1) + i1_u = UBOUND(SrcMiscData%dxdt_FW,1) + i2_l = LBOUND(SrcMiscData%dxdt_FW,2) + i2_u = UBOUND(SrcMiscData%dxdt_FW,2) + i3_l = LBOUND(SrcMiscData%dxdt_FW,3) + i3_u = UBOUND(SrcMiscData%dxdt_FW,3) + i4_l = LBOUND(SrcMiscData%dxdt_FW,4) + i4_u = UBOUND(SrcMiscData%dxdt_FW,4) + IF (.NOT. ALLOCATED(DstMiscData%dxdt_FW)) THEN + ALLOCATE(DstMiscData%dxdt_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%dxdt_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%dxdt_FW = SrcMiscData%dxdt_FW +ENDIF +IF (ALLOCATED(SrcMiscData%alpha_LL)) THEN + i1_l = LBOUND(SrcMiscData%alpha_LL,1) + i1_u = UBOUND(SrcMiscData%alpha_LL,1) + i2_l = LBOUND(SrcMiscData%alpha_LL,2) + i2_u = UBOUND(SrcMiscData%alpha_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%alpha_LL)) THEN + ALLOCATE(DstMiscData%alpha_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%alpha_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%alpha_LL = SrcMiscData%alpha_LL +ENDIF +IF (ALLOCATED(SrcMiscData%Vreln_LL)) THEN + i1_l = LBOUND(SrcMiscData%Vreln_LL,1) + i1_u = UBOUND(SrcMiscData%Vreln_LL,1) + i2_l = LBOUND(SrcMiscData%Vreln_LL,2) + i2_u = UBOUND(SrcMiscData%Vreln_LL,2) + IF (.NOT. ALLOCATED(DstMiscData%Vreln_LL)) THEN + ALLOCATE(DstMiscData%Vreln_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Vreln_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vreln_LL = SrcMiscData%Vreln_LL +ENDIF +IF (ALLOCATED(SrcMiscData%SegConnct)) THEN + i1_l = LBOUND(SrcMiscData%SegConnct,1) + i1_u = UBOUND(SrcMiscData%SegConnct,1) + i2_l = LBOUND(SrcMiscData%SegConnct,2) + i2_u = UBOUND(SrcMiscData%SegConnct,2) + IF (.NOT. ALLOCATED(DstMiscData%SegConnct)) THEN + ALLOCATE(DstMiscData%SegConnct(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%SegConnct.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%SegConnct = SrcMiscData%SegConnct +ENDIF +IF (ALLOCATED(SrcMiscData%SegPoints)) THEN + i1_l = LBOUND(SrcMiscData%SegPoints,1) + i1_u = UBOUND(SrcMiscData%SegPoints,1) + i2_l = LBOUND(SrcMiscData%SegPoints,2) + i2_u = UBOUND(SrcMiscData%SegPoints,2) + IF (.NOT. ALLOCATED(DstMiscData%SegPoints)) THEN + ALLOCATE(DstMiscData%SegPoints(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%SegPoints.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%SegPoints = SrcMiscData%SegPoints +ENDIF +IF (ALLOCATED(SrcMiscData%SegGamma)) THEN + i1_l = LBOUND(SrcMiscData%SegGamma,1) + i1_u = UBOUND(SrcMiscData%SegGamma,1) + IF (.NOT. ALLOCATED(DstMiscData%SegGamma)) THEN + ALLOCATE(DstMiscData%SegGamma(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%SegGamma.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%SegGamma = SrcMiscData%SegGamma +ENDIF +IF (ALLOCATED(SrcMiscData%SegEpsilon)) THEN + i1_l = LBOUND(SrcMiscData%SegEpsilon,1) + i1_u = UBOUND(SrcMiscData%SegEpsilon,1) + IF (.NOT. ALLOCATED(DstMiscData%SegEpsilon)) THEN + ALLOCATE(DstMiscData%SegEpsilon(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%SegEpsilon.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%SegEpsilon = SrcMiscData%SegEpsilon +ENDIF +IF (ALLOCATED(SrcMiscData%CPs)) THEN + i1_l = LBOUND(SrcMiscData%CPs,1) + i1_u = UBOUND(SrcMiscData%CPs,1) + i2_l = LBOUND(SrcMiscData%CPs,2) + i2_u = UBOUND(SrcMiscData%CPs,2) + IF (.NOT. ALLOCATED(DstMiscData%CPs)) THEN + ALLOCATE(DstMiscData%CPs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%CPs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%CPs = SrcMiscData%CPs +ENDIF +IF (ALLOCATED(SrcMiscData%Uind)) THEN + i1_l = LBOUND(SrcMiscData%Uind,1) + i1_u = UBOUND(SrcMiscData%Uind,1) + i2_l = LBOUND(SrcMiscData%Uind,2) + i2_u = UBOUND(SrcMiscData%Uind,2) + IF (.NOT. ALLOCATED(DstMiscData%Uind)) THEN + ALLOCATE(DstMiscData%Uind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%Uind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Uind = SrcMiscData%Uind +ENDIF +IF (ALLOCATED(SrcMiscData%BN_AxInd)) THEN + i1_l = LBOUND(SrcMiscData%BN_AxInd,1) + i1_u = UBOUND(SrcMiscData%BN_AxInd,1) + i2_l = LBOUND(SrcMiscData%BN_AxInd,2) + i2_u = UBOUND(SrcMiscData%BN_AxInd,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_AxInd)) THEN + ALLOCATE(DstMiscData%BN_AxInd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_AxInd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_AxInd = SrcMiscData%BN_AxInd +ENDIF +IF (ALLOCATED(SrcMiscData%BN_TanInd)) THEN + i1_l = LBOUND(SrcMiscData%BN_TanInd,1) + i1_u = UBOUND(SrcMiscData%BN_TanInd,1) + i2_l = LBOUND(SrcMiscData%BN_TanInd,2) + i2_u = UBOUND(SrcMiscData%BN_TanInd,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_TanInd)) THEN + ALLOCATE(DstMiscData%BN_TanInd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_TanInd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_TanInd = SrcMiscData%BN_TanInd +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Vrel)) THEN + i1_l = LBOUND(SrcMiscData%BN_Vrel,1) + i1_u = UBOUND(SrcMiscData%BN_Vrel,1) + i2_l = LBOUND(SrcMiscData%BN_Vrel,2) + i2_u = UBOUND(SrcMiscData%BN_Vrel,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Vrel)) THEN + ALLOCATE(DstMiscData%BN_Vrel(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Vrel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Vrel = SrcMiscData%BN_Vrel +ENDIF +IF (ALLOCATED(SrcMiscData%BN_alpha)) THEN + i1_l = LBOUND(SrcMiscData%BN_alpha,1) + i1_u = UBOUND(SrcMiscData%BN_alpha,1) + i2_l = LBOUND(SrcMiscData%BN_alpha,2) + i2_u = UBOUND(SrcMiscData%BN_alpha,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_alpha)) THEN + ALLOCATE(DstMiscData%BN_alpha(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_alpha.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_alpha = SrcMiscData%BN_alpha +ENDIF +IF (ALLOCATED(SrcMiscData%BN_phi)) THEN + i1_l = LBOUND(SrcMiscData%BN_phi,1) + i1_u = UBOUND(SrcMiscData%BN_phi,1) + i2_l = LBOUND(SrcMiscData%BN_phi,2) + i2_u = UBOUND(SrcMiscData%BN_phi,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_phi)) THEN + ALLOCATE(DstMiscData%BN_phi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_phi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_phi = SrcMiscData%BN_phi +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Re)) THEN + i1_l = LBOUND(SrcMiscData%BN_Re,1) + i1_u = UBOUND(SrcMiscData%BN_Re,1) + i2_l = LBOUND(SrcMiscData%BN_Re,2) + i2_u = UBOUND(SrcMiscData%BN_Re,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Re)) THEN + ALLOCATE(DstMiscData%BN_Re(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Re.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Re = SrcMiscData%BN_Re +ENDIF +IF (ALLOCATED(SrcMiscData%BN_URelWind_s)) THEN + i1_l = LBOUND(SrcMiscData%BN_URelWind_s,1) + i1_u = UBOUND(SrcMiscData%BN_URelWind_s,1) + i2_l = LBOUND(SrcMiscData%BN_URelWind_s,2) + i2_u = UBOUND(SrcMiscData%BN_URelWind_s,2) + i3_l = LBOUND(SrcMiscData%BN_URelWind_s,3) + i3_u = UBOUND(SrcMiscData%BN_URelWind_s,3) + IF (.NOT. ALLOCATED(DstMiscData%BN_URelWind_s)) THEN + ALLOCATE(DstMiscData%BN_URelWind_s(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%BN_URelWind_s.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_URelWind_s = SrcMiscData%BN_URelWind_s +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cl_Static)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cl_Static,1) + i1_u = UBOUND(SrcMiscData%BN_Cl_Static,1) + i2_l = LBOUND(SrcMiscData%BN_Cl_Static,2) + i2_u = UBOUND(SrcMiscData%BN_Cl_Static,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cl_Static)) THEN + ALLOCATE(DstMiscData%BN_Cl_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cl_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cl_Static = SrcMiscData%BN_Cl_Static +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cd_Static)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cd_Static,1) + i1_u = UBOUND(SrcMiscData%BN_Cd_Static,1) + i2_l = LBOUND(SrcMiscData%BN_Cd_Static,2) + i2_u = UBOUND(SrcMiscData%BN_Cd_Static,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cd_Static)) THEN + ALLOCATE(DstMiscData%BN_Cd_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cd_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cd_Static = SrcMiscData%BN_Cd_Static +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cm_Static)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cm_Static,1) + i1_u = UBOUND(SrcMiscData%BN_Cm_Static,1) + i2_l = LBOUND(SrcMiscData%BN_Cm_Static,2) + i2_u = UBOUND(SrcMiscData%BN_Cm_Static,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cm_Static)) THEN + ALLOCATE(DstMiscData%BN_Cm_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cm_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cm_Static = SrcMiscData%BN_Cm_Static +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cl)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cl,1) + i1_u = UBOUND(SrcMiscData%BN_Cl,1) + i2_l = LBOUND(SrcMiscData%BN_Cl,2) + i2_u = UBOUND(SrcMiscData%BN_Cl,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cl)) THEN + ALLOCATE(DstMiscData%BN_Cl(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cl.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cl = SrcMiscData%BN_Cl +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cd)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cd,1) + i1_u = UBOUND(SrcMiscData%BN_Cd,1) + i2_l = LBOUND(SrcMiscData%BN_Cd,2) + i2_u = UBOUND(SrcMiscData%BN_Cd,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cd)) THEN + ALLOCATE(DstMiscData%BN_Cd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cd = SrcMiscData%BN_Cd +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cm)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cm,1) + i1_u = UBOUND(SrcMiscData%BN_Cm,1) + i2_l = LBOUND(SrcMiscData%BN_Cm,2) + i2_u = UBOUND(SrcMiscData%BN_Cm,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cm)) THEN + ALLOCATE(DstMiscData%BN_Cm(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cm = SrcMiscData%BN_Cm +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cx)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cx,1) + i1_u = UBOUND(SrcMiscData%BN_Cx,1) + i2_l = LBOUND(SrcMiscData%BN_Cx,2) + i2_u = UBOUND(SrcMiscData%BN_Cx,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cx)) THEN + ALLOCATE(DstMiscData%BN_Cx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cx = SrcMiscData%BN_Cx +ENDIF +IF (ALLOCATED(SrcMiscData%BN_Cy)) THEN + i1_l = LBOUND(SrcMiscData%BN_Cy,1) + i1_u = UBOUND(SrcMiscData%BN_Cy,1) + i2_l = LBOUND(SrcMiscData%BN_Cy,2) + i2_u = UBOUND(SrcMiscData%BN_Cy,2) + IF (.NOT. ALLOCATED(DstMiscData%BN_Cy)) THEN + ALLOCATE(DstMiscData%BN_Cy(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%BN_Cy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%BN_Cy = SrcMiscData%BN_Cy +ENDIF + CALL UA_CopyMisc( SrcMiscData%m_UA, DstMiscData%m_UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL UA_CopyOutput( SrcMiscData%y_UA, DstMiscData%y_UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL UA_CopyParam( SrcMiscData%p_UA, DstMiscData%p_UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstMiscData%UA_Flag = SrcMiscData%UA_Flag +IF (ALLOCATED(SrcMiscData%Vwnd_ND)) THEN + i1_l = LBOUND(SrcMiscData%Vwnd_ND,1) + i1_u = UBOUND(SrcMiscData%Vwnd_ND,1) + i2_l = LBOUND(SrcMiscData%Vwnd_ND,2) + i2_u = UBOUND(SrcMiscData%Vwnd_ND,2) + i3_l = LBOUND(SrcMiscData%Vwnd_ND,3) + i3_u = UBOUND(SrcMiscData%Vwnd_ND,3) + IF (.NOT. ALLOCATED(DstMiscData%Vwnd_ND)) THEN + ALLOCATE(DstMiscData%Vwnd_ND(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%Vwnd_ND.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%Vwnd_ND = SrcMiscData%Vwnd_ND +ENDIF + END SUBROUTINE FVW_CopyMisc + + SUBROUTINE FVW_DestroyMisc( MiscData, ErrStat, ErrMsg ) + TYPE(FVW_MiscVarType), INTENT(INOUT) :: MiscData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyMisc' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(MiscData%LE)) THEN + DEALLOCATE(MiscData%LE) +ENDIF +IF (ALLOCATED(MiscData%TE)) THEN + DEALLOCATE(MiscData%TE) +ENDIF +IF (ALLOCATED(MiscData%r_LL)) THEN + DEALLOCATE(MiscData%r_LL) +ENDIF +IF (ALLOCATED(MiscData%s_LL)) THEN + DEALLOCATE(MiscData%s_LL) +ENDIF +IF (ALLOCATED(MiscData%chord_LL)) THEN + DEALLOCATE(MiscData%chord_LL) +ENDIF +IF (ALLOCATED(MiscData%s_CP_LL)) THEN + DEALLOCATE(MiscData%s_CP_LL) +ENDIF +IF (ALLOCATED(MiscData%chord_CP_LL)) THEN + DEALLOCATE(MiscData%chord_CP_LL) +ENDIF +IF (ALLOCATED(MiscData%CP_LL)) THEN + DEALLOCATE(MiscData%CP_LL) +ENDIF +IF (ALLOCATED(MiscData%Tang)) THEN + DEALLOCATE(MiscData%Tang) +ENDIF +IF (ALLOCATED(MiscData%Norm)) THEN + DEALLOCATE(MiscData%Norm) +ENDIF +IF (ALLOCATED(MiscData%Orth)) THEN + DEALLOCATE(MiscData%Orth) +ENDIF +IF (ALLOCATED(MiscData%dl)) THEN + DEALLOCATE(MiscData%dl) +ENDIF +IF (ALLOCATED(MiscData%Area)) THEN + DEALLOCATE(MiscData%Area) +ENDIF +IF (ALLOCATED(MiscData%diag_LL)) THEN + DEALLOCATE(MiscData%diag_LL) +ENDIF +IF (ALLOCATED(MiscData%Gamma_LL)) THEN + DEALLOCATE(MiscData%Gamma_LL) +ENDIF +IF (ALLOCATED(MiscData%Vind_LL)) THEN + DEALLOCATE(MiscData%Vind_LL) +ENDIF +IF (ALLOCATED(MiscData%Vtot_LL)) THEN + DEALLOCATE(MiscData%Vtot_LL) +ENDIF +IF (ALLOCATED(MiscData%Vstr_LL)) THEN + DEALLOCATE(MiscData%Vstr_LL) +ENDIF +IF (ALLOCATED(MiscData%Vwnd_LL)) THEN + DEALLOCATE(MiscData%Vwnd_LL) +ENDIF +IF (ALLOCATED(MiscData%Vwnd_NW)) THEN + DEALLOCATE(MiscData%Vwnd_NW) +ENDIF +IF (ALLOCATED(MiscData%Vwnd_FW)) THEN + DEALLOCATE(MiscData%Vwnd_FW) +ENDIF +IF (ALLOCATED(MiscData%Vind_NW)) THEN + DEALLOCATE(MiscData%Vind_NW) +ENDIF +IF (ALLOCATED(MiscData%Vind_FW)) THEN + DEALLOCATE(MiscData%Vind_FW) +ENDIF +IF (ALLOCATED(MiscData%r_wind)) THEN + DEALLOCATE(MiscData%r_wind) +ENDIF +IF (ALLOCATED(MiscData%PitchAndTwist)) THEN + DEALLOCATE(MiscData%PitchAndTwist) +ENDIF +IF (ALLOCATED(MiscData%dxdt_NW)) THEN + DEALLOCATE(MiscData%dxdt_NW) +ENDIF +IF (ALLOCATED(MiscData%dxdt_FW)) THEN + DEALLOCATE(MiscData%dxdt_FW) +ENDIF +IF (ALLOCATED(MiscData%alpha_LL)) THEN + DEALLOCATE(MiscData%alpha_LL) +ENDIF +IF (ALLOCATED(MiscData%Vreln_LL)) THEN + DEALLOCATE(MiscData%Vreln_LL) +ENDIF +IF (ALLOCATED(MiscData%SegConnct)) THEN + DEALLOCATE(MiscData%SegConnct) +ENDIF +IF (ALLOCATED(MiscData%SegPoints)) THEN + DEALLOCATE(MiscData%SegPoints) +ENDIF +IF (ALLOCATED(MiscData%SegGamma)) THEN + DEALLOCATE(MiscData%SegGamma) +ENDIF +IF (ALLOCATED(MiscData%SegEpsilon)) THEN + DEALLOCATE(MiscData%SegEpsilon) +ENDIF +IF (ALLOCATED(MiscData%CPs)) THEN + DEALLOCATE(MiscData%CPs) +ENDIF +IF (ALLOCATED(MiscData%Uind)) THEN + DEALLOCATE(MiscData%Uind) +ENDIF +IF (ALLOCATED(MiscData%BN_AxInd)) THEN + DEALLOCATE(MiscData%BN_AxInd) +ENDIF +IF (ALLOCATED(MiscData%BN_TanInd)) THEN + DEALLOCATE(MiscData%BN_TanInd) +ENDIF +IF (ALLOCATED(MiscData%BN_Vrel)) THEN + DEALLOCATE(MiscData%BN_Vrel) +ENDIF +IF (ALLOCATED(MiscData%BN_alpha)) THEN + DEALLOCATE(MiscData%BN_alpha) +ENDIF +IF (ALLOCATED(MiscData%BN_phi)) THEN + DEALLOCATE(MiscData%BN_phi) +ENDIF +IF (ALLOCATED(MiscData%BN_Re)) THEN + DEALLOCATE(MiscData%BN_Re) +ENDIF +IF (ALLOCATED(MiscData%BN_URelWind_s)) THEN + DEALLOCATE(MiscData%BN_URelWind_s) +ENDIF +IF (ALLOCATED(MiscData%BN_Cl_Static)) THEN + DEALLOCATE(MiscData%BN_Cl_Static) +ENDIF +IF (ALLOCATED(MiscData%BN_Cd_Static)) THEN + DEALLOCATE(MiscData%BN_Cd_Static) +ENDIF +IF (ALLOCATED(MiscData%BN_Cm_Static)) THEN + DEALLOCATE(MiscData%BN_Cm_Static) +ENDIF +IF (ALLOCATED(MiscData%BN_Cl)) THEN + DEALLOCATE(MiscData%BN_Cl) +ENDIF +IF (ALLOCATED(MiscData%BN_Cd)) THEN + DEALLOCATE(MiscData%BN_Cd) +ENDIF +IF (ALLOCATED(MiscData%BN_Cm)) THEN + DEALLOCATE(MiscData%BN_Cm) +ENDIF +IF (ALLOCATED(MiscData%BN_Cx)) THEN + DEALLOCATE(MiscData%BN_Cx) +ENDIF +IF (ALLOCATED(MiscData%BN_Cy)) THEN + DEALLOCATE(MiscData%BN_Cy) +ENDIF + CALL UA_DestroyMisc( MiscData%m_UA, ErrStat, ErrMsg ) + CALL UA_DestroyOutput( MiscData%y_UA, ErrStat, ErrMsg ) + CALL UA_DestroyParam( MiscData%p_UA, ErrStat, ErrMsg ) +IF (ALLOCATED(MiscData%Vwnd_ND)) THEN + DEALLOCATE(MiscData%Vwnd_ND) +ENDIF + END SUBROUTINE FVW_DestroyMisc + + SUBROUTINE FVW_PackMisc( 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(FVW_MiscVarType), 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 = 'FVW_PackMisc' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! FirstCall + Int_BufSz = Int_BufSz + 1 ! LE allocated yes/no + IF ( ALLOCATED(InData%LE) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! LE upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%LE) ! LE + END IF + Int_BufSz = Int_BufSz + 1 ! TE allocated yes/no + IF ( ALLOCATED(InData%TE) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! TE upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%TE) ! TE + END IF + Int_BufSz = Int_BufSz + 1 ! r_LL allocated yes/no + IF ( ALLOCATED(InData%r_LL) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! r_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%r_LL) ! r_LL + END IF + Int_BufSz = Int_BufSz + 1 ! s_LL allocated yes/no + IF ( ALLOCATED(InData%s_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! s_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%s_LL) ! s_LL + END IF + Int_BufSz = Int_BufSz + 1 ! chord_LL allocated yes/no + IF ( ALLOCATED(InData%chord_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! chord_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%chord_LL) ! chord_LL + END IF + Int_BufSz = Int_BufSz + 1 ! s_CP_LL allocated yes/no + IF ( ALLOCATED(InData%s_CP_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! s_CP_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%s_CP_LL) ! s_CP_LL + END IF + Int_BufSz = Int_BufSz + 1 ! chord_CP_LL allocated yes/no + IF ( ALLOCATED(InData%chord_CP_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! chord_CP_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%chord_CP_LL) ! chord_CP_LL + END IF + Int_BufSz = Int_BufSz + 1 ! CP_LL allocated yes/no + IF ( ALLOCATED(InData%CP_LL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! CP_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%CP_LL) ! CP_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Tang allocated yes/no + IF ( ALLOCATED(InData%Tang) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Tang upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Tang) ! Tang + END IF + Int_BufSz = Int_BufSz + 1 ! Norm allocated yes/no + IF ( ALLOCATED(InData%Norm) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Norm upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Norm) ! Norm + END IF + Int_BufSz = Int_BufSz + 1 ! Orth allocated yes/no + IF ( ALLOCATED(InData%Orth) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Orth upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Orth) ! Orth + END IF + Int_BufSz = Int_BufSz + 1 ! dl allocated yes/no + IF ( ALLOCATED(InData%dl) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! dl upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%dl) ! dl + END IF + Int_BufSz = Int_BufSz + 1 ! Area allocated yes/no + IF ( ALLOCATED(InData%Area) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Area upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Area) ! Area + END IF + Int_BufSz = Int_BufSz + 1 ! diag_LL allocated yes/no + IF ( ALLOCATED(InData%diag_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! diag_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%diag_LL) ! diag_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Gamma_LL allocated yes/no + IF ( ALLOCATED(InData%Gamma_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Gamma_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Gamma_LL) ! Gamma_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vind_LL allocated yes/no + IF ( ALLOCATED(InData%Vind_LL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vind_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vind_LL) ! Vind_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vtot_LL allocated yes/no + IF ( ALLOCATED(InData%Vtot_LL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vtot_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vtot_LL) ! Vtot_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vstr_LL allocated yes/no + IF ( ALLOCATED(InData%Vstr_LL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vstr_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vstr_LL) ! Vstr_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vwnd_LL allocated yes/no + IF ( ALLOCATED(InData%Vwnd_LL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vwnd_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vwnd_LL) ! Vwnd_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vwnd_NW allocated yes/no + IF ( ALLOCATED(InData%Vwnd_NW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! Vwnd_NW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vwnd_NW) ! Vwnd_NW + END IF + Int_BufSz = Int_BufSz + 1 ! Vwnd_FW allocated yes/no + IF ( ALLOCATED(InData%Vwnd_FW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! Vwnd_FW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vwnd_FW) ! Vwnd_FW + END IF + Int_BufSz = Int_BufSz + 1 ! Vind_NW allocated yes/no + IF ( ALLOCATED(InData%Vind_NW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! Vind_NW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vind_NW) ! Vind_NW + END IF + Int_BufSz = Int_BufSz + 1 ! Vind_FW allocated yes/no + IF ( ALLOCATED(InData%Vind_FW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! Vind_FW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vind_FW) ! Vind_FW + END IF + Int_BufSz = Int_BufSz + 1 ! nNW + Int_BufSz = Int_BufSz + 1 ! nFW + Int_BufSz = Int_BufSz + 1 ! iStep + Int_BufSz = Int_BufSz + 1 ! VTKstep + Db_BufSz = Db_BufSz + 1 ! VTKlastTime + Int_BufSz = Int_BufSz + 1 ! r_wind allocated yes/no + IF ( ALLOCATED(InData%r_wind) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! r_wind upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%r_wind) ! r_wind + END IF + Int_BufSz = Int_BufSz + 1 ! PitchAndTwist allocated yes/no + IF ( ALLOCATED(InData%PitchAndTwist) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! PitchAndTwist upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%PitchAndTwist) ! PitchAndTwist + END IF + Int_BufSz = Int_BufSz + 1 ! ComputeWakeInduced + Db_BufSz = Db_BufSz + 1 ! OldWakeTime + Re_BufSz = Re_BufSz + 1 ! tSpent + Int_BufSz = Int_BufSz + 1 ! dxdt_NW allocated yes/no + IF ( ALLOCATED(InData%dxdt_NW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! dxdt_NW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%dxdt_NW) ! dxdt_NW + END IF + Int_BufSz = Int_BufSz + 1 ! dxdt_FW allocated yes/no + IF ( ALLOCATED(InData%dxdt_FW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! dxdt_FW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%dxdt_FW) ! dxdt_FW + END IF + Int_BufSz = Int_BufSz + 1 ! alpha_LL allocated yes/no + IF ( ALLOCATED(InData%alpha_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! alpha_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%alpha_LL) ! alpha_LL + END IF + Int_BufSz = Int_BufSz + 1 ! Vreln_LL allocated yes/no + IF ( ALLOCATED(InData%Vreln_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Vreln_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vreln_LL) ! Vreln_LL + END IF + Int_BufSz = Int_BufSz + 1 ! SegConnct allocated yes/no + IF ( ALLOCATED(InData%SegConnct) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! SegConnct upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%SegConnct) ! SegConnct + END IF + Int_BufSz = Int_BufSz + 1 ! SegPoints allocated yes/no + IF ( ALLOCATED(InData%SegPoints) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! SegPoints upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%SegPoints) ! SegPoints + END IF + Int_BufSz = Int_BufSz + 1 ! SegGamma allocated yes/no + IF ( ALLOCATED(InData%SegGamma) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! SegGamma upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%SegGamma) ! SegGamma + END IF + Int_BufSz = Int_BufSz + 1 ! SegEpsilon allocated yes/no + IF ( ALLOCATED(InData%SegEpsilon) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! SegEpsilon upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%SegEpsilon) ! SegEpsilon + END IF + Int_BufSz = Int_BufSz + 1 ! CPs allocated yes/no + IF ( ALLOCATED(InData%CPs) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! CPs upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%CPs) ! CPs + END IF + Int_BufSz = Int_BufSz + 1 ! Uind allocated yes/no + IF ( ALLOCATED(InData%Uind) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Uind upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Uind) ! Uind + END IF + Int_BufSz = Int_BufSz + 1 ! BN_AxInd allocated yes/no + IF ( ALLOCATED(InData%BN_AxInd) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_AxInd upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_AxInd) ! BN_AxInd + END IF + Int_BufSz = Int_BufSz + 1 ! BN_TanInd allocated yes/no + IF ( ALLOCATED(InData%BN_TanInd) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_TanInd upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_TanInd) ! BN_TanInd + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Vrel allocated yes/no + IF ( ALLOCATED(InData%BN_Vrel) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Vrel upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Vrel) ! BN_Vrel + END IF + Int_BufSz = Int_BufSz + 1 ! BN_alpha allocated yes/no + IF ( ALLOCATED(InData%BN_alpha) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_alpha upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_alpha) ! BN_alpha + END IF + Int_BufSz = Int_BufSz + 1 ! BN_phi allocated yes/no + IF ( ALLOCATED(InData%BN_phi) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_phi upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_phi) ! BN_phi + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Re allocated yes/no + IF ( ALLOCATED(InData%BN_Re) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Re upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Re) ! BN_Re + END IF + Int_BufSz = Int_BufSz + 1 ! BN_URelWind_s allocated yes/no + IF ( ALLOCATED(InData%BN_URelWind_s) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! BN_URelWind_s upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_URelWind_s) ! BN_URelWind_s + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cl_Static allocated yes/no + IF ( ALLOCATED(InData%BN_Cl_Static) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cl_Static upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cl_Static) ! BN_Cl_Static + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cd_Static allocated yes/no + IF ( ALLOCATED(InData%BN_Cd_Static) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cd_Static upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cd_Static) ! BN_Cd_Static + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cm_Static allocated yes/no + IF ( ALLOCATED(InData%BN_Cm_Static) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cm_Static upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cm_Static) ! BN_Cm_Static + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cl allocated yes/no + IF ( ALLOCATED(InData%BN_Cl) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cl upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cl) ! BN_Cl + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cd allocated yes/no + IF ( ALLOCATED(InData%BN_Cd) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cd upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cd) ! BN_Cd + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cm allocated yes/no + IF ( ALLOCATED(InData%BN_Cm) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cm upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cm) ! BN_Cm + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cx allocated yes/no + IF ( ALLOCATED(InData%BN_Cx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cx) ! BN_Cx + END IF + Int_BufSz = Int_BufSz + 1 ! BN_Cy allocated yes/no + IF ( ALLOCATED(InData%BN_Cy) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! BN_Cy upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BN_Cy) ! BN_Cy + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! m_UA: size of buffers for each call to pack subtype + CALL UA_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%m_UA, ErrStat2, ErrMsg2, .TRUE. ) ! m_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! m_UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! m_UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! m_UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! y_UA: size of buffers for each call to pack subtype + CALL UA_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%y_UA, ErrStat2, ErrMsg2, .TRUE. ) ! y_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! y_UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! y_UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! y_UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! p_UA: size of buffers for each call to pack subtype + CALL UA_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%p_UA, ErrStat2, ErrMsg2, .TRUE. ) ! p_UA + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! p_UA + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! p_UA + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! p_UA + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! UA_Flag + Int_BufSz = Int_BufSz + 1 ! Vwnd_ND allocated yes/no + IF ( ALLOCATED(InData%Vwnd_ND) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vwnd_ND upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vwnd_ND) ! Vwnd_ND + 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 + + IntKiBuf(Int_Xferred) = TRANSFER(InData%FirstCall, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%LE) ) 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%LE,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%LE,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%LE,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%LE,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%LE,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%LE,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%LE,3), UBOUND(InData%LE,3) + DO i2 = LBOUND(InData%LE,2), UBOUND(InData%LE,2) + DO i1 = LBOUND(InData%LE,1), UBOUND(InData%LE,1) + ReKiBuf(Re_Xferred) = InData%LE(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%TE) ) 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%TE,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TE,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%TE,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TE,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%TE,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TE,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%TE,3), UBOUND(InData%TE,3) + DO i2 = LBOUND(InData%TE,2), UBOUND(InData%TE,2) + DO i1 = LBOUND(InData%TE,1), UBOUND(InData%TE,1) + ReKiBuf(Re_Xferred) = InData%TE(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%r_LL) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_LL,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_LL,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_LL,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%r_LL,4), UBOUND(InData%r_LL,4) + DO i3 = LBOUND(InData%r_LL,3), UBOUND(InData%r_LL,3) + DO i2 = LBOUND(InData%r_LL,2), UBOUND(InData%r_LL,2) + DO i1 = LBOUND(InData%r_LL,1), UBOUND(InData%r_LL,1) + ReKiBuf(Re_Xferred) = InData%r_LL(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%s_LL) ) 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%s_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%s_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%s_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%s_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%s_LL,2), UBOUND(InData%s_LL,2) + DO i1 = LBOUND(InData%s_LL,1), UBOUND(InData%s_LL,1) + ReKiBuf(Re_Xferred) = InData%s_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%chord_LL) ) 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%chord_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chord_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%chord_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chord_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%chord_LL,2), UBOUND(InData%chord_LL,2) + DO i1 = LBOUND(InData%chord_LL,1), UBOUND(InData%chord_LL,1) + ReKiBuf(Re_Xferred) = InData%chord_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%s_CP_LL) ) 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%s_CP_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%s_CP_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%s_CP_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%s_CP_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%s_CP_LL,2), UBOUND(InData%s_CP_LL,2) + DO i1 = LBOUND(InData%s_CP_LL,1), UBOUND(InData%s_CP_LL,1) + ReKiBuf(Re_Xferred) = InData%s_CP_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%chord_CP_LL) ) 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%chord_CP_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chord_CP_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%chord_CP_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%chord_CP_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%chord_CP_LL,2), UBOUND(InData%chord_CP_LL,2) + DO i1 = LBOUND(InData%chord_CP_LL,1), UBOUND(InData%chord_CP_LL,1) + ReKiBuf(Re_Xferred) = InData%chord_CP_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%CP_LL) ) 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%CP_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CP_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CP_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CP_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CP_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CP_LL,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%CP_LL,3), UBOUND(InData%CP_LL,3) + DO i2 = LBOUND(InData%CP_LL,2), UBOUND(InData%CP_LL,2) + DO i1 = LBOUND(InData%CP_LL,1), UBOUND(InData%CP_LL,1) + ReKiBuf(Re_Xferred) = InData%CP_LL(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Tang) ) 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%Tang,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Tang,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Tang,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Tang,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Tang,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Tang,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Tang,3), UBOUND(InData%Tang,3) + DO i2 = LBOUND(InData%Tang,2), UBOUND(InData%Tang,2) + DO i1 = LBOUND(InData%Tang,1), UBOUND(InData%Tang,1) + ReKiBuf(Re_Xferred) = InData%Tang(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Norm) ) 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%Norm,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Norm,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Norm,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Norm,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Norm,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Norm,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Norm,3), UBOUND(InData%Norm,3) + DO i2 = LBOUND(InData%Norm,2), UBOUND(InData%Norm,2) + DO i1 = LBOUND(InData%Norm,1), UBOUND(InData%Norm,1) + ReKiBuf(Re_Xferred) = InData%Norm(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Orth) ) 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%Orth,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Orth,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Orth,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Orth,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Orth,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Orth,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Orth,3), UBOUND(InData%Orth,3) + DO i2 = LBOUND(InData%Orth,2), UBOUND(InData%Orth,2) + DO i1 = LBOUND(InData%Orth,1), UBOUND(InData%Orth,1) + ReKiBuf(Re_Xferred) = InData%Orth(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%dl) ) 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%dl,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dl,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dl,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dl,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dl,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dl,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%dl,3), UBOUND(InData%dl,3) + DO i2 = LBOUND(InData%dl,2), UBOUND(InData%dl,2) + DO i1 = LBOUND(InData%dl,1), UBOUND(InData%dl,1) + ReKiBuf(Re_Xferred) = InData%dl(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Area) ) 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%Area,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Area,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Area,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Area,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Area,2), UBOUND(InData%Area,2) + DO i1 = LBOUND(InData%Area,1), UBOUND(InData%Area,1) + ReKiBuf(Re_Xferred) = InData%Area(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%diag_LL) ) 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%diag_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%diag_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%diag_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%diag_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%diag_LL,2), UBOUND(InData%diag_LL,2) + DO i1 = LBOUND(InData%diag_LL,1), UBOUND(InData%diag_LL,1) + ReKiBuf(Re_Xferred) = InData%diag_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Gamma_LL) ) 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%Gamma_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Gamma_LL,2), UBOUND(InData%Gamma_LL,2) + DO i1 = LBOUND(InData%Gamma_LL,1), UBOUND(InData%Gamma_LL,1) + ReKiBuf(Re_Xferred) = InData%Gamma_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vind_LL) ) 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_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_LL,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vind_LL,3), UBOUND(InData%Vind_LL,3) + DO i2 = LBOUND(InData%Vind_LL,2), UBOUND(InData%Vind_LL,2) + DO i1 = LBOUND(InData%Vind_LL,1), UBOUND(InData%Vind_LL,1) + ReKiBuf(Re_Xferred) = InData%Vind_LL(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vtot_LL) ) 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%Vtot_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vtot_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vtot_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vtot_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vtot_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vtot_LL,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vtot_LL,3), UBOUND(InData%Vtot_LL,3) + DO i2 = LBOUND(InData%Vtot_LL,2), UBOUND(InData%Vtot_LL,2) + DO i1 = LBOUND(InData%Vtot_LL,1), UBOUND(InData%Vtot_LL,1) + ReKiBuf(Re_Xferred) = InData%Vtot_LL(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vstr_LL) ) 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%Vstr_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vstr_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vstr_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vstr_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vstr_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vstr_LL,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vstr_LL,3), UBOUND(InData%Vstr_LL,3) + DO i2 = LBOUND(InData%Vstr_LL,2), UBOUND(InData%Vstr_LL,2) + DO i1 = LBOUND(InData%Vstr_LL,1), UBOUND(InData%Vstr_LL,1) + ReKiBuf(Re_Xferred) = InData%Vstr_LL(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vwnd_LL) ) 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%Vwnd_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_LL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_LL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_LL,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vwnd_LL,3), UBOUND(InData%Vwnd_LL,3) + DO i2 = LBOUND(InData%Vwnd_LL,2), UBOUND(InData%Vwnd_LL,2) + DO i1 = LBOUND(InData%Vwnd_LL,1), UBOUND(InData%Vwnd_LL,1) + ReKiBuf(Re_Xferred) = InData%Vwnd_LL(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vwnd_NW) ) 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%Vwnd_NW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_NW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_NW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_NW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_NW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_NW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_NW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_NW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%Vwnd_NW,4), UBOUND(InData%Vwnd_NW,4) + DO i3 = LBOUND(InData%Vwnd_NW,3), UBOUND(InData%Vwnd_NW,3) + DO i2 = LBOUND(InData%Vwnd_NW,2), UBOUND(InData%Vwnd_NW,2) + DO i1 = LBOUND(InData%Vwnd_NW,1), UBOUND(InData%Vwnd_NW,1) + ReKiBuf(Re_Xferred) = InData%Vwnd_NW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vwnd_FW) ) 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%Vwnd_FW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_FW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_FW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_FW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_FW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_FW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_FW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_FW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%Vwnd_FW,4), UBOUND(InData%Vwnd_FW,4) + DO i3 = LBOUND(InData%Vwnd_FW,3), UBOUND(InData%Vwnd_FW,3) + DO i2 = LBOUND(InData%Vwnd_FW,2), UBOUND(InData%Vwnd_FW,2) + DO i1 = LBOUND(InData%Vwnd_FW,1), UBOUND(InData%Vwnd_FW,1) + ReKiBuf(Re_Xferred) = InData%Vwnd_FW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vind_NW) ) 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_NW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_NW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_NW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_NW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_NW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_NW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_NW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_NW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%Vind_NW,4), UBOUND(InData%Vind_NW,4) + DO i3 = LBOUND(InData%Vind_NW,3), UBOUND(InData%Vind_NW,3) + DO i2 = LBOUND(InData%Vind_NW,2), UBOUND(InData%Vind_NW,2) + DO i1 = LBOUND(InData%Vind_NW,1), UBOUND(InData%Vind_NW,1) + ReKiBuf(Re_Xferred) = InData%Vind_NW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vind_FW) ) 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_FW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_FW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_FW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_FW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_FW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_FW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_FW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_FW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%Vind_FW,4), UBOUND(InData%Vind_FW,4) + DO i3 = LBOUND(InData%Vind_FW,3), UBOUND(InData%Vind_FW,3) + DO i2 = LBOUND(InData%Vind_FW,2), UBOUND(InData%Vind_FW,2) + DO i1 = LBOUND(InData%Vind_FW,1), UBOUND(InData%Vind_FW,1) + ReKiBuf(Re_Xferred) = InData%Vind_FW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IntKiBuf(Int_Xferred) = InData%nNW + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nFW + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%iStep + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VTKstep + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%VTKlastTime + Db_Xferred = Db_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%r_wind) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_wind,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_wind,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_wind,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_wind,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%r_wind,2), UBOUND(InData%r_wind,2) + DO i1 = LBOUND(InData%r_wind,1), UBOUND(InData%r_wind,1) + ReKiBuf(Re_Xferred) = InData%r_wind(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%PitchAndTwist) ) 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%PitchAndTwist,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PitchAndTwist,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%PitchAndTwist,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PitchAndTwist,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%PitchAndTwist,2), UBOUND(InData%PitchAndTwist,2) + DO i1 = LBOUND(InData%PitchAndTwist,1), UBOUND(InData%PitchAndTwist,1) + ReKiBuf(Re_Xferred) = InData%PitchAndTwist(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IntKiBuf(Int_Xferred) = TRANSFER(InData%ComputeWakeInduced, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%OldWakeTime + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%tSpent + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%dxdt_NW) ) 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%dxdt_NW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_NW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_NW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_NW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_NW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_NW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_NW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_NW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%dxdt_NW,4), UBOUND(InData%dxdt_NW,4) + DO i3 = LBOUND(InData%dxdt_NW,3), UBOUND(InData%dxdt_NW,3) + DO i2 = LBOUND(InData%dxdt_NW,2), UBOUND(InData%dxdt_NW,2) + DO i1 = LBOUND(InData%dxdt_NW,1), UBOUND(InData%dxdt_NW,1) + ReKiBuf(Re_Xferred) = InData%dxdt_NW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%dxdt_FW) ) 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%dxdt_FW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_FW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_FW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_FW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_FW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_FW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%dxdt_FW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%dxdt_FW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%dxdt_FW,4), UBOUND(InData%dxdt_FW,4) + DO i3 = LBOUND(InData%dxdt_FW,3), UBOUND(InData%dxdt_FW,3) + DO i2 = LBOUND(InData%dxdt_FW,2), UBOUND(InData%dxdt_FW,2) + DO i1 = LBOUND(InData%dxdt_FW,1), UBOUND(InData%dxdt_FW,1) + ReKiBuf(Re_Xferred) = InData%dxdt_FW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%alpha_LL) ) 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%alpha_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%alpha_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%alpha_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%alpha_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%alpha_LL,2), UBOUND(InData%alpha_LL,2) + DO i1 = LBOUND(InData%alpha_LL,1), UBOUND(InData%alpha_LL,1) + ReKiBuf(Re_Xferred) = InData%alpha_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vreln_LL) ) 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%Vreln_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vreln_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vreln_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vreln_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Vreln_LL,2), UBOUND(InData%Vreln_LL,2) + DO i1 = LBOUND(InData%Vreln_LL,1), UBOUND(InData%Vreln_LL,1) + ReKiBuf(Re_Xferred) = InData%Vreln_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%SegConnct) ) 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%SegConnct,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegConnct,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%SegConnct,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegConnct,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%SegConnct,2), UBOUND(InData%SegConnct,2) + DO i1 = LBOUND(InData%SegConnct,1), UBOUND(InData%SegConnct,1) + IntKiBuf(Int_Xferred) = InData%SegConnct(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%SegPoints) ) 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%SegPoints,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegPoints,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%SegPoints,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegPoints,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%SegPoints,2), UBOUND(InData%SegPoints,2) + DO i1 = LBOUND(InData%SegPoints,1), UBOUND(InData%SegPoints,1) + ReKiBuf(Re_Xferred) = InData%SegPoints(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%SegGamma) ) 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%SegGamma,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegGamma,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%SegGamma,1), UBOUND(InData%SegGamma,1) + ReKiBuf(Re_Xferred) = InData%SegGamma(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%SegEpsilon) ) 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%SegEpsilon,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%SegEpsilon,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%SegEpsilon,1), UBOUND(InData%SegEpsilon,1) + ReKiBuf(Re_Xferred) = InData%SegEpsilon(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%CPs) ) 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%CPs,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CPs,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CPs,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CPs,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%CPs,2), UBOUND(InData%CPs,2) + DO i1 = LBOUND(InData%CPs,1), UBOUND(InData%CPs,1) + ReKiBuf(Re_Xferred) = InData%CPs(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Uind) ) 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%Uind,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Uind,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Uind,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Uind,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Uind,2), UBOUND(InData%Uind,2) + DO i1 = LBOUND(InData%Uind,1), UBOUND(InData%Uind,1) + ReKiBuf(Re_Xferred) = InData%Uind(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_AxInd) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_AxInd,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_AxInd,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_AxInd,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_AxInd,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_AxInd,2), UBOUND(InData%BN_AxInd,2) + DO i1 = LBOUND(InData%BN_AxInd,1), UBOUND(InData%BN_AxInd,1) + ReKiBuf(Re_Xferred) = InData%BN_AxInd(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_TanInd) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_TanInd,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_TanInd,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_TanInd,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_TanInd,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_TanInd,2), UBOUND(InData%BN_TanInd,2) + DO i1 = LBOUND(InData%BN_TanInd,1), UBOUND(InData%BN_TanInd,1) + ReKiBuf(Re_Xferred) = InData%BN_TanInd(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Vrel) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Vrel,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Vrel,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Vrel,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Vrel,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Vrel,2), UBOUND(InData%BN_Vrel,2) + DO i1 = LBOUND(InData%BN_Vrel,1), UBOUND(InData%BN_Vrel,1) + ReKiBuf(Re_Xferred) = InData%BN_Vrel(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_alpha) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_alpha,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_alpha,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_alpha,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_alpha,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_alpha,2), UBOUND(InData%BN_alpha,2) + DO i1 = LBOUND(InData%BN_alpha,1), UBOUND(InData%BN_alpha,1) + ReKiBuf(Re_Xferred) = InData%BN_alpha(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_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%BN_phi,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_phi,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_phi,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_phi,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_phi,2), UBOUND(InData%BN_phi,2) + DO i1 = LBOUND(InData%BN_phi,1), UBOUND(InData%BN_phi,1) + ReKiBuf(Re_Xferred) = InData%BN_phi(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Re) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Re,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Re,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Re,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Re,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Re,2), UBOUND(InData%BN_Re,2) + DO i1 = LBOUND(InData%BN_Re,1), UBOUND(InData%BN_Re,1) + ReKiBuf(Re_Xferred) = InData%BN_Re(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_URelWind_s) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_URelWind_s,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_URelWind_s,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_URelWind_s,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_URelWind_s,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_URelWind_s,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_URelWind_s,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%BN_URelWind_s,3), UBOUND(InData%BN_URelWind_s,3) + DO i2 = LBOUND(InData%BN_URelWind_s,2), UBOUND(InData%BN_URelWind_s,2) + DO i1 = LBOUND(InData%BN_URelWind_s,1), UBOUND(InData%BN_URelWind_s,1) + ReKiBuf(Re_Xferred) = InData%BN_URelWind_s(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cl_Static) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cl_Static,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cl_Static,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cl_Static,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cl_Static,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cl_Static,2), UBOUND(InData%BN_Cl_Static,2) + DO i1 = LBOUND(InData%BN_Cl_Static,1), UBOUND(InData%BN_Cl_Static,1) + ReKiBuf(Re_Xferred) = InData%BN_Cl_Static(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cd_Static) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cd_Static,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cd_Static,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cd_Static,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cd_Static,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cd_Static,2), UBOUND(InData%BN_Cd_Static,2) + DO i1 = LBOUND(InData%BN_Cd_Static,1), UBOUND(InData%BN_Cd_Static,1) + ReKiBuf(Re_Xferred) = InData%BN_Cd_Static(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cm_Static) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cm_Static,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cm_Static,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cm_Static,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cm_Static,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cm_Static,2), UBOUND(InData%BN_Cm_Static,2) + DO i1 = LBOUND(InData%BN_Cm_Static,1), UBOUND(InData%BN_Cm_Static,1) + ReKiBuf(Re_Xferred) = InData%BN_Cm_Static(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cl) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cl,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cl,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cl,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cl,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cl,2), UBOUND(InData%BN_Cl,2) + DO i1 = LBOUND(InData%BN_Cl,1), UBOUND(InData%BN_Cl,1) + ReKiBuf(Re_Xferred) = InData%BN_Cl(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cd) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cd,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cd,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cd,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cd,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cd,2), UBOUND(InData%BN_Cd,2) + DO i1 = LBOUND(InData%BN_Cd,1), UBOUND(InData%BN_Cd,1) + ReKiBuf(Re_Xferred) = InData%BN_Cd(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cm) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cm,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cm,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cm,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cm,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cm,2), UBOUND(InData%BN_Cm,2) + DO i1 = LBOUND(InData%BN_Cm,1), UBOUND(InData%BN_Cm,1) + ReKiBuf(Re_Xferred) = InData%BN_Cm(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cx,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cx,2), UBOUND(InData%BN_Cx,2) + DO i1 = LBOUND(InData%BN_Cx,1), UBOUND(InData%BN_Cx,1) + ReKiBuf(Re_Xferred) = InData%BN_Cx(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%BN_Cy) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cy,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cy,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BN_Cy,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BN_Cy,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%BN_Cy,2), UBOUND(InData%BN_Cy,2) + DO i1 = LBOUND(InData%BN_Cy,1), UBOUND(InData%BN_Cy,1) + ReKiBuf(Re_Xferred) = InData%BN_Cy(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + CALL UA_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%m_UA, ErrStat2, ErrMsg2, OnlySize ) ! m_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 UA_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%y_UA, ErrStat2, ErrMsg2, OnlySize ) ! y_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 UA_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%p_UA, ErrStat2, ErrMsg2, OnlySize ) ! p_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 + IntKiBuf(Int_Xferred) = TRANSFER(InData%UA_Flag, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%Vwnd_ND) ) 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%Vwnd_ND,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_ND,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_ND,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_ND,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vwnd_ND,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vwnd_ND,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vwnd_ND,3), UBOUND(InData%Vwnd_ND,3) + DO i2 = LBOUND(InData%Vwnd_ND,2), UBOUND(InData%Vwnd_ND,2) + DO i1 = LBOUND(InData%Vwnd_ND,1), UBOUND(InData%Vwnd_ND,1) + ReKiBuf(Re_Xferred) = InData%Vwnd_ND(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + END SUBROUTINE FVW_PackMisc + + SUBROUTINE FVW_UnPackMisc( 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(FVW_MiscVarType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_UnPackMisc' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%FirstCall = TRANSFER(IntKiBuf(Int_Xferred), OutData%FirstCall) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! LE 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%LE)) DEALLOCATE(OutData%LE) + ALLOCATE(OutData%LE(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%LE.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%LE,3), UBOUND(OutData%LE,3) + DO i2 = LBOUND(OutData%LE,2), UBOUND(OutData%LE,2) + DO i1 = LBOUND(OutData%LE,1), UBOUND(OutData%LE,1) + OutData%LE(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 ! TE 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%TE)) DEALLOCATE(OutData%TE) + ALLOCATE(OutData%TE(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%TE.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%TE,3), UBOUND(OutData%TE,3) + DO i2 = LBOUND(OutData%TE,2), UBOUND(OutData%TE,2) + DO i1 = LBOUND(OutData%TE,1), UBOUND(OutData%TE,1) + OutData%TE(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 ! r_LL not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%r_LL)) DEALLOCATE(OutData%r_LL) + ALLOCATE(OutData%r_LL(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%r_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%r_LL,4), UBOUND(OutData%r_LL,4) + DO i3 = LBOUND(OutData%r_LL,3), UBOUND(OutData%r_LL,3) + DO i2 = LBOUND(OutData%r_LL,2), UBOUND(OutData%r_LL,2) + DO i1 = LBOUND(OutData%r_LL,1), UBOUND(OutData%r_LL,1) + OutData%r_LL(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! s_LL 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%s_LL)) DEALLOCATE(OutData%s_LL) + ALLOCATE(OutData%s_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%s_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%s_LL,2), UBOUND(OutData%s_LL,2) + DO i1 = LBOUND(OutData%s_LL,1), UBOUND(OutData%s_LL,1) + OutData%s_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! chord_LL 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%chord_LL)) DEALLOCATE(OutData%chord_LL) + ALLOCATE(OutData%chord_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%chord_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%chord_LL,2), UBOUND(OutData%chord_LL,2) + DO i1 = LBOUND(OutData%chord_LL,1), UBOUND(OutData%chord_LL,1) + OutData%chord_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! s_CP_LL 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%s_CP_LL)) DEALLOCATE(OutData%s_CP_LL) + ALLOCATE(OutData%s_CP_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%s_CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%s_CP_LL,2), UBOUND(OutData%s_CP_LL,2) + DO i1 = LBOUND(OutData%s_CP_LL,1), UBOUND(OutData%s_CP_LL,1) + OutData%s_CP_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! chord_CP_LL 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%chord_CP_LL)) DEALLOCATE(OutData%chord_CP_LL) + ALLOCATE(OutData%chord_CP_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%chord_CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%chord_CP_LL,2), UBOUND(OutData%chord_CP_LL,2) + DO i1 = LBOUND(OutData%chord_CP_LL,1), UBOUND(OutData%chord_CP_LL,1) + OutData%chord_CP_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CP_LL 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%CP_LL)) DEALLOCATE(OutData%CP_LL) + ALLOCATE(OutData%CP_LL(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%CP_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%CP_LL,3), UBOUND(OutData%CP_LL,3) + DO i2 = LBOUND(OutData%CP_LL,2), UBOUND(OutData%CP_LL,2) + DO i1 = LBOUND(OutData%CP_LL,1), UBOUND(OutData%CP_LL,1) + OutData%CP_LL(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 ! Tang 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%Tang)) DEALLOCATE(OutData%Tang) + ALLOCATE(OutData%Tang(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%Tang.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Tang,3), UBOUND(OutData%Tang,3) + DO i2 = LBOUND(OutData%Tang,2), UBOUND(OutData%Tang,2) + DO i1 = LBOUND(OutData%Tang,1), UBOUND(OutData%Tang,1) + OutData%Tang(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 ! Norm 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%Norm)) DEALLOCATE(OutData%Norm) + ALLOCATE(OutData%Norm(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%Norm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Norm,3), UBOUND(OutData%Norm,3) + DO i2 = LBOUND(OutData%Norm,2), UBOUND(OutData%Norm,2) + DO i1 = LBOUND(OutData%Norm,1), UBOUND(OutData%Norm,1) + OutData%Norm(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 ! Orth 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%Orth)) DEALLOCATE(OutData%Orth) + ALLOCATE(OutData%Orth(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%Orth.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Orth,3), UBOUND(OutData%Orth,3) + DO i2 = LBOUND(OutData%Orth,2), UBOUND(OutData%Orth,2) + DO i1 = LBOUND(OutData%Orth,1), UBOUND(OutData%Orth,1) + OutData%Orth(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 ! dl 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%dl)) DEALLOCATE(OutData%dl) + ALLOCATE(OutData%dl(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%dl.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%dl,3), UBOUND(OutData%dl,3) + DO i2 = LBOUND(OutData%dl,2), UBOUND(OutData%dl,2) + DO i1 = LBOUND(OutData%dl,1), UBOUND(OutData%dl,1) + OutData%dl(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 ! Area 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%Area)) DEALLOCATE(OutData%Area) + ALLOCATE(OutData%Area(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Area.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Area,2), UBOUND(OutData%Area,2) + DO i1 = LBOUND(OutData%Area,1), UBOUND(OutData%Area,1) + OutData%Area(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! diag_LL 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%diag_LL)) DEALLOCATE(OutData%diag_LL) + ALLOCATE(OutData%diag_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%diag_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%diag_LL,2), UBOUND(OutData%diag_LL,2) + DO i1 = LBOUND(OutData%diag_LL,1), UBOUND(OutData%diag_LL,1) + OutData%diag_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Gamma_LL 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%Gamma_LL)) DEALLOCATE(OutData%Gamma_LL) + ALLOCATE(OutData%Gamma_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Gamma_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Gamma_LL,2), UBOUND(OutData%Gamma_LL,2) + DO i1 = LBOUND(OutData%Gamma_LL,1), UBOUND(OutData%Gamma_LL,1) + OutData%Gamma_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vind_LL 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_LL)) DEALLOCATE(OutData%Vind_LL) + ALLOCATE(OutData%Vind_LL(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_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vind_LL,3), UBOUND(OutData%Vind_LL,3) + DO i2 = LBOUND(OutData%Vind_LL,2), UBOUND(OutData%Vind_LL,2) + DO i1 = LBOUND(OutData%Vind_LL,1), UBOUND(OutData%Vind_LL,1) + OutData%Vind_LL(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 ! Vtot_LL 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%Vtot_LL)) DEALLOCATE(OutData%Vtot_LL) + ALLOCATE(OutData%Vtot_LL(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%Vtot_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vtot_LL,3), UBOUND(OutData%Vtot_LL,3) + DO i2 = LBOUND(OutData%Vtot_LL,2), UBOUND(OutData%Vtot_LL,2) + DO i1 = LBOUND(OutData%Vtot_LL,1), UBOUND(OutData%Vtot_LL,1) + OutData%Vtot_LL(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 ! Vstr_LL 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%Vstr_LL)) DEALLOCATE(OutData%Vstr_LL) + ALLOCATE(OutData%Vstr_LL(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%Vstr_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vstr_LL,3), UBOUND(OutData%Vstr_LL,3) + DO i2 = LBOUND(OutData%Vstr_LL,2), UBOUND(OutData%Vstr_LL,2) + DO i1 = LBOUND(OutData%Vstr_LL,1), UBOUND(OutData%Vstr_LL,1) + OutData%Vstr_LL(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 ! Vwnd_LL 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%Vwnd_LL)) DEALLOCATE(OutData%Vwnd_LL) + ALLOCATE(OutData%Vwnd_LL(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%Vwnd_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vwnd_LL,3), UBOUND(OutData%Vwnd_LL,3) + DO i2 = LBOUND(OutData%Vwnd_LL,2), UBOUND(OutData%Vwnd_LL,2) + DO i1 = LBOUND(OutData%Vwnd_LL,1), UBOUND(OutData%Vwnd_LL,1) + OutData%Vwnd_LL(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 ! Vwnd_NW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Vwnd_NW)) DEALLOCATE(OutData%Vwnd_NW) + ALLOCATE(OutData%Vwnd_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vwnd_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%Vwnd_NW,4), UBOUND(OutData%Vwnd_NW,4) + DO i3 = LBOUND(OutData%Vwnd_NW,3), UBOUND(OutData%Vwnd_NW,3) + DO i2 = LBOUND(OutData%Vwnd_NW,2), UBOUND(OutData%Vwnd_NW,2) + DO i1 = LBOUND(OutData%Vwnd_NW,1), UBOUND(OutData%Vwnd_NW,1) + OutData%Vwnd_NW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vwnd_FW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Vwnd_FW)) DEALLOCATE(OutData%Vwnd_FW) + ALLOCATE(OutData%Vwnd_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vwnd_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%Vwnd_FW,4), UBOUND(OutData%Vwnd_FW,4) + DO i3 = LBOUND(OutData%Vwnd_FW,3), UBOUND(OutData%Vwnd_FW,3) + DO i2 = LBOUND(OutData%Vwnd_FW,2), UBOUND(OutData%Vwnd_FW,2) + DO i1 = LBOUND(OutData%Vwnd_FW,1), UBOUND(OutData%Vwnd_FW,1) + OutData%Vwnd_FW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vind_NW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Vind_NW)) DEALLOCATE(OutData%Vind_NW) + ALLOCATE(OutData%Vind_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vind_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%Vind_NW,4), UBOUND(OutData%Vind_NW,4) + DO i3 = LBOUND(OutData%Vind_NW,3), UBOUND(OutData%Vind_NW,3) + DO i2 = LBOUND(OutData%Vind_NW,2), UBOUND(OutData%Vind_NW,2) + DO i1 = LBOUND(OutData%Vind_NW,1), UBOUND(OutData%Vind_NW,1) + OutData%Vind_NW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vind_FW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Vind_FW)) DEALLOCATE(OutData%Vind_FW) + ALLOCATE(OutData%Vind_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vind_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%Vind_FW,4), UBOUND(OutData%Vind_FW,4) + DO i3 = LBOUND(OutData%Vind_FW,3), UBOUND(OutData%Vind_FW,3) + DO i2 = LBOUND(OutData%Vind_FW,2), UBOUND(OutData%Vind_FW,2) + DO i1 = LBOUND(OutData%Vind_FW,1), UBOUND(OutData%Vind_FW,1) + OutData%Vind_FW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + OutData%nNW = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nFW = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%iStep = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%VTKstep = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%VTKlastTime = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! r_wind 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%r_wind)) DEALLOCATE(OutData%r_wind) + ALLOCATE(OutData%r_wind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%r_wind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%r_wind,2), UBOUND(OutData%r_wind,2) + DO i1 = LBOUND(OutData%r_wind,1), UBOUND(OutData%r_wind,1) + OutData%r_wind(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! PitchAndTwist 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%PitchAndTwist)) DEALLOCATE(OutData%PitchAndTwist) + ALLOCATE(OutData%PitchAndTwist(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%PitchAndTwist.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%PitchAndTwist,2), UBOUND(OutData%PitchAndTwist,2) + DO i1 = LBOUND(OutData%PitchAndTwist,1), UBOUND(OutData%PitchAndTwist,1) + OutData%PitchAndTwist(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + OutData%ComputeWakeInduced = TRANSFER(IntKiBuf(Int_Xferred), OutData%ComputeWakeInduced) + Int_Xferred = Int_Xferred + 1 + OutData%OldWakeTime = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%tSpent = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! dxdt_NW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%dxdt_NW)) DEALLOCATE(OutData%dxdt_NW) + ALLOCATE(OutData%dxdt_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%dxdt_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%dxdt_NW,4), UBOUND(OutData%dxdt_NW,4) + DO i3 = LBOUND(OutData%dxdt_NW,3), UBOUND(OutData%dxdt_NW,3) + DO i2 = LBOUND(OutData%dxdt_NW,2), UBOUND(OutData%dxdt_NW,2) + DO i1 = LBOUND(OutData%dxdt_NW,1), UBOUND(OutData%dxdt_NW,1) + OutData%dxdt_NW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! dxdt_FW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%dxdt_FW)) DEALLOCATE(OutData%dxdt_FW) + ALLOCATE(OutData%dxdt_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%dxdt_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%dxdt_FW,4), UBOUND(OutData%dxdt_FW,4) + DO i3 = LBOUND(OutData%dxdt_FW,3), UBOUND(OutData%dxdt_FW,3) + DO i2 = LBOUND(OutData%dxdt_FW,2), UBOUND(OutData%dxdt_FW,2) + DO i1 = LBOUND(OutData%dxdt_FW,1), UBOUND(OutData%dxdt_FW,1) + OutData%dxdt_FW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! alpha_LL 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%alpha_LL)) DEALLOCATE(OutData%alpha_LL) + ALLOCATE(OutData%alpha_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%alpha_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%alpha_LL,2), UBOUND(OutData%alpha_LL,2) + DO i1 = LBOUND(OutData%alpha_LL,1), UBOUND(OutData%alpha_LL,1) + OutData%alpha_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vreln_LL 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%Vreln_LL)) DEALLOCATE(OutData%Vreln_LL) + ALLOCATE(OutData%Vreln_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vreln_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Vreln_LL,2), UBOUND(OutData%Vreln_LL,2) + DO i1 = LBOUND(OutData%Vreln_LL,1), UBOUND(OutData%Vreln_LL,1) + OutData%Vreln_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! SegConnct 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%SegConnct)) DEALLOCATE(OutData%SegConnct) + ALLOCATE(OutData%SegConnct(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%SegConnct.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%SegConnct,2), UBOUND(OutData%SegConnct,2) + DO i1 = LBOUND(OutData%SegConnct,1), UBOUND(OutData%SegConnct,1) + OutData%SegConnct(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! SegPoints 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%SegPoints)) DEALLOCATE(OutData%SegPoints) + ALLOCATE(OutData%SegPoints(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%SegPoints.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%SegPoints,2), UBOUND(OutData%SegPoints,2) + DO i1 = LBOUND(OutData%SegPoints,1), UBOUND(OutData%SegPoints,1) + OutData%SegPoints(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! SegGamma 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%SegGamma)) DEALLOCATE(OutData%SegGamma) + ALLOCATE(OutData%SegGamma(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%SegGamma.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%SegGamma,1), UBOUND(OutData%SegGamma,1) + OutData%SegGamma(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! SegEpsilon 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%SegEpsilon)) DEALLOCATE(OutData%SegEpsilon) + ALLOCATE(OutData%SegEpsilon(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%SegEpsilon.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%SegEpsilon,1), UBOUND(OutData%SegEpsilon,1) + OutData%SegEpsilon(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CPs 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%CPs)) DEALLOCATE(OutData%CPs) + ALLOCATE(OutData%CPs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%CPs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%CPs,2), UBOUND(OutData%CPs,2) + DO i1 = LBOUND(OutData%CPs,1), UBOUND(OutData%CPs,1) + OutData%CPs(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Uind 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%Uind)) DEALLOCATE(OutData%Uind) + ALLOCATE(OutData%Uind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Uind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Uind,2), UBOUND(OutData%Uind,2) + DO i1 = LBOUND(OutData%Uind,1), UBOUND(OutData%Uind,1) + OutData%Uind(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_AxInd 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%BN_AxInd)) DEALLOCATE(OutData%BN_AxInd) + ALLOCATE(OutData%BN_AxInd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_AxInd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_AxInd,2), UBOUND(OutData%BN_AxInd,2) + DO i1 = LBOUND(OutData%BN_AxInd,1), UBOUND(OutData%BN_AxInd,1) + OutData%BN_AxInd(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_TanInd 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%BN_TanInd)) DEALLOCATE(OutData%BN_TanInd) + ALLOCATE(OutData%BN_TanInd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_TanInd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_TanInd,2), UBOUND(OutData%BN_TanInd,2) + DO i1 = LBOUND(OutData%BN_TanInd,1), UBOUND(OutData%BN_TanInd,1) + OutData%BN_TanInd(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Vrel 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%BN_Vrel)) DEALLOCATE(OutData%BN_Vrel) + ALLOCATE(OutData%BN_Vrel(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Vrel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Vrel,2), UBOUND(OutData%BN_Vrel,2) + DO i1 = LBOUND(OutData%BN_Vrel,1), UBOUND(OutData%BN_Vrel,1) + OutData%BN_Vrel(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_alpha 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%BN_alpha)) DEALLOCATE(OutData%BN_alpha) + ALLOCATE(OutData%BN_alpha(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_alpha.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_alpha,2), UBOUND(OutData%BN_alpha,2) + DO i1 = LBOUND(OutData%BN_alpha,1), UBOUND(OutData%BN_alpha,1) + OutData%BN_alpha(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_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%BN_phi)) DEALLOCATE(OutData%BN_phi) + ALLOCATE(OutData%BN_phi(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_phi.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_phi,2), UBOUND(OutData%BN_phi,2) + DO i1 = LBOUND(OutData%BN_phi,1), UBOUND(OutData%BN_phi,1) + OutData%BN_phi(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Re 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%BN_Re)) DEALLOCATE(OutData%BN_Re) + ALLOCATE(OutData%BN_Re(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Re.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Re,2), UBOUND(OutData%BN_Re,2) + DO i1 = LBOUND(OutData%BN_Re,1), UBOUND(OutData%BN_Re,1) + OutData%BN_Re(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_URelWind_s not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + 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%BN_URelWind_s)) DEALLOCATE(OutData%BN_URelWind_s) + ALLOCATE(OutData%BN_URelWind_s(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%BN_URelWind_s.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%BN_URelWind_s,3), UBOUND(OutData%BN_URelWind_s,3) + DO i2 = LBOUND(OutData%BN_URelWind_s,2), UBOUND(OutData%BN_URelWind_s,2) + DO i1 = LBOUND(OutData%BN_URelWind_s,1), UBOUND(OutData%BN_URelWind_s,1) + OutData%BN_URelWind_s(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 ! BN_Cl_Static 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%BN_Cl_Static)) DEALLOCATE(OutData%BN_Cl_Static) + ALLOCATE(OutData%BN_Cl_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cl_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cl_Static,2), UBOUND(OutData%BN_Cl_Static,2) + DO i1 = LBOUND(OutData%BN_Cl_Static,1), UBOUND(OutData%BN_Cl_Static,1) + OutData%BN_Cl_Static(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cd_Static 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%BN_Cd_Static)) DEALLOCATE(OutData%BN_Cd_Static) + ALLOCATE(OutData%BN_Cd_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cd_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cd_Static,2), UBOUND(OutData%BN_Cd_Static,2) + DO i1 = LBOUND(OutData%BN_Cd_Static,1), UBOUND(OutData%BN_Cd_Static,1) + OutData%BN_Cd_Static(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cm_Static 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%BN_Cm_Static)) DEALLOCATE(OutData%BN_Cm_Static) + ALLOCATE(OutData%BN_Cm_Static(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cm_Static.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cm_Static,2), UBOUND(OutData%BN_Cm_Static,2) + DO i1 = LBOUND(OutData%BN_Cm_Static,1), UBOUND(OutData%BN_Cm_Static,1) + OutData%BN_Cm_Static(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cl 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%BN_Cl)) DEALLOCATE(OutData%BN_Cl) + ALLOCATE(OutData%BN_Cl(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cl.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cl,2), UBOUND(OutData%BN_Cl,2) + DO i1 = LBOUND(OutData%BN_Cl,1), UBOUND(OutData%BN_Cl,1) + OutData%BN_Cl(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cd 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%BN_Cd)) DEALLOCATE(OutData%BN_Cd) + ALLOCATE(OutData%BN_Cd(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cd,2), UBOUND(OutData%BN_Cd,2) + DO i1 = LBOUND(OutData%BN_Cd,1), UBOUND(OutData%BN_Cd,1) + OutData%BN_Cd(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cm 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%BN_Cm)) DEALLOCATE(OutData%BN_Cm) + ALLOCATE(OutData%BN_Cm(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cm,2), UBOUND(OutData%BN_Cm,2) + DO i1 = LBOUND(OutData%BN_Cm,1), UBOUND(OutData%BN_Cm,1) + OutData%BN_Cm(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cx 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%BN_Cx)) DEALLOCATE(OutData%BN_Cx) + ALLOCATE(OutData%BN_Cx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cx,2), UBOUND(OutData%BN_Cx,2) + DO i1 = LBOUND(OutData%BN_Cx,1), UBOUND(OutData%BN_Cx,1) + OutData%BN_Cx(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BN_Cy 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%BN_Cy)) DEALLOCATE(OutData%BN_Cy) + ALLOCATE(OutData%BN_Cy(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BN_Cy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%BN_Cy,2), UBOUND(OutData%BN_Cy,2) + DO i1 = LBOUND(OutData%BN_Cy,1), UBOUND(OutData%BN_Cy,1) + OutData%BN_Cy(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + 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_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%m_UA, ErrStat2, ErrMsg2 ) ! m_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 + 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) + 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_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%p_UA, ErrStat2, ErrMsg2 ) ! p_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) + OutData%UA_Flag = TRANSFER(IntKiBuf(Int_Xferred), OutData%UA_Flag) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vwnd_ND 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%Vwnd_ND)) DEALLOCATE(OutData%Vwnd_ND) + ALLOCATE(OutData%Vwnd_ND(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%Vwnd_ND.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vwnd_ND,3), UBOUND(OutData%Vwnd_ND,3) + DO i2 = LBOUND(OutData%Vwnd_ND,2), UBOUND(OutData%Vwnd_ND,2) + DO i1 = LBOUND(OutData%Vwnd_ND,1), UBOUND(OutData%Vwnd_ND,1) + OutData%Vwnd_ND(i1,i2,i3) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + END SUBROUTINE FVW_UnPackMisc + + SUBROUTINE FVW_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_InputType), INTENT(INOUT) :: SrcInputData + TYPE(FVW_InputType), INTENT(INOUT) :: DstInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_CopyInput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcInputData%WingsMesh)) THEN + i1_l = LBOUND(SrcInputData%WingsMesh,1) + i1_u = UBOUND(SrcInputData%WingsMesh,1) + IF (.NOT. ALLOCATED(DstInputData%WingsMesh)) THEN + ALLOCATE(DstInputData%WingsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%WingsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcInputData%WingsMesh,1), UBOUND(SrcInputData%WingsMesh,1) + CALL MeshCopy( SrcInputData%WingsMesh(i1), DstInputData%WingsMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcInputData%V_wind)) THEN + i1_l = LBOUND(SrcInputData%V_wind,1) + i1_u = UBOUND(SrcInputData%V_wind,1) + i2_l = LBOUND(SrcInputData%V_wind,2) + i2_u = UBOUND(SrcInputData%V_wind,2) + IF (.NOT. ALLOCATED(DstInputData%V_wind)) THEN + ALLOCATE(DstInputData%V_wind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%V_wind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%V_wind = SrcInputData%V_wind +ENDIF + DstInputData%HubOrientation = SrcInputData%HubOrientation + DstInputData%HubPosition = SrcInputData%HubPosition + END SUBROUTINE FVW_CopyInput + + SUBROUTINE FVW_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(FVW_InputType), INTENT(INOUT) :: InputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InputData%WingsMesh)) THEN +DO i1 = LBOUND(InputData%WingsMesh,1), UBOUND(InputData%WingsMesh,1) + CALL MeshDestroy( InputData%WingsMesh(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(InputData%WingsMesh) +ENDIF +IF (ALLOCATED(InputData%V_wind)) THEN + DEALLOCATE(InputData%V_wind) +ENDIF + END SUBROUTINE FVW_DestroyInput + + SUBROUTINE FVW_PackInput( 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(FVW_InputType), 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 = 'FVW_PackInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! WingsMesh allocated yes/no + IF ( ALLOCATED(InData%WingsMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WingsMesh upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%WingsMesh,1), UBOUND(InData%WingsMesh,1) + Int_BufSz = Int_BufSz + 3 ! WingsMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! WingsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! WingsMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! WingsMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! WingsMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! V_wind allocated yes/no + IF ( ALLOCATED(InData%V_wind) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! V_wind upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%V_wind) ! V_wind + END IF + Re_BufSz = Re_BufSz + SIZE(InData%HubOrientation) ! HubOrientation + Re_BufSz = Re_BufSz + SIZE(InData%HubPosition) ! HubPosition + 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%WingsMesh) ) 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%WingsMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WingsMesh,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WingsMesh,1), UBOUND(InData%WingsMesh,1) + CALL MeshPack( InData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! WingsMesh + 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%V_wind) ) 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%V_wind,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%V_wind,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%V_wind,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%V_wind,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%V_wind,2), UBOUND(InData%V_wind,2) + DO i1 = LBOUND(InData%V_wind,1), UBOUND(InData%V_wind,1) + ReKiBuf(Re_Xferred) = InData%V_wind(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + DO i2 = LBOUND(InData%HubOrientation,2), UBOUND(InData%HubOrientation,2) + DO i1 = LBOUND(InData%HubOrientation,1), UBOUND(InData%HubOrientation,1) + ReKiBuf(Re_Xferred) = InData%HubOrientation(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + DO i1 = LBOUND(InData%HubPosition,1), UBOUND(InData%HubPosition,1) + ReKiBuf(Re_Xferred) = InData%HubPosition(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE FVW_PackInput + + SUBROUTINE FVW_UnPackInput( 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(FVW_InputType), 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 = 'FVW_UnPackInput' + ! 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 ! WingsMesh 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%WingsMesh)) DEALLOCATE(OutData%WingsMesh) + ALLOCATE(OutData%WingsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WingsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WingsMesh,1), UBOUND(OutData%WingsMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! WingsMesh + 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 ! V_wind 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%V_wind)) DEALLOCATE(OutData%V_wind) + ALLOCATE(OutData%V_wind(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%V_wind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%V_wind,2), UBOUND(OutData%V_wind,2) + DO i1 = LBOUND(OutData%V_wind,1), UBOUND(OutData%V_wind,1) + OutData%V_wind(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + i1_l = LBOUND(OutData%HubOrientation,1) + i1_u = UBOUND(OutData%HubOrientation,1) + i2_l = LBOUND(OutData%HubOrientation,2) + i2_u = UBOUND(OutData%HubOrientation,2) + DO i2 = LBOUND(OutData%HubOrientation,2), UBOUND(OutData%HubOrientation,2) + DO i1 = LBOUND(OutData%HubOrientation,1), UBOUND(OutData%HubOrientation,1) + OutData%HubOrientation(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + i1_l = LBOUND(OutData%HubPosition,1) + i1_u = UBOUND(OutData%HubPosition,1) + DO i1 = LBOUND(OutData%HubPosition,1), UBOUND(OutData%HubPosition,1) + OutData%HubPosition(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE FVW_UnPackInput + + SUBROUTINE FVW_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_OutputType), INTENT(IN) :: SrcOutputData + TYPE(FVW_OutputType), INTENT(INOUT) :: DstOutputData + 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 = 'FVW_CopyOutput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcOutputData%Vind)) THEN + i1_l = LBOUND(SrcOutputData%Vind,1) + i1_u = UBOUND(SrcOutputData%Vind,1) + i2_l = LBOUND(SrcOutputData%Vind,2) + i2_u = UBOUND(SrcOutputData%Vind,2) + i3_l = LBOUND(SrcOutputData%Vind,3) + i3_u = UBOUND(SrcOutputData%Vind,3) + IF (.NOT. ALLOCATED(DstOutputData%Vind)) THEN + ALLOCATE(DstOutputData%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 DstOutputData%Vind.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%Vind = SrcOutputData%Vind +ENDIF +IF (ALLOCATED(SrcOutputData%Cl_KJ)) THEN + i1_l = LBOUND(SrcOutputData%Cl_KJ,1) + i1_u = UBOUND(SrcOutputData%Cl_KJ,1) + i2_l = LBOUND(SrcOutputData%Cl_KJ,2) + i2_u = UBOUND(SrcOutputData%Cl_KJ,2) + IF (.NOT. ALLOCATED(DstOutputData%Cl_KJ)) THEN + ALLOCATE(DstOutputData%Cl_KJ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%Cl_KJ.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%Cl_KJ = SrcOutputData%Cl_KJ +ENDIF + END SUBROUTINE FVW_CopyOutput + + SUBROUTINE FVW_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(FVW_OutputType), INTENT(INOUT) :: OutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(OutputData%Vind)) THEN + DEALLOCATE(OutputData%Vind) +ENDIF +IF (ALLOCATED(OutputData%Cl_KJ)) THEN + DEALLOCATE(OutputData%Cl_KJ) +ENDIF + END SUBROUTINE FVW_DestroyOutput + + SUBROUTINE FVW_PackOutput( 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(FVW_OutputType), 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 = 'FVW_PackOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! 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 ! Cl_KJ allocated yes/no + IF ( ALLOCATED(InData%Cl_KJ) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Cl_KJ upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Cl_KJ) ! Cl_KJ + 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%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%Cl_KJ) ) 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%Cl_KJ,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Cl_KJ,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Cl_KJ,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Cl_KJ,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Cl_KJ,2), UBOUND(InData%Cl_KJ,2) + DO i1 = LBOUND(InData%Cl_KJ,1), UBOUND(InData%Cl_KJ,1) + ReKiBuf(Re_Xferred) = InData%Cl_KJ(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_PackOutput + + SUBROUTINE FVW_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(FVW_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: 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 = 'FVW_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! 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 ! Cl_KJ 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%Cl_KJ)) DEALLOCATE(OutData%Cl_KJ) + ALLOCATE(OutData%Cl_KJ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Cl_KJ.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Cl_KJ,2), UBOUND(OutData%Cl_KJ,2) + DO i1 = LBOUND(OutData%Cl_KJ,1), UBOUND(OutData%Cl_KJ,1) + OutData%Cl_KJ(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_UnPackOutput + + SUBROUTINE FVW_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(FVW_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) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_CopyContState' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcContStateData%Gamma_NW)) THEN + i1_l = LBOUND(SrcContStateData%Gamma_NW,1) + i1_u = UBOUND(SrcContStateData%Gamma_NW,1) + i2_l = LBOUND(SrcContStateData%Gamma_NW,2) + i2_u = UBOUND(SrcContStateData%Gamma_NW,2) + i3_l = LBOUND(SrcContStateData%Gamma_NW,3) + i3_u = UBOUND(SrcContStateData%Gamma_NW,3) + IF (.NOT. ALLOCATED(DstContStateData%Gamma_NW)) THEN + ALLOCATE(DstContStateData%Gamma_NW(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%Gamma_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%Gamma_NW = SrcContStateData%Gamma_NW +ENDIF +IF (ALLOCATED(SrcContStateData%Gamma_FW)) THEN + i1_l = LBOUND(SrcContStateData%Gamma_FW,1) + i1_u = UBOUND(SrcContStateData%Gamma_FW,1) + i2_l = LBOUND(SrcContStateData%Gamma_FW,2) + i2_u = UBOUND(SrcContStateData%Gamma_FW,2) + i3_l = LBOUND(SrcContStateData%Gamma_FW,3) + i3_u = UBOUND(SrcContStateData%Gamma_FW,3) + IF (.NOT. ALLOCATED(DstContStateData%Gamma_FW)) THEN + ALLOCATE(DstContStateData%Gamma_FW(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%Gamma_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%Gamma_FW = SrcContStateData%Gamma_FW +ENDIF +IF (ALLOCATED(SrcContStateData%r_NW)) THEN + i1_l = LBOUND(SrcContStateData%r_NW,1) + i1_u = UBOUND(SrcContStateData%r_NW,1) + i2_l = LBOUND(SrcContStateData%r_NW,2) + i2_u = UBOUND(SrcContStateData%r_NW,2) + i3_l = LBOUND(SrcContStateData%r_NW,3) + i3_u = UBOUND(SrcContStateData%r_NW,3) + i4_l = LBOUND(SrcContStateData%r_NW,4) + i4_u = UBOUND(SrcContStateData%r_NW,4) + IF (.NOT. ALLOCATED(DstContStateData%r_NW)) THEN + ALLOCATE(DstContStateData%r_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%r_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%r_NW = SrcContStateData%r_NW +ENDIF +IF (ALLOCATED(SrcContStateData%r_FW)) THEN + i1_l = LBOUND(SrcContStateData%r_FW,1) + i1_u = UBOUND(SrcContStateData%r_FW,1) + i2_l = LBOUND(SrcContStateData%r_FW,2) + i2_u = UBOUND(SrcContStateData%r_FW,2) + i3_l = LBOUND(SrcContStateData%r_FW,3) + i3_u = UBOUND(SrcContStateData%r_FW,3) + i4_l = LBOUND(SrcContStateData%r_FW,4) + i4_u = UBOUND(SrcContStateData%r_FW,4) + IF (.NOT. ALLOCATED(DstContStateData%r_FW)) THEN + ALLOCATE(DstContStateData%r_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%r_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%r_FW = SrcContStateData%r_FW +ENDIF + END SUBROUTINE FVW_CopyContState + + SUBROUTINE FVW_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(FVW_ContinuousStateType), INTENT(INOUT) :: ContStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyContState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ContStateData%Gamma_NW)) THEN + DEALLOCATE(ContStateData%Gamma_NW) +ENDIF +IF (ALLOCATED(ContStateData%Gamma_FW)) THEN + DEALLOCATE(ContStateData%Gamma_FW) +ENDIF +IF (ALLOCATED(ContStateData%r_NW)) THEN + DEALLOCATE(ContStateData%r_NW) +ENDIF +IF (ALLOCATED(ContStateData%r_FW)) THEN + DEALLOCATE(ContStateData%r_FW) +ENDIF + END SUBROUTINE FVW_DestroyContState + + SUBROUTINE FVW_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(FVW_ContinuousStateType), 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 = 'FVW_PackContState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! Gamma_NW allocated yes/no + IF ( ALLOCATED(InData%Gamma_NW) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Gamma_NW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Gamma_NW) ! Gamma_NW + END IF + Int_BufSz = Int_BufSz + 1 ! Gamma_FW allocated yes/no + IF ( ALLOCATED(InData%Gamma_FW) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Gamma_FW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Gamma_FW) ! Gamma_FW + END IF + Int_BufSz = Int_BufSz + 1 ! r_NW allocated yes/no + IF ( ALLOCATED(InData%r_NW) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! r_NW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%r_NW) ! r_NW + END IF + Int_BufSz = Int_BufSz + 1 ! r_FW allocated yes/no + IF ( ALLOCATED(InData%r_FW) ) THEN + 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 + 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%Gamma_NW) ) 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%Gamma_NW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_NW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_NW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_NW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_NW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_NW,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Gamma_NW,3), UBOUND(InData%Gamma_NW,3) + DO i2 = LBOUND(InData%Gamma_NW,2), UBOUND(InData%Gamma_NW,2) + DO i1 = LBOUND(InData%Gamma_NW,1), UBOUND(InData%Gamma_NW,1) + ReKiBuf(Re_Xferred) = InData%Gamma_NW(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Gamma_FW) ) 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%Gamma_FW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_FW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_FW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_FW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_FW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_FW,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Gamma_FW,3), UBOUND(InData%Gamma_FW,3) + DO i2 = LBOUND(InData%Gamma_FW,2), UBOUND(InData%Gamma_FW,2) + DO i1 = LBOUND(InData%Gamma_FW,1), UBOUND(InData%Gamma_FW,1) + ReKiBuf(Re_Xferred) = InData%Gamma_FW(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%r_NW) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_NW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_NW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_NW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_NW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_NW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_NW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_NW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_NW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%r_NW,4), UBOUND(InData%r_NW,4) + DO i3 = LBOUND(InData%r_NW,3), UBOUND(InData%r_NW,3) + DO i2 = LBOUND(InData%r_NW,2), UBOUND(InData%r_NW,2) + DO i1 = LBOUND(InData%r_NW,1), UBOUND(InData%r_NW,1) + ReKiBuf(Re_Xferred) = InData%r_NW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%r_FW) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_FW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_FW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_FW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_FW,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_FW,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_FW,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%r_FW,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%r_FW,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%r_FW,4), UBOUND(InData%r_FW,4) + DO i3 = LBOUND(InData%r_FW,3), UBOUND(InData%r_FW,3) + DO i2 = LBOUND(InData%r_FW,2), UBOUND(InData%r_FW,2) + DO i1 = LBOUND(InData%r_FW,1), UBOUND(InData%r_FW,1) + ReKiBuf(Re_Xferred) = InData%r_FW(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE FVW_PackContState + + SUBROUTINE FVW_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(FVW_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) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_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 ! Gamma_NW 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%Gamma_NW)) DEALLOCATE(OutData%Gamma_NW) + ALLOCATE(OutData%Gamma_NW(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%Gamma_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Gamma_NW,3), UBOUND(OutData%Gamma_NW,3) + DO i2 = LBOUND(OutData%Gamma_NW,2), UBOUND(OutData%Gamma_NW,2) + DO i1 = LBOUND(OutData%Gamma_NW,1), UBOUND(OutData%Gamma_NW,1) + OutData%Gamma_NW(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 ! Gamma_FW 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%Gamma_FW)) DEALLOCATE(OutData%Gamma_FW) + ALLOCATE(OutData%Gamma_FW(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%Gamma_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Gamma_FW,3), UBOUND(OutData%Gamma_FW,3) + DO i2 = LBOUND(OutData%Gamma_FW,2), UBOUND(OutData%Gamma_FW,2) + DO i1 = LBOUND(OutData%Gamma_FW,1), UBOUND(OutData%Gamma_FW,1) + OutData%Gamma_FW(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 ! r_NW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%r_NW)) DEALLOCATE(OutData%r_NW) + ALLOCATE(OutData%r_NW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%r_NW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%r_NW,4), UBOUND(OutData%r_NW,4) + DO i3 = LBOUND(OutData%r_NW,3), UBOUND(OutData%r_NW,3) + DO i2 = LBOUND(OutData%r_NW,2), UBOUND(OutData%r_NW,2) + DO i1 = LBOUND(OutData%r_NW,1), UBOUND(OutData%r_NW,1) + OutData%r_NW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! r_FW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%r_FW)) DEALLOCATE(OutData%r_FW) + ALLOCATE(OutData%r_FW(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%r_FW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%r_FW,4), UBOUND(OutData%r_FW,4) + DO i3 = LBOUND(OutData%r_FW,3), UBOUND(OutData%r_FW,3) + DO i2 = LBOUND(OutData%r_FW,2), UBOUND(OutData%r_FW,2) + DO i1 = LBOUND(OutData%r_FW,1), UBOUND(OutData%r_FW,1) + OutData%r_FW(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE FVW_UnPackContState + + SUBROUTINE FVW_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(FVW_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 = 'FVW_CopyDiscState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstDiscStateData%NULL = SrcDiscStateData%NULL + CALL UA_CopyDiscState( SrcDiscStateData%UA, DstDiscStateData%UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + END SUBROUTINE FVW_CopyDiscState + + SUBROUTINE FVW_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(FVW_DiscreteStateType), INTENT(INOUT) :: DiscStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyDiscState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + CALL UA_DestroyDiscState( DiscStateData%UA, ErrStat, ErrMsg ) + END SUBROUTINE FVW_DestroyDiscState + + SUBROUTINE FVW_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(FVW_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 = 'FVW_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 ! NULL + ! 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_PackDiscState( 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 + 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 + + ReKiBuf(Re_Xferred) = InData%NULL + Re_Xferred = Re_Xferred + 1 + CALL UA_PackDiscState( 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_PackDiscState + + SUBROUTINE FVW_UnPackDiscState( 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(FVW_DiscreteStateType), 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) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_UnPackDiscState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%NULL = ReKiBuf(Re_Xferred) + 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_UnpackDiscState( 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_UnPackDiscState + + SUBROUTINE FVW_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_ConstraintStateType), INTENT(IN) :: SrcConstrStateData + TYPE(FVW_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + 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 = 'FVW_CopyConstrState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstConstrStateData%residual = SrcConstrStateData%residual +IF (ALLOCATED(SrcConstrStateData%Gamma_LL)) THEN + i1_l = LBOUND(SrcConstrStateData%Gamma_LL,1) + i1_u = UBOUND(SrcConstrStateData%Gamma_LL,1) + i2_l = LBOUND(SrcConstrStateData%Gamma_LL,2) + i2_u = UBOUND(SrcConstrStateData%Gamma_LL,2) + IF (.NOT. ALLOCATED(DstConstrStateData%Gamma_LL)) THEN + ALLOCATE(DstConstrStateData%Gamma_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstConstrStateData%Gamma_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstConstrStateData%Gamma_LL = SrcConstrStateData%Gamma_LL +ENDIF + END SUBROUTINE FVW_CopyConstrState + + SUBROUTINE FVW_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) + TYPE(FVW_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyConstrState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ConstrStateData%Gamma_LL)) THEN + DEALLOCATE(ConstrStateData%Gamma_LL) +ENDIF + END SUBROUTINE FVW_DestroyConstrState + + SUBROUTINE FVW_PackConstrState( 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(FVW_ConstraintStateType), 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 = 'FVW_PackConstrState' + ! 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 ! residual + Int_BufSz = Int_BufSz + 1 ! Gamma_LL allocated yes/no + IF ( ALLOCATED(InData%Gamma_LL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Gamma_LL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Gamma_LL) ! Gamma_LL + 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 + + ReKiBuf(Re_Xferred) = InData%residual + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%Gamma_LL) ) 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%Gamma_LL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_LL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Gamma_LL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma_LL,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Gamma_LL,2), UBOUND(InData%Gamma_LL,2) + DO i1 = LBOUND(InData%Gamma_LL,1), UBOUND(InData%Gamma_LL,1) + ReKiBuf(Re_Xferred) = InData%Gamma_LL(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_PackConstrState + + SUBROUTINE FVW_UnPackConstrState( 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(FVW_ConstraintStateType), 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 = 'FVW_UnPackConstrState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%residual = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Gamma_LL 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%Gamma_LL)) DEALLOCATE(OutData%Gamma_LL) + ALLOCATE(OutData%Gamma_LL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Gamma_LL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Gamma_LL,2), UBOUND(OutData%Gamma_LL,2) + DO i1 = LBOUND(OutData%Gamma_LL,1), UBOUND(OutData%Gamma_LL,1) + OutData%Gamma_LL(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_UnPackConstrState + + SUBROUTINE FVW_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_OtherStateType), INTENT(IN) :: SrcOtherStateData + TYPE(FVW_OtherStateType), INTENT(INOUT) :: DstOtherStateData + 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 = 'FVW_CopyOtherState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstOtherStateData%NULL = SrcOtherStateData%NULL + CALL UA_CopyOtherState( SrcOtherStateData%UA, DstOtherStateData%UA, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcOtherStateData%UA_Flag)) THEN + i1_l = LBOUND(SrcOtherStateData%UA_Flag,1) + i1_u = UBOUND(SrcOtherStateData%UA_Flag,1) + i2_l = LBOUND(SrcOtherStateData%UA_Flag,2) + i2_u = UBOUND(SrcOtherStateData%UA_Flag,2) + IF (.NOT. ALLOCATED(DstOtherStateData%UA_Flag)) THEN + ALLOCATE(DstOtherStateData%UA_Flag(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOtherStateData%UA_Flag.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOtherStateData%UA_Flag = SrcOtherStateData%UA_Flag +ENDIF + END SUBROUTINE FVW_CopyOtherState + + SUBROUTINE FVW_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) + TYPE(FVW_OtherStateType), INTENT(INOUT) :: OtherStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyOtherState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + CALL UA_DestroyOtherState( OtherStateData%UA, ErrStat, ErrMsg ) +IF (ALLOCATED(OtherStateData%UA_Flag)) THEN + DEALLOCATE(OtherStateData%UA_Flag) +ENDIF + END SUBROUTINE FVW_DestroyOtherState + + SUBROUTINE FVW_PackOtherState( 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(FVW_OtherStateType), 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 = 'FVW_PackOtherState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! NULL + ! 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_PackOtherState( 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 + 1 ! UA_Flag allocated yes/no + IF ( ALLOCATED(InData%UA_Flag) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! UA_Flag upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%UA_Flag) ! UA_Flag + 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 + + IntKiBuf(Int_Xferred) = InData%NULL + Int_Xferred = Int_Xferred + 1 + CALL UA_PackOtherState( 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 + IF ( .NOT. ALLOCATED(InData%UA_Flag) ) 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%UA_Flag,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%UA_Flag,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%UA_Flag,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%UA_Flag,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%UA_Flag,2), UBOUND(InData%UA_Flag,2) + DO i1 = LBOUND(InData%UA_Flag,1), UBOUND(InData%UA_Flag,1) + IntKiBuf(Int_Xferred) = TRANSFER(InData%UA_Flag(i1,i2), IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_PackOtherState + + SUBROUTINE FVW_UnPackOtherState( 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(FVW_OtherStateType), 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 = 'FVW_UnPackOtherState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%NULL = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL UA_UnpackOtherState( 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) + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! UA_Flag 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%UA_Flag)) DEALLOCATE(OutData%UA_Flag) + ALLOCATE(OutData%UA_Flag(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%UA_Flag.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%UA_Flag,2), UBOUND(OutData%UA_Flag,2) + DO i1 = LBOUND(OutData%UA_Flag,1), UBOUND(OutData%UA_Flag,1) + OutData%UA_Flag(i1,i2) = TRANSFER(IntKiBuf(Int_Xferred), OutData%UA_Flag(i1,i2)) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE FVW_UnPackOtherState + + SUBROUTINE FVW_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_InitInputType), INTENT(INOUT) :: SrcInitInputData + TYPE(FVW_InitInputType), INTENT(INOUT) :: DstInitInputData + 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 = 'FVW_CopyInitInput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInitInputData%FVWFileName = SrcInitInputData%FVWFileName + DstInitInputData%RootName = SrcInitInputData%RootName +IF (ALLOCATED(SrcInitInputData%WingsMesh)) THEN + i1_l = LBOUND(SrcInitInputData%WingsMesh,1) + i1_u = UBOUND(SrcInitInputData%WingsMesh,1) + IF (.NOT. ALLOCATED(DstInitInputData%WingsMesh)) THEN + ALLOCATE(DstInitInputData%WingsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%WingsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcInitInputData%WingsMesh,1), UBOUND(SrcInitInputData%WingsMesh,1) + CALL MeshCopy( SrcInitInputData%WingsMesh(i1), DstInitInputData%WingsMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcInitInputData%AFindx)) THEN + i1_l = LBOUND(SrcInitInputData%AFindx,1) + i1_u = UBOUND(SrcInitInputData%AFindx,1) + i2_l = LBOUND(SrcInitInputData%AFindx,2) + i2_u = UBOUND(SrcInitInputData%AFindx,2) + IF (.NOT. ALLOCATED(DstInitInputData%AFindx)) THEN + ALLOCATE(DstInitInputData%AFindx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%AFindx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%AFindx = SrcInitInputData%AFindx +ENDIF +IF (ALLOCATED(SrcInitInputData%Chord)) THEN + i1_l = LBOUND(SrcInitInputData%Chord,1) + i1_u = UBOUND(SrcInitInputData%Chord,1) + i2_l = LBOUND(SrcInitInputData%Chord,2) + i2_u = UBOUND(SrcInitInputData%Chord,2) + IF (.NOT. ALLOCATED(DstInitInputData%Chord)) THEN + ALLOCATE(DstInitInputData%Chord(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%Chord.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%Chord = SrcInitInputData%Chord +ENDIF +IF (ALLOCATED(SrcInitInputData%RElm)) THEN + i1_l = LBOUND(SrcInitInputData%RElm,1) + i1_u = UBOUND(SrcInitInputData%RElm,1) + IF (.NOT. ALLOCATED(DstInitInputData%RElm)) THEN + ALLOCATE(DstInitInputData%RElm(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%RElm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%RElm = SrcInitInputData%RElm +ENDIF +IF (ALLOCATED(SrcInitInputData%zHub)) THEN + i1_l = LBOUND(SrcInitInputData%zHub,1) + i1_u = UBOUND(SrcInitInputData%zHub,1) + IF (.NOT. ALLOCATED(DstInitInputData%zHub)) THEN + ALLOCATE(DstInitInputData%zHub(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%zHub.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%zHub = SrcInitInputData%zHub +ENDIF +IF (ALLOCATED(SrcInitInputData%zLocal)) THEN + i1_l = LBOUND(SrcInitInputData%zLocal,1) + i1_u = UBOUND(SrcInitInputData%zLocal,1) + i2_l = LBOUND(SrcInitInputData%zLocal,2) + i2_u = UBOUND(SrcInitInputData%zLocal,2) + IF (.NOT. ALLOCATED(DstInitInputData%zLocal)) THEN + ALLOCATE(DstInitInputData%zLocal(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%zLocal.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%zLocal = SrcInitInputData%zLocal +ENDIF +IF (ALLOCATED(SrcInitInputData%zTip)) THEN + i1_l = LBOUND(SrcInitInputData%zTip,1) + i1_u = UBOUND(SrcInitInputData%zTip,1) + IF (.NOT. ALLOCATED(DstInitInputData%zTip)) THEN + ALLOCATE(DstInitInputData%zTip(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%zTip.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%zTip = SrcInitInputData%zTip +ENDIF +IF (ALLOCATED(SrcInitInputData%rLocal)) THEN + i1_l = LBOUND(SrcInitInputData%rLocal,1) + i1_u = UBOUND(SrcInitInputData%rLocal,1) + i2_l = LBOUND(SrcInitInputData%rLocal,2) + i2_u = UBOUND(SrcInitInputData%rLocal,2) + IF (.NOT. ALLOCATED(DstInitInputData%rLocal)) THEN + ALLOCATE(DstInitInputData%rLocal(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitInputData%rLocal.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitInputData%rLocal = SrcInitInputData%rLocal +ENDIF + DstInitInputData%NumBlades = SrcInitInputData%NumBlades + DstInitInputData%NumBladeNodes = SrcInitInputData%NumBladeNodes + DstInitInputData%DTaero = SrcInitInputData%DTaero + DstInitInputData%KinVisc = SrcInitInputData%KinVisc + DstInitInputData%UAMod = SrcInitInputData%UAMod + DstInitInputData%UA_Flag = SrcInitInputData%UA_Flag + DstInitInputData%Flookup = SrcInitInputData%Flookup + DstInitInputData%a_s = SrcInitInputData%a_s + END SUBROUTINE FVW_CopyInitInput + + SUBROUTINE FVW_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) + TYPE(FVW_InitInputType), INTENT(INOUT) :: InitInputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyInitInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InitInputData%WingsMesh)) THEN +DO i1 = LBOUND(InitInputData%WingsMesh,1), UBOUND(InitInputData%WingsMesh,1) + CALL MeshDestroy( InitInputData%WingsMesh(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(InitInputData%WingsMesh) +ENDIF +IF (ALLOCATED(InitInputData%AFindx)) THEN + DEALLOCATE(InitInputData%AFindx) +ENDIF +IF (ALLOCATED(InitInputData%Chord)) THEN + DEALLOCATE(InitInputData%Chord) +ENDIF +IF (ALLOCATED(InitInputData%RElm)) THEN + DEALLOCATE(InitInputData%RElm) +ENDIF +IF (ALLOCATED(InitInputData%zHub)) THEN + DEALLOCATE(InitInputData%zHub) +ENDIF +IF (ALLOCATED(InitInputData%zLocal)) THEN + DEALLOCATE(InitInputData%zLocal) +ENDIF +IF (ALLOCATED(InitInputData%zTip)) THEN + DEALLOCATE(InitInputData%zTip) +ENDIF +IF (ALLOCATED(InitInputData%rLocal)) THEN + DEALLOCATE(InitInputData%rLocal) +ENDIF + END SUBROUTINE FVW_DestroyInitInput + + SUBROUTINE FVW_PackInitInput( 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(FVW_InitInputType), 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 = 'FVW_PackInitInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1*LEN(InData%FVWFileName) ! FVWFileName + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Int_BufSz = Int_BufSz + 1 ! WingsMesh allocated yes/no + IF ( ALLOCATED(InData%WingsMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WingsMesh upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%WingsMesh,1), UBOUND(InData%WingsMesh,1) + Int_BufSz = Int_BufSz + 3 ! WingsMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! WingsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! WingsMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! WingsMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! WingsMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! AFindx allocated yes/no + IF ( ALLOCATED(InData%AFindx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! AFindx upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%AFindx) ! AFindx + END IF + Int_BufSz = Int_BufSz + 1 ! Chord allocated yes/no + IF ( ALLOCATED(InData%Chord) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! Chord upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Chord) ! Chord + END IF + Int_BufSz = Int_BufSz + 1 ! RElm allocated yes/no + IF ( ALLOCATED(InData%RElm) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! RElm upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%RElm) ! RElm + END IF + Int_BufSz = Int_BufSz + 1 ! zHub allocated yes/no + IF ( ALLOCATED(InData%zHub) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! zHub upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%zHub) ! zHub + END IF + Int_BufSz = Int_BufSz + 1 ! zLocal allocated yes/no + IF ( ALLOCATED(InData%zLocal) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! zLocal upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%zLocal) ! zLocal + END IF + Int_BufSz = Int_BufSz + 1 ! zTip allocated yes/no + IF ( ALLOCATED(InData%zTip) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! zTip upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%zTip) ! zTip + 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 + Re_BufSz = Re_BufSz + SIZE(InData%rLocal) ! rLocal + END IF + Int_BufSz = Int_BufSz + 1 ! NumBlades + Int_BufSz = Int_BufSz + 1 ! NumBladeNodes + Db_BufSz = Db_BufSz + 1 ! DTaero + Re_BufSz = Re_BufSz + 1 ! KinVisc + Int_BufSz = Int_BufSz + 1 ! UAMod + Int_BufSz = Int_BufSz + 1 ! UA_Flag + Int_BufSz = Int_BufSz + 1 ! Flookup + Re_BufSz = Re_BufSz + 1 ! a_s + 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 I = 1, LEN(InData%FVWFileName) + IntKiBuf(Int_Xferred) = ICHAR(InData%FVWFileName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + IF ( .NOT. ALLOCATED(InData%WingsMesh) ) 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%WingsMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WingsMesh,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WingsMesh,1), UBOUND(InData%WingsMesh,1) + CALL MeshPack( InData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! WingsMesh + 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%AFindx) ) 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%AFindx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AFindx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%AFindx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AFindx,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%AFindx,2), UBOUND(InData%AFindx,2) + DO i1 = LBOUND(InData%AFindx,1), UBOUND(InData%AFindx,1) + IntKiBuf(Int_Xferred) = InData%AFindx(i1,i2) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Chord) ) 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%Chord,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Chord,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Chord,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Chord,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%Chord,2), UBOUND(InData%Chord,2) + DO i1 = LBOUND(InData%Chord,1), UBOUND(InData%Chord,1) + ReKiBuf(Re_Xferred) = InData%Chord(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%RElm) ) 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%RElm,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RElm,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%RElm,1), UBOUND(InData%RElm,1) + ReKiBuf(Re_Xferred) = InData%RElm(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%zHub) ) 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%zHub,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%zHub,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%zHub,1), UBOUND(InData%zHub,1) + ReKiBuf(Re_Xferred) = InData%zHub(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%zLocal) ) 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%zLocal,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%zLocal,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%zLocal,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%zLocal,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%zLocal,2), UBOUND(InData%zLocal,2) + DO i1 = LBOUND(InData%zLocal,1), UBOUND(InData%zLocal,1) + ReKiBuf(Re_Xferred) = InData%zLocal(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%zTip) ) 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%zTip,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%zTip,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%zTip,1), UBOUND(InData%zTip,1) + ReKiBuf(Re_Xferred) = InData%zTip(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%rLocal) ) 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%rLocal,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%rLocal,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%rLocal,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%rLocal,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%rLocal,2), UBOUND(InData%rLocal,2) + DO i1 = LBOUND(InData%rLocal,1), UBOUND(InData%rLocal,1) + ReKiBuf(Re_Xferred) = InData%rLocal(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IntKiBuf(Int_Xferred) = InData%NumBlades + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%NumBladeNodes + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTaero + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%KinVisc + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%UAMod + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%UA_Flag, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%Flookup, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%a_s + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE FVW_PackInitInput + + SUBROUTINE FVW_UnPackInitInput( 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(FVW_InitInputType), 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 = 'FVW_UnPackInitInput' + ! 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 + DO I = 1, LEN(OutData%FVWFileName) + OutData%FVWFileName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%RootName) + OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WingsMesh 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%WingsMesh)) DEALLOCATE(OutData%WingsMesh) + ALLOCATE(OutData%WingsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WingsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WingsMesh,1), UBOUND(OutData%WingsMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%WingsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! WingsMesh + 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 ! AFindx 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%AFindx)) DEALLOCATE(OutData%AFindx) + ALLOCATE(OutData%AFindx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%AFindx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%AFindx,2), UBOUND(OutData%AFindx,2) + DO i1 = LBOUND(OutData%AFindx,1), UBOUND(OutData%AFindx,1) + OutData%AFindx(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Chord 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%Chord)) DEALLOCATE(OutData%Chord) + ALLOCATE(OutData%Chord(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Chord.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%Chord,2), UBOUND(OutData%Chord,2) + DO i1 = LBOUND(OutData%Chord,1), UBOUND(OutData%Chord,1) + OutData%Chord(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RElm 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%RElm)) DEALLOCATE(OutData%RElm) + ALLOCATE(OutData%RElm(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RElm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%RElm,1), UBOUND(OutData%RElm,1) + OutData%RElm(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! zHub 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%zHub)) DEALLOCATE(OutData%zHub) + ALLOCATE(OutData%zHub(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%zHub.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%zHub,1), UBOUND(OutData%zHub,1) + OutData%zHub(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! zLocal 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%zLocal)) DEALLOCATE(OutData%zLocal) + ALLOCATE(OutData%zLocal(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%zLocal.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%zLocal,2), UBOUND(OutData%zLocal,2) + DO i1 = LBOUND(OutData%zLocal,1), UBOUND(OutData%zLocal,1) + OutData%zLocal(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! zTip 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%zTip)) DEALLOCATE(OutData%zTip) + ALLOCATE(OutData%zTip(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%zTip.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%zTip,1), UBOUND(OutData%zTip,1) + OutData%zTip(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! rLocal 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%rLocal)) DEALLOCATE(OutData%rLocal) + ALLOCATE(OutData%rLocal(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%rLocal.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%rLocal,2), UBOUND(OutData%rLocal,2) + DO i1 = LBOUND(OutData%rLocal,1), UBOUND(OutData%rLocal,1) + OutData%rLocal(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + OutData%NumBlades = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%NumBladeNodes = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%DTaero = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%KinVisc = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%UAMod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%UA_Flag = TRANSFER(IntKiBuf(Int_Xferred), OutData%UA_Flag) + Int_Xferred = Int_Xferred + 1 + OutData%Flookup = TRANSFER(IntKiBuf(Int_Xferred), OutData%Flookup) + Int_Xferred = Int_Xferred + 1 + OutData%a_s = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE FVW_UnPackInitInput + + SUBROUTINE FVW_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_InputFile), INTENT(IN) :: SrcInputFileData + TYPE(FVW_InputFile), INTENT(INOUT) :: DstInputFileData + 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 = 'FVW_CopyInputFile' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInputFileData%CirculationMethod = SrcInputFileData%CirculationMethod + DstInputFileData%CirculationFile = SrcInputFileData%CirculationFile + DstInputFileData%CircSolvMaxIter = SrcInputFileData%CircSolvMaxIter + DstInputFileData%CircSolvConvCrit = SrcInputFileData%CircSolvConvCrit + DstInputFileData%CircSolvRelaxation = SrcInputFileData%CircSolvRelaxation + DstInputFileData%IntMethod = SrcInputFileData%IntMethod + DstInputFileData%FreeWake = SrcInputFileData%FreeWake + DstInputFileData%FreeWakeStart = SrcInputFileData%FreeWakeStart + DstInputFileData%FullCirculationStart = SrcInputFileData%FullCirculationStart + DstInputFileData%DTfvw = SrcInputFileData%DTfvw + DstInputFileData%CircSolvPolar = SrcInputFileData%CircSolvPolar + DstInputFileData%nNWPanels = SrcInputFileData%nNWPanels + DstInputFileData%nFWPanels = SrcInputFileData%nFWPanels + DstInputFileData%nFWPanelsFree = SrcInputFileData%nFWPanelsFree + DstInputFileData%FWShedVorticity = SrcInputFileData%FWShedVorticity + DstInputFileData%DiffusionMethod = SrcInputFileData%DiffusionMethod + DstInputFileData%CoreSpreadEddyVisc = SrcInputFileData%CoreSpreadEddyVisc + DstInputFileData%RegDeterMethod = SrcInputFileData%RegDeterMethod + DstInputFileData%RegFunction = SrcInputFileData%RegFunction + DstInputFileData%WakeRegMethod = SrcInputFileData%WakeRegMethod + DstInputFileData%WakeRegParam = SrcInputFileData%WakeRegParam + DstInputFileData%WingRegParam = SrcInputFileData%WingRegParam + DstInputFileData%ShearModel = SrcInputFileData%ShearModel + DstInputFileData%TwrShadowOnWake = SrcInputFileData%TwrShadowOnWake + DstInputFileData%VelocityMethod = SrcInputFileData%VelocityMethod + DstInputFileData%TreeBranchFactor = SrcInputFileData%TreeBranchFactor + DstInputFileData%PartPerSegment = SrcInputFileData%PartPerSegment + DstInputFileData%WrVTK = SrcInputFileData%WrVTK + DstInputFileData%VTKBlades = SrcInputFileData%VTKBlades + DstInputFileData%DTvtk = SrcInputFileData%DTvtk + DstInputFileData%VTKCoord = SrcInputFileData%VTKCoord + END SUBROUTINE FVW_CopyInputFile + + SUBROUTINE FVW_DestroyInputFile( InputFileData, ErrStat, ErrMsg ) + TYPE(FVW_InputFile), INTENT(INOUT) :: InputFileData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyInputFile' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE FVW_DestroyInputFile + + SUBROUTINE FVW_PackInputFile( 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(FVW_InputFile), 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 = 'FVW_PackInputFile' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! CirculationMethod + Int_BufSz = Int_BufSz + 1*LEN(InData%CirculationFile) ! CirculationFile + Int_BufSz = Int_BufSz + 1 ! CircSolvMaxIter + Re_BufSz = Re_BufSz + 1 ! CircSolvConvCrit + Re_BufSz = Re_BufSz + 1 ! CircSolvRelaxation + Int_BufSz = Int_BufSz + 1 ! IntMethod + Int_BufSz = Int_BufSz + 1 ! FreeWake + Re_BufSz = Re_BufSz + 1 ! FreeWakeStart + Re_BufSz = Re_BufSz + 1 ! FullCirculationStart + Db_BufSz = Db_BufSz + 1 ! DTfvw + Int_BufSz = Int_BufSz + 1 ! CircSolvPolar + Int_BufSz = Int_BufSz + 1 ! nNWPanels + Int_BufSz = Int_BufSz + 1 ! nFWPanels + Int_BufSz = Int_BufSz + 1 ! nFWPanelsFree + Int_BufSz = Int_BufSz + 1 ! FWShedVorticity + Int_BufSz = Int_BufSz + 1 ! DiffusionMethod + Re_BufSz = Re_BufSz + 1 ! CoreSpreadEddyVisc + Int_BufSz = Int_BufSz + 1 ! RegDeterMethod + Int_BufSz = Int_BufSz + 1 ! RegFunction + Int_BufSz = Int_BufSz + 1 ! WakeRegMethod + Re_BufSz = Re_BufSz + 1 ! WakeRegParam + Re_BufSz = Re_BufSz + 1 ! WingRegParam + Int_BufSz = Int_BufSz + 1 ! ShearModel + Int_BufSz = Int_BufSz + 1 ! TwrShadowOnWake + Int_BufSz = Int_BufSz + 1 ! VelocityMethod + Re_BufSz = Re_BufSz + 1 ! TreeBranchFactor + Int_BufSz = Int_BufSz + 1 ! PartPerSegment + Int_BufSz = Int_BufSz + 1 ! WrVTK + Int_BufSz = Int_BufSz + 1 ! VTKBlades + Db_BufSz = Db_BufSz + 1 ! DTvtk + Int_BufSz = Int_BufSz + 1 ! VTKCoord + 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 + + IntKiBuf(Int_Xferred) = InData%CirculationMethod + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(InData%CirculationFile) + IntKiBuf(Int_Xferred) = ICHAR(InData%CirculationFile(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + IntKiBuf(Int_Xferred) = InData%CircSolvMaxIter + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CircSolvConvCrit + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CircSolvRelaxation + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%IntMethod + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%FreeWake, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%FreeWakeStart + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%FullCirculationStart + Re_Xferred = Re_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTfvw + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%CircSolvPolar + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nNWPanels + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nFWPanels + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%nFWPanelsFree + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%FWShedVorticity, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%DiffusionMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%CoreSpreadEddyVisc + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%RegDeterMethod + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%RegFunction + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%WakeRegMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%WakeRegParam + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%WingRegParam + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%ShearModel + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%TwrShadowOnWake, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VelocityMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TreeBranchFactor + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%PartPerSegment + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%WrVTK + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VTKBlades + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DTvtk + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%VTKCoord + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE FVW_PackInputFile + + SUBROUTINE FVW_UnPackInputFile( 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(FVW_InputFile), 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) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_UnPackInputFile' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%CirculationMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(OutData%CirculationFile) + OutData%CirculationFile(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + OutData%CircSolvMaxIter = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%CircSolvConvCrit = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%CircSolvRelaxation = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%IntMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%FreeWake = TRANSFER(IntKiBuf(Int_Xferred), OutData%FreeWake) + Int_Xferred = Int_Xferred + 1 + OutData%FreeWakeStart = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%FullCirculationStart = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%DTfvw = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%CircSolvPolar = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nNWPanels = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nFWPanels = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%nFWPanelsFree = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%FWShedVorticity = TRANSFER(IntKiBuf(Int_Xferred), OutData%FWShedVorticity) + Int_Xferred = Int_Xferred + 1 + OutData%DiffusionMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%CoreSpreadEddyVisc = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RegDeterMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%RegFunction = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%WakeRegMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%WakeRegParam = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%WingRegParam = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%ShearModel = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%TwrShadowOnWake = TRANSFER(IntKiBuf(Int_Xferred), OutData%TwrShadowOnWake) + Int_Xferred = Int_Xferred + 1 + OutData%VelocityMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%TreeBranchFactor = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%PartPerSegment = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%WrVTK = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%VTKBlades = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%DTvtk = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%VTKCoord = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE FVW_UnPackInputFile + + SUBROUTINE FVW_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(FVW_InitOutputType), INTENT(IN) :: SrcInitOutputData + TYPE(FVW_InitOutputType), INTENT(INOUT) :: DstInitOutputData + 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 = 'FVW_CopyInitOutput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInitOutputData%Null = SrcInitOutputData%Null + END SUBROUTINE FVW_CopyInitOutput + + SUBROUTINE FVW_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) + TYPE(FVW_InitOutputType), INTENT(INOUT) :: InitOutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_DestroyInitOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE FVW_DestroyInitOutput + + SUBROUTINE FVW_PackInitOutput( 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(FVW_InitOutputType), 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 = 'FVW_PackInitOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! Null + 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 + + IntKiBuf(Int_Xferred) = InData%Null + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE FVW_PackInitOutput + + SUBROUTINE FVW_UnPackInitOutput( 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(FVW_InitOutputType), 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) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_UnPackInitOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%Null = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE FVW_UnPackInitOutput + + + SUBROUTINE FVW_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(FVW_InputType), INTENT(INOUT) :: u(:) ! Input at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Inputs + TYPE(FVW_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_Input_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 FVW_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL FVW_Input_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 FVW_Input_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 FVW_Input_ExtrapInterp + + + SUBROUTINE FVW_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(FVW_InputType), INTENT(INOUT) :: u1 ! Input at t1 > t2 + TYPE(FVW_InputType), INTENT(INOUT) :: u2 ! Input at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs + TYPE(FVW_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_Input_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 :: 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 = "" + ! 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) +IF (ALLOCATED(u_out%WingsMesh) .AND. ALLOCATED(u1%WingsMesh)) THEN + DO i1 = LBOUND(u_out%WingsMesh,1),UBOUND(u_out%WingsMesh,1) + CALL MeshExtrapInterp1(u1%WingsMesh(i1), u2%WingsMesh(i1), tin, u_out%WingsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(u_out%V_wind) .AND. ALLOCATED(u1%V_wind)) THEN + DO i2 = LBOUND(u_out%V_wind,2),UBOUND(u_out%V_wind,2) + DO i1 = LBOUND(u_out%V_wind,1),UBOUND(u_out%V_wind,1) + b = -(u1%V_wind(i1,i2) - u2%V_wind(i1,i2)) + u_out%V_wind(i1,i2) = u1%V_wind(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated + DO i2 = LBOUND(u_out%HubOrientation,2),UBOUND(u_out%HubOrientation,2) + DO i1 = LBOUND(u_out%HubOrientation,1),UBOUND(u_out%HubOrientation,1) + b = -(u1%HubOrientation(i1,i2) - u2%HubOrientation(i1,i2)) + u_out%HubOrientation(i1,i2) = u1%HubOrientation(i1,i2) + b * ScaleFactor + END DO + END DO + DO i1 = LBOUND(u_out%HubPosition,1),UBOUND(u_out%HubPosition,1) + b = -(u1%HubPosition(i1) - u2%HubPosition(i1)) + u_out%HubPosition(i1) = u1%HubPosition(i1) + b * ScaleFactor + END DO + END SUBROUTINE FVW_Input_ExtrapInterp1 + + + SUBROUTINE FVW_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(FVW_InputType), INTENT(INOUT) :: u1 ! Input at t1 > t2 > t3 + TYPE(FVW_InputType), INTENT(INOUT) :: u2 ! Input at t2 > t3 + TYPE(FVW_InputType), INTENT(INOUT) :: u3 ! Input at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs + TYPE(FVW_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: 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 = 'FVW_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 = "" + ! 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))) +IF (ALLOCATED(u_out%WingsMesh) .AND. ALLOCATED(u1%WingsMesh)) THEN + DO i1 = LBOUND(u_out%WingsMesh,1),UBOUND(u_out%WingsMesh,1) + CALL MeshExtrapInterp2(u1%WingsMesh(i1), u2%WingsMesh(i1), u3%WingsMesh(i1), tin, u_out%WingsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(u_out%V_wind) .AND. ALLOCATED(u1%V_wind)) THEN + DO i2 = LBOUND(u_out%V_wind,2),UBOUND(u_out%V_wind,2) + DO i1 = LBOUND(u_out%V_wind,1),UBOUND(u_out%V_wind,1) + b = (t(3)**2*(u1%V_wind(i1,i2) - u2%V_wind(i1,i2)) + t(2)**2*(-u1%V_wind(i1,i2) + u3%V_wind(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%V_wind(i1,i2) + t(3)*u2%V_wind(i1,i2) - t(2)*u3%V_wind(i1,i2) ) * scaleFactor + u_out%V_wind(i1,i2) = u1%V_wind(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated + DO i2 = LBOUND(u_out%HubOrientation,2),UBOUND(u_out%HubOrientation,2) + DO i1 = LBOUND(u_out%HubOrientation,1),UBOUND(u_out%HubOrientation,1) + b = (t(3)**2*(u1%HubOrientation(i1,i2) - u2%HubOrientation(i1,i2)) + t(2)**2*(-u1%HubOrientation(i1,i2) + u3%HubOrientation(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*u1%HubOrientation(i1,i2) + t(3)*u2%HubOrientation(i1,i2) - t(2)*u3%HubOrientation(i1,i2) ) * scaleFactor + u_out%HubOrientation(i1,i2) = u1%HubOrientation(i1,i2) + b + c * t_out + END DO + END DO + DO i1 = LBOUND(u_out%HubPosition,1),UBOUND(u_out%HubPosition,1) + b = (t(3)**2*(u1%HubPosition(i1) - u2%HubPosition(i1)) + t(2)**2*(-u1%HubPosition(i1) + u3%HubPosition(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%HubPosition(i1) + t(3)*u2%HubPosition(i1) - t(2)*u3%HubPosition(i1) ) * scaleFactor + u_out%HubPosition(i1) = u1%HubPosition(i1) + b + c * t_out + END DO + END SUBROUTINE FVW_Input_ExtrapInterp2 + + + SUBROUTINE FVW_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is given by the size of y +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(FVW_OutputType), INTENT(IN) :: y(:) ! Output at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Outputs + TYPE(FVW_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_Output_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(y)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(y)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(y) - 1 + IF ( order .eq. 0 ) THEN + CALL FVW_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL FVW_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL FVW_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(y) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE FVW_Output_ExtrapInterp + + + SUBROUTINE FVW_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = y1, f(t2) = y2 +! +!.................................................................................................................................. + + TYPE(FVW_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 + TYPE(FVW_OutputType), INTENT(IN) :: y2 ! Output at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs + TYPE(FVW_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'FVW_Output_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 :: i02 ! dim2 level 0 counter variable for arrays of ddts + INTEGER :: i03 ! dim3 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + INTEGER :: i2 ! dim2 counter variable for arrays + INTEGER :: i3 ! dim3 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) +IF (ALLOCATED(y_out%Vind) .AND. ALLOCATED(y1%Vind)) THEN + DO i3 = LBOUND(y_out%Vind,3),UBOUND(y_out%Vind,3) + DO i2 = LBOUND(y_out%Vind,2),UBOUND(y_out%Vind,2) + DO i1 = LBOUND(y_out%Vind,1),UBOUND(y_out%Vind,1) + b = -(y1%Vind(i1,i2,i3) - y2%Vind(i1,i2,i3)) + y_out%Vind(i1,i2,i3) = y1%Vind(i1,i2,i3) + b * ScaleFactor + END DO + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%Cl_KJ) .AND. ALLOCATED(y1%Cl_KJ)) THEN + DO i2 = LBOUND(y_out%Cl_KJ,2),UBOUND(y_out%Cl_KJ,2) + DO i1 = LBOUND(y_out%Cl_KJ,1),UBOUND(y_out%Cl_KJ,1) + b = -(y1%Cl_KJ(i1,i2) - y2%Cl_KJ(i1,i2)) + y_out%Cl_KJ(i1,i2) = y1%Cl_KJ(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated + END SUBROUTINE FVW_Output_ExtrapInterp1 + + + SUBROUTINE FVW_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 +! +!.................................................................................................................................. + + TYPE(FVW_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 > t3 + TYPE(FVW_OutputType), INTENT(IN) :: y2 ! Output at t2 > t3 + TYPE(FVW_OutputType), INTENT(IN) :: y3 ! Output at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs + TYPE(FVW_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: 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 = 'FVW_Output_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i02 ! dim2 level 0 counter variable for arrays of ddts + INTEGER :: i03 ! dim3 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + INTEGER :: i2 ! dim2 counter variable for arrays + INTEGER :: i3 ! dim3 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))) +IF (ALLOCATED(y_out%Vind) .AND. ALLOCATED(y1%Vind)) THEN + DO i3 = LBOUND(y_out%Vind,3),UBOUND(y_out%Vind,3) + DO i2 = LBOUND(y_out%Vind,2),UBOUND(y_out%Vind,2) + DO i1 = LBOUND(y_out%Vind,1),UBOUND(y_out%Vind,1) + b = (t(3)**2*(y1%Vind(i1,i2,i3) - y2%Vind(i1,i2,i3)) + t(2)**2*(-y1%Vind(i1,i2,i3) + y3%Vind(i1,i2,i3)))* scaleFactor + c = ( (t(2)-t(3))*y1%Vind(i1,i2,i3) + t(3)*y2%Vind(i1,i2,i3) - t(2)*y3%Vind(i1,i2,i3) ) * scaleFactor + y_out%Vind(i1,i2,i3) = y1%Vind(i1,i2,i3) + b + c * t_out + END DO + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%Cl_KJ) .AND. ALLOCATED(y1%Cl_KJ)) THEN + DO i2 = LBOUND(y_out%Cl_KJ,2),UBOUND(y_out%Cl_KJ,2) + DO i1 = LBOUND(y_out%Cl_KJ,1),UBOUND(y_out%Cl_KJ,1) + b = (t(3)**2*(y1%Cl_KJ(i1,i2) - y2%Cl_KJ(i1,i2)) + t(2)**2*(-y1%Cl_KJ(i1,i2) + y3%Cl_KJ(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%Cl_KJ(i1,i2) + t(3)*y2%Cl_KJ(i1,i2) - t(2)*y3%Cl_KJ(i1,i2) ) * scaleFactor + y_out%Cl_KJ(i1,i2) = y1%Cl_KJ(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated + END SUBROUTINE FVW_Output_ExtrapInterp2 + +END MODULE FVW_Types +!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/aerodyn/src/FVW_VTK.f90 b/modules/aerodyn/src/FVW_VTK.f90 new file mode 100644 index 0000000000..8770d43b83 --- /dev/null +++ b/modules/aerodyn/src/FVW_VTK.f90 @@ -0,0 +1,565 @@ +module FVW_VTK + !use PrecisionMod, only: ReKi + use NWTC_Library, only: ReKi, GetNewUnit + implicit none +! character(8), parameter :: RFMT='F14.5' + !character(8), parameter :: RFMT='E24.15E3' + character(8), parameter :: RFMT='E17.8E3' + character(8), parameter :: IFMT='I7' + + TYPE, PUBLIC :: FVW_VTK_Misc + integer :: vtk_unit + logical :: bFileOpen=.false. + + integer :: nData=0; + integer :: nPoints=0; + + logical :: bBinary = .false. + character(len=255) :: buffer + + ! Reference Frame + real(ReKi),dimension(3,3) :: T_g2b + real(ReKi),dimension(3) :: PO_g + END TYPE FVW_VTK_Misc + + character(1), parameter :: NL = char(10) ! New Line character + + interface vtk_dataset_structured_grid; module procedure & + vtk_dataset_structured_grid_flat, & + vtk_dataset_structured_grid_grid + end interface + + interface vtk_point_data_vector; module procedure & + vtk_point_data_vector_flat, & + vtk_point_data_vector_grid2D,& + vtk_point_data_vector_grid + end interface + interface vtk_point_data_scalar; module procedure & + vtk_point_data_scalar_flat, & + vtk_point_data_scalar_grid2D, & + vtk_point_data_scalar_grid + end interface + interface vtk_cell_data_scalar; module procedure & + vtk_cell_data_scalar_1d,& + vtk_cell_data_scalar_2d + end interface + + public + +contains + + subroutine vtk_misc_init(mvtk) + type(FVW_VTK_Misc),intent(inout) :: mvtk + mvtk%vtk_unit = -1 !< VTK output unit [-] + mvtk%bFileOpen = .false. !< binary file is open [-] + mvtk%bBinary = .false. !< write binary files [-] + mvtk%nData = 0 !< number of data lines [-] + mvtk%nPoints = 0 !< number of points [-] + end subroutine + + !> + subroutine set_vtk_binary_format(bBin,mvtk) + logical, intent(in)::bBin + type(FVW_VTK_Misc),intent(inout) :: mvtk + mvtk%bBinary=bBin + end subroutine + + + !> Save a coordinate transform + ! ALL VTK Will be exported in this coordinate system! + subroutine set_vtk_coordinate_transform(T_g2b_in,PO_g_in,mvtk) + real(ReKi),dimension(3,3), intent(in) :: T_g2b_in + real(ReKi),dimension(3) , intent(in) :: PO_g_in + type(FVW_VTK_Misc),intent(inout) :: mvtk + mvtk%T_g2b=T_g2b_in + mvtk%PO_g=PO_g_in + end subroutine + + logical function vtk_new_ascii_file(filename,label,mvtk) + !use MainIO, only: get_free_unit ,check_io + !use MainIOData, only: bSTOP_ALLOWED + !use FileSystem, only: file_exists + !use Logging, only: log_warning,log_error,log_info + ! + character(len=*),intent(in) :: filename + character(len=*),intent(in) :: label + type(FVW_VTK_Misc),intent(inout) :: mvtk + ! + integer :: iostatvar + logical :: b + + if (.not. mvtk%bFileOpen) then + CALL GetNewUnit( mvtk%vtk_unit ) + if (mvtk%bBinary) then + ! Fortran 2003 stream, otherwise intel fortran ! + !form='UNFORMATTED',access='SEQUENTIAL',action='WRITE',convert='BIG_ENDIAN',recordtype='STREAM',buffered='YES', + !print*,'Not available for this compiler' !COMPAQ-COMPILER + !STOP !COMPAQ-COMPILER + open(unit = mvtk%vtk_unit,file= trim(adjustl(filename)),form='UNFORMATTED',access = 'stream',& !OTHER-COMPILER + action = 'WRITE',convert= 'BIG_ENDIAN',iostat=iostatvar,status='replace') !OTHER-COMPILER + else + open(mvtk%vtk_unit,file=trim(adjustl(filename)),iostat=iostatvar,action="write",status='replace') + endif + if (iostatvar == 0) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'# vtk DataFile Version 3.0'//NL + write(mvtk%vtk_unit)trim(label)//NL + write(mvtk%vtk_unit)'BINARY'//NL + else + write(mvtk%vtk_unit,'(a)') '# vtk DataFile Version 2.0' + write(mvtk%vtk_unit,'(a)') label + write(mvtk%vtk_unit,'(a)') 'ASCII' + write(mvtk%vtk_unit,'(a)') ' ' + endif + + mvtk%bFileOpen=.true. + mvtk%nData=-1; + endif + else + b=.false. + !call log_error('VTK: Cannot open two vtk files at the same time, call vtk_close first') + endif + if (iostatvar ==0) then + vtk_new_ascii_file=.true. + else + vtk_new_ascii_file=.false. + endif + end function + + subroutine vtk_close_file(mvtk) + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + close(mvtk%vtk_unit) + mvtk%bFileOpen=.false. + endif + endsubroutine + + + ! ------------------------------------------------------------------------- + ! --- POLYDATA STUFF + ! ------------------------------------------------------------------------- + subroutine vtk_dataset_polydata(Points,mvtk,bladeFrame) + real(ReKi), dimension(:,:),intent(in) :: Points !< 3 x n + type(FVW_VTK_Misc),intent(inout) :: mvtk + logical, intent(in) :: bladeFrame + integer :: i + if ( mvtk%bFileOpen ) then + mvtk%nPoints=size(Points,2) + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'DATASET POLYDATA'//NL + write(mvtk%buffer,'(A,I0,A)') 'POINTS ', mvtk%nPoints ,' double' + write(mvtk%vtk_unit)trim(mvtk%buffer)//NL + if (bladeFrame) then + do i=1,mvtk%nPoints + write(mvtk%vtk_unit)matmul(mvtk%T_g2b,Points(1:3,i)-mvtk%PO_g) + enddo + else + do i=1,mvtk%nPoints + write(mvtk%vtk_unit)Points(1:3,i) + enddo + endif + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A)') 'DATASET POLYDATA' + write(mvtk%vtk_unit,'(A,I0,A)') 'POINTS ', mvtk%nPoints ,' double' + if (bladeFrame) then + do i=1,mvtk%nPoints + write(mvtk%vtk_unit,'(3'//RFMT//')') matmul(mvtk%T_g2b,Points(1:3,i)-mvtk%PO_g) + enddo + else + do i=1,mvtk%nPoints + write(mvtk%vtk_unit,'(3'//RFMT//')') Points(1:3,i) + enddo + endif + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + + subroutine vtk_lines(L,mvtk) + integer, dimension(:,:),intent(in) :: L !< 2 x n + type(FVW_VTK_Misc),intent(inout) :: mvtk + + integer :: i + + if ( mvtk%bFileOpen ) then + mvtk%nData=size(L,2) + if (mvtk%bBinary) then + write(mvtk%buffer,'(A,I0,A,I0)')'LINES ',mvtk%nData,' ',3*mvtk%nData + write(mvtk%vtk_unit)trim(mvtk%buffer)//NL + do i=1,mvtk%nData + write(mvtk%vtk_unit)2,L(1:2,i) + enddo + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,I0,A,I0)')'LINES ',mvtk%nData,' ',3*mvtk%nData + do i=1,mvtk%nData + write(mvtk%vtk_unit,'(3'//IFMT//')') 2, L(1:2,i) + enddo + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + subroutine vtk_quad(Q,mvtk) + integer, dimension(:,:),intent(in) :: Q !< 4 x n + type(FVW_VTK_Misc),intent(inout) :: mvtk + integer :: i + if ( mvtk%bFileOpen ) then + mvtk%nData=size(Q,2) + if (mvtk%bBinary) then + write(mvtk%buffer,'(A,I0,A,I0)')'POLYGONS ',mvtk%nData,' ',5*mvtk%nData + write(mvtk%vtk_unit)trim(mvtk%buffer)//NL + do i=1,mvtk%nData + write(mvtk%vtk_unit)4,Q(1:4,i) + enddo + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,I0,A,I0)') 'POLYGONS ', mvtk%nData,' ',5*mvtk%nData + do i=1,mvtk%nData + write(mvtk%vtk_unit,'(5'//IFMT//')') 4, Q(1:4,i) + enddo + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + ! ------------------------------------------------------------------------- + ! --- RECTILINEAR + ! ------------------------------------------------------------------------- + subroutine vtk_dataset_rectilinear(v1,v2,v3,mvtk) + real(ReKi), dimension(:),intent(in) :: v1,v2,v3 !< n + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + mvtk%nPoints=size(v1)*size(v2)*size(v3) + if (mvtk%bBinary) then + write(mvtk%vtk_unit) 'DATASET RECTILINEAR_GRID'//NL + write(mvtk%buffer,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', size(v1),' ',size(v2),' ',size(v3) + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%buffer,'(A,I0,A)') 'X_COORDINATES ', size(v1), ' double' + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%vtk_unit)v1 + write(mvtk%vtk_unit)NL + write(mvtk%buffer,'(A,I0,A)') 'Y_COORDINATES ', size(v2), ' double' + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%vtk_unit)v2 + write(mvtk%vtk_unit)NL + write(mvtk%buffer,'(A,I0,A)') 'Z_COORDINATES ', size(v3), ' double' + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%vtk_unit)v3 + !write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A)') 'DATASET RECTILINEAR_GRID' + write(mvtk%vtk_unit,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', size(v1),' ',size(v2),' ',size(v3) + write(mvtk%vtk_unit,'(A,I0,A)') 'X_COORDINATES ', size(v1), ' double' + write(mvtk%vtk_unit,'('//RFMT//')') v1 + write(mvtk%vtk_unit,'(A,I0,A)') 'Y_COORDINATES ', size(v2), ' double' + write(mvtk%vtk_unit,'('//RFMT//')') v2 + write(mvtk%vtk_unit,'(A,I0,A)') 'Z_COORDINATES ', size(v3), ' double' + write(mvtk%vtk_unit,'('//RFMT//')') v3 + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + ! ------------------------------------------------------------------------- + ! --- STRUCTURED GRID (Points dumped without for loop since memory is in proper order) + ! ------------------------------------------------------------------------- + !> Subroutine using flat data as input (not in natural order) + subroutine vtk_dataset_structured_grid_flat(D,n1,n2,n3,mvtk) + integer , intent(in) :: n1,n2,n3 + real(ReKi), dimension(:,:),intent(in)::D + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + mvtk%nPoints=n1*n2*n3 + if (mvtk%bBinary) then + write(mvtk%vtk_unit) 'DATASET STRUCTURED_GRID'//NL + write(mvtk%buffer,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', n1,' ',n2,' ',n3 + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%buffer,'(A,I0,A)') 'POINTS ', mvtk%nPoints, ' double' + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A)') 'DATASET STRUCTURED_GRID' + write(mvtk%vtk_unit,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', n1,' ',n2,' ',n3 + write(mvtk%vtk_unit,'(A,I0,A)') 'POINTS ', mvtk%nPoints, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + !> Using Grid data 4d as input + subroutine vtk_dataset_structured_grid_grid(D,n1,n2,n3,mvtk) + integer , intent(in) :: n1,n2,n3 + real(ReKi), dimension(:,:,:,:),intent(in)::D + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + mvtk%nPoints=n1*n2*n3 + if (mvtk%bBinary) then + write(mvtk%vtk_unit) 'DATASET STRUCTURED_GRID'//NL + write(mvtk%buffer,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', n1,' ',n2,' ',n3 + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%buffer,'(A,I0,A)') 'POINTS ', mvtk%nPoints, ' double' + write(mvtk%vtk_unit) trim(mvtk%buffer)//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A)') 'DATASET STRUCTURED_GRID' + write(mvtk%vtk_unit,'(A,I0,A,I0,A,I0)') 'DIMENSIONS ', n1,' ',n2,' ',n3 + write(mvtk%vtk_unit,'(A,I0,A)') 'POINTS ', mvtk%nPoints, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + write(mvtk%vtk_unit,*) ' ' + endif + endif + end subroutine + + + + ! ------------------------------------------------------------------------- + ! --- POINT DATA + ! ------------------------------------------------------------------------- + subroutine vtk_point_data_init(mvtk) + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if(mvtk%bBinary) then + write(mvtk%buffer,'(A,I0)')'POINT_DATA ',mvtk%nPoints + write(mvtk%vtk_unit)trim(mvtk%buffer)//NL + else + write(mvtk%vtk_unit,'(A,I0)') 'POINT_DATA ', mvtk%nPoints + endif + endif + end subroutine + + subroutine vtk_point_data_scalar_flat(D,sname,mvtk) + real(ReKi), dimension(:),intent(in)::D + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'SCALARS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)'LOOKUP_TABLE default'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'SCALARS ', sname, ' double' + write(mvtk%vtk_unit,'(A)') 'LOOKUP_TABLE default' + write(mvtk%vtk_unit,'(1'//RFMT//')')D + endif + endif + end subroutine + + subroutine vtk_point_data_scalar_grid(D,sname,mvtk) + real(ReKi), dimension(:,:,:,:),intent(in)::D + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'SCALARS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)'LOOKUP_TABLE default'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'SCALARS ', sname, ' double' + write(mvtk%vtk_unit,'(A)') 'LOOKUP_TABLE default' + write(mvtk%vtk_unit,'(1'//RFMT//')')D + endif + endif + end subroutine + + subroutine vtk_point_data_scalar_grid2D(D,sname,mvtk) + real(ReKi), dimension(:,:,:),intent(in)::D + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'SCALARS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)'LOOKUP_TABLE default'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'SCALARS ', sname, ' double' + write(mvtk%vtk_unit,'(A)') 'LOOKUP_TABLE default' + write(mvtk%vtk_unit,'(1'//RFMT//')')D + endif + endif + end subroutine + + !> + subroutine vtk_point_data_vector_flat(D,sname,mvtk) + real(ReKi), dimension(:,:),intent(in) :: D !< 3 x n + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'VECTORS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'VECTORS ', sname, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + endif + endif + end subroutine + !> + subroutine vtk_point_data_vector_grid(D,sname,mvtk) + real(ReKi), dimension(:,:,:,:),intent(in) :: D !< 3 x n + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'VECTORS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'VECTORS ', sname, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + endif + endif + end subroutine + !> + subroutine vtk_point_data_vector_grid2D(D,sname,mvtk) + real(ReKi), dimension(:,:,:),intent(in) :: D !< + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'VECTORS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'VECTORS ', sname, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + endif + endif + end subroutine + + + ! ------------------------------------------------------------------------- + ! --- CELL DATA + ! ------------------------------------------------------------------------- + subroutine vtk_cell_data_init(mvtk) + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%buffer,'(A,I0)')'CELL_DATA ',mvtk%nData + write(mvtk%vtk_unit)trim(mvtk%buffer)//NL + else + write(mvtk%vtk_unit,'(A,I0)') 'CELL_DATA ', mvtk%nData + endif + endif + end subroutine + + subroutine vtk_cell_data_scalar_1d(D,sname,mvtk) + real(ReKi), dimension(:),intent(in)::D + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'SCALARS '//trim(sname)//' double 1'//NL + write(mvtk%vtk_unit)'LOOKUP_TABLE default'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,fmt='(A,A,A)') 'SCALARS ', sname, ' double' + write(mvtk%vtk_unit,'(A)') 'LOOKUP_TABLE default' + write(mvtk%vtk_unit,'(1'//RFMT//')')D + endif + endif + end subroutine + + subroutine vtk_cell_data_scalar_2d(D,sname,mvtk) + real(ReKi), dimension(:,:),intent(in)::D + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'SCALARS '//trim(sname)//' double 1'//NL + write(mvtk%vtk_unit)'LOOKUP_TABLE default'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,fmt='(A,A,A)') 'SCALARS ', sname, ' double' + write(mvtk%vtk_unit,'(A)') 'LOOKUP_TABLE default' + write(mvtk%vtk_unit,'(1'//RFMT//')')D + endif + endif + end subroutine + + + subroutine vtk_cell_data_vector(D,sname,mvtk) + real(ReKi), dimension(:,:),intent(in) :: D !< 3 x n + character(len=*),intent(in) ::sname + type(FVW_VTK_Misc),intent(inout) :: mvtk + if ( mvtk%bFileOpen ) then + if (mvtk%bBinary) then + write(mvtk%vtk_unit)'VECTORS '//trim(sname)//' double'//NL + write(mvtk%vtk_unit)D + write(mvtk%vtk_unit)NL + else + write(mvtk%vtk_unit,'(A,A,A)') 'VECTORS ', sname, ' double' + write(mvtk%vtk_unit,'(3'//RFMT//')')D + endif + endif + end subroutine + + ! --------------------------------------------------------------------------------} + ! --- VTK Tools + ! --------------------------------------------------------------------------------{ + !> Exports a Plane From a mesh + subroutine export_plane_grid3d(fname,v1,v2,v3,Values,mvtk) + character(len=*),intent(in) :: fname + real(ReKi),dimension(:), intent(in) :: v1,v2,v3 + real(ReKi),dimension(:,:,:,:), intent(in) :: Values + type(FVW_VTK_Misc),intent(inout) :: mvtk + ! Variables + integer :: nD + + ! Writting + if ( vtk_new_ascii_file(trim(fname),'grid',mvtk)) then + nD=size(Values,1) + call vtk_dataset_rectilinear(v1,v2,v3,mvtk) + ! Output as a structured grid, No need to reorder + call vtk_point_data_init(mvtk) + ! Could be a function of nDim, be careful + if(nD==3) then + call vtk_point_data_vector(Values(1:3,:,:,:),'Velocity',mvtk) ! Label... + endif + + call vtk_close_file(mvtk) + endif ! file opening + end subroutine + + !> Exports a Plane From a mesh + subroutine export_plane_grid2d(fname,v1,v2,v3,Values,mvtk) + character(len=*),intent(in) :: fname + real(ReKi),dimension(:), intent(in) :: v1,v2,v3 + real(ReKi),dimension(:,:,:), intent(in) :: Values + type(FVW_VTK_Misc),intent(inout) :: mvtk + ! Variables + integer :: nD + + ! Writting + if ( vtk_new_ascii_file(trim(fname),'plane',mvtk) ) then + nD=size(Values,1) + call vtk_dataset_rectilinear(v1,v2,v3,mvtk) + ! Output as a structured grid, No need to reorder + call vtk_point_data_init(mvtk) + ! Could be a function of nDim, be careful + if(nD==3) then + call vtk_point_data_vector(Values(1:3,:,:),'Velocity',mvtk) ! Label... + endif + + call vtk_close_file(mvtk) + endif ! file opening + end subroutine +end module FVW_VTK diff --git a/modules/aerodyn/src/FVW_VortexTools.f90 b/modules/aerodyn/src/FVW_VortexTools.f90 new file mode 100644 index 0000000000..dc97783624 --- /dev/null +++ b/modules/aerodyn/src/FVW_VortexTools.f90 @@ -0,0 +1,892 @@ +module FVW_VortexTools + ! Contains Typical Tools for vortex methods + + ! Should be *independent* of the Framework and any derived type + + ! Only low level functions ! + + use NWTC_LIBRARY + + implicit none + + ! Tree parameters + integer, parameter :: IK1 = selected_int_kind(1) ! to store particle branch number (from 1 to 8) + integer,parameter :: M0 = 1, M1_1=2, M1_2=3, M1_3=4, M2_11=5, M2_21=6, M2_22=7, M2_31=8, M2_32=9, M2_33=10 ! For moment coefficients + integer,parameter :: M0_000 = 1 + integer,parameter :: M1_100 = 2 + integer,parameter :: M1_010 = 3 + integer,parameter :: M1_001 = 4 + + !> + type T_Part + real(ReKi), dimension(:,:), pointer :: P =>null() + real(ReKi), dimension(:,:), pointer :: Alpha =>null() + real(ReKi), dimension(:), pointer :: RegParam =>null() + integer(IntKi) :: RegFunction =-1 + integer(IntKi) :: n =-1 + end type T_Part + + !> The node type is recursive and is used to make a chained-list of nodes for the tree + type T_Node + real(ReKi) :: radius !< Typical dimension of a cell (max of x,y,z extent) + real(ReKi),dimension(3) :: center + real(ReKi),dimension(3,10) :: Moments + integer,dimension(:),pointer :: iPart=>null() !< indexes of particles stored in this node + integer,dimension(:),pointer :: leaves=>null() ! NOTE: leaves are introduced to save memory + type(T_Node),dimension(:), pointer :: branches =>null() + integer :: nPart = -1 ! Number of particles in branches and leaves of this node + end type T_Node + + !> The type tree contains some basic data, a chained-list of nodes, and a pointer to the Particle data that were used + type T_Tree + type(T_Part) :: Part !< Storage for all particles + integer :: iStep =-1 !< Time step at which the tree was built + logical :: bGrown =.false. !< Is the tree build + type(T_Node) :: Root !< Contains the chained-list of nodes + end type T_Tree + + interface cut_tree + module procedure cut_tree_parallel ; ! to switch between parallel and rec easily + end interface + +contains + + subroutine VecToLattice(PointVectors, iDepthStart, LatticeVectors, iHeadP) + real(Reki), dimension(:,:), intent(in ) :: PointVectors !< nVal x n + integer(IntKi), intent(in ) :: iDepthStart !< Start index for depth dimension + real(ReKi), dimension(:,:,:), intent(inout) :: LatticeVectors !< nVal x nSpan x nDepth + integer(IntKi), intent(inout) :: iHeadP !< Index indicating where to start in PointVectors + integer(IntKi) :: iSpan, iDepth + do iDepth = iDepthStart, size(LatticeVectors,3) + do iSpan = 1, size(LatticeVectors,2) + LatticeVectors(:, iSpan, iDepth) = PointVectors(:, iHeadP) + iHeadP=iHeadP+1 + enddo + enddo + end subroutine + + subroutine LatticeToPoints(LatticePoints, iDepthStart, Points, iHeadP) + real(Reki), dimension(:,:,:), intent(in ) :: LatticePoints !< Points 3 x nSpan x nDepth + integer(IntKi), intent(in ) :: iDepthStart !< Start index for depth dimension + real(ReKi), dimension(:,:), intent(inout) :: Points !< + integer(IntKi), intent(inout) :: iHeadP !< Index indicating where to start in Points + ! Local + integer(IntKi) :: iSpan, iDepth + ! Points are flattened as follows: (Loop order is important) + ! + ! 3---6 + ! | | + ! 2---5 + ! | | + ! 1---4 + ! + do iDepth = iDepthStart, size(LatticePoints,3) + do iSpan = 1, size(LatticePoints,2) + Points(1:3,iHeadP) = LatticePoints(1:3, iSpan, iDepth) + iHeadP=iHeadP+1 + enddo + enddo + + endsubroutine LatticeToPoints + + subroutine LatticeToSegments(LatticePoints, LatticeGamma, iDepthStart, SegPoints, SegConnct, SegGamma, iHeadP, iHeadC, bShedVorticity, bShedLastVorticity ) + real(Reki), dimension(:,:,:), intent(in ) :: LatticePoints !< Points 3 x nSpan x nDepth + real(Reki), dimension(:,:), intent(in ) :: LatticeGamma !< GammaPanl nSpan x nDepth + integer(IntKi), intent(in ) :: iDepthStart !< Start index for depth dimension + real(ReKi), dimension(:,:), intent(inout) :: SegPoints !< + integer(IntKi), dimension(:,:), intent(inout) :: SegConnct !< + real(ReKi), dimension(:), intent(inout) :: SegGamma !< + integer(IntKi), intent(inout) :: iHeadP !< Index indicating where to start in SegPoints + integer(IntKi), intent(inout) :: iHeadC !< Index indicating where to start in SegConnct + logical , intent(in ) :: bShedVorticity !< Shed vorticity is included if true + logical , intent(in ) :: bShedLastVorticity !< Shed the last vorticity segment if true + ! Local + integer(IntKi) :: nSpan, nDepth + integer(IntKi) :: iSpan, iDepth + integer(IntKi) :: iHeadP0, iseg1, iseg2, iseg3 ,iseg4 !< Index indicating where to start in SegPoints + real(ReKi) :: Gamma12 + real(ReKi) :: Gamma41 + + nSpan = size(LatticePoints,2) + nDepth= size(LatticePoints,3) + + + iHeadP0=iHeadP ! Storing + ! --- Flattening LatticePoints into SegPoints array, and increment iHeadP + ! We will need all the points, we flatten the point array + call LatticeToPoints(LatticePoints, iDepthStart, SegPoints, iHeadP) + + ! --- Creating segments + ! Naming convention for point indices and segments of a panel: + ! 2---3 + ! | | + ! 1---4 + ! We go "Panel per panel" , for a given Panel, we create + ! - Segment 1-2 + ! - Segment 1-4 + ! - Segment 4-3 if the last Depth panel + ! - Segment 2-3 if the last Span panel + ! Circulation is defined positive as follows (clockwise): + ! 2->-3 + ! ^ v + ! 1-<-4 + do iDepth = iDepthStart, nDepth-1 + do iSpan = 1, nSpan-1 + iseg1 = iHeadP0 + (iSpan-1) +(iDepth-1-iDepthStart+1)*nSpan ! Point 1 + iseg2 = iHeadP0 + (iSpan ) +(iDepth-1-iDepthStart+1)*nSpan ! Point 2 + iseg3 = iHeadP0 + (iSpan ) +(iDepth -iDepthStart+1)*nSpan ! Point 3 + iseg4 = iHeadP0 + (iSpan-1) +(iDepth -iDepthStart+1)*nSpan ! Point 4 + if (iDepth==iDepthStart) then + Gamma12 = LatticeGamma(iSpan,iDepth) + else + Gamma12 = LatticeGamma(iSpan,iDepth)-LatticeGamma(iSpan,iDepth-1) + endif + if (iSpan==1) then + Gamma41 = LatticeGamma(iSpan,iDepth) + else + Gamma41 = LatticeGamma(iSpan,iDepth)-LatticeGamma(iSpan-1,iDepth) + endif + ! Segment 1-2 + if (bShedVorticity) then + SegConnct(1,iHeadC) = iseg1 + SegConnct(2,iHeadC) = iseg2 + SegConnct(3,iHeadC) = iDepth + SegConnct(4,iHeadC) = iSpan + SegGamma (iHeadC ) = Gamma12 + iHeadC=iHeadC+1 + endif + ! Segment 1-4 + SegConnct(1,iHeadC) = iseg1 + SegConnct(2,iHeadC) = iseg4 + SegConnct(3,iHeadC) = iDepth + SegConnct(4,iHeadC) = iSpan + SegGamma (iHeadC ) = -Gamma41 + iHeadC=iHeadC+1 + ! Segment 4-3 + if (iDepth==nDepth-1) then + if ((bShedVorticity) .and. (bShedLastVorticity)) then + SegConnct(1,iHeadC) = iseg4 + SegConnct(2,iHeadC) = iseg3 + SegConnct(3,iHeadC) = iDepth + SegConnct(4,iHeadC) = iSpan + SegGamma (iHeadC ) = - LatticeGamma(iSpan,iDepth) + iHeadC=iHeadC+1 + endif + endif + ! Segment 2-3 + if (iSpan==nSpan-1) then + SegConnct(1,iHeadC) = iseg2 + SegConnct(2,iHeadC) = iseg3 + SegConnct(3,iHeadC) = iDepth + SegConnct(4,iHeadC) = iSpan + SegGamma (iHeadC ) = LatticeGamma(iSpan,iDepth) + iHeadC=iHeadC+1 + endif + enddo + enddo + end subroutine LatticeToSegments + + !> Convert segments between index iSegStart and iSegEnd to particles. + subroutine SegmentsToPart(SegPoints, SegConnct, SegGamma, SegEpsilon, iSegStart, iSegEnd, nPartPerSeg, PartPoints, PartAlpha, PartEpsilon, iHeadPart) + real(ReKi), dimension(:,:), intent(in ) :: SegPoints !< + integer(IntKi), dimension(:,:), intent(in ) :: SegConnct !< + real(ReKi), dimension(:), intent(in ) :: SegGamma !< + real(ReKi), dimension(:), intent(in ) :: SegEpsilon !< + integer, intent(in ) :: iSegStart !< Index where to start in Seg* vectors + integer, intent(in ) :: iSegEnd !< + integer, intent(in ) :: nPartPerSeg !< Segments will be dividied into nPartPerSeg particles + real(ReKi), dimension(:,:), intent(inout) :: PartPoints !< Particle points (3 x nPart) + real(ReKi), dimension(:,:), intent(inout) :: PartAlpha !< Particle intensities (3 x nPart) + real(ReKi), dimension(:), intent(inout) :: PartEpsilon !< Particle regularization parameter (nPart) + integer, optional, intent(inout) :: iHeadPart !< Index where to start in Part* vectors + real(ReKi), dimension(3) :: P1, P2, DP !< Segment extremities + real(ReKi), dimension(3) :: SegDir !< direction vector + real(ReKi), dimension(3) :: PartInt + real(ReKi) :: PartLen !< Initial "length" of the blob + real(ReKi) :: PartEps !< Regularization of the blob + real(ReKi) :: SegLen + integer(IntKi) :: iPart !< index in particle vectors + integer(IntKi) :: iSeg, iSubPart + if (present(iHeadPart)) then + iPart = iHeadPart + else + iPart = 1 + endif + ! loop on selected segments + do iSeg=iSegStart,iSegEnd + P1 = SegPoints(1:3,SegConnct(1,iSeg)) ! Segment extremities + P2 = SegPoints(1:3,SegConnct(2,iSeg)) + DP = P2-P1 + SegLen = sqrt(DP(1)**2 + DP(2)**2 + DP(3)**2) + SegDir = DP/SegLen ! Unit vector along segment direction + PartInt = DP*SegGamma(iSeg)/nPartPerSeg ! alpha = Gamma.L/n = omega.dV [m^3/s] + PartEps = SegEpsilon(iSeg) ! TODO this might need tuning depending on RegFunction and n_new + PartLen = SegLen/nPartPerSeg + do iSubPart=0,nPartPerSeg-1 + PartPoints(1:3, iPart) = P1(1:3) + (0.5_ReKi+iSubPart)*PartLen*SegDir(1:3) ! ds/2:ds:L + PartAlpha (1:3, iPart) = PartInt(1:3) + PartEpsilon( iPart) = PartEps + iPart = iPart +1 + enddo + enddo + if (present(iHeadPart)) then + iHeadPart=iPart + endif + end subroutine SegmentsToPart + + subroutine print_mean_4d(M, Label) + real(ReKi), dimension(:,:,:,:), intent(in) :: M + character(len=*), intent(in) :: Label + integer(IntKi) :: i, j, k + real(ReKi), dimension(3) :: U + ! + U(1:3)=0 + if ((size(M,4)*size(M,3)*size(M,2) )>0) then + do i=1,size(M,4); do j=1,size(M,3); do k=1,size(M,2); + U(1:3)= U(1:3)+ M(1:3, k, j, i) + enddo; enddo; enddo; + U(1:3)=U(1:3)/ (size(M,4)*size(M,3)*size(M,2)) + endif + print'(A25,3F12.4)',trim(Label),U + end subroutine + + subroutine print_mean_3d(M, Label) + real(ReKi), dimension(:,:,:), intent(in) :: M + character(len=*), intent(in) :: Label + integer(IntKi) :: i, j + real(ReKi), dimension(3) :: U + ! + U(1:3)=0 + if ((size(M,3)*size(M,2))>0) then + do i=1,size(M,3); do j=1,size(M,2) + U(1:3)= U(1:3)+ M(1:3, j, i) + enddo; enddo; + U(1:3)=U(1:3)/ (size(M,3)*size(M,2)) + endif + print'(A24,3F12.4)',trim(Label),U + end subroutine + + !> Perform interpolation from control points to nodes assuming CP are between nodes + subroutine interpextrap_cp2node(xin, yin, xnew, ynew) + real(ReKi), intent(in ) :: xin(:) + real(ReKi), intent(in ) :: yin(:) + real(ReKi), intent(in ) :: xnew(:) + real(ReKi), intent( out) :: ynew(:) + integer(IntKi) :: n + n=size(xin) + call InterpArray(xin, yin, xnew(2:n), ynew(2:n)) + ! Boundaries + if (n>1) then ! If more than 2 panels, use extrapolation + ynew(1) = lin_extrap(xnew(1) , xin(1), yin(1), xin(2) , yin(2)) + ynew(n+1) = lin_extrap(xnew(n+1), xin(n), yin(n), xin(n-1), yin(n-1)) + else ! If one panel, duplicate the unique point on both side + ynew(1) = yin(1) + ynew(n+1) = yin(n) !n=1 + endif + contains + !> Perform linear extrapolation to get value of y(x0), using y(x1) and y(x2) + real(ReKi) function lin_extrap(x0, x1, y1, x2, y2) result(y0) + real(ReKi), intent(in) :: x0, x1, y1, x2, y2 + real(ReKi) :: a + a = (x0-x1)/(x0-x2) + y0 = 1._ReKi/(1._ReKi-a) * (y1-a*y2) + end function lin_extrap + end subroutine interpextrap_cp2node + + ! --------------------------------------------------------------------------------} + ! --- Tree -Grow + ! --------------------------------------------------------------------------------{ + subroutine grow_tree(Tree, PartP, PartAlpha, PartRegFunction, PartRegParam, iStep) + type(T_Tree), intent(inout), target :: Tree !< + real(ReKi), dimension(:,:), intent(in ), target :: PartP !< + real(ReKi), dimension(:,:), intent(in ), target :: PartAlpha !< + integer(IntKi), intent(in ) :: PartRegFunction !< + real(ReKi), dimension(:), intent(in ), target :: PartRegParam !< + integer(IntKi), intent(in ) :: iStep !< + type(T_Node), pointer :: node !< Alias + type(T_Part), pointer :: Part !< Alias + real(ReKi) :: max_x,max_y,max_z !< for domain dimension + real(ReKi) :: min_x,min_y,min_z !< for domain dimension + integer(IntKi) :: i + + ! Cutting tree if it already has content + if (associated(Tree%root%branches).or.associated(Tree%root%leaves)) then + call cut_tree_parallel(Tree) + endif + ! Linking tree particles to given part, no copy! + nullify(Tree%Part%P) + nullify(Tree%Part%Alpha) + nullify(Tree%Part%RegParam) + Tree%Part%P => PartP + Tree%Part%Alpha => PartAlpha + Tree%Part%RegParam => PartRegParam + Tree%Part%RegFunction = PartRegFunction + Tree%Part%n = size(PartP,2) + + ! --- Handle special case for root node + node => Tree%Root + Part => Tree%Part + if (Part%n==0) then + ! Do nothing + node%radius = -9999.99_ReKi + node%center = -9999.99_ReKi + node%Moments= -9999.99_ReKi + else if (Tree%Part%n==1) then + node%radius=0 + node%center(1:3)=Part%P(1:3,1) + node%Moments=0.0_ReKi + nullify(node%iPart) + nullify(node%branches) + allocate(node%leaves(1:1)) + node%leaves(1) = Part%n !< index + node%nPart = 1 + else + ! Domain dimensions + max_x=maxval(Part%P(1,1:Part%n)); max_y=maxval(Part%P(2,1:Part%n)); max_z=maxval(Part%P(3,1:Part%n)) + min_x=minval(Part%P(1,1:Part%n)); min_y=minval(Part%P(2,1:Part%n)); min_z=minval(Part%P(3,1:Part%n)) + + ! Init of trunc + ! Radius taken slightly bigger than domain extent. This radius will be divided by 2 successively + node%radius = max(abs(max_x-min_x),abs(max_y-min_y),abs(max_z-min_z))*1.001_ReKi + if(node%radius>1e6) then + print*,'[Error] Domain extent too large, particle points must be invalid'; + print*, min_x, max_x, min_y, max_y, min_z, max_z + STOP + endif + node%center = (/ (max_x+min_x)/2._ReKi, (max_y+min_y)/2._ReKi, (max_z+min_z)/2._ReKi /) + node%Moments=0.0_ReKi + if(associated(node%iPart)) then ; print*,'[Error] Node part allocated'; STOP; endif + allocate(node%iPart(1:Part%n)) + do i=1,Part%n + node%iPart(i) = i + end do + if(associated(node%branches)) then; print*,'node branches allocated'; STOP; endif + if(associated(node%leaves)) then; print*,'node leaves allocated'; STOP; endif + node%branches=>null() + node%leaves=>null() + node%nPart=Part%n + ! --- Calling grow function on subbrances + call grow_tree_parallel(Tree%root, Tree%Part) +! call grow_tree_rec(Tree%root, Tree%Part) + endif + Tree%iStep = iStep + Tree%bGrown = .true. + end subroutine grow_tree + + !> Recursive function to grow/setup a tree. + !! Note, needed preliminary calc are done by grow_tree before + recursive subroutine grow_tree_rec(node, Part) + type(T_Node), target :: node !< + type(T_Part), intent(in) :: Part !< + integer :: i + ! Sub Step: + ! - compute moments and center for the current node + ! - allocate branches and leaves + call grow_tree_substep(node, Part) + ! Call grow_tree on branches + if(associated(node%branches)) then + do i = 1,size(node%branches) + call grow_tree_rec(node%branches(i), Part) + end do + endif + end subroutine grow_tree_rec + + !> Perform a substep of tree growth, growing sub branches from a given node/cell + !! Parent has already setup node%iPart, indices of the particle in this cell + !! Steps are: + !! - Compute node center (barycenter of vorticity) + !! - Compute node moments + !! - Distribute particles in each 8 octants. Branches are not created for empty octant + !! - Allocate branches and leaves and distribute particles to them + subroutine grow_tree_substep(node, Part) + type(T_Node), intent(inout) :: node !< Current node we are growing from + type(T_Part), intent(in) :: Part !< All particles info + integer(IK1) :: iPartOctant !< Index corresponding to which octant the particle falls into + integer :: nLeaves, nBranches + integer :: iLeaf, iOctant, iBranch + integer :: i1,i2,i3,i4,i5,i6,i7,i8 + integer :: i,j,k + real(ReKi) :: wTot, wLoc ! Total and local vorticity strength + real(ReKi) :: halfSize ! TODO remove me + real(ReKi),dimension(3) :: locCenter, DeltaP,PartPos,PartAlpha + real(ReKi),dimension(3) :: nodeGeomCenter !< Geometric center from division of the domain in powers of 2 + real(ReKi),dimension(3) :: nodeBaryCenter !< Vorticity weighted center + integer(IK1),dimension(:),allocatable :: PartOctant !< Stores the octant (1-8) where each particle belongs + integer,dimension(8) :: npart_per_octant !< Number of particle per octant + integer,dimension(8) :: octant2branches !< Mapping between 8 octants, to index of non empty branch + integer,dimension(8) :: octant2leaves !< Idem for singleton/leaves + real(ReKi) :: max_x,max_y,max_z !< for domain dimension + real(ReKi) :: min_x,min_y,min_z !< for domain dimension + nodeGeomCenter = node%center ! NOTE: we rely on the fact that our parent has set this to the Geometric value + nodeBaryCenter = 0.0_ReKi + wTot = 0.0_ReKi + ! --- Barycenter of vorticity of the node + do i = 1,node%nPart + PartPos = Part%P(:,node%iPart(i)) + PartAlpha = Part%Alpha(:,node%iPart(i)) + wLoc = (PartAlpha(1)**2 + PartAlpha(2)**2 + PartAlpha(3)**2)**0.5_ReKi ! Vorticity norm + nodeBaryCenter = nodeBaryCenter + wLoc*PartPos ! Sum coordinates weighted by vorticity + wTot = wTot + wLoc ! Total vorticity + end do + ! There is no vorticity, we make it a empty node and we exit + if(EqualRealNos(abs(wTot),0.0_ReKi)) then + node%nPart=0 + if (associated(node%iPart)) deallocate(node%iPart) + return ! NOTE: we exit + endif + nodeBaryCenter = nodeBaryCenter/wTot ! barycenter of vorticity + node%center = nodeBaryCenter ! updating + + ! --- Calculation of moments about nodeBaryCenter + do i = 1,node%nPart + PartPos = Part%P (:,node%iPart(i)) + PartAlpha = Part%Alpha(:,node%iPart(i)) + DeltaP = PartPos-nodeBaryCenter + ! Order 0 + node%Moments(1:3,M0_000) = node%Moments(1:3,M0_000) + PartAlpha + ! 1st order + node%Moments(1:3,M1_100) = node%Moments(1:3,M1_100) + PartAlpha*DeltaP(1) ! 100 + node%Moments(1:3,M1_010) = node%Moments(1:3,M1_010) + PartAlpha*DeltaP(2) ! 010 + node%Moments(1:3,M1_001) = node%Moments(1:3,M1_001) + PartAlpha*DeltaP(3) ! 001 + ! 2nd order + do j=1,3 + do k=1,j + node%Moments(1:3,3+j+k+j/3) = node%Moments(1:3,3+j+k+j/3) + PartAlpha*DeltaP(j)*DeltaP(k) + end do + end do + end do + + ! --- Distributing particles to the 8 octants (based on the geometric center!) + allocate (PartOctant(1:node%nPart)) + npart_per_octant(1:8)=0 + do i = 1,node%nPart + PartPos = Part%P(:,node%iPart(i)) + ! index corresponding to which octant the particle falls into + iPartOctant = int(1,IK1) + if (PartPos(1) > nodeGeomCenter(1)) iPartOctant = iPartOctant + int(1,IK1) + if (PartPos(2) > nodeGeomCenter(2)) iPartOctant = iPartOctant + int(2,IK1) + if (PartPos(3) > nodeGeomCenter(3)) iPartOctant = iPartOctant + int(4,IK1) + npart_per_octant(iPartOctant) = npart_per_octant(iPartOctant) + 1 ! Counter of particles per octant + PartOctant(i)=iPartOctant ! Store in which octant particle i is + end do + + ! --- Leaves and branches + ! A node contains a combination of child nodes and leaves (single particles) + ! TODO: introduce a "minimum cell size", (e.g. cell radius is less than the Distance for direct evaluation, then all should be leaves) + nLeaves = 0 + nBranches = 0 + octant2branches = 0 + octant2leaves = 0 + do iOctant = 1,8 + if(npart_per_octant(iOctant)==1) then + nLeaves = nLeaves+1 + octant2leaves(iOctant) = nLeaves + else if(npart_per_octant(iOctant)>1) then + if (npart_per_octant(iOctant)==node%nPart) then + ! All particle falls into the same octant, if they all have the same location, we would divide forever. + ! Quick fix below + max_x=maxval(Part%P(1,node%iPart(:))); max_y=maxval(Part%P(2,node%iPart(:))); max_z=maxval(Part%P(3,node%iPart(:))) + min_x=minval(Part%P(1,node%iPart(:))); min_y=minval(Part%P(2,node%iPart(:))); min_z=minval(Part%P(3,node%iPart(:))) + if (max(abs(max_x-min_x),abs(max_y-min_y),abs(max_z-min_z))< 1.0e-5) then + nLeaves=node%nPart + allocate (node%leaves(1:nLeaves)) + do i = 1,node%nPart + node%leaves(i)=node%iPart(i) + enddo + ! Cleanup and exit! + if (associated(node%iPart)) deallocate(node%iPart) ! Freeing memory + if (allocated(PartOctant)) deallocate(PartOctant) + return + endif + endif + nBranches = nBranches+1 + octant2branches(iOctant) = nBranches + endif + enddo + if (associated(node%branches)) then + print*,'Tree build: error, branches associated' + STOP + endif + if (associated(node%leaves)) then + print*,'Tree build: error, leaves associated' + STOP + end if + + if(nBranches>0) allocate (node%branches(1:nBranches)) + if(nLeaves>0) allocate (node%leaves(1:nLeaves)) + + ! --- Initializing the branches nodes and leaves + halfSize = node%radius/2._ReKi + do iOctant = 1,8 ! there is max 8 octant + iBranch = octant2branches(iOctant) + if (iBranch>0) then ! this node has branches + allocate(node%branches(iBranch)%iPart(1:npart_per_octant(iOctant))) + node%branches(iBranch)%nPart=npart_per_octant(iOctant) + ! NOTE: this is geometric center not barycenter + locCenter = nodeGeomCenter + 0.5*halfSize*(/ (-1)**(iOctant), (-1)**floor(0.5*real(iOctant-1)+1), (-1)**floor(0.25*real(iOctant-1)+1) /) + ! Init of branches + node%branches(iBranch)%radius = halfSize ! + node%branches(iBranch)%center = locCenter ! NOTE: this is the geometric center + node%branches(iBranch)%Moments = 0.0_ReKi ! + node%branches(iBranch)%branches=>null() + node%branches(iBranch)%leaves=>null() + endif + ! other cases are leaves or dead branches + end do + + ! Store indices of the particles the sub-branch contains + i1=0; i2=0; i3=0; i4=0; i5=0; i6=0; i7=0; i8=0; + do i = 1,node%nPart + iBranch = octant2branches(PartOctant(i)) + if(iBranch>0) then + select case(iBranch) + case(1);i1=i1+1; node%branches(1)%iPart(i1) = node%iPart(i) + case(2);i2=i2+1; node%branches(2)%iPart(i2) = node%iPart(i) + case(3);i3=i3+1; node%branches(3)%iPart(i3) = node%iPart(i) + case(4);i4=i4+1; node%branches(4)%iPart(i4) = node%iPart(i) + case(5);i5=i5+1; node%branches(5)%iPart(i5) = node%iPart(i) + case(6);i6=i6+1; node%branches(6)%iPart(i6) = node%iPart(i) + case(7);i7=i7+1; node%branches(7)%iPart(i7) = node%iPart(i) + case(8);i8=i8+1; node%branches(8)%iPart(i8) = node%iPart(i) + end select + else + iLeaf = octant2leaves(PartOctant(i)) + if(iLeaf>0) then + node%leaves(iLeaf)=node%iPart(i) + else + print*,'This particle do not belong to anybody!!',i + STOP + endif + endif + end do + if (associated(node%iPart)) deallocate(node%iPart) ! Freeing memory + if (allocated(PartOctant)) deallocate(PartOctant) + end subroutine grow_tree_substep + + !> Grow a tree in "parallel", since recursive calls cannot be parallized easily, we unroll the different layer calls + !! Note, needed preliminary calc are done by grow_tree before! + subroutine grow_tree_parallel(Root, Part) + type(T_Node), intent(inout) :: Root + type(T_Part), intent(in) :: Part + integer :: i, nBranches + integer :: i1 + integer :: i2 + + ! --- Unrolled version of grow_tree for the first node + ! Sub Step: + ! - compute moments and center for the current node + ! - allocate branches and leaves + call grow_tree_substep(Root, Part) + + if(.not. associated(Root%branches)) then + nBranches=0 + else + nBranches=size(Root%branches) + if (nBranches==0) then + print*,'No branches' ! This should not happen + STOP + else + ! Call "grow_tree" on branches + + !$OMP PARALLEL default(shared) + + ! --- Unrolled version of grow_tree for the second levels + !$OMP do private(i) schedule(runtime) + do i = 1,nBranches ! maximum 8 branches + if(Root%branches(i)%nPart>1) then ! I dont think this test is needed + call grow_tree_substep(Root%branches(i), Part) + endif + end do + !$OMP end do + !$OMP barrier ! we need to be sure that all the branches were built + ! --- Unrolled version of grow_tree for third node levels + !$OMP do private(i,i1,i2) schedule(runtime) + do i = 1,nBranches*8 ! maximum 64 sub branches + i1=(i-1)/8+1; + i2=mod(i-1,8)+1; + if(associated(Root%branches(i1)%branches)) then + if (i2<=size(Root%branches(i1)%branches)) then + call grow_tree_rec(Root%branches(i1)%branches(i2), Part) + endif + endif + enddo + !$OMP end do + !Note: We could add more levels + !$OMP END PARALLEL + endif + endif + end subroutine grow_tree_parallel + + + + ! -------------------------------------------------------------------------------- + ! --- Cut tree + ! -------------------------------------------------------------------------------- + !> Cut a tree and all its subbranches in a recursive manner + recursive subroutine cut_tree_rec(node) + integer :: i + type(T_Node),intent(inout) :: node + call cut_substep(node) + if (associated(node%branches)) then + do i=1,size(node%branches) + call cut_tree_rec(node%branches(i)) + end do + deallocate(node%branches) + node%branches=> null() + end if + end subroutine cut_tree_rec + + !> Perform a substep of tree cutting (used by recursive and parallel calls) + subroutine cut_substep(node) + type(T_Node), intent(inout) :: node + if (associated(node%leaves)) then + deallocate(node%leaves) + end if + if (associated(node%iPart)) then + print*,'The tree particles were not properly cleaned' + STOP + deallocate(node%iPart) + end if + end subroutine cut_substep + + !> Cut a tree and all its sub-branches, unrolled to use parallelization for the first 3 levels + subroutine cut_tree_parallel(Tree) + type(T_Tree), intent(inout) :: Tree + integer :: i,i1,i2,nBranches + ! --- Unlinking particles + nullify(Tree%Part%P) + nullify(Tree%Part%Alpha) + nullify(Tree%Part%RegParam) + ! --- Unrolled version of cut_tree for the first node + call cut_substep(Tree%root) + if(associated(Tree%Root%branches)) then + nBranches=size(Tree%Root%branches) + !$OMP PARALLEL default(shared) + + ! --- Unrolled version for the second levels + !$OMP do private(i) schedule(runtime) + do i = 1,nBranches ! maximum 8 branches + call cut_substep(Tree%Root%branches(i)) + end do + !$OMP end do + !$OMP barrier ! we need to be sure that all the branches were cut + + ! --- Unrolled version for third node levels + !$OMP do private(i,i1,i2) schedule(runtime) + do i = 1,nBranches*8 ! maximum 64 sub branches + i1=(i-1)/8+1; + i2=mod(i-1,8)+1; + if(associated(Tree%Root%branches(i1)%branches)) then + if (i2<=size(Tree%Root%branches(i1)%branches)) then + call cut_tree_rec(Tree%Root%branches(i1)%branches(i2)) + endif + endif + enddo + !$OMP end do + !$OMP END PARALLEL + + ! --- Cleanup second level + do i = 1,nBranches ! maximum 8 branches + if (associated(Tree%root%branches(i)%branches)) then + deallocate(Tree%root%branches(i)%branches) + nullify(Tree%root%branches(i)%branches) + endif + end do + + ! --- Cleanup First level + deallocate(Tree%root%branches) + nullify(Tree%root%branches) + endif + if (associated(Tree%root%branches)) then + print*,'Tree cut: branches are still allocated' + STOP + endif + Tree%iStep=-1 + Tree%root%nPart=-1 + Tree%bGrown=.false. + end subroutine cut_tree_parallel + + subroutine print_tree(Tree) + type(T_Tree) :: Tree + character(len=1024) :: preffix + preffix='root' + print '(A, L1)', trim(preffix)//':partP_assoc = ',associated(Tree%Part%P) + print '(A, L1)', trim(preffix)//':bGrown = ',Tree%bGrown + print '(A, I0)', trim(preffix)//':iStep = ',Tree%iStep + call print_tree_rec(Tree%Root, preffix) + contains + recursive subroutine print_tree_rec(node, preffix) + type(T_Node), target :: node !< + character(len=*), intent(in) :: preffix + integer :: i + ! Test if there are enough particles on the node to build new branchess + ! The case of only one particle should be handled upstream by allocating one leaf to the parent node + print'(A)' ,trim(preffix)//':nPart = '//Num2LStr(node%nPart) + print'(A,3F12.3)',trim(preffix)//':center =',node%center + print'(A,1F12.3)',trim(preffix)//':radius =',node%radius + if(associated(node%leaves)) then + do i = 1,size(node%leaves) + print'(A)',trim(preffix)//':leaf'//trim(Num2LStr(i))//'='//trim(Num2LStr(node%leaves(i))) + end do + endif + if(associated(node%branches)) then + do i = 1,size(node%branches) + call print_tree_rec(node%branches(i), trim(preffix)//':branch'//trim(Num2LStr(i))) + end do + endif + end subroutine print_tree_rec + end subroutine print_tree + + ! -------------------------------------------------------------------------------- + ! --- Velocity computation + ! -------------------------------------------------------------------------------- + subroutine ui_tree(Tree, CPs, ioff, icp_beg, icp_end, BranchFactor, DistanceDirect, Uind, ErrStat, ErrMsg) + use FVW_BiotSavart, only: fourpi_inv, ui_part_nograd_11 + type(T_Tree), target, intent(inout) :: Tree !< + integer, intent(in ) :: ioff !< + integer, intent(in ) :: icp_beg !< + integer, intent(in ) :: icp_end !< + real(ReKi), intent(in ) :: BranchFactor !< + real(ReKi), intent(in ) :: DistanceDirect !< Distance under which direct evaluation should be done no matter what the tree cell size is + real(ReKi), dimension(:,:), intent(in ) :: CPs !< Control Points (3 x nCPs) + real(ReKi), dimension(:,:), intent(inout) :: Uind !< Induced velocity at CPs, with side effects (3 x nCPs) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + real(ReKi), dimension(3) :: Uind_tmp !< + real(ReKi), dimension(3) :: CP !< Current CP + integer :: icp, nDirect, nQuad + type(T_Part), pointer :: Part ! Alias + Part => Tree%Part + if(.not. associated(Part%P)) then + ErrMsg='Ui Part Tree called but tree particles not associated'; ErrStat=ErrID_Fatal; return + endif + !$OMP PARALLEL DEFAULT(SHARED) + !$OMP DO PRIVATE(icp,CP,Uind_tmp,nDirect,nQuad) schedule(runtime) + do icp=icp_beg,icp_end + CP = CPs(1:3,icp) + Uind_tmp(1:3) = 0.0_ReKi + nDirect =0 + nQuad =0 + call ui_tree_11(Tree%root, CP, Uind_tmp, nDirect, nQuad) !< SIDE EFFECTS + !print*,'Number of direct calls, and quad calls',nDirect, nQuad + Uind(1:3,ioff+icp-icp_beg+1) = Uind(1:3,ioff+icp-icp_beg+1) + Uind_tmp(1:3) + enddo + !$OMP END DO + !$OMP END PARALLEL + contains + !> Velocity at one control point from the entire tree + recursive subroutine ui_tree_11(node, CP, Uind, nDirect, nQuad) + real(ReKi),dimension(3),intent(inout) :: CP, Uind !< Velocity at control point, with side effect + integer, intent(inout) :: nDirect,nQuad + type(T_Node), intent(inout) :: node + real(ReKi) :: distDirect, coeff + real(ReKi),dimension(3) :: DeltaP, phi, Uloc + real(ReKi) :: x,y,z,mx,my,mz,r + integer :: i,j,ieqj + integer :: iPart + if (node%nPart<=0) then + ! We skip the dead leaf + elseif (.not.associated(node%branches)) then + ! Loop on leaves + if(associated(node%leaves)) then + do i =1,size(node%leaves) + iPart=node%leaves(i) + DeltaP = CP(1:3) - Part%P(1:3,iPart) + call ui_part_nograd_11(DeltaP, Part%Alpha(1:3,iPart), Part%RegFunction, Part%RegParam(iPart), Uloc) + nDirect=nDirect+1 + Uind(1:3) = Uind(1:3) + Uloc + enddo + endif + else + distDirect = max(BranchFactor*node%radius, DistanceDirect) ! Under this distance-> Direct eval., Above it -> quadrupole calculation + DeltaP = - node%center + CP(1:3) ! Vector between the control point and the center of the branch + r = sqrt( DeltaP(1)**2 + DeltaP(2)**2 + DeltaP(3)**2) + ! Test if the control point is too close from the branch node so that a direct evaluation is needed + if (r Meshing function. Create a 1D mesh of size `n`, based on a `method` and an input vector `x` + subroutine Meshing(method, x, n, y) + ! Arguments declarations + character(len=*), intent(in) :: method !< String defining the method used + integer(IntKi), intent(in) :: n !< size of vector y + real(ReKi), dimension(:),intent(in) :: x !< input vector of nodes or (/ min, max/) + real(ReKi), dimension(:), intent(out) :: y !< output vector with meshing values + ! Variable declarations + real(ReKi), dimension(:),allocatable :: dx !< + integer::jr + y = 0.0_ReKi + select case (method) ! + case ('middle') ! + allocate(dx(1:n)) + dx=diff(x) ! dx is the width of each panel + y(1:n)=x(1:n)+dx(1:n)/2._ReKi + deallocate(dx) + + case ('fullcosineapprox') ! + ! x is assumed to be of size n+1 + if (n==1) then + y(1)=(x(1)+x(2))/2._ReKi ! middle + return + else + allocate(dx(1:n)) + dx=diff(x) ! dx is the width of each panel + y(1) = x(1)+(dx(1) /(dx(1) +dx(2)))*dx(1) + y(n) = x(n)+(dx(n-1)/(dx(n-1)+dx(n)))*dx(n) + do jr=2,n-1 + y(jr)=x(jr)+0.25_ReKi*(dx(jr-1)/(dx(jr-1)+dx(jr)) + dx(jr)/(dx(jr)+dx(jr+1))+1 )*dx(jr) + end do + deallocate(dx) + endif + end select + + contains + !> Compute: x(2:n)-x(1:n-1) + function diff(d) + real(ReKi),dimension(:),intent(in) ::d + real(ReKi),dimension(size(d)-1) ::diff + integer::i + do i=1,size(d)-1 + diff(i)=d(i+1)-d(i) + enddo + end function + end subroutine Meshing + + + !---------------------------------------------------------------------------------------------------------------------------------- + !> Based on an input mesh, sets the following: + !! - s_LL : Dimensionless spanwise coordinate of LL + !! - s_CP_LL : Dimensionless spanwise coordinate of LL CP + !! - chord_LL : chord on LL + !! - chord_LL_CP: chord on LL cp + subroutine Wings_Panelling_Init(Meshes, p, m, ErrStat, ErrMsg ) + type(MeshType), dimension(:), intent(in ) :: Meshes !< Wings mesh + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local + !integer(IntKi) :: ErrStat2 ! temporary error status of the operation + !character(ErrMsgLen) :: ErrMsg2 ! temporary error message + integer(IntKi) :: iW, iSpan + real(ReKi), dimension(3) :: DP + real(ReKi), dimension(:),allocatable :: s_in !< Dimensionless spanwise coordinate of input + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + ! --- Meshing + do iW = 1,p%nWings + if (allocated(s_in)) deallocate(s_in) + allocate(s_in(1:Meshes(iW)%nNodes)) + ! --- Computing spanwise coordinate of input mesh normalized from 0 to 1 +!Note: this info also exists in InitInp%zLocal + s_in(:) = -999 + 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) + enddo + + ! --- Setting up Lifting line variables based on input and a "meshing" method (TODO) + if (Meshes(iW)%nNodes /= p%nSpan+1) then + ! TODO Possibly interpolate based on FVW meshing + ! NOTE: p%chord is copied from the InitInput + ErrMsg ='TODO different discretization InputMesh / vortex code'; ErrStat=ErrID_Fatal; return + endif + do iSpan = 1, p%nSpan+1 + m%s_LL (iSpan, iW) = s_in(iSpan) + m%chord_LL(iSpan, iW) = p%chord(iSpan,iW) + enddo + ! --- Control points spanwise location + ! NOTE: we use the cos approximation of VanGarrel. For equispacing, it returns mid point + ! otherwise, points are slightly closer to panels that are shorter + !call Meshing('middle' , m%s_LL(:,iW), p%nSpan, m%s_CP_LL(:,iW)) + call Meshing('fullcosineapprox' , m%s_LL(:,iW), p%nSpan, m%s_CP_LL(:,iW)) + call InterpArray(m%s_LL(:,iW), m%chord_LL(:,iW), m%s_CP_LL(:,iW), m%chord_CP_LL(:,iW)) + enddo + end subroutine Wings_Panelling_Init + !---------------------------------------------------------------------------------------------------------------------------------- + !> Based on an input mesh, sets the following: + !! - LE : Leading edge points (3 x nSpan+1 x nWings) + !! - TE : Trailing edge points (3 x nSpan+1 x nWings) + !! - CP_LL : Coordinates of LL CP" (3 x nSpan x nWings) + !! - Tang : Unit Tangential vector on LL CP" - + !! - Norm : Unit Normal vector on LL CP " - + !! - Orth : Unit Orthogonal vector on LL CP" - + !! - Vstr_LL : Structural velocity on LL CP" m/s + subroutine Wings_Panelling(Meshes, p, m, ErrStat, ErrMsg ) + type(MeshType), dimension(:), intent(in ) :: Meshes !< Wings mesh + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + ! Local + !integer(IntKi) :: ErrStat2 ! temporary error status of the operation + !character(ErrMsgLen) :: ErrMsg2 ! temporary error message + integer(IntKi) ::iSpan , iW + real(ReKi), dimension(3) :: P_ref ! Reference point of Input Mesh (e.g. AeroDynamic Center?) + real(ReKi), dimension(3) :: DP_LE ! Distance between reference point and Leading edge + real(ReKi), dimension(3) :: DP_TE ! Distance between reference point and trailing edge + real(ReKi), dimension(3) :: P1,P2,P3,P4,P5,P7,P8,P6,P9,P10 + real(ReKi), dimension(3) :: DP1, DP2, DP3 + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! --- Position of leading edge (LE) and trailing edge (TE) + ! NOTE, this assumes one to one between InputMesh and FVW Mesh + do iW = 1,p%nWings + do iSpan = 1,p%nSpan+1 + P_ref = Meshes(iW)%Position(1:3, iSpan )+Meshes(iW)%TranslationDisp(1:3, iSpan) + DP_LE(1:3) = 0.0 + DP_LE(1) = -m%chord_LL(iSpan,iW)/4. + DP_TE(1:3) = 0.0 + DP_TE(1) = +3.*m%chord_LL(iSpan,iW)/4. + m%LE(1:3, iSpan, iW) = P_ref + DP_LE(1)*Meshes(iW)%Orientation(2,1:3,iSpan) + m%TE(1:3, iSpan, iW) = P_ref + DP_TE(1)*Meshes(iW)%Orientation(2,1:3,iSpan) + enddo + enddo + ! --- Generic code below to compute normal/tangential vectors of a lifting line panel + ! Notations follow vanGarrel [ECN-C--03-079, Development of a wind turbine aerodynamics simulation module,2003] + ! + ! P4 -P10---P7------ P3 + ! | + ! P8 P6 + ! | + ! P1 -P9----P5------ P2 + ! + do iW = 1,p%nWings + do iSpan = 1,p%nSpan + P1 = m%LE(:,iSpan , iw) + P4 = m%LE(:,iSpan+1, iw) + P3 = m%TE(:,iSpan+1, iw) + P2 = m%TE(:,iSpan , iw) + P8 = (P1+P4)/2 + P6 = (P2+P3)/2 + P5 = (P1+P2)/2 + P7 = (P4+P3)/2 + P9 = 0.75_ReKi*P1+0.25_ReKi*P2 + P10 = 0.75_ReKi*P4+0.25_ReKi*P3 + DP1 = P6-P8 + 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%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)) + DP3 = P1-P3 + m%diag_LL(iSpan, iW) = norm2(DP3) + end do + enddo +!FIXME: does it make sense to use the position mesh for this info? + ! --- Lifting Line/ Bound Circulation panel + ! For now: goes from 1/4 chord to TE + ! More panelling options may be considered in the future + do iW = 1,p%nWings + do iSpan = 1,p%nSpan+1 + m%r_LL(1:3,iSpan,1,iW)= m%TE(1:3,iSpan,iW)*0.25_ReKi+m%LE(1:3,iSpan,iW)*0.75_ReKi ! 1/4 chord + m%r_LL(1:3,iSpan,2,iW)= m%TE(1:3,iSpan,iW) ! TE + enddo + enddo + + ! --- Position of control points CP_LL + ! For now: placed exactly on the LL panel + ! NOTE: separated from other loops just in case a special discretization is used + do iW = 1,p%nWings + call InterpArray(m%s_LL(:,iW), m%r_LL(1,:,1,iW), m%s_CP_LL(:,iW), m%CP_LL(1,:,iW)) + call InterpArray(m%s_LL(:,iW), m%r_LL(2,:,1,iW), m%s_CP_LL(:,iW), m%CP_LL(2,:,iW)) + call InterpArray(m%s_LL(:,iW), m%r_LL(3,:,1,iW), m%s_CP_LL(:,iW), m%CP_LL(3,:,iW)) + enddo + + ! --- Structural velocity on LL + ! TODO: difference meshes in/LL + do iW = 1,p%nWings + call InterpArray(m%s_LL(:,iW), Meshes(iW)%TranslationVel(1,:) ,m%s_CP_LL(:,iW), m%Vstr_LL(1,:,iW)) + call InterpArray(m%s_LL(:,iW), Meshes(iW)%TranslationVel(2,:) ,m%s_CP_LL(:,iW), m%Vstr_LL(2,:,iW)) + call InterpArray(m%s_LL(:,iW), Meshes(iW)%TranslationVel(3,:) ,m%s_CP_LL(:,iW), m%Vstr_LL(3,:,iW)) + enddo + end subroutine Wings_Panelling + + !---------------------------------------------------------------------------------------------------------------------------------- + !> + subroutine Wings_ComputeCirculation(t, Gamma_LL, Gamma_LL_prev, u, p, x, m, AFInfo, ErrStat, ErrMsg, iLabel) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + real(ReKi), dimension(:,:), intent(inout) :: Gamma_LL !< Circulation on all the lifting lines + real(ReKi), dimension(:,:), intent(in ) :: Gamma_LL_prev !< Previous/Guessed circulation + type(FVW_InputType), intent(in ) :: u !< Parameters + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< 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 + integer(IntKi), intent(in) :: iLabel + ! Local + integer(IntKi) :: iW + real(DbKi) :: s, RealAxis + real(ReKi) :: GammaScale + ErrStat = ErrID_None + ErrMsg = "" + + if (t= 9) then + ! Smooth approximations of the Heavyside function + ! Example 1: 1/2 (1+2/pi arctan(k x) ) x \in ]-infty,+infty [ + ! Example 2: 1/(1+exp(k x) ) x \in ]-infty,+infty [ + ! Example 3: sin(pi/2*s)**2 s \in [0,1] + RealAxis = (1-2*s)/(s*(s-1._DbKi)-1.0e-02_DbKi) ! Scaling from 0-1 to real axis + GammaScale = 1._ReKi- 1._ReKi/(1._ReKi+exp(real(RealAxis,ReKi))) + else + GammaScale = s ! Using a linear scaling + endif + endif + else + GammaScale=1.0_ReKi + endif + + if (p%CirculationMethod==idCircPrescribed) then + do iW = 1, p%nWings !Loop over lifting lines + Gamma_LL(1:p%nSpan,iW) = p%PrescribedCirculation(1:p%nSpan) + enddo + + else if (p%CirculationMethod==idCircPolarData) then + ! --- Solve for circulation using polar data + CALL Wings_ComputeCirculationPolarData(Gamma_LL, Gamma_LL_prev, p, x, m, AFInfo, GammaScale, ErrStat, ErrMsg, iLabel) + + else if (p%CirculationMethod==idCircNoFlowThrough) then + ! --- Solve for circulation using the no-flow through condition + ErrMsg='Circulation method nor implemented'; ErrStat=ErrID_Fatal; return ! should never happen + else + ErrMsg='Circulation method nor implemented'; ErrStat=ErrID_Fatal; return ! should never happen + endif + + ! Scale circulation (for initial transient) + Gamma_LL = Gamma_LL * GammaScale + + + endsubroutine Wings_ComputeCirculation + + !---------------------------------------------------------------------------------------------------------------------------------- + !> + subroutine Wings_ComputeCirculationPolarData(Gamma_LL, Gamma_LL_prev, p, x, m, AFInfo, GammaScale, ErrStat, ErrMsg, iLabel) + real(ReKi), dimension(:,:), intent(inout) :: Gamma_LL !< Circulation on all the lifting lines + real(ReKi), dimension(:,:), intent(in ) :: Gamma_LL_prev !< Previous/Guessed circulation + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_ContinuousStateType), intent(in ) :: x !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< Initial misc/optimization variables + real(ReKi), intent(in ) :: GammaScale !< Scaling factor used at init + 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 + integer(IntKi), intent(in) :: iLabel + ! Local + real(ReKi), dimension(:,:), allocatable :: DGamma !< + real(ReKi), dimension(:,:), allocatable :: GammaLastIter !< + logical :: bConverged !< + integer(IntKi) :: iIter !< iteration step number + real(ReKi) :: MeanGamma + real(ReKi), dimension(:,:,:), allocatable :: Vcst !< Part of the velocity that is constant + real(ReKi), dimension(:,:,:), allocatable :: Vvar !< Part of the velocity that is varies due to the solve + integer(IntKi) :: iW, iSpan, iDepth, iWCP, nCPs + real(ReKi), dimension(3) :: P1, P2, P3, P4 + real(ReKi) :: Gamm + ! Error handling + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + !print*,'Parameters for circulation solv: ',p%CircSolvConvCrit ,p%CircSolvRelaxation ,p%CircSolvMaxIter + + allocate(DGamma (1:p%nSpan,1:p%nWings)) + allocate(GammaLastIter(1:p%nSpan,1:p%nWings)) + + ! --- Last iteration circulation + if (m%FirstCall) then + ! We find a guess by looking simply at the Wind and Elasticity velocity + m%Vtot_ll = m%Vwnd_LL - m%Vstr_ll + call CirculationFromPolarData(GammaLastIter, p, m, AFInfo,ErrStat2,ErrMsg2); if(Failed()) return; + else + ! NOTE: we need to inverse the scaling to speed up the convergence + if (.not. EqualRealNos(GammaScale, 0.0_ReKi)) then + GammaLastIter(1:p%nSpan,1:p%nWings) = Gamma_LL_prev(1:p%nSpan,1:p%nWings) / GammaScale + else + GammaLastIter(1:p%nSpan,1:p%nWings) = Gamma_LL_prev(1:p%nSpan,1:p%nWings) + endif + endif + + if (any(x%r_NW(1,:,1:m%nNW+1,:)<-999)) then + ErrMsg='Wings_ComputeCirculationPolarData: Problem in input NW points'; ErrStat=ErrID_Fatal; return + endif + + + ! --- Setting up Vcst: part of the velocity that is constant withing the iteration loop + ! Vrel_ll_cst = U_u0 - U_body + call AllocAry(Vvar, 3, p%nSpan, p%nWings, 'Vvar', ErrStat2, ErrMsg2); if(Failed()) return; + call AllocAry(Vcst, 3, p%nSpan, p%nWings, 'Vcst', ErrStat2, ErrMsg2); if(Failed()) return; + + ! Set m%Vind_LL Induced velocity from Known wake only (after iNWStart+1) + call LiftingLineInducedVelocities(p, x, iNWStart+1, m, ErrStat2, ErrMsg2); if(Failed()) return; + + Vcst = m%Vind_LL + m%Vwnd_LL - m%Vstr_ll + + if (any(m%Vind_LL(1:3,:,:)<-99)) then + ErrMsg='Wings_ComputeCirculationPolarData: Problem in induced velocity on LL points'; ErrStat=ErrID_Fatal; return + endif + if (any(m%Vwnd_LL(1:3,:,:)<-99)) then + ErrMsg='Wings_ComputeCirculationPolarData: Problem in wind velocity on LL points'; ErrStat=ErrID_Fatal; return + endif + + ! --- Convergence loop until near wake gives induction coherent with circulation + bConverged=.false. + iIter=0 + do while (.not.(bConverged) .and. iIter= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine CleanUp() + if(allocated(DGamma )) deallocate(DGamma ) + if(allocated(GammaLastIter)) deallocate(GammaLastIter) + if(allocated(Vcst)) deallocate(Vcst) + if(allocated(Vvar)) deallocate(Vvar) + end subroutine + end subroutine Wings_ComputeCirculationPolarData + + + !> Compute circulation based on polar data + !! Uses m%Vtot_ll to compute Gamma_ll + subroutine CirculationFromPolarData(Gamma_LL, p, m, AFInfo, ErrStat, ErrMsg) + real(ReKi), dimension(:,:), intent(inout) :: Gamma_LL !< Circulation on all the lifting lines + type(FVW_ParameterType), intent(in ) :: p !< Parameters + type(FVW_MiscVarType), intent(inout) :: m !< 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 + + ! Local + integer(IntKi) :: iW, iCP !< Index on wings and spanwise control points + real(ReKi), dimension(3) :: N, Tc !< Normal and Tangent vector + real(ReKi), dimension(3) :: Vrel, Vrel_orth, Vjouk, Vjouk_orth + real(ReKi) :: Vrel_orth_norm, Vjouk_orth_norm, Vrel_norm + real(ReKi) :: alpha, Re, Cl, Cd, Cm + type(AFI_OutputType) :: AFI_interp + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + do iW=1,p%nWings + do icp=1,p%nSpan + ! Aliases to shorten notations + N = m%Norm(1:3, icp, iW) + Tc = m%Tang(1:3, icp, iW) + 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)) + 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) + + alpha = atan2(dot_product(Vrel,N) , dot_product(Vrel,Tc) ) ! [rad] + Re = p%Chord(icp,iW) * Vrel_norm / p%KinVisc / 1.0E6 + + !if (p%CircSolvPolar==idPolarAeroDyn) then + ! compute steady Airfoil Coefs ! NOTE: UserProp set to 0.0_ReKi (no idea what it does). Also, note this assumes airfoils at nodes. +!TODO: AFindx is on the nodes, not control points. + call AFI_ComputeAirfoilCoefs( alpha, Re, 0.0_ReKi, AFInfo(p%AFindx(icp,iW)), AFI_interp, ErrStat2, ErrMsg2 ); if(Failed()) return; + Cl = AFI_interp%Cl + Cd = AFI_interp%Cd + Cm = AFI_interp%Cm + ! Simple method: + ! Gamma_LL=(0.5 * Cl * Vrel_orth_norm*chord) + ! VanGarrel's method: + Gamma_LL(icp,iW) =(0.5_ReKi * Cl * Vrel_orth_norm**2*m%Area(icp,iW)/(Vjouk_orth_norm)) + ! Convenient storage + m%alpha_LL(icp, iW) = alpha ! [rad] + m%Vreln_LL(icp, iW) = Vrel_norm + enddo + enddo + contains + logical function Failed() + character(25) :: NodeText + if (ErrStat2 /= ErrID_None) then + NodeText = '(node '//trim(num2lstr(icp))//', blade '//trim(num2lstr(iW))//')' + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'CirculationFromPolarData'//trim(NodeText)) + end if + Failed = ErrStat >= AbortErrLev + end function Failed + end subroutine CirculationFromPolarData + +end module FVW_Wings diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index c85b2ceeda..0f525800ad 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -421,7 +421,6 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ KC%dalpha0 = KC%alpha_filt_cur - BL_p%alpha0 - ! Compute Kalpha using Eqn 1.7 @@ -492,9 +491,14 @@ 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 +else + KC%X1 = 0.0_ReKi ! u%alpha (and alpha_filt_cur) contains shed vorticity effect already + KC%X2 = 0.0_ReKi ! so that alpha_e = u%alpha-alpha0 directly +endif KC%alpha_e = (KC%alpha_filt_cur - BL_p%alpha0) - KC%X1 - KC%X2 ! Eqn 1.14 @@ -502,9 +506,14 @@ subroutine ComputeKelvinChain( i, j, u, p, xd, OtherState, misc, AFInfo, KC, BL_ if ( p%UAMod == UA_Gonzalez ) then ! Compute X3 and X4 using Eqn 1.16a and then add Cn_q_circ (Eqn 1.16) to the previously computed Cn_alpha_q_circ +if (p%ShedEffect) then KC%X3 = Get_ExpEqn( KC%ds*beta_M_Sqrd*BL_p%b1, 1.0_ReKi, xd%X3_minus1(i,j), BL_p%A1*(KC%q_f_cur - q_f_minus1), 0.0_ReKi ) ! Eqn 1.16a [1] KC%X4 = Get_ExpEqn( KC%ds*beta_M_Sqrd*BL_p%b2, 1.0_ReKi, xd%X4_minus1(i,j), BL_p%A2*(KC%q_f_cur - q_f_minus1), 0.0_ReKi ) ! Eqn 1.16a [2] - +else + 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) @@ -515,7 +524,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! @@ -949,48 +958,48 @@ 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) = 'ALPHA_filt'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 2) = 'VREL'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 3) = 'Cn'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 4) = 'Cc'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 5) = 'Cl'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 6) = 'Cd'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 7) = 'Cm'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 8) = 'Cn_aq_circ'//chanPrefix - InitOut%WriteOutputHdr(iOffset+ 9) = 'Cn_aq_nc'//chanPrefix - InitOut%WriteOutputHdr(iOffset+10) = 'Cn_pot'//chanPrefix - InitOut%WriteOutputHdr(iOffset+11) = 'Dp'//chanPrefix - InitOut%WriteOutputHdr(iOffset+12) = 'Cn_prime'//chanPrefix - InitOut%WriteOutputHdr(iOffset+13) = 'fprime'//chanPrefix - InitOut%WriteOutputHdr(iOffset+14) = 'Df'//chanPrefix - InitOut%WriteOutputHdr(iOffset+15) = 'Cn_v'//chanPrefix - InitOut%WriteOutputHdr(iOffset+16) = 'Tau_V'//chanPrefix - InitOut%WriteOutputHdr(iOffset+17) = 'LESF'//chanPrefix - InitOut%WriteOutputHdr(iOffset+18) = 'TESF'//chanPrefix - InitOut%WriteOutputHdr(iOffset+19) = 'VRTX'//chanPrefix - InitOut%WriteOutputHdr(iOffset+20) = 'C_v'//chanPrefix - InitOut%WriteOutputHdr(iOffset+21) = 'Cm_a_nc'//chanPrefix - InitOut%WriteOutputHdr(iOffset+22) = 'Cm_q_nc'//chanPrefix - InitOut%WriteOutputHdr(iOffset+23) = 'Cm_v'//chanPrefix - InitOut%WriteOutputHdr(iOffset+24) = 'alpha_p_f'//chanPrefix - InitOut%WriteOutputHdr(iOffset+25) = 'Dalphaf'//chanPrefix - InitOut%WriteOutputHdr(iOffset+26) = 'PMC'//chanPrefix - InitOut%WriteOutputHdr(iOffset+27) = 'T_f'//chanPrefix - InitOut%WriteOutputHdr(iOffset+28) = 'T_V'//chanPrefix - InitOut%WriteOutputHdr(iOffset+29) = 'dS'//chanPrefix - InitOut%WriteOutputHdr(iOffset+30) = 'T_alpha'//chanPrefix - InitOut%WriteOutputHdr(iOffset+31) = 'T_q'//chanPrefix - InitOut%WriteOutputHdr(iOffset+32) = 'k_alpha'//chanPrefix - InitOut%WriteOutputHdr(iOffset+33) = 'k_q'//chanPrefix - InitOut%WriteOutputHdr(iOffset+34) = 'alpha_e'//chanPrefix - InitOut%WriteOutputHdr(iOffset+35) = 'X1'//chanPrefix - InitOut%WriteOutputHdr(iOffset+36) = 'X2'//chanPrefix - InitOut%WriteOutputHdr(iOffset+37) = 'cn_q_nc'//chanPrefix - InitOut%WriteOutputHdr(iOffset+38) = 'alpha_f'//chanPrefix - InitOut%WriteOutputHdr(iOffset+39) = 'fprimeprime'//chanPrefix - InitOut%WriteOutputHdr(iOffset+40) = 'sigma1'//chanPrefix - InitOut%WriteOutputHdr(iOffset+41) = 'sigma3'//chanPrefix - InitOut%WriteOutputHdr(iOffset+42) = 'T_sh'//chanPrefix + InitOut%WriteOutputHdr(iOffset+ 1) = trim(chanPrefix)//'ALPHA_filt' + 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%WriteOutputUnt(iOffset+1) ='(deg)' diff --git a/modules/aerodyn/src/UnsteadyAero_Registry.txt b/modules/aerodyn/src/UnsteadyAero_Registry.txt index be524e7bd6..f10e9aefbe 100644 --- a/modules/aerodyn/src/UnsteadyAero_Registry.txt +++ b/modules/aerodyn/src/UnsteadyAero_Registry.txt @@ -183,6 +183,7 @@ typedef ^ ^ CHARACTER(2 typedef ^ ^ CHARACTER(20) OutSFmt - - - "Output format for header strings" - 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)" - # # diff --git a/modules/aerodyn/src/UnsteadyAero_Types.f90 b/modules/aerodyn/src/UnsteadyAero_Types.f90 index 6e79d82c90..86605ad912 100644 --- a/modules/aerodyn/src/UnsteadyAero_Types.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Types.f90 @@ -189,6 +189,7 @@ MODULE UnsteadyAero_Types CHARACTER(20) :: OutSFmt !< Output format for header strings [-] 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) [-] END TYPE UA_ParameterType ! ======================= ! ========= UA_InputType ======= @@ -4597,6 +4598,7 @@ SUBROUTINE UA_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) DstParamData%OutSFmt = SrcParamData%OutSFmt DstParamData%Delim = SrcParamData%Delim DstParamData%UnOutFile = SrcParamData%UnOutFile + DstParamData%ShedEffect = SrcParamData%ShedEffect END SUBROUTINE UA_CopyParam SUBROUTINE UA_DestroyParam( ParamData, ErrStat, ErrMsg ) @@ -4665,6 +4667,7 @@ SUBROUTINE UA_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si Int_BufSz = Int_BufSz + 1*LEN(InData%OutSFmt) ! OutSFmt Int_BufSz = Int_BufSz + 1*LEN(InData%Delim) ! Delim Int_BufSz = Int_BufSz + 1 ! UnOutFile + Int_BufSz = Int_BufSz + 1 ! ShedEffect IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4742,6 +4745,8 @@ SUBROUTINE UA_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si END DO ! I IntKiBuf(Int_Xferred) = InData%UnOutFile Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%ShedEffect, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE UA_PackParam SUBROUTINE UA_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -4825,6 +4830,8 @@ SUBROUTINE UA_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg END DO ! I OutData%UnOutFile = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%ShedEffect = TRANSFER(IntKiBuf(Int_Xferred), OutData%ShedEffect) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE UA_UnPackParam SUBROUTINE UA_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/aerodyn/tests/test_FVW_testsuite.F90 b/modules/aerodyn/tests/test_FVW_testsuite.F90 new file mode 100644 index 0000000000..57a72ea24b --- /dev/null +++ b/modules/aerodyn/tests/test_FVW_testsuite.F90 @@ -0,0 +1,48 @@ +@test +subroutine test_AD_FVW() + ! test branches + ! - known valid checks for various FVW routines (contained in own module) + ! - known invalid rotation matrix: halve the angle of the diagonal elements + + use pFUnit_mod + use NWTC_Num + use FVW_Tests + + implicit none + + integer(IntKi) :: ErrStat + character(ErrMsgLen) :: ErrMsg + character(1024) :: testname + + ! initialize NWTC_Num constants + call SetConstants() + +!This is a single routine that contains the test cases below. + ! -------------------------------------------------------------------------- + testname = "Set of FVW tests" + call FVW_RunTests( ErrStat, ErrMsg ) + @assertEqual(0, ErrStat, testname) + + +! test routines from FVW_RunTests to be run individually -- except these are all private +! ! -------------------------------------------------------------------------- +! testname = "known valid Biot-Savart segment" +! call Test_BiotSavart_Sgmt(testname, ErrStat, ErrMsg) +! @assertEqual(0, ErrStat, testname) +! +! ! -------------------------------------------------------------------------- +! testname = "known valid Biot-Savart part" +! call Test_BiotSavart_Part(testname, ErrStat, ErrMsg) +! @assertEqual(0, ErrStat, testname) +! +! ! -------------------------------------------------------------------------- +! testname = "known valid Biot-Savart to part-tree" +! call Test_BiotSavart_PartTree(testname, ErrStat, ErrMsg) +! @assertEqual(0, ErrStat, testname) +! +! ! -------------------------------------------------------------------------- +! testname = "known valid segment split to parts" +! call Test_SegmentsToPart(testname, ErrStat, ErrMsg) +! @assertEqual(0, ErrStat, testname) + +end subroutine test_AD_FVW diff --git a/modules/aerodyn14/src/AD14AeroConf_Types.f90 b/modules/aerodyn14/src/AD14AeroConf_Types.f90 new file mode 100644 index 0000000000..91c5a37363 --- /dev/null +++ b/modules/aerodyn14/src/AD14AeroConf_Types.f90 @@ -0,0 +1,2921 @@ +!STARTOFREGISTRYGENERATEDFILE 'AD14AeroConf_Types.f90' +! +! WARNING This file is generated automatically by the FAST registry. +! Do not edit. Your changes to this file will be lost. +! +! FAST Registry +!********************************************************************************************************************************* +! AD14AeroConf_Types +!................................................................................................................................. +! This file is part of AD14AeroConf. +! +! Copyright (C) 2012-2016 National Renewable Energy Laboratory +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +! +! W A R N I N G : This file was automatically generated from the FAST registry. Changes made to this file may be lost. +! +!********************************************************************************************************************************* +!> This module contains the user-defined types needed in AD14AeroConf. It also contains copy, destroy, pack, and +!! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. +MODULE AD14AeroConf_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE NWTC_Library +IMPLICIT NONE +! ========= Marker ======= + TYPE, PUBLIC :: Marker + REAL(ReKi) , DIMENSION(1:3) :: Position + REAL(ReKi) , DIMENSION(1:3,1:3) :: Orientation + REAL(ReKi) , DIMENSION(1:3) :: TranslationVel + REAL(ReKi) , DIMENSION(1:3) :: RotationVel + END TYPE Marker +! ======================= +! ========= AD14AeroConf_MiscVarType ======= + TYPE, PUBLIC :: AD14AeroConf_MiscVarType + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AL + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: CD + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: CL + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: CM + REAL(ReKi) :: PMC + REAL(ReKi) :: MulTabLoc + END TYPE AD14AeroConf_MiscVarType +! ======================= +! ========= AD14AeroConf_ParameterType ======= + TYPE, PUBLIC :: AD14AeroConf_ParameterType + INTEGER(IntKi) :: MaxTable = 20 + INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: NTables + INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: NLift + INTEGER(IntKi) :: NumCL + INTEGER(IntKi) :: NumFoil + INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: NFoil + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: MulTabMet + CHARACTER(1024) , DIMENSION(:), ALLOCATABLE :: FoilNm + END TYPE AD14AeroConf_ParameterType +! ======================= +! ========= AD14AeroConf_InputType ======= + TYPE, PUBLIC :: AD14AeroConf_InputType + TYPE(Marker) , DIMENSION(:), ALLOCATABLE :: Blade + TYPE(Marker) :: Hub + TYPE(Marker) :: RotorFurl + TYPE(Marker) :: Nacelle + TYPE(Marker) :: TailFin + TYPE(Marker) :: Tower + TYPE(Marker) :: SubStructure + TYPE(Marker) :: Foundation + REAL(ReKi) :: BladeLength + END TYPE AD14AeroConf_InputType +! ======================= +! ========= AD14AeroConf_OutputType ======= + TYPE, PUBLIC :: AD14AeroConf_OutputType + REAL(ReKi) :: Dummy + END TYPE AD14AeroConf_OutputType +! ======================= +CONTAINS + SUBROUTINE AD14AeroConf_CopyMarker( SrcMarkerData, DstMarkerData, CtrlCode, ErrStat, ErrMsg ) + TYPE(Marker), INTENT(IN) :: SrcMarkerData + TYPE(Marker), INTENT(INOUT) :: DstMarkerData + 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 = 'AD14AeroConf_CopyMarker' +! + ErrStat = ErrID_None + ErrMsg = "" + DstMarkerData%Position = SrcMarkerData%Position + DstMarkerData%Orientation = SrcMarkerData%Orientation + DstMarkerData%TranslationVel = SrcMarkerData%TranslationVel + DstMarkerData%RotationVel = SrcMarkerData%RotationVel + END SUBROUTINE AD14AeroConf_CopyMarker + + SUBROUTINE AD14AeroConf_DestroyMarker( MarkerData, ErrStat, ErrMsg ) + TYPE(Marker), INTENT(INOUT) :: MarkerData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_DestroyMarker' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE AD14AeroConf_DestroyMarker + + SUBROUTINE AD14AeroConf_PackMarker( 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(Marker), 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 = 'AD14AeroConf_PackMarker' + ! 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%Position) ! Position + Re_BufSz = Re_BufSz + SIZE(InData%Orientation) ! Orientation + Re_BufSz = Re_BufSz + SIZE(InData%TranslationVel) ! TranslationVel + Re_BufSz = Re_BufSz + SIZE(InData%RotationVel) ! RotationVel + 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 + + ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%Position))-1 ) = PACK(InData%Position,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%Position) + ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%Orientation))-1 ) = PACK(InData%Orientation,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%Orientation) + ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%TranslationVel))-1 ) = PACK(InData%TranslationVel,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%TranslationVel) + ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%RotationVel))-1 ) = PACK(InData%RotationVel,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%RotationVel) + END SUBROUTINE AD14AeroConf_PackMarker + + SUBROUTINE AD14AeroConf_UnPackMarker( 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(Marker), 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 + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + 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 = 'AD14AeroConf_UnPackMarker' + ! 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%Position,1) + i1_u = UBOUND(OutData%Position,1) + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + OutData%Position = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%Position))-1 ), mask1, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%Position) + DEALLOCATE(mask1) + i1_l = LBOUND(OutData%Orientation,1) + i1_u = UBOUND(OutData%Orientation,1) + i2_l = LBOUND(OutData%Orientation,2) + i2_u = UBOUND(OutData%Orientation,2) + ALLOCATE(mask2(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask2.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask2 = .TRUE. + OutData%Orientation = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%Orientation))-1 ), mask2, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%Orientation) + DEALLOCATE(mask2) + i1_l = LBOUND(OutData%TranslationVel,1) + i1_u = UBOUND(OutData%TranslationVel,1) + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + OutData%TranslationVel = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%TranslationVel))-1 ), mask1, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%TranslationVel) + DEALLOCATE(mask1) + i1_l = LBOUND(OutData%RotationVel,1) + i1_u = UBOUND(OutData%RotationVel,1) + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + OutData%RotationVel = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%RotationVel))-1 ), mask1, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%RotationVel) + DEALLOCATE(mask1) + END SUBROUTINE AD14AeroConf_UnPackMarker + + SUBROUTINE AD14AeroConf_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(AD14AeroConf_MiscVarType), INTENT(INOUT) :: DstMiscData + 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 = 'AD14AeroConf_CopyMisc' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcMiscData%AL)) THEN + i1_l = LBOUND(SrcMiscData%AL,1) + i1_u = UBOUND(SrcMiscData%AL,1) + i2_l = LBOUND(SrcMiscData%AL,2) + i2_u = UBOUND(SrcMiscData%AL,2) + IF (.NOT. ALLOCATED(DstMiscData%AL)) THEN + ALLOCATE(DstMiscData%AL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%AL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%AL = SrcMiscData%AL +ENDIF +IF (ALLOCATED(SrcMiscData%CD)) THEN + i1_l = LBOUND(SrcMiscData%CD,1) + i1_u = UBOUND(SrcMiscData%CD,1) + i2_l = LBOUND(SrcMiscData%CD,2) + i2_u = UBOUND(SrcMiscData%CD,2) + i3_l = LBOUND(SrcMiscData%CD,3) + i3_u = UBOUND(SrcMiscData%CD,3) + IF (.NOT. ALLOCATED(DstMiscData%CD)) THEN + ALLOCATE(DstMiscData%CD(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%CD.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%CD = SrcMiscData%CD +ENDIF +IF (ALLOCATED(SrcMiscData%CL)) THEN + i1_l = LBOUND(SrcMiscData%CL,1) + i1_u = UBOUND(SrcMiscData%CL,1) + i2_l = LBOUND(SrcMiscData%CL,2) + i2_u = UBOUND(SrcMiscData%CL,2) + i3_l = LBOUND(SrcMiscData%CL,3) + i3_u = UBOUND(SrcMiscData%CL,3) + IF (.NOT. ALLOCATED(DstMiscData%CL)) THEN + ALLOCATE(DstMiscData%CL(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%CL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%CL = SrcMiscData%CL +ENDIF +IF (ALLOCATED(SrcMiscData%CM)) THEN + i1_l = LBOUND(SrcMiscData%CM,1) + i1_u = UBOUND(SrcMiscData%CM,1) + i2_l = LBOUND(SrcMiscData%CM,2) + i2_u = UBOUND(SrcMiscData%CM,2) + i3_l = LBOUND(SrcMiscData%CM,3) + i3_u = UBOUND(SrcMiscData%CM,3) + IF (.NOT. ALLOCATED(DstMiscData%CM)) THEN + ALLOCATE(DstMiscData%CM(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%CM.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%CM = SrcMiscData%CM +ENDIF + DstMiscData%PMC = SrcMiscData%PMC + DstMiscData%MulTabLoc = SrcMiscData%MulTabLoc + END SUBROUTINE AD14AeroConf_CopyMisc + + SUBROUTINE AD14AeroConf_DestroyMisc( MiscData, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_MiscVarType), INTENT(INOUT) :: MiscData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_DestroyMisc' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(MiscData%AL)) THEN + DEALLOCATE(MiscData%AL) +ENDIF +IF (ALLOCATED(MiscData%CD)) THEN + DEALLOCATE(MiscData%CD) +ENDIF +IF (ALLOCATED(MiscData%CL)) THEN + DEALLOCATE(MiscData%CL) +ENDIF +IF (ALLOCATED(MiscData%CM)) THEN + DEALLOCATE(MiscData%CM) +ENDIF + END SUBROUTINE AD14AeroConf_DestroyMisc + + SUBROUTINE AD14AeroConf_PackMisc( 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(AD14AeroConf_MiscVarType), 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 = 'AD14AeroConf_PackMisc' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! AL allocated yes/no + IF ( ALLOCATED(InData%AL) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! AL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%AL) ! AL + END IF + Int_BufSz = Int_BufSz + 1 ! CD allocated yes/no + IF ( ALLOCATED(InData%CD) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! CD upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%CD) ! CD + END IF + Int_BufSz = Int_BufSz + 1 ! CL allocated yes/no + IF ( ALLOCATED(InData%CL) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! CL upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%CL) ! CL + END IF + Int_BufSz = Int_BufSz + 1 ! CM allocated yes/no + IF ( ALLOCATED(InData%CM) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! CM upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%CM) ! CM + END IF + Re_BufSz = Re_BufSz + 1 ! PMC + Re_BufSz = Re_BufSz + 1 ! MulTabLoc + 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%AL) ) 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%AL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%AL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AL,2) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%AL)>0) ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%AL))-1 ) = PACK(InData%AL,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%AL) + END IF + IF ( .NOT. ALLOCATED(InData%CD) ) 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%CD,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CD,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CD,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CD,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CD,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CD,3) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%CD)>0) ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%CD))-1 ) = PACK(InData%CD,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%CD) + END IF + IF ( .NOT. ALLOCATED(InData%CL) ) 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%CL,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CL,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CL,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CL,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CL,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CL,3) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%CL)>0) ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%CL))-1 ) = PACK(InData%CL,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%CL) + END IF + IF ( .NOT. ALLOCATED(InData%CM) ) 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%CM,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CM,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CM,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CM,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%CM,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%CM,3) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%CM)>0) ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%CM))-1 ) = PACK(InData%CM,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%CM) + END IF + ReKiBuf ( Re_Xferred:Re_Xferred+(1)-1 ) = InData%PMC + Re_Xferred = Re_Xferred + 1 + ReKiBuf ( Re_Xferred:Re_Xferred+(1)-1 ) = InData%MulTabLoc + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_PackMisc + + SUBROUTINE AD14AeroConf_UnPackMisc( 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(AD14AeroConf_MiscVarType), 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 + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + 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 = 'AD14AeroConf_UnPackMisc' + ! 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 ! AL 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%AL)) DEALLOCATE(OutData%AL) + ALLOCATE(OutData%AL(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%AL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask2(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask2.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask2 = .TRUE. + IF (SIZE(OutData%AL)>0) OutData%AL = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%AL))-1 ), mask2, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%AL) + DEALLOCATE(mask2) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CD 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%CD)) DEALLOCATE(OutData%CD) + ALLOCATE(OutData%CD(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%CD.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask3(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask3.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask3 = .TRUE. + IF (SIZE(OutData%CD)>0) OutData%CD = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%CD))-1 ), mask3, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%CD) + DEALLOCATE(mask3) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CL 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%CL)) DEALLOCATE(OutData%CL) + ALLOCATE(OutData%CL(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%CL.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask3(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask3.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask3 = .TRUE. + IF (SIZE(OutData%CL)>0) OutData%CL = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%CL))-1 ), mask3, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%CL) + DEALLOCATE(mask3) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CM 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%CM)) DEALLOCATE(OutData%CM) + ALLOCATE(OutData%CM(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%CM.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask3(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask3.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask3 = .TRUE. + IF (SIZE(OutData%CM)>0) OutData%CM = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%CM))-1 ), mask3, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%CM) + DEALLOCATE(mask3) + END IF + OutData%PMC = ReKiBuf( Re_Xferred ) + Re_Xferred = Re_Xferred + 1 + OutData%MulTabLoc = ReKiBuf( Re_Xferred ) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_UnPackMisc + + SUBROUTINE AD14AeroConf_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_ParameterType), INTENT(IN) :: SrcParamData + TYPE(AD14AeroConf_ParameterType), INTENT(INOUT) :: DstParamData + 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 = 'AD14AeroConf_CopyParam' +! + ErrStat = ErrID_None + ErrMsg = "" + DstParamData%MaxTable = SrcParamData%MaxTable +IF (ALLOCATED(SrcParamData%NTables)) THEN + i1_l = LBOUND(SrcParamData%NTables,1) + i1_u = UBOUND(SrcParamData%NTables,1) + IF (.NOT. ALLOCATED(DstParamData%NTables)) THEN + ALLOCATE(DstParamData%NTables(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%NTables.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%NTables = SrcParamData%NTables +ENDIF +IF (ALLOCATED(SrcParamData%NLift)) THEN + i1_l = LBOUND(SrcParamData%NLift,1) + i1_u = UBOUND(SrcParamData%NLift,1) + IF (.NOT. ALLOCATED(DstParamData%NLift)) THEN + ALLOCATE(DstParamData%NLift(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%NLift.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%NLift = SrcParamData%NLift +ENDIF + DstParamData%NumCL = SrcParamData%NumCL + DstParamData%NumFoil = SrcParamData%NumFoil +IF (ALLOCATED(SrcParamData%NFoil)) THEN + i1_l = LBOUND(SrcParamData%NFoil,1) + i1_u = UBOUND(SrcParamData%NFoil,1) + IF (.NOT. ALLOCATED(DstParamData%NFoil)) THEN + ALLOCATE(DstParamData%NFoil(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%NFoil.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%NFoil = SrcParamData%NFoil +ENDIF +IF (ALLOCATED(SrcParamData%MulTabMet)) THEN + i1_l = LBOUND(SrcParamData%MulTabMet,1) + i1_u = UBOUND(SrcParamData%MulTabMet,1) + i2_l = LBOUND(SrcParamData%MulTabMet,2) + i2_u = UBOUND(SrcParamData%MulTabMet,2) + IF (.NOT. ALLOCATED(DstParamData%MulTabMet)) THEN + ALLOCATE(DstParamData%MulTabMet(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%MulTabMet.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%MulTabMet = SrcParamData%MulTabMet +ENDIF +IF (ALLOCATED(SrcParamData%FoilNm)) THEN + i1_l = LBOUND(SrcParamData%FoilNm,1) + i1_u = UBOUND(SrcParamData%FoilNm,1) + IF (.NOT. ALLOCATED(DstParamData%FoilNm)) THEN + ALLOCATE(DstParamData%FoilNm(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%FoilNm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%FoilNm = SrcParamData%FoilNm +ENDIF + END SUBROUTINE AD14AeroConf_CopyParam + + SUBROUTINE AD14AeroConf_DestroyParam( ParamData, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_ParameterType), INTENT(INOUT) :: ParamData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_DestroyParam' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ParamData%NTables)) THEN + DEALLOCATE(ParamData%NTables) +ENDIF +IF (ALLOCATED(ParamData%NLift)) THEN + DEALLOCATE(ParamData%NLift) +ENDIF +IF (ALLOCATED(ParamData%NFoil)) THEN + DEALLOCATE(ParamData%NFoil) +ENDIF +IF (ALLOCATED(ParamData%MulTabMet)) THEN + DEALLOCATE(ParamData%MulTabMet) +ENDIF +IF (ALLOCATED(ParamData%FoilNm)) THEN + DEALLOCATE(ParamData%FoilNm) +ENDIF + END SUBROUTINE AD14AeroConf_DestroyParam + + SUBROUTINE AD14AeroConf_PackParam( 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(AD14AeroConf_ParameterType), 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 = 'AD14AeroConf_PackParam' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! MaxTable + Int_BufSz = Int_BufSz + 1 ! NTables allocated yes/no + IF ( ALLOCATED(InData%NTables) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! NTables upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%NTables) ! NTables + END IF + Int_BufSz = Int_BufSz + 1 ! NLift allocated yes/no + IF ( ALLOCATED(InData%NLift) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! NLift upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%NLift) ! NLift + END IF + Int_BufSz = Int_BufSz + 1 ! NumCL + Int_BufSz = Int_BufSz + 1 ! NumFoil + Int_BufSz = Int_BufSz + 1 ! NFoil allocated yes/no + IF ( ALLOCATED(InData%NFoil) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! NFoil upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%NFoil) ! NFoil + END IF + Int_BufSz = Int_BufSz + 1 ! MulTabMet allocated yes/no + IF ( ALLOCATED(InData%MulTabMet) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! MulTabMet upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%MulTabMet) ! MulTabMet + END IF + Int_BufSz = Int_BufSz + 1 ! FoilNm allocated yes/no + IF ( ALLOCATED(InData%FoilNm) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! FoilNm upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%FoilNm)*LEN(InData%FoilNm) ! FoilNm + 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 + + IntKiBuf ( Int_Xferred:Int_Xferred+(1)-1 ) = InData%MaxTable + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%NTables) ) 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%NTables,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%NTables,1) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%NTables)>0) IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(InData%NTables))-1 ) = PACK(InData%NTables,.TRUE.) + Int_Xferred = Int_Xferred + SIZE(InData%NTables) + END IF + IF ( .NOT. ALLOCATED(InData%NLift) ) 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%NLift,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%NLift,1) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%NLift)>0) IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(InData%NLift))-1 ) = PACK(InData%NLift,.TRUE.) + Int_Xferred = Int_Xferred + SIZE(InData%NLift) + END IF + IntKiBuf ( Int_Xferred:Int_Xferred+(1)-1 ) = InData%NumCL + Int_Xferred = Int_Xferred + 1 + IntKiBuf ( Int_Xferred:Int_Xferred+(1)-1 ) = InData%NumFoil + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%NFoil) ) 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%NFoil,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%NFoil,1) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%NFoil)>0) IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(InData%NFoil))-1 ) = PACK(InData%NFoil,.TRUE.) + Int_Xferred = Int_Xferred + SIZE(InData%NFoil) + END IF + IF ( .NOT. ALLOCATED(InData%MulTabMet) ) 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%MulTabMet,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%MulTabMet,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%MulTabMet,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%MulTabMet,2) + Int_Xferred = Int_Xferred + 2 + + IF (SIZE(InData%MulTabMet)>0) ReKiBuf ( Re_Xferred:Re_Xferred+(SIZE(InData%MulTabMet))-1 ) = PACK(InData%MulTabMet,.TRUE.) + Re_Xferred = Re_Xferred + SIZE(InData%MulTabMet) + END IF + IF ( .NOT. ALLOCATED(InData%FoilNm) ) 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%FoilNm,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%FoilNm,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%FoilNm,1), UBOUND(InData%FoilNm,1) + DO I = 1, LEN(InData%FoilNm) + IntKiBuf(Int_Xferred) = ICHAR(InData%FoilNm(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO !i1 + END IF + END SUBROUTINE AD14AeroConf_PackParam + + SUBROUTINE AD14AeroConf_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(AD14AeroConf_ParameterType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + 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 = 'AD14AeroConf_UnPackParam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%MaxTable = IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! NTables 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%NTables)) DEALLOCATE(OutData%NTables) + ALLOCATE(OutData%NTables(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%NTables.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + IF (SIZE(OutData%NTables)>0) OutData%NTables = UNPACK( IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(OutData%NTables))-1 ), mask1, 0_IntKi ) + Int_Xferred = Int_Xferred + SIZE(OutData%NTables) + DEALLOCATE(mask1) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! NLift 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%NLift)) DEALLOCATE(OutData%NLift) + ALLOCATE(OutData%NLift(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%NLift.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + IF (SIZE(OutData%NLift)>0) OutData%NLift = UNPACK( IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(OutData%NLift))-1 ), mask1, 0_IntKi ) + Int_Xferred = Int_Xferred + SIZE(OutData%NLift) + DEALLOCATE(mask1) + END IF + OutData%NumCL = IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + OutData%NumFoil = IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! NFoil 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%NFoil)) DEALLOCATE(OutData%NFoil) + ALLOCATE(OutData%NFoil(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%NFoil.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + IF (SIZE(OutData%NFoil)>0) OutData%NFoil = UNPACK( IntKiBuf ( Int_Xferred:Int_Xferred+(SIZE(OutData%NFoil))-1 ), mask1, 0_IntKi ) + Int_Xferred = Int_Xferred + SIZE(OutData%NFoil) + DEALLOCATE(mask1) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! MulTabMet 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%MulTabMet)) DEALLOCATE(OutData%MulTabMet) + ALLOCATE(OutData%MulTabMet(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%MulTabMet.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask2(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask2.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask2 = .TRUE. + IF (SIZE(OutData%MulTabMet)>0) OutData%MulTabMet = UNPACK(ReKiBuf( Re_Xferred:Re_Xferred+(SIZE(OutData%MulTabMet))-1 ), mask2, 0.0_ReKi ) + Re_Xferred = Re_Xferred + SIZE(OutData%MulTabMet) + DEALLOCATE(mask2) + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! FoilNm 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%FoilNm)) DEALLOCATE(OutData%FoilNm) + ALLOCATE(OutData%FoilNm(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%FoilNm.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + ALLOCATE(mask1(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating mask1.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + mask1 = .TRUE. + DO i1 = LBOUND(OutData%FoilNm,1), UBOUND(OutData%FoilNm,1) + DO I = 1, LEN(OutData%FoilNm) + OutData%FoilNm(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO !i1 + DEALLOCATE(mask1) + END IF + END SUBROUTINE AD14AeroConf_UnPackParam + + SUBROUTINE AD14AeroConf_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_InputType), INTENT(IN) :: SrcInputData + TYPE(AD14AeroConf_InputType), INTENT(INOUT) :: DstInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_CopyInput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcInputData%Blade)) THEN + i1_l = LBOUND(SrcInputData%Blade,1) + i1_u = UBOUND(SrcInputData%Blade,1) + IF (.NOT. ALLOCATED(DstInputData%Blade)) THEN + ALLOCATE(DstInputData%Blade(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%Blade.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcInputData%Blade,1), UBOUND(SrcInputData%Blade,1) + CALL AD14AeroConf_Copymarker( SrcInputData%Blade(i1), DstInputData%Blade(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF + CALL AD14AeroConf_Copymarker( SrcInputData%Hub, DstInputData%Hub, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%RotorFurl, DstInputData%RotorFurl, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%Nacelle, DstInputData%Nacelle, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%TailFin, DstInputData%TailFin, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%Tower, DstInputData%Tower, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%SubStructure, DstInputData%SubStructure, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL AD14AeroConf_Copymarker( SrcInputData%Foundation, DstInputData%Foundation, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstInputData%BladeLength = SrcInputData%BladeLength + END SUBROUTINE AD14AeroConf_CopyInput + + SUBROUTINE AD14AeroConf_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_InputType), INTENT(INOUT) :: InputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_DestroyInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InputData%Blade)) THEN +DO i1 = LBOUND(InputData%Blade,1), UBOUND(InputData%Blade,1) + CALL AD14AeroConf_Destroymarker( InputData%Blade(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(InputData%Blade) +ENDIF + CALL AD14AeroConf_Destroymarker( InputData%Hub, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%RotorFurl, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%Nacelle, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%TailFin, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%Tower, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%SubStructure, ErrStat, ErrMsg ) + CALL AD14AeroConf_Destroymarker( InputData%Foundation, ErrStat, ErrMsg ) + END SUBROUTINE AD14AeroConf_DestroyInput + + SUBROUTINE AD14AeroConf_PackInput( 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(AD14AeroConf_InputType), 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 = 'AD14AeroConf_PackInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! Blade allocated yes/no + IF ( ALLOCATED(InData%Blade) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Blade upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%Blade,1), UBOUND(InData%Blade,1) + Int_BufSz = Int_BufSz + 3 ! Blade: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Blade(i1), ErrStat2, ErrMsg2, .TRUE. ) ! Blade + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Blade + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Blade + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Blade + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 3 ! Hub: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Hub, ErrStat2, ErrMsg2, .TRUE. ) ! Hub + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Hub + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Hub + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Hub + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! RotorFurl: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%RotorFurl, ErrStat2, ErrMsg2, .TRUE. ) ! RotorFurl + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! RotorFurl + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! RotorFurl + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! RotorFurl + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! Nacelle: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Nacelle, ErrStat2, ErrMsg2, .TRUE. ) ! Nacelle + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Nacelle + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Nacelle + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Nacelle + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! TailFin: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%TailFin, ErrStat2, ErrMsg2, .TRUE. ) ! TailFin + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! TailFin + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! TailFin + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! TailFin + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! Tower: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Tower, ErrStat2, ErrMsg2, .TRUE. ) ! Tower + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Tower + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Tower + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Tower + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! SubStructure: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%SubStructure, ErrStat2, ErrMsg2, .TRUE. ) ! SubStructure + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! SubStructure + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! SubStructure + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! SubStructure + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! Foundation: size of buffers for each call to pack subtype + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Foundation, ErrStat2, ErrMsg2, .TRUE. ) ! Foundation + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Foundation + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Foundation + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Foundation + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Re_BufSz = Re_BufSz + 1 ! BladeLength + 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%Blade) ) 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%Blade,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Blade,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Blade,1), UBOUND(InData%Blade,1) + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Blade(i1), ErrStat2, ErrMsg2, OnlySize ) ! Blade + 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 + CALL AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Hub, ErrStat2, ErrMsg2, OnlySize ) ! Hub + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%RotorFurl, ErrStat2, ErrMsg2, OnlySize ) ! RotorFurl + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Nacelle, ErrStat2, ErrMsg2, OnlySize ) ! Nacelle + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%TailFin, ErrStat2, ErrMsg2, OnlySize ) ! TailFin + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Tower, ErrStat2, ErrMsg2, OnlySize ) ! Tower + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%SubStructure, ErrStat2, ErrMsg2, OnlySize ) ! SubStructure + 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 AD14AeroConf_Packmarker( Re_Buf, Db_Buf, Int_Buf, InData%Foundation, ErrStat2, ErrMsg2, OnlySize ) ! Foundation + 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 + ReKiBuf ( Re_Xferred:Re_Xferred+(1)-1 ) = InData%BladeLength + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_PackInput + + SUBROUTINE AD14AeroConf_UnPackInput( 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(AD14AeroConf_InputType), 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 + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_UnPackInput' + ! 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 ! Blade 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%Blade)) DEALLOCATE(OutData%Blade) + ALLOCATE(OutData%Blade(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Blade.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Blade,1), UBOUND(OutData%Blade,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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%Blade(i1), ErrStat2, ErrMsg2 ) ! Blade + 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 + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%Hub, ErrStat2, ErrMsg2 ) ! Hub + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%RotorFurl, ErrStat2, ErrMsg2 ) ! RotorFurl + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%Nacelle, ErrStat2, ErrMsg2 ) ! Nacelle + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%TailFin, ErrStat2, ErrMsg2 ) ! TailFin + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%Tower, ErrStat2, ErrMsg2 ) ! Tower + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%SubStructure, ErrStat2, ErrMsg2 ) ! SubStructure + 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 AD14AeroConf_Unpackmarker( Re_Buf, Db_Buf, Int_Buf, OutData%Foundation, ErrStat2, ErrMsg2 ) ! Foundation + 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%BladeLength = ReKiBuf( Re_Xferred ) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_UnPackInput + + SUBROUTINE AD14AeroConf_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: SrcOutputData + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: DstOutputData + 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 = 'AD14AeroConf_CopyOutput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstOutputData%Dummy = SrcOutputData%Dummy + END SUBROUTINE AD14AeroConf_CopyOutput + + SUBROUTINE AD14AeroConf_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: OutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_DestroyOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE AD14AeroConf_DestroyOutput + + SUBROUTINE AD14AeroConf_PackOutput( 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(AD14AeroConf_OutputType), 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 = 'AD14AeroConf_PackOutput' + ! 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 ! Dummy + 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 + + ReKiBuf ( Re_Xferred:Re_Xferred+(1)-1 ) = InData%Dummy + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_PackOutput + + SUBROUTINE AD14AeroConf_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%Dummy = ReKiBuf( Re_Xferred ) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE AD14AeroConf_UnPackOutput + + + SUBROUTINE AD14AeroConf_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u(:) ! Input at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Inputs + TYPE(AD14AeroConf_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Input_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 AD14AeroConf_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL AD14AeroConf_Input_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 AD14AeroConf_Input_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 AD14AeroConf_Input_ExtrapInterp + + + SUBROUTINE AD14AeroConf_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u2 ! Input at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs + TYPE(AD14AeroConf_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Input_ExtrapInterp1' + REAL(DbKi) :: b0 ! temporary for extrapolation/interpolation + REAL(DbKi) :: c0 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:) :: b1 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:) :: c1 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:,:) :: b2 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:,:) :: c2 ! 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 + ! 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 +IF (ALLOCATED(u_out%Blade) .AND. ALLOCATED(u1%Blade)) THEN + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%Position,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%Position,1))) + b1 = -(u1%Blade(i01)%Position - u2%Blade(i01)%Position)/t(2) + u_out%Blade(i01)%Position = u1%Blade(i01)%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b2(SIZE(u_out%Blade(i01)%Orientation,1),SIZE(u_out%Blade(i01)%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Blade(i01)%Orientation,1),SIZE(u_out%Blade(i01)%Orientation,2) )) + b2 = -(u1%Blade(i01)%Orientation - u2%Blade(i01)%Orientation)/t(2) + u_out%Blade(i01)%Orientation = u1%Blade(i01)%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%TranslationVel,1))) + b1 = -(u1%Blade(i01)%TranslationVel - u2%Blade(i01)%TranslationVel)/t(2) + u_out%Blade(i01)%TranslationVel = u1%Blade(i01)%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%RotationVel,1))) + b1 = -(u1%Blade(i01)%RotationVel - u2%Blade(i01)%RotationVel)/t(2) + u_out%Blade(i01)%RotationVel = u1%Blade(i01)%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO +END IF ! check if allocated + ALLOCATE(b1(SIZE(u_out%Hub%Position,1))) + ALLOCATE(c1(SIZE(u_out%Hub%Position,1))) + b1 = -(u1%Hub%Position - u2%Hub%Position)/t(2) + u_out%Hub%Position = u1%Hub%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Hub%Orientation,1),SIZE(u_out%Hub%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Hub%Orientation,1),SIZE(u_out%Hub%Orientation,2) )) + b2 = -(u1%Hub%Orientation - u2%Hub%Orientation)/t(2) + u_out%Hub%Orientation = u1%Hub%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Hub%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Hub%TranslationVel,1))) + b1 = -(u1%Hub%TranslationVel - u2%Hub%TranslationVel)/t(2) + u_out%Hub%TranslationVel = u1%Hub%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Hub%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Hub%RotationVel,1))) + b1 = -(u1%Hub%RotationVel - u2%Hub%RotationVel)/t(2) + u_out%Hub%RotationVel = u1%Hub%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%RotorFurl%Position,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%Position,1))) + b1 = -(u1%RotorFurl%Position - u2%RotorFurl%Position)/t(2) + u_out%RotorFurl%Position = u1%RotorFurl%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%RotorFurl%Orientation,1),SIZE(u_out%RotorFurl%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%RotorFurl%Orientation,1),SIZE(u_out%RotorFurl%Orientation,2) )) + b2 = -(u1%RotorFurl%Orientation - u2%RotorFurl%Orientation)/t(2) + u_out%RotorFurl%Orientation = u1%RotorFurl%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%RotorFurl%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%TranslationVel,1))) + b1 = -(u1%RotorFurl%TranslationVel - u2%RotorFurl%TranslationVel)/t(2) + u_out%RotorFurl%TranslationVel = u1%RotorFurl%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%RotorFurl%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%RotationVel,1))) + b1 = -(u1%RotorFurl%RotationVel - u2%RotorFurl%RotationVel)/t(2) + u_out%RotorFurl%RotationVel = u1%RotorFurl%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Nacelle%Position,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%Position,1))) + b1 = -(u1%Nacelle%Position - u2%Nacelle%Position)/t(2) + u_out%Nacelle%Position = u1%Nacelle%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Nacelle%Orientation,1),SIZE(u_out%Nacelle%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Nacelle%Orientation,1),SIZE(u_out%Nacelle%Orientation,2) )) + b2 = -(u1%Nacelle%Orientation - u2%Nacelle%Orientation)/t(2) + u_out%Nacelle%Orientation = u1%Nacelle%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Nacelle%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%TranslationVel,1))) + b1 = -(u1%Nacelle%TranslationVel - u2%Nacelle%TranslationVel)/t(2) + u_out%Nacelle%TranslationVel = u1%Nacelle%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Nacelle%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%RotationVel,1))) + b1 = -(u1%Nacelle%RotationVel - u2%Nacelle%RotationVel)/t(2) + u_out%Nacelle%RotationVel = u1%Nacelle%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%TailFin%Position,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%Position,1))) + b1 = -(u1%TailFin%Position - u2%TailFin%Position)/t(2) + u_out%TailFin%Position = u1%TailFin%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%TailFin%Orientation,1),SIZE(u_out%TailFin%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%TailFin%Orientation,1),SIZE(u_out%TailFin%Orientation,2) )) + b2 = -(u1%TailFin%Orientation - u2%TailFin%Orientation)/t(2) + u_out%TailFin%Orientation = u1%TailFin%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%TailFin%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%TranslationVel,1))) + b1 = -(u1%TailFin%TranslationVel - u2%TailFin%TranslationVel)/t(2) + u_out%TailFin%TranslationVel = u1%TailFin%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%TailFin%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%RotationVel,1))) + b1 = -(u1%TailFin%RotationVel - u2%TailFin%RotationVel)/t(2) + u_out%TailFin%RotationVel = u1%TailFin%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Tower%Position,1))) + ALLOCATE(c1(SIZE(u_out%Tower%Position,1))) + b1 = -(u1%Tower%Position - u2%Tower%Position)/t(2) + u_out%Tower%Position = u1%Tower%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Tower%Orientation,1),SIZE(u_out%Tower%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Tower%Orientation,1),SIZE(u_out%Tower%Orientation,2) )) + b2 = -(u1%Tower%Orientation - u2%Tower%Orientation)/t(2) + u_out%Tower%Orientation = u1%Tower%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Tower%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Tower%TranslationVel,1))) + b1 = -(u1%Tower%TranslationVel - u2%Tower%TranslationVel)/t(2) + u_out%Tower%TranslationVel = u1%Tower%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Tower%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Tower%RotationVel,1))) + b1 = -(u1%Tower%RotationVel - u2%Tower%RotationVel)/t(2) + u_out%Tower%RotationVel = u1%Tower%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%SubStructure%Position,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%Position,1))) + b1 = -(u1%SubStructure%Position - u2%SubStructure%Position)/t(2) + u_out%SubStructure%Position = u1%SubStructure%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%SubStructure%Orientation,1),SIZE(u_out%SubStructure%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%SubStructure%Orientation,1),SIZE(u_out%SubStructure%Orientation,2) )) + b2 = -(u1%SubStructure%Orientation - u2%SubStructure%Orientation)/t(2) + u_out%SubStructure%Orientation = u1%SubStructure%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%SubStructure%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%TranslationVel,1))) + b1 = -(u1%SubStructure%TranslationVel - u2%SubStructure%TranslationVel)/t(2) + u_out%SubStructure%TranslationVel = u1%SubStructure%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%SubStructure%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%RotationVel,1))) + b1 = -(u1%SubStructure%RotationVel - u2%SubStructure%RotationVel)/t(2) + u_out%SubStructure%RotationVel = u1%SubStructure%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Foundation%Position,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%Position,1))) + b1 = -(u1%Foundation%Position - u2%Foundation%Position)/t(2) + u_out%Foundation%Position = u1%Foundation%Position + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Foundation%Orientation,1),SIZE(u_out%Foundation%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Foundation%Orientation,1),SIZE(u_out%Foundation%Orientation,2) )) + b2 = -(u1%Foundation%Orientation - u2%Foundation%Orientation)/t(2) + u_out%Foundation%Orientation = u1%Foundation%Orientation + b2 * t_out + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Foundation%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%TranslationVel,1))) + b1 = -(u1%Foundation%TranslationVel - u2%Foundation%TranslationVel)/t(2) + u_out%Foundation%TranslationVel = u1%Foundation%TranslationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Foundation%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%RotationVel,1))) + b1 = -(u1%Foundation%RotationVel - u2%Foundation%RotationVel)/t(2) + u_out%Foundation%RotationVel = u1%Foundation%RotationVel + b1 * t_out + DEALLOCATE(b1) + DEALLOCATE(c1) + b0 = -(u1%BladeLength - u2%BladeLength)/t(2) + u_out%BladeLength = u1%BladeLength + b0 * t_out + END SUBROUTINE AD14AeroConf_Input_ExtrapInterp1 + + + SUBROUTINE AD14AeroConf_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 > t3 + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u2 ! Input at t2 > t3 + TYPE(AD14AeroConf_InputType), INTENT(IN) :: u3 ! Input at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs + TYPE(AD14AeroConf_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b0 ! temporary for extrapolation/interpolation + REAL(DbKi) :: c0 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:) :: b1 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:) :: c1 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:,:) :: b2 ! temporary for extrapolation/interpolation + REAL(DbKi),ALLOCATABLE,DIMENSION(:,:) :: c2 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Input_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + ! 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 +IF (ALLOCATED(u_out%Blade) .AND. ALLOCATED(u1%Blade)) THEN + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%Position,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%Position,1))) + b1 = (t(3)**2*(u1%Blade(i01)%Position - u2%Blade(i01)%Position) + t(2)**2*(-u1%Blade(i01)%Position + u3%Blade(i01)%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Blade(i01)%Position + t(3)*u2%Blade(i01)%Position - t(2)*u3%Blade(i01)%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Blade(i01)%Position = u1%Blade(i01)%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b2(SIZE(u_out%Blade(i01)%Orientation,1),SIZE(u_out%Blade(i01)%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Blade(i01)%Orientation,1),SIZE(u_out%Blade(i01)%Orientation,2) )) + b2 = (t(3)**2*(u1%Blade(i01)%Orientation - u2%Blade(i01)%Orientation) + t(2)**2*(-u1%Blade(i01)%Orientation + u3%Blade(i01)%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%Blade(i01)%Orientation + t(3)*u2%Blade(i01)%Orientation - t(2)*u3%Blade(i01)%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Blade(i01)%Orientation = u1%Blade(i01)%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%TranslationVel,1))) + b1 = (t(3)**2*(u1%Blade(i01)%TranslationVel - u2%Blade(i01)%TranslationVel) + t(2)**2*(-u1%Blade(i01)%TranslationVel + u3%Blade(i01)%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Blade(i01)%TranslationVel + t(3)*u2%Blade(i01)%TranslationVel - t(2)*u3%Blade(i01)%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Blade(i01)%TranslationVel = u1%Blade(i01)%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO + DO i01 = LBOUND(u_out%Blade,1),UBOUND(u_out%Blade,1) + ALLOCATE(b1(SIZE(u_out%Blade(i01)%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Blade(i01)%RotationVel,1))) + b1 = (t(3)**2*(u1%Blade(i01)%RotationVel - u2%Blade(i01)%RotationVel) + t(2)**2*(-u1%Blade(i01)%RotationVel + u3%Blade(i01)%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Blade(i01)%RotationVel + t(3)*u2%Blade(i01)%RotationVel - t(2)*u3%Blade(i01)%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Blade(i01)%RotationVel = u1%Blade(i01)%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ENDDO +END IF ! check if allocated + ALLOCATE(b1(SIZE(u_out%Hub%Position,1))) + ALLOCATE(c1(SIZE(u_out%Hub%Position,1))) + b1 = (t(3)**2*(u1%Hub%Position - u2%Hub%Position) + t(2)**2*(-u1%Hub%Position + u3%Hub%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Hub%Position + t(3)*u2%Hub%Position - t(2)*u3%Hub%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Hub%Position = u1%Hub%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Hub%Orientation,1),SIZE(u_out%Hub%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Hub%Orientation,1),SIZE(u_out%Hub%Orientation,2) )) + b2 = (t(3)**2*(u1%Hub%Orientation - u2%Hub%Orientation) + t(2)**2*(-u1%Hub%Orientation + u3%Hub%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%Hub%Orientation + t(3)*u2%Hub%Orientation - t(2)*u3%Hub%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Hub%Orientation = u1%Hub%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Hub%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Hub%TranslationVel,1))) + b1 = (t(3)**2*(u1%Hub%TranslationVel - u2%Hub%TranslationVel) + t(2)**2*(-u1%Hub%TranslationVel + u3%Hub%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Hub%TranslationVel + t(3)*u2%Hub%TranslationVel - t(2)*u3%Hub%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Hub%TranslationVel = u1%Hub%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Hub%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Hub%RotationVel,1))) + b1 = (t(3)**2*(u1%Hub%RotationVel - u2%Hub%RotationVel) + t(2)**2*(-u1%Hub%RotationVel + u3%Hub%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Hub%RotationVel + t(3)*u2%Hub%RotationVel - t(2)*u3%Hub%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Hub%RotationVel = u1%Hub%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%RotorFurl%Position,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%Position,1))) + b1 = (t(3)**2*(u1%RotorFurl%Position - u2%RotorFurl%Position) + t(2)**2*(-u1%RotorFurl%Position + u3%RotorFurl%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%RotorFurl%Position + t(3)*u2%RotorFurl%Position - t(2)*u3%RotorFurl%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%RotorFurl%Position = u1%RotorFurl%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%RotorFurl%Orientation,1),SIZE(u_out%RotorFurl%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%RotorFurl%Orientation,1),SIZE(u_out%RotorFurl%Orientation,2) )) + b2 = (t(3)**2*(u1%RotorFurl%Orientation - u2%RotorFurl%Orientation) + t(2)**2*(-u1%RotorFurl%Orientation + u3%RotorFurl%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%RotorFurl%Orientation + t(3)*u2%RotorFurl%Orientation - t(2)*u3%RotorFurl%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%RotorFurl%Orientation = u1%RotorFurl%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%RotorFurl%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%TranslationVel,1))) + b1 = (t(3)**2*(u1%RotorFurl%TranslationVel - u2%RotorFurl%TranslationVel) + t(2)**2*(-u1%RotorFurl%TranslationVel + u3%RotorFurl%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%RotorFurl%TranslationVel + t(3)*u2%RotorFurl%TranslationVel - t(2)*u3%RotorFurl%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%RotorFurl%TranslationVel = u1%RotorFurl%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%RotorFurl%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%RotorFurl%RotationVel,1))) + b1 = (t(3)**2*(u1%RotorFurl%RotationVel - u2%RotorFurl%RotationVel) + t(2)**2*(-u1%RotorFurl%RotationVel + u3%RotorFurl%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%RotorFurl%RotationVel + t(3)*u2%RotorFurl%RotationVel - t(2)*u3%RotorFurl%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%RotorFurl%RotationVel = u1%RotorFurl%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Nacelle%Position,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%Position,1))) + b1 = (t(3)**2*(u1%Nacelle%Position - u2%Nacelle%Position) + t(2)**2*(-u1%Nacelle%Position + u3%Nacelle%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Nacelle%Position + t(3)*u2%Nacelle%Position - t(2)*u3%Nacelle%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Nacelle%Position = u1%Nacelle%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Nacelle%Orientation,1),SIZE(u_out%Nacelle%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Nacelle%Orientation,1),SIZE(u_out%Nacelle%Orientation,2) )) + b2 = (t(3)**2*(u1%Nacelle%Orientation - u2%Nacelle%Orientation) + t(2)**2*(-u1%Nacelle%Orientation + u3%Nacelle%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%Nacelle%Orientation + t(3)*u2%Nacelle%Orientation - t(2)*u3%Nacelle%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Nacelle%Orientation = u1%Nacelle%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Nacelle%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%TranslationVel,1))) + b1 = (t(3)**2*(u1%Nacelle%TranslationVel - u2%Nacelle%TranslationVel) + t(2)**2*(-u1%Nacelle%TranslationVel + u3%Nacelle%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Nacelle%TranslationVel + t(3)*u2%Nacelle%TranslationVel - t(2)*u3%Nacelle%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Nacelle%TranslationVel = u1%Nacelle%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Nacelle%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Nacelle%RotationVel,1))) + b1 = (t(3)**2*(u1%Nacelle%RotationVel - u2%Nacelle%RotationVel) + t(2)**2*(-u1%Nacelle%RotationVel + u3%Nacelle%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Nacelle%RotationVel + t(3)*u2%Nacelle%RotationVel - t(2)*u3%Nacelle%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Nacelle%RotationVel = u1%Nacelle%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%TailFin%Position,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%Position,1))) + b1 = (t(3)**2*(u1%TailFin%Position - u2%TailFin%Position) + t(2)**2*(-u1%TailFin%Position + u3%TailFin%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%TailFin%Position + t(3)*u2%TailFin%Position - t(2)*u3%TailFin%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%TailFin%Position = u1%TailFin%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%TailFin%Orientation,1),SIZE(u_out%TailFin%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%TailFin%Orientation,1),SIZE(u_out%TailFin%Orientation,2) )) + b2 = (t(3)**2*(u1%TailFin%Orientation - u2%TailFin%Orientation) + t(2)**2*(-u1%TailFin%Orientation + u3%TailFin%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%TailFin%Orientation + t(3)*u2%TailFin%Orientation - t(2)*u3%TailFin%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%TailFin%Orientation = u1%TailFin%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%TailFin%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%TranslationVel,1))) + b1 = (t(3)**2*(u1%TailFin%TranslationVel - u2%TailFin%TranslationVel) + t(2)**2*(-u1%TailFin%TranslationVel + u3%TailFin%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%TailFin%TranslationVel + t(3)*u2%TailFin%TranslationVel - t(2)*u3%TailFin%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%TailFin%TranslationVel = u1%TailFin%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%TailFin%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%TailFin%RotationVel,1))) + b1 = (t(3)**2*(u1%TailFin%RotationVel - u2%TailFin%RotationVel) + t(2)**2*(-u1%TailFin%RotationVel + u3%TailFin%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%TailFin%RotationVel + t(3)*u2%TailFin%RotationVel - t(2)*u3%TailFin%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%TailFin%RotationVel = u1%TailFin%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Tower%Position,1))) + ALLOCATE(c1(SIZE(u_out%Tower%Position,1))) + b1 = (t(3)**2*(u1%Tower%Position - u2%Tower%Position) + t(2)**2*(-u1%Tower%Position + u3%Tower%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Tower%Position + t(3)*u2%Tower%Position - t(2)*u3%Tower%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Tower%Position = u1%Tower%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Tower%Orientation,1),SIZE(u_out%Tower%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Tower%Orientation,1),SIZE(u_out%Tower%Orientation,2) )) + b2 = (t(3)**2*(u1%Tower%Orientation - u2%Tower%Orientation) + t(2)**2*(-u1%Tower%Orientation + u3%Tower%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%Tower%Orientation + t(3)*u2%Tower%Orientation - t(2)*u3%Tower%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Tower%Orientation = u1%Tower%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Tower%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Tower%TranslationVel,1))) + b1 = (t(3)**2*(u1%Tower%TranslationVel - u2%Tower%TranslationVel) + t(2)**2*(-u1%Tower%TranslationVel + u3%Tower%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Tower%TranslationVel + t(3)*u2%Tower%TranslationVel - t(2)*u3%Tower%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Tower%TranslationVel = u1%Tower%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Tower%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Tower%RotationVel,1))) + b1 = (t(3)**2*(u1%Tower%RotationVel - u2%Tower%RotationVel) + t(2)**2*(-u1%Tower%RotationVel + u3%Tower%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Tower%RotationVel + t(3)*u2%Tower%RotationVel - t(2)*u3%Tower%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Tower%RotationVel = u1%Tower%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%SubStructure%Position,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%Position,1))) + b1 = (t(3)**2*(u1%SubStructure%Position - u2%SubStructure%Position) + t(2)**2*(-u1%SubStructure%Position + u3%SubStructure%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%SubStructure%Position + t(3)*u2%SubStructure%Position - t(2)*u3%SubStructure%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%SubStructure%Position = u1%SubStructure%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%SubStructure%Orientation,1),SIZE(u_out%SubStructure%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%SubStructure%Orientation,1),SIZE(u_out%SubStructure%Orientation,2) )) + b2 = (t(3)**2*(u1%SubStructure%Orientation - u2%SubStructure%Orientation) + t(2)**2*(-u1%SubStructure%Orientation + u3%SubStructure%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%SubStructure%Orientation + t(3)*u2%SubStructure%Orientation - t(2)*u3%SubStructure%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%SubStructure%Orientation = u1%SubStructure%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%SubStructure%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%TranslationVel,1))) + b1 = (t(3)**2*(u1%SubStructure%TranslationVel - u2%SubStructure%TranslationVel) + t(2)**2*(-u1%SubStructure%TranslationVel + u3%SubStructure%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%SubStructure%TranslationVel + t(3)*u2%SubStructure%TranslationVel - t(2)*u3%SubStructure%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%SubStructure%TranslationVel = u1%SubStructure%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%SubStructure%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%SubStructure%RotationVel,1))) + b1 = (t(3)**2*(u1%SubStructure%RotationVel - u2%SubStructure%RotationVel) + t(2)**2*(-u1%SubStructure%RotationVel + u3%SubStructure%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%SubStructure%RotationVel + t(3)*u2%SubStructure%RotationVel - t(2)*u3%SubStructure%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%SubStructure%RotationVel = u1%SubStructure%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Foundation%Position,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%Position,1))) + b1 = (t(3)**2*(u1%Foundation%Position - u2%Foundation%Position) + t(2)**2*(-u1%Foundation%Position + u3%Foundation%Position))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Foundation%Position + t(3)*u2%Foundation%Position - t(2)*u3%Foundation%Position ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Foundation%Position = u1%Foundation%Position + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b2(SIZE(u_out%Foundation%Orientation,1),SIZE(u_out%Foundation%Orientation,2) )) + ALLOCATE(c2(SIZE(u_out%Foundation%Orientation,1),SIZE(u_out%Foundation%Orientation,2) )) + b2 = (t(3)**2*(u1%Foundation%Orientation - u2%Foundation%Orientation) + t(2)**2*(-u1%Foundation%Orientation + u3%Foundation%Orientation))/(t(2)*t(3)*(t(2) - t(3))) + c2 = ( (t(2)-t(3))*u1%Foundation%Orientation + t(3)*u2%Foundation%Orientation - t(2)*u3%Foundation%Orientation ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Foundation%Orientation = u1%Foundation%Orientation + b2 * t_out + c2 * t_out**2 + DEALLOCATE(b2) + DEALLOCATE(c2) + ALLOCATE(b1(SIZE(u_out%Foundation%TranslationVel,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%TranslationVel,1))) + b1 = (t(3)**2*(u1%Foundation%TranslationVel - u2%Foundation%TranslationVel) + t(2)**2*(-u1%Foundation%TranslationVel + u3%Foundation%TranslationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Foundation%TranslationVel + t(3)*u2%Foundation%TranslationVel - t(2)*u3%Foundation%TranslationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Foundation%TranslationVel = u1%Foundation%TranslationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + ALLOCATE(b1(SIZE(u_out%Foundation%RotationVel,1))) + ALLOCATE(c1(SIZE(u_out%Foundation%RotationVel,1))) + b1 = (t(3)**2*(u1%Foundation%RotationVel - u2%Foundation%RotationVel) + t(2)**2*(-u1%Foundation%RotationVel + u3%Foundation%RotationVel))/(t(2)*t(3)*(t(2) - t(3))) + c1 = ( (t(2)-t(3))*u1%Foundation%RotationVel + t(3)*u2%Foundation%RotationVel - t(2)*u3%Foundation%RotationVel ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%Foundation%RotationVel = u1%Foundation%RotationVel + b1 * t_out + c1 * t_out**2 + DEALLOCATE(b1) + DEALLOCATE(c1) + b0 = (t(3)**2*(u1%BladeLength - u2%BladeLength) + t(2)**2*(-u1%BladeLength + u3%BladeLength))/(t(2)*t(3)*(t(2) - t(3))) + c0 = ( (t(2)-t(3))*u1%BladeLength + t(3)*u2%BladeLength - t(2)*u3%BladeLength ) / (t(2)*t(3)*(t(2) - t(3))) + u_out%BladeLength = u1%BladeLength + b0 * t_out + c0 * t_out**2 + END SUBROUTINE AD14AeroConf_Input_ExtrapInterp2 + + + SUBROUTINE AD14AeroConf_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is given by the size of y +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y(:) ! Output at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Outputs + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Output_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(y)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(y)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(y) - 1 + IF ( order .eq. 0 ) THEN + CALL AD14AeroConf_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL AD14AeroConf_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL AD14AeroConf_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(y) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE AD14AeroConf_Output_ExtrapInterp + + + SUBROUTINE AD14AeroConf_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = y1, f(t2) = y2 +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y2 ! Output at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Output_ExtrapInterp1' + REAL(DbKi) :: b0 ! temporary for extrapolation/interpolation + REAL(DbKi) :: c0 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + ! 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 + b0 = -(y1%Dummy - y2%Dummy)/t(2) + y_out%Dummy = y1%Dummy + b0 * t_out + END SUBROUTINE AD14AeroConf_Output_ExtrapInterp1 + + + SUBROUTINE AD14AeroConf_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 +! +!.................................................................................................................................. + + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 > t3 + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y2 ! Output at t2 > t3 + TYPE(AD14AeroConf_OutputType), INTENT(IN) :: y3 ! Output at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs + TYPE(AD14AeroConf_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b0 ! temporary for extrapolation/interpolation + REAL(DbKi) :: c0 ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'AD14AeroConf_Output_ExtrapInterp2' + ! 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 + b0 = (t(3)**2*(y1%Dummy - y2%Dummy) + t(2)**2*(-y1%Dummy + y3%Dummy))/(t(2)*t(3)*(t(2) - t(3))) + c0 = ( (t(2)-t(3))*y1%Dummy + t(3)*y2%Dummy - t(2)*y3%Dummy ) / (t(2)*t(3)*(t(2) - t(3))) + y_out%Dummy = y1%Dummy + b0 * t_out + c0 * t_out**2 + END SUBROUTINE AD14AeroConf_Output_ExtrapInterp2 + +END MODULE AD14AeroConf_Types +!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/aerodyn14/src/AeroDyn14.f90 b/modules/aerodyn14/src/AeroDyn14.f90 index 321d114d76..b608cef645 100644 --- a/modules/aerodyn14/src/AeroDyn14.f90 +++ b/modules/aerodyn14/src/AeroDyn14.f90 @@ -165,6 +165,11 @@ SUBROUTINE AD14_Init( InitInp, u, p, x, xd, z, O, y, m, Interval, InitOut, ErrSt CALL AllocAry(m%Element%Alpha, p%Element%NELM, p%NumBl,'m%Element%Alpha',ErrStatLcl,ErrMessLcl ) CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName) END IF + + IF (.NOT. ALLOCATED(m%Element%PitNow) ) THEN + CALL AllocAry(m%Element%PitNow, p%Element%NELM, p%NumBl,'m%Element%PitNow',ErrStatLcl,ErrMessLcl ) + CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName) + END IF IF (ErrStat >= AbortErrLev ) RETURN @@ -726,6 +731,7 @@ SUBROUTINE AD14_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrSt ! identify which variables are states. END SUBROUTINE AD14_UpdateStates + !---------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) ! Routine for computing outputs, used in both loose and tight coupling. @@ -736,11 +742,11 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) USE DWM REAL(DbKi), INTENT(IN ) :: Time ! Current simulation time in seconds - TYPE(AD14_InputType), INTENT(IN ) :: u ! Inputs at Time + TYPE(AD14_InputType), INTENT(INOUT) :: u ! Inputs at Time TYPE(AD14_ParameterType), INTENT(IN ) :: p ! Parameters TYPE(AD14_ContinuousStateType), INTENT(IN ) :: x ! Continuous states at Time TYPE(AD14_DiscreteStateType), INTENT(IN ) :: xd ! Discrete states at Time - TYPE(AD14_ConstraintStateType), INTENT(IN ) :: z ! Constraint states at Time + TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Constraint states at Time TYPE(AD14_OtherStateType), INTENT(IN ) :: O ! Other states at Time TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Outputs computed at Time (Input only so that mesh con- ! nectivity information does not have to be recalculated) @@ -752,15 +758,22 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) ! Local variables REAL(DbKi), PARAMETER :: OnePlusEpsilon = 1 + EPSILON(Time) - REAL(ReKi) :: VNElement REAL(ReKi) :: VelNormalToRotor2 + REAL(ReKi) :: VTWind REAL(ReKi) :: VNWind + REAL(ReKi) :: VNElement + REAL(ReKi) :: VTElement + REAL(ReKi) :: VN_ind + REAL(ReKi) :: VT_ind + REAL(ReKi) :: VN + REAL(ReKi) :: VT REAL(ReKi) :: VTTotal REAL(ReKi) :: DFN REAL(ReKi) :: DFT REAL(ReKi) :: PMA REAL(ReKi) :: SPitch ! sine of PitNow REAL(ReKi) :: CPitch ! cosine of PitNow + REAL(ReKi) :: Phi ! Local value of Phi REAL(ReKi) :: AvgVelNacelleRotorFurlYaw REAL(ReKi) :: AvgVelTowerBaseNacelleYaw @@ -772,6 +785,8 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) REAL(ReKi) :: rTowerBaseHub (2) REAL(ReKi) :: tmpVector (3) + REAL(ReKi) :: norm_Vector (3) ! Unit vector normal to chord + REAL(ReKi) :: tang_Vector (3) ! Unit vector tangent to chord REAL(ReKi) :: VelocityVec (3) INTEGER :: ErrStatLcL ! Error status returned by called routines. @@ -782,7 +797,7 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) INTEGER :: I CHARACTER(ErrMsgLen) :: ErrMessLcl ! Error message returned by called routines. - + CHARACTER(*), PARAMETER :: RoutineName = 'AD14_AeroSubs' !KS Not sure why I added this ! Initialize ErrStat ErrStat = ErrID_None @@ -913,7 +928,20 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) ! end of NewTime routine !................................................................................................. + ! Set blade element pitches + DO IBlade = 1,p%NumBl + DO IElement = 1,p%Element%NElm + ! calculate element pitch + m%Element%PitNow(IElement,IBlade) = -1.*ATAN2( -1.*DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:), & + u%InputMarkers(IBlade)%Orientation(2,:,IElement) ) , & + DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:), & + u%InputMarkers(IBlade)%Orientation(1,:,IElement) ) ) + ENDDO + ENDDO + + Node = 0 + ! --- Loop on blades DO IBlade = 1,p%NumBl ! calculate the azimuth angle ( we add pi because AeroDyn defines 0 as pointing downward) @@ -924,24 +952,13 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) u%TurbineComponents%RotorFurl%Orientation(2,:) ), & DOT_PRODUCT( u%TurbineComponents%Hub%Orientation(3,:), & u%TurbineComponents%RotorFurl%Orientation(3,:) ) ) + pi + (IBlade - 1)*p%TwoPiNB - - - + ! --- Loop on elements DO IElement = 1,p%Element%NElm - ! calculate element pitch - - m%Element%PitNow = -1.*ATAN2( -1.*DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:), & - u%InputMarkers(IBlade)%Orientation(2,:,IElement) ) , & - DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:), & - u%InputMarkers(IBlade)%Orientation(1,:,IElement) ) ) - - SPitch = SIN( m%Element%PitNow ) - CPitch = COS( m%Element%PitNow ) - + SPitch = SIN( m%Element%PitNow(IElement,IBlade) ) + CPitch = COS( m%Element%PitNow(IElement,IBlade) ) ! calculate distance between hub and element - tmpVector = u%InputMarkers(IBlade)%Position(:,IElement) - u%TurbineComponents%Hub%Position(:) rLocal = SQRT( DOT_PRODUCT( tmpVector, u%TurbineComponents%Hub%Orientation(2,:) )**2 & + DOT_PRODUCT( tmpVector, u%TurbineComponents%Hub%Orientation(3,:) )**2 ) @@ -1028,30 +1045,53 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) !----------------------------------------------------------------------------------------------------------------------- - - - + ! NOTE: VelocityVec is freestream with disturbances from Tower Shadow and Wakes (DWM) VelNormalToRotor2 = ( VelocityVec(3) * m%Rotor%STilt + (VelocityVec(1) * m%Rotor%CYaw & - VelocityVec(2) * m%Rotor%SYaw) * m%Rotor%CTilt )**2 !------------------------------------------------------------------------------------------- - ! reproduce GetVNVT routine: + ! Normal and tangential velocities from wind and relative blade motion !------------------------------------------------------------------------------------------- - tmpVector = -1.*SPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) & - + CPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement) - VTTotal = DOT_PRODUCT( tmpVector, VelocityVec - u%InputMarkers(IBlade)%TranslationVel(:,IElement) ) + tang_Vector = - SPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) & + & + CPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement) + norm_Vector = CPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) & + & + SPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement) - tmpVector = CPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) & - + SPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement) - VNWind = DOT_PRODUCT( tmpVector, VelocityVec ) - VNElement = -1.*DOT_PRODUCT( tmpVector, u%InputMarkers(IBlade)%TranslationVel(:,IElement ) ) + VTTotal = DOT_PRODUCT( tang_Vector, VelocityVec - u%InputMarkers(IBlade)%TranslationVel(:,IElement) ) + VTElement = - DOT_PRODUCT( tang_Vector, u%InputMarkers(IBlade)%TranslationVel(:,IElement) ) + VNElement = - DOT_PRODUCT( norm_Vector, u%InputMarkers(IBlade)%TranslationVel(:,IElement ) ) + + VTWind = DOT_PRODUCT( tang_Vector, VelocityVec) + VNWind = DOT_PRODUCT( norm_Vector, VelocityVec) !------------------------------------------------------------------------------------------- ! Get blade element forces and induced velocity !------------------------------------------------------------------------------------------- - CALL ELEMFRC( p, m, ErrStatLcl, ErrMessLcl, & - AzimuthAngle, rLocal, IElement, IBlade, VelNormalToRotor2, VTTotal, VNWind, & - VNElement, DFN, DFT, PMA, m%NoLoadsCalculated ) + ! --------------------------------------------------------------------------------} + ! --- Setting Element% values: W2, Alpha, A, AP + ! --------------------------------------------------------------------------------{ + ! --- BEM + CALL ELEM_INDUCTIONS( p, m, ErrStatLcl, ErrMessLcl, & + AzimuthAngle, rLocal, IElement, IBlade, VelNormalToRotor2, VTTotal, VNWind, & + VNElement, m%NoLoadsCalculated) + ! Normal and tangential induced velocities + VN_ind = - VNWind * m%Element%A (IElement, IBLADE) + VT_ind = VTTotal * m%Element%AP(IElement, IBLADE) + + ! Cumulative (integrated) induction over the blades + m%InducedVel%SumInfl = m%InducedVel%SumInfl - VN_IND * RLOCAL * p%Blade%DR(IElement) + + ! --- Total flow velocity at the blade element + VN = VN_IND + VNWind + VNElement ! Normal velocity : Indution + Wind + Rel. blade vel + VT = VT_IND + VTTotal ! Tangential velocity : Indution + (Wind + Rel. blade vel) + + PHI = ATAN2( VN, VT) ! Flow angle [rad] + m%Element%ALPHA(IElement,IBlade) = PHI - m%Element%PitNow(IElement,IBlade) ! Angle of attack [rad] + CALL MPI2PI ( m%Element%ALPHA(IElement,IBlade) ) + m%Element%W2(IElement,IBlade) = VN * VN + VT * VT ! Relative velocity norm + + CALL ELEMFRC2( p, m, ErrStatLcl, ErrMessLcl, IElement, IBlade, & + DFN, DFT, PMA, m%NoLoadsCalculated, phi ) CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput' ) IF (ErrStat >= AbortErrLev) THEN CALL CleanUp() @@ -1113,7 +1153,6 @@ SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess ) m%NoLoadsCalculated = .FALSE. - DO IBlade=1,p%NumBl DO IElement=1,p%Element%Nelm y%OutputLoads(IBlade)%Force(:,IElement) = m%StoredForces(:,IElement,IBlade) diff --git a/modules/aerodyn14/src/AeroDyn14_Types.f90 b/modules/aerodyn14/src/AeroDyn14_Types.f90 index ad4321d6bf..287f17597c 100644 --- a/modules/aerodyn14/src/AeroDyn14_Types.f90 +++ b/modules/aerodyn14/src/AeroDyn14_Types.f90 @@ -209,22 +209,22 @@ MODULE AeroDyn14_Types ! ======================= ! ========= Element ======= TYPE, PUBLIC :: Element - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: A - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AP - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: ALPHA - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: W2 + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: A !< - [Axial induction factor] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AP !< - [Tangential induction factor] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: ALPHA !< - [Angle of attack] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: W2 !< - [Relative velocity norm ] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: OLD_A_NS REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: OLD_AP_NS - REAL(ReKi) :: PITNOW + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PITNOW !< - [Current pitch angle - Based on blade orientation (to verify)] END TYPE Element ! ======================= ! ========= ElementParms ======= TYPE, PUBLIC :: ElementParms - INTEGER(IntKi) :: NELM - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TWIST - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RELM - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: HLCNST - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TLCNST + INTEGER(IntKi) :: NELM !< - [Number of elements (constant)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TWIST !< - [Airfoil twist angle (constant)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RELM !< - [Radius of element (constant)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: HLCNST !< - [Hub loss constant B/2*(r-rh)/rh (constant)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TLCNST !< - [Tip loss constant B/2*(R-r)/R (constant) ] END TYPE ElementParms ! ======================= ! ========= ElOutParms ======= @@ -243,6 +243,7 @@ MODULE AeroDyn14_Types REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: PMM REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: PITSAV REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: ReyNum + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Gamma !< - [Circulation along the span, 1/2 c Vrel Cl] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SaveVX REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SaveVY REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SaveVZ @@ -7193,7 +7194,20 @@ SUBROUTINE AD14_CopyElement( SrcElementData, DstElementData, CtrlCode, ErrStat, END IF DstElementData%OLD_AP_NS = SrcElementData%OLD_AP_NS ENDIF +IF (ALLOCATED(SrcElementData%PITNOW)) THEN + i1_l = LBOUND(SrcElementData%PITNOW,1) + i1_u = UBOUND(SrcElementData%PITNOW,1) + i2_l = LBOUND(SrcElementData%PITNOW,2) + i2_u = UBOUND(SrcElementData%PITNOW,2) + IF (.NOT. ALLOCATED(DstElementData%PITNOW)) THEN + ALLOCATE(DstElementData%PITNOW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstElementData%PITNOW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF DstElementData%PITNOW = SrcElementData%PITNOW +ENDIF END SUBROUTINE AD14_CopyElement SUBROUTINE AD14_DestroyElement( ElementData, ErrStat, ErrMsg ) @@ -7222,6 +7236,9 @@ SUBROUTINE AD14_DestroyElement( ElementData, ErrStat, ErrMsg ) ENDIF IF (ALLOCATED(ElementData%OLD_AP_NS)) THEN DEALLOCATE(ElementData%OLD_AP_NS) +ENDIF +IF (ALLOCATED(ElementData%PITNOW)) THEN + DEALLOCATE(ElementData%PITNOW) ENDIF END SUBROUTINE AD14_DestroyElement @@ -7290,7 +7307,11 @@ SUBROUTINE AD14_PackElement( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Int_BufSz = Int_BufSz + 2*2 ! OLD_AP_NS upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%OLD_AP_NS) ! OLD_AP_NS END IF - Re_BufSz = Re_BufSz + 1 ! PITNOW + Int_BufSz = Int_BufSz + 1 ! PITNOW allocated yes/no + IF ( ALLOCATED(InData%PITNOW) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! PITNOW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%PITNOW) ! PITNOW + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -7438,8 +7459,26 @@ SUBROUTINE AD14_PackElement( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg END DO END DO END IF - ReKiBuf(Re_Xferred) = InData%PITNOW - Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%PITNOW) ) 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%PITNOW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PITNOW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%PITNOW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PITNOW,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%PITNOW,2), UBOUND(InData%PITNOW,2) + DO i1 = LBOUND(InData%PITNOW,1), UBOUND(InData%PITNOW,1) + ReKiBuf(Re_Xferred) = InData%PITNOW(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD14_PackElement SUBROUTINE AD14_UnPackElement( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -7608,8 +7647,29 @@ SUBROUTINE AD14_UnPackElement( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err END DO END DO END IF - OutData%PITNOW = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! PITNOW 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%PITNOW)) DEALLOCATE(OutData%PITNOW) + ALLOCATE(OutData%PITNOW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%PITNOW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%PITNOW,2), UBOUND(OutData%PITNOW,2) + DO i1 = LBOUND(OutData%PITNOW,1), UBOUND(OutData%PITNOW,1) + OutData%PITNOW(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF END SUBROUTINE AD14_UnPackElement SUBROUTINE AD14_CopyElementParms( SrcElementParmsData, DstElementParmsData, CtrlCode, ErrStat, ErrMsg ) @@ -8135,6 +8195,18 @@ SUBROUTINE AD14_CopyElOutParms( SrcElOutParmsData, DstElOutParmsData, CtrlCode, END IF DstElOutParmsData%ReyNum = SrcElOutParmsData%ReyNum ENDIF +IF (ALLOCATED(SrcElOutParmsData%Gamma)) THEN + i1_l = LBOUND(SrcElOutParmsData%Gamma,1) + i1_u = UBOUND(SrcElOutParmsData%Gamma,1) + IF (.NOT. ALLOCATED(DstElOutParmsData%Gamma)) THEN + ALLOCATE(DstElOutParmsData%Gamma(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstElOutParmsData%Gamma.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstElOutParmsData%Gamma = SrcElOutParmsData%Gamma +ENDIF IF (ALLOCATED(SrcElOutParmsData%SaveVX)) THEN i1_l = LBOUND(SrcElOutParmsData%SaveVX,1) i1_u = UBOUND(SrcElOutParmsData%SaveVX,1) @@ -8283,6 +8355,9 @@ SUBROUTINE AD14_DestroyElOutParms( ElOutParmsData, ErrStat, ErrMsg ) IF (ALLOCATED(ElOutParmsData%ReyNum)) THEN DEALLOCATE(ElOutParmsData%ReyNum) ENDIF +IF (ALLOCATED(ElOutParmsData%Gamma)) THEN + DEALLOCATE(ElOutParmsData%Gamma) +ENDIF IF (ALLOCATED(ElOutParmsData%SaveVX)) THEN DEALLOCATE(ElOutParmsData%SaveVX) ENDIF @@ -8411,6 +8486,11 @@ SUBROUTINE AD14_PackElOutParms( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + 2*1 ! ReyNum upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%ReyNum) ! ReyNum END IF + Int_BufSz = Int_BufSz + 1 ! Gamma allocated yes/no + IF ( ALLOCATED(InData%Gamma) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Gamma upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Gamma) ! Gamma + END IF Int_BufSz = Int_BufSz + 1 ! SaveVX allocated yes/no IF ( ALLOCATED(InData%SaveVX) ) THEN Int_BufSz = Int_BufSz + 2*2 ! SaveVX upper/lower bounds for each dimension @@ -8688,6 +8768,21 @@ SUBROUTINE AD14_PackElOutParms( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( .NOT. ALLOCATED(InData%Gamma) ) 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%Gamma,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Gamma,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Gamma,1), UBOUND(InData%Gamma,1) + ReKiBuf(Re_Xferred) = InData%Gamma(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( .NOT. ALLOCATED(InData%SaveVX) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -9100,6 +9195,24 @@ SUBROUTINE AD14_UnPackElOutParms( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Gamma 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%Gamma)) DEALLOCATE(OutData%Gamma) + ALLOCATE(OutData%Gamma(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Gamma.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Gamma,1), UBOUND(OutData%Gamma,1) + OutData%Gamma(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! SaveVX not allocated Int_Xferred = Int_Xferred + 1 ELSE diff --git a/modules/aerodyn14/src/AeroSubs.f90 b/modules/aerodyn14/src/AeroSubs.f90 index c6141806c5..3ca457193a 100644 --- a/modules/aerodyn14/src/AeroSubs.f90 +++ b/modules/aerodyn14/src/AeroSubs.f90 @@ -385,7 +385,6 @@ SUBROUTINE AD14_GetInput(InitInp, P, x, xd, z, m, y, ErrStat, ErrMess ) END IF - ! Read in the air density CALL ReadVar( UnIn, InitInp%ADFileName, P%Wind%Rho, VarName='Rho', VarDescr='Air density', ErrStat=ErrStat, ErrMsg=ErrMess) IF (ErrStat >= AbortErrLev) THEN @@ -1619,18 +1618,13 @@ SUBROUTINE READTwr(UnIn, InitInp, P, x, xd, z, m, y, ErrStat, ErrMess ) END SUBROUTINE READTwr -! Dynamics Program aerodynamics force interface gateway - ! **************************************************** - SUBROUTINE ELEMFRC(P, m, ErrStat, ErrMess, & - PSI, RLOCAL, J, IBlade, VNROTOR2, VT, VNW, & - VNB, DFN, DFT, PMA, Initial) -! SUBROUTINE ELEMFRC (PSI, RLOCAL, J, IBlade, VNROTOR2, VT, VNW, & -! VNB, DFN, DFT, PMA, Initial) - ! **************************************************** - ! calculates the aerodynamic forces on one - ! blade element. Inputs include all velocities. - ! Normal and tangential forces and 'A' are returned. !==================================================================================================== +!> Calculates the axial and tangential induction factor for each annular segment +! and time step (i.e. sets m%Element%A and m%Element%AP) + SUBROUTINE ELEM_INDUCTIONS( p, m, ErrStat, ErrMess, & + PSI, RLOCAL, J, IBlade, VNROTOR2, VT, VNW, & + VNB, Initial) + IMPLICIT NONE ! Passed Variables: TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters @@ -1638,102 +1632,97 @@ SUBROUTINE ELEMFRC(P, m, ErrStat, ErrMess, & INTEGER, INTENT(OUT) :: ErrStat CHARACTER(*), INTENT(OUT) :: ErrMess - REAL(ReKi),INTENT(OUT) :: DFN - REAL(ReKi),INTENT(OUT) :: DFT - REAL(ReKi),INTENT(OUT) :: PMA REAL(ReKi),INTENT(IN) :: PSI REAL(ReKi),INTENT(IN) :: RLOCAL - REAL(ReKi),INTENT(IN) :: VNB + REAL(ReKi), INTENT(IN ) :: VNB ! Normal (relative) velocity of the element REAL(ReKi),INTENT(IN) :: VNROTOR2 REAL(ReKi),INTENT(IN) :: VNW - REAL(ReKi),INTENT(INOUT) :: VT + REAL(ReKi), INTENT(IN ) :: VT INTEGER, INTENT(IN) :: J INTEGER, INTENT(IN) :: IBlade LOGICAL, INTENT(IN) :: Initial - ! Local Variables: - - REAL(ReKi) :: CDA - REAL(ReKi) :: CLA - REAL(ReKi) :: CMA - REAL(ReKi) :: CPHI - REAL(ReKi) :: PHI - REAL(ReKi) :: QA - REAL(ReKi) :: ReNum - REAL(ReKi) :: SPHI - REAL(ReKi) :: Vinduced - REAL(ReKi) :: VN - INTEGER :: ErrStatLcL ! Error status returned by called routines. CHARACTER(ErrMsgLen) :: ErrMessLcl ! Error message returned by called routines. ErrStat = ErrID_None ErrMess = "" - - ! initialize TanInd variables -m%Element%A (J,IBLADE) = 0.0 -m%Element%AP(J,IBLADE) = 0.0 - - !-mlb Check for being at the center of rotation. ! If we are at the center of rotation, the induction equations ! are undefined, so let's just USE zeros. - -IF ( RLOCAL < 0.01 ) THEN +! initialize AxInd and TanInd variables m%Element%A (J,IBLADE) = 0.0 m%Element%AP(J,IBLADE) = 0.0 + +IF ( RLOCAL < 0.01 ) THEN + ! Already set to 0 ELSEIF( P%DYNINFL .AND. P%Blade%R * m%Rotor%REVS < 2.0 ) THEN !ACH 3/10/03 This block deals with dyn. inflow problems at low tip speed - m%Element%A (J,IBLADE) = 0.0 - m%Element%AP(J,IBLADE) = 0.0 + ! Already set to 0 m%DYNINIT = .TRUE. !Re-initialize if we begin using dynamic inflow again ELSE ! Turn wake off when using dynamic inflow and tip speed goes low. Wake will remain off. - ! Get induction factor = A using static airfoil coefficients IF ( P%WAKE .AND. .NOT. Initial) THEN IF ( P%DYNINFL ) THEN ! USE dynamic inflow model to find A CALL VINDINF( P, m, ErrStatLcl, ErrMessLcl, & - J, IBlade, RLOCAL, VNW, VNB, VT, PSI ) !possibly changes VT, A, and AP - CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' ) + J, IBlade, RLOCAL, VNW, VNB, VT, PSI ) !possibly changes A, and AP + CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEM_INDUCTIONS' ) IF (ErrStat >= AbortErrLev) RETURN ELSE ! USE momentum balance to find A CALL VIND( P, m, ErrStatLcl, ErrMessLcl, & - J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT ) !changes VT, A, and AP - CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' ) + J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT ) !changes A, and AP + CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEM_INDUCTIONS' ) IF (ErrStat >= AbortErrLev) RETURN ! Apply skewed-wake correction, if applicable IF( m%SKEW ) CALL VNMOD( P, m, ErrStatLcl, ErrMessLcl,& J, IBlade, RLOCAL, PSI ) !changes A - CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' ) + CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEM_INDUCTIONS' ) IF (ErrStat >= AbortErrLev) RETURN ENDIF - ELSE - ! Ignore the wake calculation entirely - m%Element%A (J,IBLADE) = 0.0 - m%Element%AP(J,IBLADE) = 0.0 ENDIF - ENDIF -Vinduced = VNW * m%Element%A(J,IBLADE) -VN = VNW + VNB - Vinduced +END SUBROUTINE ELEM_INDUCTIONS + +SUBROUTINE ELEMFRC2( p, m, ErrStat, ErrMess, J, IBlade, & + DFN, DFT, PMA, Initial, phi ) -m%InducedVel%SumInfl = m%InducedVel%SumInfl + Vinduced * RLOCAL * p%Blade%DR(J) + IMPLICIT NONE + ! Passed Variables: + TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters + TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization variables + INTEGER, INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMess + + REAL(ReKi), INTENT( OUT) :: DFN + REAL(ReKi), INTENT( OUT) :: DFT + REAL(ReKi), INTENT( OUT) :: PMA + INTEGER, INTENT(IN) :: J + INTEGER, INTENT(IN) :: IBlade + LOGICAL, INTENT(IN) :: Initial - ! Get the angle of attack + ! Local Variables: -PHI = ATAN2( VN, VT ) -m%Element%ALPHA(J,IBlade) = PHI - m%Element%PITNOW + REAL(ReKi) :: CDA + REAL(ReKi) :: CLA + REAL(ReKi) :: CMA + REAL(ReKi) :: CPHI + REAL(ReKi), intent(in) :: PHI + REAL(ReKi) :: QA + REAL(ReKi) :: ReNum + REAL(ReKi) :: SPHI -CALL MPI2PI ( m%Element%ALPHA(J,IBlade) ) + INTEGER :: ErrStatLcL ! Error status returned by called routines. + CHARACTER(ErrMsgLen) :: ErrMessLcl ! Error message returned by called routines. -m%Element%W2(J,IBlade) = VN * VN + VT * VT + ErrStat = ErrID_None + ErrMess = "" ! Get the Reynold's number for the element ! Returns Reynold's number x 10^6 !bjj: Reynold's number x 10^-6 ? @@ -1799,22 +1788,22 @@ SUBROUTINE ELEMFRC(P, m, ErrStat, ErrMess, & m%ElOut%DFNSAV ( m%ElOut%ElPrList(J) ) = DFN m%ElOut%DFTSAV ( m%ElOut%ElPrList(J) ) = DFT m%ElOut%DynPres( m%ElOut%ElPrList(J) ) = 0.5 * P%Wind%RHO * m%Element%W2(J,IBlade) - m%ElOut%PITSAV ( m%ElOut%ElPrList(J) ) = m%Element%PITNOW * R2D + m%ElOut%PITSAV ( m%ElOut%ElPrList(J) ) = m%Element%PitNow(J,IBlade) * R2D m%ElOut%PMM ( m%ElOut%ElPrList(J) ) = PMA m%ElOut%ReyNum ( m%ElOut%ElPrList(J) ) = ReNum + m%ElOut%Gamma ( m%ElOut%ElPrList(J) ) = 0.5 * P%Blade%C(J) * sqrt(m%Element%W2(J,IBlade)) * CLA ! 1/2 c Urel Cl [m^2/s] ENDIF ENDIF RETURN -END SUBROUTINE ELEMFRC +END SUBROUTINE ELEMFRC2 !====================================================== - SUBROUTINE VIND( P, m, ErrStat, ErrMess, & + SUBROUTINE VIND( p, m, ErrStat, ErrMess, & J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT ) -! SUBROUTINE VIND( J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT ) - ! calculates the axial induction factor for each - ! annular segment and time step. + ! Calculates the axial and tangential induction factor for each annular segment + ! and time step (i.e. sets m%Element%A and m%Element%AP) ! *************************************************** IMPLICIT NONE ! Passed Variables: @@ -1825,7 +1814,7 @@ SUBROUTINE VIND( P, m, ErrStat, ErrMess, & REAL(ReKi), INTENT(IN ) :: VNB REAL(ReKi), INTENT(IN ) :: VNROTOR2 REAL(ReKi), INTENT(IN ) :: VNW - REAL(ReKi), INTENT(INOUT) :: VT + REAL(ReKi), INTENT(IN ) :: VT ! tangential velocity from relative blade motion and wind, no induction INTEGER, INTENT(IN ) :: J INTEGER, INTENT(IN ) :: IBlade @@ -1912,12 +1901,12 @@ SUBROUTINE VIND( P, m, ErrStat, ErrMess, & IF ( ABS( VNB ) > 100. ) THEN m%Element%A( J, IBLADE ) = 0.0 - CALL VINDERR( P, m, ErrStat, ErrMess, & + CALL VINDERR( m, ErrStat, ErrMess, & VNW, VNB, 'VNB', J, IBLADE ) RETURN ELSEIF ( ABS( VT ) > 400. ) THEN m%Element%A( J, IBLADE ) = 0.0 - CALL VINDERR( P, m, ErrStat, ErrMess, & + CALL VINDERR( m, ErrStat, ErrMess, & VNW, VT, 'VT', J, IBLADE ) RETURN ENDIF @@ -1926,7 +1915,7 @@ SUBROUTINE VIND( P, m, ErrStat, ErrMess, & CALL AXIND ( P, m, ErrStat, ErrMess, & VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, A2P, & - J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) + J, IBlade, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) IF (ErrStat >= AbortErrLev) RETURN DAI = A2 - AI @@ -1946,7 +1935,7 @@ SUBROUTINE VIND( P, m, ErrStat, ErrMess, & CALL AXIND ( P, m, ErrStatLcl, ErrMessLcl, & VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, A2P, & - J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) + J, IBlade, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,'VIND' ) IF (ErrStat >= AbortErrLev) RETURN @@ -1979,7 +1968,6 @@ SUBROUTINE VIND( P, m, ErrStat, ErrMess, & ! Passed test, we're done m%Element%A (J,IBLADE) = A2 m%Element%AP(J,IBLADE) = A2P -VT = VT * ( 1. + A2P ) !bjj: why are we changing the total velocity? m%Element%OLD_A_NS (J,IBLADE) = A2 m%Element%OLD_AP_NS (J,IBLADE) = A2P @@ -1988,7 +1976,7 @@ END SUBROUTINE VIND ! *************************************************** - SUBROUTINE VINDERR( P, m, ErrStat, ErrMess, & + SUBROUTINE VINDERR( m, ErrStat, ErrMess, & VNW, VX, VID, J, IBLADE ) ! SUBROUTINE VINDERR( VNW, VX, VID, J, IBLADE ) ! used to write warning messages to the screen @@ -1996,7 +1984,6 @@ SUBROUTINE VINDERR( P, m, ErrStat, ErrMess, & ! *************************************************** IMPLICIT NONE ! Passed Variables: - TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization variables INTEGER, INTENT(OUT) :: ErrStat CHARACTER(*), INTENT(OUT) :: ErrMess @@ -2036,7 +2023,7 @@ END SUBROUTINE VINDERR ! ****************************************************** SUBROUTINE AXIND (P, m, ErrStat, ErrMess, & VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, & - A2P, J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) + A2P, J, IBlade, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) ! SUBROUTINE AXIND ( VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, & ! A2P, J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL ) ! calculates a new axial induction factor from @@ -2068,6 +2055,7 @@ SUBROUTINE AXIND (P, m, ErrStat, ErrMess, & REAL(ReKi),INTENT(OUT) :: VTA INTEGER ,INTENT(IN) :: J + INTEGER ,INTENT(IN) :: IBlade ! Local Variables: @@ -2087,7 +2075,7 @@ SUBROUTINE AXIND (P, m, ErrStat, ErrMess, & ! Get airfoil CL and CD PHI = ATAN2( VNA, VTA ) -ALPHA = PHI - m%Element%PITNOW +ALPHA = PHI - m%Element%PitNow(J,IBlade) CALL MPI2PI ( ALPHA ) @@ -4114,16 +4102,16 @@ SUBROUTINE GetRM ( P, m, ErrStat, ErrMess, & !+++++++++++++++++++++++++++++++++++++++++++++++++++++ !Suzuki's method !DO mode = MaxInflo+1, maxInfl -! m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) * COS( REAL(MRvector(mode)) * psiBar ) -! m%DynInflow%RMS_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) * SIN( REAL(MRvector(mode)) * psiBar ) +! m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) * COS( REAL(MRvector(mode), ReKi) * psiBar ) +! m%DynInflow%RMS_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) * SIN( REAL(MRvector(mode), ReKi) * psiBar ) !END DO ! mode ! Shawler's method DO mode = p%DynInflow%MaxInflo+1, maxInfl - m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl, ErrMessLcl ) * COS( REAL(MRvector(mode)) * WindPsi ) + m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl, ErrMessLcl ) * COS( REAL(MRvector(mode), ReKi) * WindPsi ) CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'GetRM' ) IF (ErrStat >= AbortErrLev) RETURN - m%DynInflow%RMS_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl, ErrMessLcl ) * SIN( REAL(MRvector(mode)) * WindPsi ) + m%DynInflow%RMS_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl, ErrMessLcl ) * SIN( REAL(MRvector(mode), ReKi) * WindPsi ) CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'GetRM' ) IF (ErrStat >= AbortErrLev) RETURN @@ -4738,10 +4726,11 @@ SUBROUTINE infdist( P, m, ErrStat, ErrMess ) END SUBROUTINE infdist ! ************************************************************* - SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & + SUBROUTINE VINDINF( P, m, ErrStat, ErrMess, & iradius, iblade, rlocal, vnw, VNB, VT, psi ) - ! vindinf calculates the axial induction factor for each - ! element position using the calculated inflow parameters. + ! Calculates the axial and tangential induction factor for each annular segment + ! and time step (i.e. sets m%Element%A and m%Element%AP) + ! Uses the calculated inflow parameters ! Called by ElemFrc for each element at a new time step. ! ************************************************************* @@ -4757,7 +4746,7 @@ SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & REAL(ReKi),INTENT(IN) :: rlocal REAL(ReKi),INTENT(IN) :: VNB REAL(ReKi),INTENT(IN) :: vnw - REAL(ReKi),INTENT(INOUT) :: VT + REAL(ReKi),INTENT(IN ) :: VT ! Tangential velocity from relative blade motion and wind, no induction INTEGER, INTENT(IN) :: iradius INTEGER, INTENT(IN) :: iblade @@ -4801,7 +4790,7 @@ SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & DO mode = 1, p%DynInflow%MaxInflo m%Element%A(iRadius,iBlade) = m%Element%A(iRadius,iBlade) & + xphi(Rzero,mode,ErrStatLcl, ErrMessLcl) * m%DynInflow%xAlpha(mode) - CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'vindinf' ) + CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'VINDINF' ) IF (ErrStat >= AbortErrLev) RETURN ! & + phis(Rzero, MRvector(mode), NJvector(mode) )* xAlpha(mode) @@ -4812,15 +4801,15 @@ SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & !DO mode = MaxInflo+1, maxInfl ! A(iRadius,iBlade) = A(iRadius,iBlade) + xphi(Rzero,mode) * & !! & + phis(Rzero, MRvector(mode), NJvector(mode) ) * -! ( xAlpha(mode) * COS( REAL(MRvector(MODE)) * psibar ) & -! + xBeta (mode) * SIN( REAL(MRvector(MODE)) * psibar ) ) +! ( xAlpha(mode) * COS( REAL(MRvector(MODE), ReKi) * psibar ) & +! + xBeta (mode) * SIN( REAL(MRvector(MODE), ReKi) * psibar ) ) !END DO !mode ! Shawler: DO mode = p%DynInflow%MaxInflo+1, maxInfl m%Element%A(iRadius,iBlade) = m%Element%A(iRadius,iBlade) + xphi(Rzero,mode,ErrStatLcl, ErrMessLcl) * & - ( m%DynInflow%xAlpha(mode) * COS( REAL(MRvector(MODE)) * Windpsi ) & - + m%DynInflow%xBeta (mode) * SIN( REAL(MRvector(MODE)) * Windpsi ) ) - CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'vindinf' ) + ( m%DynInflow%xAlpha(mode) * COS( REAL(MRvector(MODE), ReKi) * Windpsi ) & + + m%DynInflow%xBeta (mode) * SIN( REAL(MRvector(MODE), ReKi) * Windpsi ) ) + CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'VINDINF' ) IF (ErrStat >= AbortErrLev) RETURN END DO !mode @@ -4832,13 +4821,14 @@ SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & ! Calculate induced swirl (a') if desired. +m%Element%AP(iRadius,iBlade) = 0.0_ReKi ! Default value + IF ( P%SWIRL ) THEN ! akihiro 10/26/99 SWRLARG = 1.0 + 4.0 * m%Element%A(iradius,iblade) * VNW * & ( (1.0 - m%Element%A(iradius,iblade)) * VNW + VNB ) / VT / VT IF ( SWRLARG > 0.0 ) THEN A2P = 0.5 * ( -1.0 + SQRT( SWRLARG ) ) - VT = VT * ( 1.0 + A2P) ! bjj: this value was not properly set before. We could also just replace the local A2P variable with AP() instead. m%Element%AP(iRadius,iBlade) = A2P ENDIF @@ -4846,7 +4836,7 @@ SUBROUTINE vindinf( P, m, ErrStat, ErrMess, & ENDIF RETURN -END SUBROUTINE vindinf +END SUBROUTINE VINDINF ! *********************************************************************** SUBROUTINE ABPRECOR( F, OLDF, DFDT, DT, N, N0 ) @@ -5190,14 +5180,14 @@ FUNCTION FGAMMA( R, J, M, N ) IF ( MOD(R+M,2) == 0 ) THEN FGAMMA = (-1)**((N+J-2*R)*.5) * 2. & - * SQRT( REAL( (2*N+1) * (2*J+1) ) ) & + * SQRT( REAL( (2*N+1) * (2*J+1), ReKi ) ) & / SQRT( HFUNC(M,N) * HFUNC(R,J) ) & - / REAL( (J+N) * (J+N+2) * ((J-N)*(J-N)-1) ) + / REAL( (J+N) * (J+N+2) * ((J-N)*(J-N)-1), ReKi ) ELSE IF ( ABS(J-N) == 1 ) THEN !bjj: why don't we use the pi() variable? or PibyTwo - FGAMMA = 3.14159265 * SIGN(1., REAL(R-M) ) * .5 & + FGAMMA = 3.14159265 * SIGN(1., REAL(R-M, ReKi) ) * .5 & / SQRT( HFUNC(M,N) * HFUNC(R,J) ) & - / SQRT( REAL( (2*N+1) * (2*J+1) ) ) + / SQRT( REAL( (2*N+1) * (2*J+1) , ReKi) ) ELSE FGAMMA = 0. @@ -5245,8 +5235,8 @@ FUNCTION HFUNC( M, N ) NPM = N + M NMM = N - M -HFUNC = ( REAL( IDUBFACT(NPM-1) ) / REAL( IDUBFACT(NPM) ) ) & - * ( REAL( IDUBFACT(NMM-1) ) / REAL( IDUBFACT(NMM) ) ) +HFUNC = ( REAL( IDUBFACT(NPM-1), ReKi ) / REAL( IDUBFACT(NPM), ReKi ) ) & + * ( REAL( IDUBFACT(NMM-1), ReKi ) / REAL( IDUBFACT(NMM), ReKi ) ) @@ -5390,11 +5380,11 @@ FUNCTION phis( Rzero, r, j ) DO q = r, j-1, 2 phis = phis & - + Rzero ** q * (-1.) **((q-r)/2) * REAL( idubfact(j+q) ) & - / REAL( idubfact(q-r) * idubfact(q+r) * idubfact(j-q-1) ) + + Rzero ** q * (-1.) **((q-r)/2) * REAL( idubfact(j+q), ReKi ) & + / REAL( idubfact(q-r) * idubfact(q+r) * idubfact(j-q-1), ReKi ) END DO !q -phis = phis * SQRT( REAL( 2*j+1 ) * hfunc(r,j) ) +phis = phis * SQRT( REAL( 2*j+1, ReKi ) * hfunc(r,j) ) RETURN diff --git a/modules/aerodyn14/src/GenSubs.f90 b/modules/aerodyn14/src/GenSubs.f90 index 54fe3e9f57..e02fd5cbc4 100644 --- a/modules/aerodyn14/src/GenSubs.f90 +++ b/modules/aerodyn14/src/GenSubs.f90 @@ -332,6 +332,9 @@ SUBROUTINE AllocArrays ( InitInp, P, xc, xd, z, m, y, Arg ) IF (.NOT. ALLOCATED(m%ElOut%ReyNum)) ALLOCATE ( m%ElOut%ReyNum(NumElOut) , STAT=Sttus ) IF ( Sttus /= 0 ) CALL ProgAbort ( ' Error allocating memory for ReyNum array.' ) + IF (.NOT. ALLOCATED(m%ElOut%Gamma)) ALLOCATE ( m%ElOut%Gamma(NumElOut) , STAT=Sttus ) + IF ( Sttus /= 0 ) CALL ProgAbort ( ' Error allocating memory for Gamma array.' ) + IF (.NOT. ALLOCATED(m%ElOut%ElPrNum)) ALLOCATE ( m%ElOut%ElPrNum(NumElOut) , STAT=Sttus ) IF ( Sttus /= 0 ) CALL ProgAbort ( ' Error allocating memory for ElPrNum array.' ) m%ElOut%ElPrNum ( : ) = 0 @@ -462,7 +465,7 @@ SUBROUTINE ElemOpen (ElemFile, P, m, ErrStat, ErrMsg, AD14_Ver ) Frmt = '( A4, 3(A1,A2,I2.2), (: A1, A, I2.2 ) )' IF ( p%PMOMENT ) THEN - WRITE(Frmt(22:24), '(I3)') 14*m%ElOut%NumElOut + WRITE(Frmt(22:24), '(I3)') 15*m%ElOut%NumElOut WRITE(p%UnElem, Frmt) 'Time', & TAB, 'VX', p%Element%NELM, & TAB, 'VY', p%Element%NELM, & @@ -481,10 +484,11 @@ SUBROUTINE ElemOpen (ElemFile, P, m, ErrStat, ErrMsg, AD14_Ver ) TAB, 'ForcT', m%ElOut%ElPrNum(JE), & TAB, 'Pmomt', m%ElOut%ElPrNum(JE), & TAB, 'ReNum', m%ElOut%ElPrNum(JE), & + TAB, 'Gamma', m%ElOut%ElPrNum(JE), & JE = 1, m%ElOut%NumElOut ) Frmt = '( A5, 3(A1,A8), (: A1, A ) )' - WRITE(Frmt(17:19), '(I3)') 14*m%ElOut%NumElOut + WRITE(Frmt(17:19), '(I3)') 15*m%ElOut%NumElOut WRITE(p%UnElem, Frmt) '(sec)', & TAB, '('//TRIM(Dst_Unit)//'/sec)', & TAB, '('//TRIM(Dst_Unit)//'/sec)', & @@ -503,10 +507,11 @@ SUBROUTINE ElemOpen (ElemFile, P, m, ErrStat, ErrMsg, AD14_Ver ) TAB, '('//TRIM(Frc_Unit)//')', & TAB, '('//TRIM(Frc_Unit)//'-'//TRIM(Dst_Unit)//')', & TAB, '(x10^6)', & + TAB, '(m^2/sec)', & JE = 1, m%ElOut%NumElOut ) ELSE - WRITE(Frmt(22:24), '(I3)') 12*m%ElOut%NumElOut + WRITE(Frmt(22:24), '(I3)') 13*m%ElOut%NumElOut WRITE(p%UnElem, Frmt) 'Time', & TAB, 'VX', p%Element%NELM, & TAB, 'VY', p%Element%NELM, & @@ -523,10 +528,11 @@ SUBROUTINE ElemOpen (ElemFile, P, m, ErrStat, ErrMsg, AD14_Ver ) TAB, 'ForcN', m%ElOut%ElPrNum(JE), & TAB, 'ForcT', m%ElOut%ElPrNum(JE), & TAB, 'ReNum', m%ElOut%ElPrNum(JE), & + TAB, 'Gamma', m%ElOut%ElPrNum(JE), & JE = 1, m%ElOut%NumElOut ) Frmt = '( A5, 3(A1,A8), (: A1, A ) )' - WRITE(Frmt(17:19), '(I3)') 12*m%ElOut%NumElOut + WRITE(Frmt(17:19), '(I3)') 13*m%ElOut%NumElOut WRITE(p%UnElem, Frmt) '(sec)', & TAB, '('//TRIM(Dst_Unit)//'/sec)', & TAB, '('//TRIM(Dst_Unit)//'/sec)', & @@ -543,6 +549,7 @@ SUBROUTINE ElemOpen (ElemFile, P, m, ErrStat, ErrMsg, AD14_Ver ) TAB, '('//TRIM(Frc_Unit)//')', & TAB, '('//TRIM(Frc_Unit)//')', & TAB, '(x10^6)', & + TAB, '(m^2/sec)', & JE = 1, m%ElOut%NumElOut ) ENDIF @@ -596,7 +603,7 @@ SUBROUTINE ElemOut( time, P, m ) Frmt = '( F10.3, ( : A1, ES12.5 ) )' IF ( P%PMOMENT ) THEN - WRITE(Frmt(10:12), '(I3)') 14*m%ElOut%NumElOut + 3 + WRITE(Frmt(10:12), '(I3)') 15*m%ElOut%NumElOut + 3 WRITE(p%UnElem,Frmt) TIME, & TAB, m%ElOut%VXSAV, & TAB, m%ElOut%VYSAV, & @@ -615,11 +622,12 @@ SUBROUTINE ElemOut( time, P, m ) TAB, m%ElOut%DFTSAV (JE), & TAB, m%ElOut%PMM (JE), & TAB, m%ElOut%ReyNum (JE), & + TAB, m%ElOut%Gamma (JE), & JE= 1, m%ElOut%NumElOut ) ELSE - WRITE(Frmt(10:12), '(I3)') 12*m%ElOut%NumElOut + 3 + WRITE(Frmt(10:12), '(I3)') 13*m%ElOut%NumElOut + 3 WRITE(p%UnElem,Frmt) TIME, & TAB, m%ElOut%VXSAV, & TAB, m%ElOut%VYSAV, & @@ -636,6 +644,7 @@ SUBROUTINE ElemOut( time, P, m ) TAB, m%ElOut%DFNSAV (JE), & TAB, m%ElOut%DFTSAV (JE), & TAB, m%ElOut%ReyNum (JE), & + TAB, m%ElOut%Gamma (JE), & JE= 1, m%ElOut%NumElOut ) ENDIF ! PMOMENT diff --git a/modules/aerodyn14/src/Registry-AD14.txt b/modules/aerodyn14/src/Registry-AD14.txt index 992927fff0..59eceb2c7b 100644 --- a/modules/aerodyn14/src/Registry-AD14.txt +++ b/modules/aerodyn14/src/Registry-AD14.txt @@ -168,18 +168,18 @@ typedef ^ DynInflowParms IntKi MAXINFLO - 2 - #should be possible to spec with m typedef ^ DynInflowParms ReKi xMinv {maxinfl} - - #Element -typedef ^ Element ReKi A {:}{:} - - - -typedef ^ Element ReKi AP {:}{:} - - - -typedef ^ Element ReKi ALPHA {:}{:} - - - -typedef ^ Element ReKi W2 {:}{:} - - - +typedef ^ Element ReKi A {:}{:} - - - "Axial induction factor" - +typedef ^ Element ReKi AP {:}{:} - - - "Tangential induction factor" - +typedef ^ Element ReKi ALPHA {:}{:} - - - "Angle of attack" rad +typedef ^ Element ReKi W2 {:}{:} - - - "Relative velocity norm " m/s typedef ^ Element ReKi OLD_A_NS {:}{:} - - - #allocated in VIND typedef ^ Element ReKi OLD_AP_NS {:}{:} - - - #allocated in VIND -typedef ^ Element ReKi PITNOW - - - - -typedef ^ ElementParms IntKi NELM - - - - -typedef ^ ElementParms ReKi TWIST {:} - - - -typedef ^ ElementParms ReKi RELM {:} - - - -typedef ^ ElementParms ReKi HLCNST {:} - - - -typedef ^ ElementParms ReKi TLCNST {:} - - - +typedef ^ Element ReKi PITNOW :: - - - "Current pitch angle - Based on blade orientation (to verify)" rad +typedef ^ ElementParms IntKi NELM - - - - "Number of elements (constant)" - +typedef ^ ElementParms ReKi TWIST {:} - - - "Airfoil twist angle (constant)" - rad +typedef ^ ElementParms ReKi RELM {:} - - - "Radius of element (constant)" m +typedef ^ ElementParms ReKi HLCNST {:} - - - "Hub loss constant B/2*(r-rh)/rh (constant)" - +typedef ^ ElementParms ReKi TLCNST {:} - - - "Tip loss constant B/2*(R-r)/R (constant) " - #ElOutParams typedef ^ ElOutParms ReKi AAA {:} - - - @@ -196,6 +196,7 @@ typedef ^ ElOutParms ReKi DynPres {:} - - - typedef ^ ElOutParms ReKi PMM {:} - - - typedef ^ ElOutParms ReKi PITSAV {:} - - - typedef ^ ElOutParms ReKi ReyNum {:} - - - +typedef ^ ElOutParms ReKi Gamma {:} - - - "Circulation along the span, 1/2 c Vrel Cl" m^2/s typedef ^ ElOutParms ReKi SaveVX {:}{:} - - - typedef ^ ElOutParms ReKi SaveVY {:}{:} - - - typedef ^ ElOutParms ReKi SaveVZ {:}{:} - - - diff --git a/modules/aerodyn14/src/Registry-AD14AeroConf.txt b/modules/aerodyn14/src/Registry-AD14AeroConf.txt new file mode 100644 index 0000000000..920e646bcc --- /dev/null +++ b/modules/aerodyn14/src/Registry-AD14AeroConf.txt @@ -0,0 +1,56 @@ +################################################################################################################################### +# Registry for AD14AeroConf in the FAST Modularization Framework +# This Registry file is used to create MODULE AD14AeroConf_Types which contains all of the user-defined types needed in AD14AeroConf. +# This module is used within the FVW_Types and AeroDyn_Types modules. +# It also contains copy, destroy, pack, and unpack routines associated with each defined data types. +# See the NWTC Programmer's Handbook for further information on the format/contents of this file. +################################################################################################################################### +# Entries are of the form +# +# +# Use ^ as a shortcut for the value in the same column from the previous line. +################################################################################################################################### +include Registry_NWTC_Library.txt + + +## This bit is redundant with AD14 registry. Could not figure out how to have both this and the AD14 registry use a third common chunk +# AeroDyn Subtypes +typedef AD14AeroConf/AD14AeroConf Marker Reki Position 3 0.0 - - +typedef ^ Marker ^ Orientation {3}{3} 0.0 - - +typedef ^ Marker ^ TranslationVel 3 0.0 - - +typedef ^ Marker ^ RotationVel 3 0.0 - - + + +# Airfoil +typedef AD14AeroConf/AD14AeroConf MiscVarType ReKi AL :: - - - +typedef ^ MiscVarType ReKi CD ::: - - - +typedef ^ MiscVarType ReKi CL ::: - - - +typedef ^ MiscVarType ReKi CM ::: - - - +typedef ^ MiscVarType ReKi PMC - - - - +typedef ^ MiscVarType ReKi MulTabLoc - - - - + +# Parameters: this used to be called AirFoilParms +typedef ^ ParameterType IntKi MaxTable - 20 - - +typedef ^ ParameterType IntKi NTables : - - - +typedef ^ ParameterType IntKi NLift : - - - +typedef ^ ParameterType IntKi NumCL - - - - +typedef ^ ParameterType IntKi NumFoil - - - - +typedef ^ ParameterType IntKi NFoil : - - - +typedef ^ ParameterType ReKi MulTabMet :: - - - +typedef ^ ParameterType CHARACTER(1024) FoilNm : "Number of airfoil data sets" - - + + +# Aero input-type --> this used to be called AeroConfig +typedef AD14AeroConf/AD14AeroConf InputType Marker Blade : - - - +typedef ^ InputType ^ Hub - - - - +typedef ^ InputType ^ RotorFurl - - - - +typedef ^ InputType ^ Nacelle - - - - +typedef ^ InputType ^ TailFin - - - - +typedef ^ InputType ^ Tower - - - - +typedef ^ InputType ^ SubStructure - - - - +typedef ^ InputType ^ Foundation - - - - +typedef ^ InputType ReKi BladeLength - - - - + +# Dummy outputtype so that the registry is happy +typedef AD14AeroConf/AD14AeroConf OutputType ReKi Dummy - - - - + diff --git a/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 b/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 index 0eb1c40681..9cc98cb5d4 100644 --- a/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 @@ -245,6 +245,7 @@ SUBROUTINE BldNdOuts_InitOut( InitOut, p, ErrStat, ErrMsg ) ! Populate the header an unit lines for all blades and nodes ! First set a counter so we know where in the output array we are in + ! NOTE: we populate invalid names as well (some names are not valid outputs for certain configurations). That means we will have zeros in those values. INDX = p%NumOuts + 1 ! p%NumOuts is the number of outputs from the normal BeamDyn output. The WriteOutput array is sized to p%NumOuts + num(BldNdOuts) diff --git a/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 b/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 index 3c668bd57e..91c2ed0669 100644 --- a/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 @@ -99,6 +99,7 @@ SUBROUTINE AllBldNdOuts_InitOut( InitOut, p, ErrStat, ErrMsg ) ErrStat = ErrID_None ! First set a counter so we know where in the output array we are in + ! NOTE: we populate invalid names as well (some names are not valid outputs for certain configurations). That means we will have zeros in those values. INDX = p%NumOuts + 1 ! p%NumOuts is the number of outputs from the normal ElastoDyn output. The WriteOutput array is sized to p%NumOuts + num(AllBldNdOuts) ! Populate the header and unit lines for all blades and nodes diff --git a/modules/inflowwind/src/IfW_BladedFFWind.f90 b/modules/inflowwind/src/IfW_BladedFFWind.f90 index dac44e47c8..d5cf83db65 100644 --- a/modules/inflowwind/src/IfW_BladedFFWind.f90 +++ b/modules/inflowwind/src/IfW_BladedFFWind.f90 @@ -1604,17 +1604,21 @@ SUBROUTINE IfW_BladedFFWind_CalcOutput(Time, PositionXYZ, ParamData, Velocity, D ! Step through all the positions and get the velocities DO PointNum = 1, NumPoints - ! Calculate the velocity for the position - Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),ParamData,MiscVars,TmpErrStat,TmpErrMsg) - - ! Error handling - IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, "IfW_BladedFFWind:CalcOutput [position=("// & - TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(3,PointNum)))//")]" ) - IF (ErrStat >= AbortErrLev) RETURN - END IF + ! If the position is (0,0,0), assume it was never set and skip calculating + if ( TwoNorm(PositionXYZ(1:3,PointNum)) > 0.0_ReKi ) then + + ! Calculate the velocity for the position + Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),ParamData,MiscVars,TmpErrStat,TmpErrMsg) + + ! Error handling + IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, "IfW_BladedFFWind:CalcOutput [position=("// & + TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(3,PointNum)))//")]" ) + IF (ErrStat >= AbortErrLev) RETURN + END IF + endif ENDDO diff --git a/modules/inflowwind/src/IfW_HAWCWind.f90 b/modules/inflowwind/src/IfW_HAWCWind.f90 index 66e8748e9f..7f4d24872d 100644 --- a/modules/inflowwind/src/IfW_HAWCWind.f90 +++ b/modules/inflowwind/src/IfW_HAWCWind.f90 @@ -534,18 +534,22 @@ SUBROUTINE IfW_HAWCWind_CalcOutput(Time, PositionXYZ, p, Velocity, DiskVel, Misc ! Step through all the positions and get the velocities DO PointNum = 1, NumPoints - ! Calculate the velocity for the position - Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),p,MiscVars,TmpErrStat,TmpErrMsg) - - - ! Error handling - IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName//" [position=("// & - TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(3,PointNum)))//") in wind-file coordinates]" ) - IF (ErrStat >= AbortErrLev) RETURN - END IF + ! If the position is (0,0,0), assume it was never set and skip calculating + if ( TwoNorm(PositionXYZ(1:3,PointNum)) > 0.0_ReKi ) then + + ! Calculate the velocity for the position + Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),p,MiscVars,TmpErrStat,TmpErrMsg) + + + ! Error handling + IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName//" [position=("// & + TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(3,PointNum)))//") in wind-file coordinates]" ) + IF (ErrStat >= AbortErrLev) RETURN + END IF + endif ENDDO diff --git a/modules/inflowwind/src/IfW_TSFFWind.f90 b/modules/inflowwind/src/IfW_TSFFWind.f90 index 56872d883c..aaf554d6fc 100644 --- a/modules/inflowwind/src/IfW_TSFFWind.f90 +++ b/modules/inflowwind/src/IfW_TSFFWind.f90 @@ -640,23 +640,36 @@ SUBROUTINE IfW_TSFFWind_CalcOutput(Time, PositionXYZ, ParamData, Velocity, Disk ! Step through all the positions and get the velocities + + !$OMP PARALLEL default(shared) if(PointNum>1000) + !$OMP do private(PointNum, TmpErrStat, TmpErrMsg ) schedule(runtime) DO PointNum = 1, NumPoints - ! Calculate the velocity for the position - Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),ParamData,MiscVars,TmpErrStat,TmpErrMsg) + ! If the position is (0,0,0), assume it was never set and skip calculating + if ( TwoNorm(PositionXYZ(1:3,PointNum)) > 0.0_ReKi ) then + + ! Calculate the velocity for the position + Velocity(:,PointNum) = FF_Interp(Time,PositionXYZ(:,PointNum),ParamData,MiscVars,TmpErrStat,TmpErrMsg) - ! Error handling - IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time - CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName//" [position=("// & - TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & - TRIM(Num2LStr(PositionXYZ(3,PointNum)))//") in wind-file coordinates]" ) - IF (ErrStat >= AbortErrLev) RETURN - END IF + ! Error handling + IF (TmpErrStat /= ErrID_None) THEN ! adding this so we don't have to convert numbers to strings every time + !$OMP CRITICAL ! Needed to avoid data race on ErrStat and ErrMsg + ErrStat = ErrID_None + ErrMsg = "" + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName//" [position=("// & + TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & + TRIM(Num2LStr(PositionXYZ(3,PointNum)))//") in wind-file coordinates]" ) + !$OMP END CRITICAL + END IF + endif ENDDO + !$OMP END DO + !$OMP END PARALLEL + IF (ErrStat >= AbortErrLev) RETURN ! Return cannot be in parallel loop !REMOVE THIS for AeroDyn 15 diff --git a/modules/inflowwind/src/IfW_UniformWind.f90 b/modules/inflowwind/src/IfW_UniformWind.f90 index c40b00a27a..8d4b7882ff 100644 --- a/modules/inflowwind/src/IfW_UniformWind.f90 +++ b/modules/inflowwind/src/IfW_UniformWind.f90 @@ -535,24 +535,32 @@ SUBROUTINE IfW_UniformWind_CalcOutput(Time, PositionXYZ, p, Velocity, DiskVel, m CALL InterpParams(Time, p, m, op) ! Step through all the positions and get the velocities + !$OMP PARALLEL default(shared) if(NumPoints>1000) + !$OMP do private(PointNum, TmpErrStat, TmpErrMsg ) schedule(runtime) DO PointNum = 1, NumPoints ! Calculate the velocity for the position call GetWindSpeed(PositionXYZ(:,PointNum), p, m, op, Velocity(:,PointNum), TmpErrStat, TmpErrMsg) ! Error handling - CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - IF (ErrStat >= AbortErrLev) THEN - TmpErrMsg= " Error calculating the wind speed at position ("// & + !CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) + IF (TmpErrStat >= AbortErrLev) THEN + TmpErrMsg= trim(TmpErrMsg)//" Error calculating the wind speed at position ("// & TRIM(Num2LStr(PositionXYZ(1,PointNum)))//", "// & TRIM(Num2LStr(PositionXYZ(2,PointNum)))//", "// & TRIM(Num2LStr(PositionXYZ(3,PointNum)))//") in the wind-file coordinates" + !$OMP CRITICAL ! Needed to avoid data race on ErrStat and ErrMsg + ErrStat = ErrID_None + ErrMsg = "" CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - RETURN + !$OMP END CRITICAL ENDIF ENDDO + !$OMP END DO + !$OMP END PARALLEL + IF (ErrStat >= AbortErrLev) RETURN ! Return cannot be in parallel loop ! DiskVel term -- this represents the average across the disk -- sort of. This changes for AeroDyn 15 DiskVel = WindInf_ADhack_diskVel(Time, p, m, TmpErrStat, TmpErrMsg) @@ -677,6 +685,7 @@ SUBROUTINE GetWindSpeed(InputPosition, p, m, op, WindSpeed, ErrStat, ErrMsg) if ( InputPosition(3) < 0.0_ReKi ) then call SetErrStat(ErrID_Fatal,'Height must not be negative.',ErrStat,ErrMsg,'GetWindSpeed') + return end if !> Let \f{eqnarray}{ V_h & = & V \, \left( \frac{Z}{Z_{ref}} \right) ^ {V_{shr}} & \mbox{power-law wind shear} \\ diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 6b74089698..deb83b3523 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -139,7 +139,7 @@ MODULE NWTC_IO END INTERFACE !> \copydoc nwtc_io::parsechvarwdefault - INTERFACE ParseVarWDefault ! Parses a character variable name and value from a string, potentially sets to a default value if "Default" is parsed. + INTERFACE ParseVarWDefault ! Parses a boolean variable name and value from a string, potentially sets to a default value if "Default" is parsed. MODULE PROCEDURE ParseChVarWDefault ! Parses a character string from a string, potentially sets to a default value if "Default" is parsed. MODULE PROCEDURE ParseDbVarWDefault ! Parses a double-precision REAL from a string, potentially sets to a default value if "Default" is parsed. MODULE PROCEDURE ParseInVarWDefault ! Parses an INTEGER from a string, potentially sets to a default value if "Default" is parsed. @@ -176,7 +176,7 @@ MODULE NWTC_IO INTERFACE ReadVarWDefault !MODULE PROCEDURE ReadCVar MODULE PROCEDURE ReadIVarWDefault - !MODULE PROCEDURE ReadLVar + MODULE PROCEDURE ReadLVarWDefault ! Logical MODULE PROCEDURE ReadR4VarWDefault ! 4-byte real MODULE PROCEDURE ReadR8VarWDefault ! 8-byte real MODULE PROCEDURE ReadR16VarWDefault ! 16-byte real @@ -5662,6 +5662,56 @@ SUBROUTINE ReadIVarWDefault ( UnIn, Fil, Var, VarName, VarDescr, VarDefault, Err RETURN END SUBROUTINE ReadIVarWDefault !======================================================================= +!> This routine reads a logical variable from the next line of the input file. +!! Use ReadVarWDefault (nwtc_io::readvarwdefault) instead of directly calling a specific routine in the generic interface. +!! WARNING: this routine limits the size of the number being read to 30 characters + SUBROUTINE ReadLVarWDefault ( UnIn, Fil, Var, VarName, VarDescr, VarDefault, ErrStat, ErrMsg, UnEc ) + + ! Argument declarations: + + LOGICAL, INTENT(OUT) :: Var !< variable being read + LOGICAL, INTENT(IN) :: VarDefault !< default value of variable being read + INTEGER, INTENT(IN) :: UnIn !< I/O unit for input file. + INTEGER, INTENT(IN), OPTIONAL:: UnEc !< I/O unit for echo file. If present and > 0, write to UnEc + INTEGER(IntKi), INTENT(OUT) :: ErrStat !< Error status; if present, program does not abort on error + CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message + + CHARACTER(*), INTENT(IN) :: Fil !< Name of the input file. + CHARACTER(*), INTENT(IN) :: VarDescr !< Text string describing the variable. + CHARACTER(*), INTENT(IN) :: VarName !< Text string containing the variable name. + + + ! Local declarations: + + INTEGER :: IOS ! I/O status returned from the read statement. + + CHARACTER(30) :: Word ! String to hold the first word on the line. + + + CALL ReadNum ( UnIn, Fil, Word, VarName, ErrStat, ErrMsg ) + IF ( ErrStat >= AbortErrLev ) RETURN ! If we're about to read a T/F and treat it as a number, we have a less severe ErrStat + + CALL Conv2UC( Word ) + IF ( INDEX(Word, "DEFAULT" ) /= 1 ) THEN ! If it's not "default", read this variable; otherwise use the DEFAULT value + READ (Word,*,IOSTAT=IOS) Var + + CALL CheckIOS ( IOS, Fil, VarName, NumType, ErrStat, ErrMsg ) + + IF (ErrStat >= AbortErrLev) RETURN + ELSE + Var = VarDefault + END IF + + IF ( PRESENT(UnEc) ) THEN + IF ( UnEc > 0 ) & + WRITE (UnEc,Ec_IntFrmt) Var, VarName, VarDescr + END IF + + + RETURN + END SUBROUTINE ReadLVarWDefault +!======================================================================= + !> \copydoc nwtc_io::readcary SUBROUTINE ReadLAry ( UnIn, Fil, Ary, AryLen, AryName, AryDescr, ErrStat, ErrMsg, UnEc ) diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 714d05f043..4c0803b8e3 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -180,6 +180,13 @@ MODULE NWTC_Num MODULE PROCEDURE InterpStpReal16 END INTERFACE + !> \copydoc nwtc_num::interparrayr4 + INTERFACE InterpArray + MODULE PROCEDURE InterpArrayR4 + MODULE PROCEDURE InterpArrayR8 + MODULE PROCEDURE InterpArrayR16 + END INTERFACE + !> \copydoc nwtc_num::interpwrappedstpreal4 INTERFACE InterpWrappedStpReal MODULE PROCEDURE InterpWrappedStpReal4 @@ -3706,6 +3713,132 @@ FUNCTION InterpWrappedStpReal16( XValIn, XAry, YAry, Ind, AryLen ) END FUNCTION InterpWrappedStpReal16 !======================================================================= +!> This subroutine calculates interpolated values for an array of input values. +!! The size of the xknown and yknown arrays must match, and the size of the +!! xnew and ynew arrays must match. Xknown must be in ascending order. +!! Values outside the range of xknown are fixed to the end points. + SUBROUTINE InterpArrayR4( xknown, yknown, xnew, ynew ) + REAL(SiKi), INTENT(IN ) :: xknown(:) + REAL(SiKi), INTENT(IN ) :: yknown(:) + REAL(SiKi), INTENT(IN ) :: xnew(:) + REAL(SiKi), INTENT( OUT) :: ynew(:) + integer(IntKi) i,itmp,nknown + nknown=size(xknown) + do i=1,size(xnew) + itmp=minloc(abs(xnew(i)-xknown),dim=1) + if (itmp==nknown) then + if (xknown(itmp)>xnew(i)) then + ynew(i)=interp_lin0(xnew(i),xknown(itmp-1),xknown(itmp),yknown(itmp-1),yknown(itmp)) + else + ! The current x is above the max of xknown + ! extrapolation required, here fixed to upper bound + ynew(i)=yknown(nknown) + endif + elseif (xknown(itmp) \copydoc nwtc_num::interparrayr4 + SUBROUTINE InterpArrayR8( xknown, yknown, xnew, ynew ) + REAL(R8Ki), INTENT(IN ) :: xknown(:) + REAL(R8Ki), INTENT(IN ) :: yknown(:) + REAL(R8Ki), INTENT(IN ) :: xnew(:) + REAL(R8Ki), INTENT( OUT) :: ynew(:) + integer(IntKi) i,itmp,nknown + nknown=size(xknown) + do i=1,size(xnew) + itmp=minloc(abs(xnew(i)-xknown),dim=1) + if (itmp==nknown) then + if (xknown(itmp)>xnew(i)) then + ynew(i)=interp_lin0(xnew(i),xknown(itmp-1),xknown(itmp),yknown(itmp-1),yknown(itmp)) + else + ! The current x is above the max of xknown + ! extrapolation required, here fixed to upper bound + ynew(i)=yknown(nknown) + endif + elseif (xknown(itmp) \copydoc nwtc_num::interparrayr4 + SUBROUTINE InterpArrayR16( xknown, yknown, xnew, ynew ) + REAL(QuKi), INTENT(IN ) :: xknown(:) + REAL(QuKi), INTENT(IN ) :: yknown(:) + REAL(QuKi), INTENT(IN ) :: xnew(:) + REAL(QuKi), INTENT( OUT) :: ynew(:) + integer(IntKi) i,itmp,nknown + nknown=size(xknown) + do i=1,size(xnew) + itmp=minloc(abs(xnew(i)-xknown),dim=1) + if (itmp==nknown) then + if (xknown(itmp)>xnew(i)) then + ynew(i)=interp_lin0(xnew(i),xknown(itmp-1),xknown(itmp),yknown(itmp-1),yknown(itmp)) + else + ! The current x is above the max of xknown + ! extrapolation required, here fixed to upper bound + ynew(i)=yknown(nknown) + endif + elseif (xknown(itmp) This subroutine calculates the iosparametric coordinates, isopc, which is a value between -1 and 1 !! (for each dimension of a dataset), indicating where InCoord falls between posLo and posHi. !! It is used in InterpStpReal2D (nwtcnum::interpstpreal2d) and InterpStpReal3D (nwtcnum::interpstpreal3d). diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 81c35893b6..c6ab8755fa 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -330,12 +330,13 @@ SUBROUTINE ED_InputSolve( p_FAST, u_ED, y_ED, p_AD14, y_AD14, y_AD, y_SrvD, u_AD END SUBROUTINE ED_InputSolve !---------------------------------------------------------------------------------------------------------------------------------- !> This routine determines the points in space where InflowWind needs to compute wind speeds. -SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, y_ED, ErrStat, ErrMsg ) +SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_AD, y_ED, ErrStat, ErrMsg ) - TYPE(InflowWind_InputType), INTENT(INOUT) :: u_IfW !< The inputs to InflowWind + TYPE(InflowWind_InputType), INTENT(INOUT) :: u_IfW(:) !< The inputs to InflowWind TYPE(InflowWind_ParameterType), INTENT(IN ) :: p_IfW !< The parameters to InflowWind TYPE(AD14_InputType), INTENT(IN) :: u_AD14 !< The input meshes (already calculated) from AeroDyn14 TYPE(AD_InputType), INTENT(IN) :: u_AD !< The input meshes (already calculated) from AeroDyn + TYPE(AD_OtherStateType), INTENT(IN) :: OtherSt_AD !< The wake points from AeroDyn are in here (Free Vortex Wake) TYPE(ED_OutputType), INTENT(IN) :: y_ED !< The outputs of the structural dynamics module (for IfW Lidar) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data TYPE(FAST_MiscVarType), INTENT(IN ) :: m_FAST !< misc FAST data, including inputs from external codes like Simulink @@ -359,7 +360,7 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, y_ED, Err Node = 0 IF (p_FAST%CompServo == MODULE_SrvD) THEN Node = Node + 1 - u_IfW%PositionXYZ(:,Node) = y_ED%HubPtMotion%Position(:,1) ! undisplaced position. Maybe we want to use the displaced position (y_ED%HubPtMotion%TranslationDisp) at some point in time. + u_IfW(1)%PositionXYZ(:,Node) = y_ED%HubPtMotion%Position(:,1) ! undisplaced position. Maybe we want to use the displaced position (y_ED%HubPtMotion%TranslationDisp) at some point in time. END IF IF (p_FAST%CompAero == MODULE_AD14) THEN @@ -367,13 +368,13 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, y_ED, Err DO K = 1,SIZE(u_AD14%InputMarkers) DO J = 1,u_AD14%InputMarkers(K)%nnodes !this mesh isn't properly set up (it's got the global [absolute] position and no reference position) Node = Node + 1 - u_IfW%PositionXYZ(:,Node) = u_AD14%InputMarkers(K)%Position(:,J) + u_IfW(1)%PositionXYZ(:,Node) = u_AD14%InputMarkers(K)%Position(:,J) END DO !J = 1,p%BldNodes ! Loop through the blade nodes / elements END DO !K = 1,p%NumBl DO J=1,u_AD14%Twr_InputMarkers%nnodes Node = Node + 1 - u_IfW%PositionXYZ(:,Node) = u_AD14%Twr_InputMarkers%TranslationDisp(:,J) + u_AD14%Twr_InputMarkers%Position(:,J) + u_IfW(1)%PositionXYZ(:,Node) = u_AD14%Twr_InputMarkers%TranslationDisp(:,J) + u_AD14%Twr_InputMarkers%Position(:,J) END DO ELSEIF (p_FAST%CompAero == MODULE_AD) THEN @@ -382,21 +383,31 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, y_ED, Err DO J = 1,u_AD%BladeMotion(k)%Nnodes Node = Node + 1 - u_IfW%PositionXYZ(:,Node) = u_AD%BladeMotion(k)%TranslationDisp(:,j) + u_AD%BladeMotion(k)%Position(:,j) + u_IfW(1)%PositionXYZ(:,Node) = u_AD%BladeMotion(k)%TranslationDisp(:,j) + u_AD%BladeMotion(k)%Position(:,j) END DO !J = 1,p%BldNodes ! Loop through the blade nodes / elements END DO !K = 1,p%NumBl DO J=1,u_AD%TowerMotion%nnodes - Node = Node + 1 - u_IfW%PositionXYZ(:,Node) = u_AD%TowerMotion%TranslationDisp(:,J) + u_AD%TowerMotion%Position(:,J) + Node = Node + 1 + u_IfW(1)%PositionXYZ(:,Node) = u_AD%TowerMotion%TranslationDisp(:,J) + u_AD%TowerMotion%Position(:,J) END DO - + ! vortex points from FVW in AD15 + if (allocated(OtherSt_AD%WakeLocationPoints)) then + do J=1,size(OtherSt_AD%WakeLocationPoints,DIM=2) + Node = Node + 1 + u_IfW(1)%PositionXYZ(:,Node) = OtherSt_AD%WakeLocationPoints(:,J) + ! rewrite the history of this so that extrapolation doesn't make a mess of things + do k=2,size(u_IfW) + if (allocated(u_IfW(k)%PositionXYZ)) u_IfW(k)%PositionXYZ(:,Node) = u_IfW(1)%PositionXYZ(:,Node) + end do + enddo + end if END IF - CALL IfW_SetExternalInputs( p_IfW, m_FAST, y_ED, u_IfW ) + CALL IfW_SetExternalInputs( p_IfW, m_FAST, y_ED, u_IfW(1) ) END SUBROUTINE IfW_InputSolve @@ -475,6 +486,15 @@ SUBROUTINE AD_InputSolve_IfW( p_FAST, u_AD, y_IfW, y_OpFM, ErrStat, ErrMsg ) node = node + 1 end do end if + ! velocity at vortex wake points velocity array handoff here + if ( allocated(u_AD%InflowWakeVel) ) then + Nnodes = size(u_AD%InflowWakeVel,DIM=2) + do j=1,Nnodes + u_AD%InflowWakeVel(:,j) = y_IfW%VelocityUVW(:,node) + node = node + 1 + end do + end if + ELSEIF ( p_FAST%CompInflow == MODULE_OpFM ) THEN node = 2 !start of inputs to AD15 @@ -643,7 +663,7 @@ SUBROUTINE AD14_InputSolve_IfW( p_FAST, u_AD14, y_IfW, y_OpFM, ErrStat, ErrMsg ) END IF u_AD14%AvgInfVel = y_IfW%DiskVel - + END SUBROUTINE AD14_InputSolve_IfW !---------------------------------------------------------------------------------------------------------------------------------- @@ -4605,7 +4625,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca END IF IF ( p_FAST%CompInflow == Module_IfW ) THEN - CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(1), IfW%p, AD14%Input(1), AD%Input(1), ED%y, ErrStat2, ErrMsg2 ) + CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(:), IfW%p, AD14%Input(1), AD%Input(1), AD%OtherSt(1), ED%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ELSE IF ( p_FAST%CompInflow == Module_OpFM ) THEN ! OpenFOAM is the driver and it sets these inputs outside of this solve; the OpenFOAM inputs and outputs thus don't change @@ -4925,7 +4945,7 @@ SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, IF (p_FAST%CompInflow == Module_IfW) THEN ! must be done after ED_CalcOutput and before AD_CalcOutput and SrvD - CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(1), IfW%p, AD14%Input(1), AD%Input(1), ED%y, ErrStat2, ErrMsg2 ) + CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(:), IfW%p, AD14%Input(1), AD%Input(1), AD%OtherSt(1), ED%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) !ELSE IF ( p_FAST%CompInflow == Module_OpFM ) THEN ! ! OpenFOAM is the driver and it computes outputs outside of this solve; the OpenFOAM inputs and outputs thus don't change @@ -4976,7 +4996,7 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, IF (p_FAST%CompInflow == Module_IfW) THEN - + CALL InflowWind_CalcOutput( this_time, IfW%Input(1), IfW%p, IfW%x(this_state), IfW%xd(this_state), IfW%z(this_state), & IfW%OtherSt(this_state), IfW%y, IfW%m, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -5277,7 +5297,7 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL AD_CopyOtherState( AD%OtherSt(STATE_CURR), AD%OtherSt(STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2) CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - + DO j_ss = 1, p_FAST%n_substeps( MODULE_AD ) n_t_module = n_t_global*p_FAST%n_substeps( MODULE_AD ) + j_ss - 1 t_module = n_t_module*p_FAST%dt_module( MODULE_AD ) + t_initial @@ -5285,6 +5305,10 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr CALL AD_UpdateStates( t_module, n_t_module, AD%Input, AD%InputTimes, AD%p, AD%x(STATE_PRED), & AD%xd(STATE_PRED), AD%z(STATE_PRED), AD%OtherSt(STATE_PRED), AD%m, ErrStat2, ErrMsg2 ) CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ! We don't want to extrapolate any values for the WakeLocations (those are exactly calculated) + if (allocated(AD%OtherSt(STATE_PRED)%WakeLocationPoints)) then + AD%OtherSt(STATE_CURR)%WakeLocationPoints = AD%OtherSt(STATE_PRED)%WakeLocationPoints + endif END DO !j_ss END IF diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 2cca60d7fc..1ba775af77 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -521,6 +521,9 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, DO k=1,Init%OutData_ED%NumBl Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints + AD%Input(1)%BladeMotion(k)%NNodes END DO + if (allocated(AD%OtherSt(STATE_CURR)%WakeLocationPoints)) then + Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints + size(AD%OtherSt(STATE_CURR)%WakeLocationPoints,DIM=2) + end if END IF ! lidar @@ -4991,6 +4994,7 @@ END SUBROUTINE WriteVTK !---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes all the committed meshes to VTK-formatted files. It doesn't bother with returning an error code. SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + use FVW_IO, only: WrVTK_FVW TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code TYPE(FAST_OutputFileType),INTENT(IN ) :: y_FAST !< Output variables for the glue code @@ -5119,6 +5123,7 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%BladeRootMotion(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_BladeRootMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%BladeMotion(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_BladeMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) END DO + call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%HubMotion, trim(p_FAST%VTK_OutFileRoot)//'.AD_HubMotion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%TowerMotion, trim(p_FAST%VTK_OutFileRoot)//'.AD_TowerMotion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) @@ -5128,7 +5133,18 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H call MeshWrVTK(p_FAST%TurbinePos, AD%y%TowerLoad, trim(p_FAST%VTK_OutFileRoot)//'.AD_Tower', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, AD%Input(1)%TowerMotion ) end if - + + ! FVW submodule of AD15 + if (allocated(AD%m%FVW_u)) then + if (allocated(AD%m%FVW_u(1)%WingsMesh)) then + DO K=1,NumBl + call MeshWrVTK(p_FAST%TurbinePos, AD%m%FVW_u(1)%WingsMesh(k), trim(p_FAST%VTK_OutFileRoot)//'.FVW_WingsMesh'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, AD%Input(1)%BladeMotion(k) ) + !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%BladeMotion(K), trim(p_FAST%OutFileRoot)//'.AD_BladeMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2 ) + END DO + ! Free wake + call WrVTK_FVW(AD%p%FVW, AD%x(1)%FVW, AD%z(1)%FVW, AD%m%FVW, trim(p_FAST%VTK_OutFileRoot)//'.FVW', y_FAST%VTK_count, p_FAST%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + end if + end if END IF ! HydroDyn @@ -5316,6 +5332,7 @@ END SUBROUTINE WrVTK_BasicMeshes !> This routine writes a minimal subset of meshes with surfaces to VTK-formatted files. It doesn't bother with !! returning an error code. SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + use FVW_IO, only: WrVTK_FVW REAL(DbKi), INTENT(IN ) :: t_global !< Current global time TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code @@ -5386,7 +5403,14 @@ SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth , verts=p_FAST%VTK_Surface%BladeShape(K)%AirfoilCoords ) END DO END IF - + +! Free wake + if (allocated(AD%m%FVW_u)) then + if (allocated(AD%m%FVW_u(1)%WingsMesh)) then + call WrVTK_FVW(AD%p%FVW, AD%x(1)%FVW, AD%z(1)%FVW, AD%m%FVW, trim(p_FAST%VTK_OutFileRoot)//'.FVW', y_FAST%VTK_count, p_FAST%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + end if + end if + ! Platform ! call MeshWrVTK_PointSurface (p_FAST%TurbinePos, ED%y%PlatformPtMesh, trim(p_FAST%VTK_OutFileRoot)//'.PlatformSurface', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2, Radius = p_FAST%VTK_Surface%GroundRad ) diff --git a/modules/openfast-library/src/FAST_Types.f90 b/modules/openfast-library/src/FAST_Types.f90 index db2c1df716..79f0e6cf2e 100644 --- a/modules/openfast-library/src/FAST_Types.f90 +++ b/modules/openfast-library/src/FAST_Types.f90 @@ -49,6 +49,7 @@ MODULE FAST_Types USE UnsteadyAero_Types USE DBEMT_Types USE BEMT_Types +USE FVW_Types USE AeroDyn_Types USE SubDyn_Types USE Current_Types diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 343b8c2776..8c012d210d 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -102,7 +102,7 @@ of_regression("WP_VSP_WTurb_PitchFail" "openfast;elastodyn;aerodyn14;se of_regression("WP_VSP_ECD" "openfast;elastodyn;aerodyn15;servodyn") of_regression("WP_VSP_WTurb" "openfast;elastodyn;aerodyn15;servodyn") of_regression("SWRT_YFree_VS_EDG01" "openfast;elastodyn;aerodyn15;servodyn") -of_regression("SWRT_YFree_VS_EDC01" "openfast;elastodyn;aerodyn15;servodyn") +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") @@ -114,6 +114,8 @@ of_regression("5MW_OC3Spar_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerod of_regression("5MW_OC4Semi_WSt_WavesWN" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn") 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") +of_regression("EllipticalWing_OLAF" "openfast;aerodyn15;olaf") # Linearized OpenFAST regression tests of_regression_linear("WP_Stationary_Linear" "openfast;linear;elastodyn;aerodyn15") diff --git a/reg_tests/r-test b/reg_tests/r-test index 8fb74c6e5a..bee6168250 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 8fb74c6e5aca388b72488c88df5032df9a340491 +Subproject commit bee616825018687428358728c99bfd76730f7a91 diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index cfd3cdfbcf..4caee9fa32 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -71,3 +71,4 @@ endif() ### Add the unit tests here add_subdirectory("beamdyn") add_subdirectory("nwtc-library") +add_subdirectory("aerodyn") diff --git a/unit_tests/aerodyn/CMakeLists.txt b/unit_tests/aerodyn/CMakeLists.txt new file mode 100644 index 0000000000..4e0bf86852 --- /dev/null +++ b/unit_tests/aerodyn/CMakeLists.txt @@ -0,0 +1,61 @@ +# +# 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 "fvw") +set(module_directory "aerodyn") +set(module_library "fvwlib") + +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 + test_FVW_testsuite +) +foreach(test ${testlist}) + set(test_dependency pfunit ${source_modulesdirectory}/${module_directory}/tests/${test}.F90) + add_custom_command( + OUTPUT ${build_testdirectory}/${module_directory}/${test}.F90 + COMMAND ${PYTHON_EXECUTABLE} ${pfunit_directory}/bin/pFUnitParser.py ${source_modulesdirectory}/${module_directory}/tests/${test}.F90 ${build_testdirectory}/${module_directory}/${test}.F90 + DEPENDS ${test_dependency} + ) + set(test_sources ${test_sources} ${build_testdirectory}/${module_directory}/${test}.F90) + file(APPEND ${build_testdirectory}/${module_directory}/testSuites.inc "ADD_TEST_SUITE(${test}_suite)\n") +endforeach() + +add_executable( + ${module_name}_utest + ${pfunit_directory}/include/driver.F90 + ${test_sources} +) + +target_link_libraries( + ${module_name}_utest + ${pfunit_directory}${pfunit_lib} + ${module_library} +) + +add_test( + ${module_name}_utest + ${PROJECT_BINARY_DIR}/${module_directory}/${module_name}_utest +) diff --git a/vs-build/AeroDyn/AeroDyn_Driver.vfproj b/vs-build/AeroDyn/AeroDyn_Driver.vfproj index df3e8d2c01..10fc1c8681 100644 --- a/vs-build/AeroDyn/AeroDyn_Driver.vfproj +++ b/vs-build/AeroDyn/AeroDyn_Driver.vfproj @@ -5,7 +5,7 @@ - + @@ -15,7 +15,7 @@ - + @@ -25,7 +25,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -75,7 +75,7 @@ - + @@ -124,19 +124,19 @@ - - + + - - + + @@ -154,19 +154,19 @@ - - + + - - + + @@ -183,19 +183,19 @@ - - + + - - + + @@ -214,19 +214,19 @@ - - + + - - + + @@ -238,6 +238,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -264,19 +345,19 @@ - - + + - - + + diff --git a/vs-build/FASTlib/FASTlib.vfproj b/vs-build/FASTlib/FASTlib.vfproj index 1394dd2e70..43e2ef8162 100644 --- a/vs-build/FASTlib/FASTlib.vfproj +++ b/vs-build/FASTlib/FASTlib.vfproj @@ -121,29 +121,38 @@ + + + + + + + + + - - + + - - - + - + - + + + @@ -159,25 +168,25 @@ - - + + - - - + - + - + + + @@ -193,25 +202,25 @@ - - + + - - - + - + - + + + @@ -227,25 +236,25 @@ - - + + - - - + - + - + + + @@ -258,28 +267,62 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - + + + @@ -316,25 +359,25 @@ - - + + - - - + - + - + + + @@ -353,25 +396,25 @@ - - + + - - - + - + - + + + @@ -392,25 +435,25 @@ - - + + - - - + - + - + + + @@ -423,25 +466,25 @@ - - + + - - - + - + - + + + @@ -463,25 +506,25 @@ - - + + - - - + - + - + + + @@ -501,25 +544,25 @@ - - + + - - - + - + - + + + @@ -541,25 +584,25 @@ - - + + - - - + - + - + + + @@ -575,25 +618,25 @@ - - + + - - - + - + - + + + @@ -609,25 +652,25 @@ - - + + - - - + - + - + + + @@ -643,25 +686,25 @@ - - + + - - - + - + - + + + @@ -711,25 +754,25 @@ - - + + - - - + - + - + + + @@ -745,50 +788,50 @@ - - + + - - - + - + - + + + - - + + - - - + - + - + + + @@ -813,50 +856,50 @@ - - + + - - - + - + - + + + - - + + - - - + - + - + + + @@ -911,25 +954,25 @@ - - + + - - - + - + - + + + @@ -939,25 +982,25 @@ - - + + - - - + - + - + + + @@ -988,25 +1031,25 @@ - - + + - - - + - + - + + + @@ -1022,25 +1065,25 @@ - - - + - + - + - + - + - + + + @@ -1056,25 +1099,25 @@ - - + + - - - + - + - + + + @@ -1090,25 +1133,25 @@ - - + + - - - + - + - + + + @@ -1124,25 +1167,25 @@ - - + + - - - + - + - + + + @@ -1158,25 +1201,25 @@ - - + + - - - + - + - + + + @@ -1192,25 +1235,25 @@ - - + + - - - + - + - + + + @@ -1226,25 +1269,25 @@ - - + + - - - + - + - + + + @@ -1272,25 +1315,25 @@ - - + + - - - + - + - + + + @@ -1347,21 +1390,23 @@ + + - - - + - + - + + + @@ -1380,25 +1425,25 @@ - - + + - - - + - + - + + + @@ -1418,25 +1463,25 @@ - - + + - - - + - + - + + + @@ -1460,21 +1505,23 @@ + + - - - + - + - + + + @@ -1486,21 +1533,23 @@ + + - - - + - + - + + + @@ -1511,21 +1560,23 @@ + + - - - + - + - + + + @@ -1555,42 +1606,42 @@ - + - + - - + + - - + + - - - + - + - + + + @@ -1609,25 +1660,25 @@ - - + + - - - + - + - + + + @@ -1643,25 +1694,25 @@ - - + + - - - + - + - + + + @@ -1685,25 +1736,25 @@ - - + + - - - + - + - + + + @@ -1725,25 +1776,25 @@ - - + + - - - + - + - + + + diff --git a/vs-build/RunRegistry.bat b/vs-build/RunRegistry.bat index 3719c14711..6aa6d5222c 100644 --- a/vs-build/RunRegistry.bat +++ b/vs-build/RunRegistry.bat @@ -144,6 +144,12 @@ SET Output_Loc=%CURR_LOC% %REGISTRY% "%CURR_LOC%\UnsteadyAero_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" GOTO checkError +:FVW +SET CURR_LOC=%AD_Loc% +SET Output_Loc=%CURR_LOC% +%REGISTRY% "%CURR_LOC%\FVW_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" +GOTO checkError + :AeroDyn14 SET CURR_LOC=%AD14_Loc% SET Output_Loc=%CURR_LOC% @@ -312,4 +318,4 @@ SET ALL_FAST_Includes= echo %lines% set lines= -:PathsOnly \ No newline at end of file +:PathsOnly