diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 6f9958f135..6cd85bb42e 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -204,6 +204,7 @@ jobs: -DVARIABLE_TRACKING=OFF \ -DBUILD_FASTFARM:BOOL=ON \ -DBUILD_OPENFAST_CPP_API:BOOL=ON \ + -DBUILD_OPENFAST_LIB_DRIVER:BOOL=ON \ -DBUILD_OPENFAST_CPP_DRIVER:BOOL=ON \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_TESTING:BOOL=ON \ @@ -248,7 +249,7 @@ jobs: - name: Build OpenFAST C-Interfaces working-directory: ${{runner.workspace}}/openfast/build run: | - cmake --build . --target openfastlib openfast_cpp_driver openfastcpp aerodyn_inflow_c_binding moordyn_c_binding ifw_c_binding hydrodyn_c_binding regression_test_controllers + cmake --build . --target openfastlib openfast_lib_driver openfastcpp aerodyn_inflow_c_binding moordyn_c_binding ifw_c_binding hydrodyn_c_binding regression_test_controllers - name: Cache the workspace uses: actions/cache@v4 with: diff --git a/.github/workflows/build-docker-image-manual.yml b/.github/workflows/build-docker-image-manual.yml index 608bd02307..a017443a06 100644 --- a/.github/workflows/build-docker-image-manual.yml +++ b/.github/workflows/build-docker-image-manual.yml @@ -20,9 +20,9 @@ jobs: timeout-minutes: 300 env: DOCKERFILE_PATH: share/docker/Dockerfile - DOCKERFILE_PERMALINK: https://raw.githubusercontent.com/OpenFAST/openfast/main/share/docker/Dockerfile + DOCKERFILE_PERMALINK: https://raw.githubusercontent.com/openfast/openfast/main/share/docker/Dockerfile DOCKERHUB_REPOSITORY: nrel/openfast - GH_REGISTRY: ghcr.io/OpenFAST/openfast + GH_REGISTRY: ghcr.io/openfast/openfast permissions: contents: read packages: write diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 180969d6fa..f28aee59ce 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,7 +41,7 @@ jobs: env: DOCKERFILE_PATH: share/docker/Dockerfile DOCKERHUB_REPOSITORY: nrel/openfast - GH_REGISTRY: ghcr.io/OpenFAST/openfast + GH_REGISTRY: ghcr.io/openfast/openfast permissions: contents: read packages: write @@ -68,7 +68,11 @@ jobs: - name: Extract tag from release candidate branch name id: extract-tag - run: echo "openfast-tag=$(expr substr "${{ github.head_ref }}" 4 100)" >> $GITHUB_OUTPUT + run: | + TAG="${{ github.event.release.tag_name }}" + CLEAN_TAG="${TAG#v}" + echo "openfast-tag=$CLEAN_TAG" >> $GITHUB_OUTPUT + echo "Extracted tag $CLEAN_TAG" - name: Build and push to registry uses: docker/build-push-action@v5 @@ -77,7 +81,7 @@ jobs: file: ${{ env.DOCKERFILE_PATH }} platforms: linux/amd64,linux/aarch64 tags: | - ${{ env.GH_REGISTRY }}:${{ steps.extract-tag.outputs.openfast-tag }},${{ env.DOCKERHUB_REPOSITORY }}:latest + ${{ env.GH_REGISTRY }}:${{ steps.extract-tag.outputs.openfast-tag }},${{ env.GH_REGISTRY }}:latest # ${{ env.DOCKERHUB_REPOSITORY }}:${{ steps.extract-tag.outputs.openfast-tag }},${{ env.DOCKERHUB_REPOSITORY }}:latest push: true cache-from: type=gha diff --git a/CMakeLists.txt b/CMakeLists.txt index 257aa06029..04a042661f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,8 @@ option(FPE_TRAP_ENABLED "Enable FPE trap in compiler options" off) option(ORCA_DLL_LOAD "Enable OrcaFlex Library Load" on) option(BUILD_FASTFARM "Enable building FAST.Farm" off) option(BUILD_OPENFAST_CPP_API "Enable building OpenFAST - C++ API" off) -option(BUILD_OPENFAST_CPP_DRIVER "Enable building OpenFAST C++ driver using C++ API" off) +option(BUILD_OPENFAST_CPP_DRIVER "Enable building OpenFAST C++ driver using C++ CFD API" off) +option(BUILD_OPENFAST_LIB_DRIVER "Enable building OpenFAST driver using C++ Library API" off) option(BUILD_OPENFAST_SIMULINK_API "Enable building OpenFAST for use with Simulink" off) option(OPENMP "Enable OpenMP support" off) option(USE_LOCAL_STATIC_LAPACK "Enable downloading and building static LAPACK and BLAS libs" off) @@ -231,8 +232,8 @@ endforeach(IDIR IN ITEMS ${OPENFAST_MODULES}) add_subdirectory(glue-codes) # Install fortran .mod files also to installation directory -install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY}/ - DESTINATION ${CMAKE_INSTALL_PREFIX}/include/openfast/ +install(DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY} + DESTINATION include/openfast/ FILES_MATCHING PATTERN "*.mod" ) diff --git a/docs/changelogs/v3.5.5.md b/docs/changelogs/v3.5.5.md new file mode 100644 index 0000000000..0ac516dbc0 --- /dev/null +++ b/docs/changelogs/v3.5.5.md @@ -0,0 +1,107 @@ +**Feature or improvement description** +Pull request to merge `rc-3.5.5` into `main` and create a tagged release for v3.5.5. + +See the milestone and project pages for additional information + + https://github.com/OpenFAST/openfast/milestone/15 + +Test results, if applicable +See GitHub Actions + +### Release checklist: +- [ ] Update the documentation version in docs/conf.py +- [ ] Update the versions in docs/source/user/api_change.rst +- [ ] Verify readthedocs builds correctly +- [ ] Create a tag in OpenFAST +- [ ] Create a merge commit in r-test and add a corresponding annotated tag +- [ ] Compile executables for Windows builds + - [ ] AeroDyn_Driver_x64.exe + - [ ] AeroDyn_Driver_x64_OpenMP.exe + - [ ] AeroDyn_Inflow_C_Binding_x64.dll + - [ ] AeroDyn_Inflow_C_Binding_x64_OpenMP.dll + - [ ] BeamDyn_Driver_x64.exe + - [ ] DISCON.dll (x64) + - [ ] DISCON_ITIBarge.dll (x64) + - [ ] DISCON_OC3Hywind.dll (x64) + - [ ] DISCON_SC.dll (x64) + - [ ] FAST.Farm_x64.exe + - [ ] FAST.Farm_x64_OMP.exe + - [ ] FAST_SFunc.mexw64 + - [ ] HydroDynDriver_x64.exe + - [ ] HydroDyn_C_Binding_x64.dll + - [ ] IfW_C_Binding_x64.dll + - [ ] InflowWind_Driver_x64.exe + - [ ] InflowWind_Driver_x64_OpenMP.exe + - [ ] MoorDyn_Driver_x64.exe + - [ ] MoorDyn_C_Binding_x64.dll + - [ ] OpenFAST-Simulink_x64.dll + - [ ] openfast_x64.exe + - [ ] Turbsim_x64.exe + +# Changelog + +## Overview + +This release includes multiple small bug-fixes for compilation with CMake, compilation with the IFX compilers, file opening issues when OpenMP is used, and a couple of infrequent segmentation faults from improper usage. One minor feature improvement is the increase in the number of output planes available in _FAST.Farm_ from 99 to 999. + +We recommend all users currently using any 3.5.x version to update to this version. There are no input files changes or API changes for calling from other codes since version 3.5.0. + + + +## General + +### Build systems + +#2497 `CMAKE_INSTALL_PREFIX` was incorrectly being prepended to the install direcotry (@deslaughter) Derek Slaughter + +#2564 Create `BUILD_OPENFAST_LIB_DRIVER` flag for the OpenFAST C++ Library Interface (not CFD) (@deslaughter) + + +### Docker + +#2498 Docker: typo was preventing docker build upload to GH (@andrew-platt) + + + +## Solvers + +### FAST.Farm + +#2536 FAST.Farm: increase number of output planes to 999 (@andrew-platt) + +#2554 Add `!$OMP critical` directives around some `GetNewUnit/Open*File` to reduce probability of file unit conflicts (@andrew-platt) + +#2569 Disable LiDAR in IfW at FAST.Farm level (@andrew-platt) + + +## Module changes + +### AeroDyn + +#2501 Remove `$OMP` directives from `AeroDyn_Inflow` due to Intel compiler bug (@deslaughter) + +#2516 AD bugfix: Segmentation fault with ifx compiler (@andrew-platt) + + +### InflowWind + +#2518, #2530 ADI bugfix: BoxExceed was not enabled for OLAF with ADI (@andrew-platt) + +#2532 bugfix: IfW rotor points for disk average incorrect (@andrew-platt) + + +### NWTC-Library + +#2558 Allow ParseVar to parse file paths containing spaces. (@deslaughter) + + + + +## Input file changes + +No input files change with this release as this only includes minor bugfixes (input files are identical across all 3.5.x releases). + +Full list of changes: https://openfast.readthedocs.io/en/main/source/user/api_change.html + +Full input file sets: https://github.com/OpenFAST/r-test/tree/v3.5.5 (example input files from the regression testing) + diff --git a/docs/conf.py b/docs/conf.py index 38764e4a10..ab28d9e418 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -138,7 +138,7 @@ def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): # The short X.Y version. version = u'3.5' # The full version, including alpha/beta/rc tags. -release = u'v3.5.4' +release = u'v3.5.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/user/api_change.rst b/docs/source/user/api_change.rst index 30d3a351f0..28085bea34 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -11,7 +11,7 @@ Thus, be sure to implement each in order so that subsequent line numbers are cor -OpenFAST v3.5.4 to OpenFAST dev +OpenFAST v3.5.5 to OpenFAST dev ---------------------------------- The HydroDyn module was split into HydroDyn and SeaState. This results in a @@ -105,6 +105,11 @@ Old inputs Corresponding new inputs =========================== ========================================================= +OpenFAST v3.5.4 to OpenFAST v3.5.5 +---------------------------------- + +No input file changes were made. + OpenFAST v3.5.3 to OpenFAST v3.5.4 ---------------------------------- diff --git a/docs/source/user/inflowwind/examples/inflowwind_driver_example.inp b/docs/source/user/inflowwind/examples/inflowwind_driver_example.inp index ada6a15427..6f10820ae7 100644 --- a/docs/source/user/inflowwind/examples/inflowwind_driver_example.inp +++ b/docs/source/user/inflowwind/examples/inflowwind_driver_example.inp @@ -24,4 +24,11 @@ InflowWind driver input file. 6,0,15 GridCtrCoord -- coordinate of center of grid (m) 1,1,0 GridDx,GridDY,GridDZ -- Step size of grid (m) 1,1,0 GridNx,GridNY,GridNZ -- number of grid points in X, Y and Z directions (-) +---- Output VTK slices ------------------------------------------------------ + 0 NOutWindXY -- Number of XY planes for output .XY.t.vtk (-) [0 to 9] + 90 OutWindZ -- Z coordinates of XY planes for output (m) [1 to NOutWindXY] [unused for NOutWindXY=0] + 0 NOutWindXZ -- Number of XZ planes for output .YZ.t.vtk (-) [0 to 9] + 0 OutWindY -- Y coordinates of XZ planes for output (m) [1 to NOutWindXZ] [unused for NOutWindXZ=0] + 0 NOutWindYZ -- Number of YZ planes for output .YZ.t.vtk (-) [0 to 9] + 0 OutWindX -- X coordinates of YZ planes for output (m) [1 to NOutWindYZ] [unused for NOutWindYZ=0] END of driver input file diff --git a/glue-codes/fast-farm/src/FAST_Farm_IO.f90 b/glue-codes/fast-farm/src/FAST_Farm_IO.f90 index 8b7937b2a4..8e544a91d5 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_IO.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_IO.f90 @@ -10,7 +10,7 @@ module FAST_Farm_IO TYPE(ProgDesc), PARAMETER :: Farm_Ver = ProgDesc( 'FAST.Farm', '', '' ) !< module date/version information integer, parameter :: maxOutputPoints = 9 - integer, parameter :: maxOutputPlanes = 99 ! Allow up to 99 outpt planes + integer, parameter :: maxOutputPlanes = 999 ! Allow up to 99 outpt planes contains @@ -871,17 +871,17 @@ SUBROUTINE Farm_ReadPrimaryFile( InputFile, p, WD_InitInp, AWAE_InitInp, SC_Init CALL ReadVar( UnIn, InputFile, AWAE_InitInp%WrDisWind, "WrDisWind", "Write disturbed wind data to .Low.Dis.t.vtk etc.? (flag)", ErrStat2, ErrMsg2, UnEc); if (Failed()) return ! XY planes - CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindXY, "NOutDisWindXY", "Number of XY planes for output of disturbed wind data across the low-resolution domain to .Low.DisXY..t.vtk (-) [0 to 99]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return + CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindXY, "NOutDisWindXY", "Number of XY planes for output of disturbed wind data across the low-resolution domain to .Low.DisXY..t.vtk (-) [0 to 999]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return call allocAry( AWAE_InitInp%OutDisWindZ, AWAE_InitInp%NOutDisWindXY, "OutDisWindZ", ErrStat2, ErrMsg2 ); if (Failed()) return CALL ReadAry( UnIn, InputFile, AWAE_InitInp%OutDisWindZ, AWAE_InitInp%NOutDisWindXY, "OutDisWindZ", "Z coordinates of XY planes for output of disturbed wind data across the low-resolution domain (m) [1 to NOutDisWindXY] [unused for NOutDisWindXY=0]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return ! YZ planes - CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindYZ, "NOutDisWindYZ", "Number of YZ planes for output of disturbed wind data across the low-resolution domain to .Low.DisYZ..t.vtk (-) [0 to 9]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return + CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindYZ, "NOutDisWindYZ", "Number of YZ planes for output of disturbed wind data across the low-resolution domain to .Low.DisYZ..t.vtk (-) [0 to 999]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return call allocAry( AWAE_InitInp%OutDisWindX, AWAE_InitInp%NOutDisWindYZ, "OutDisWindX", ErrStat2, ErrMsg2 ); if (Failed()) return CALL ReadAry( UnIn, InputFile, AWAE_InitInp%OutDisWindX, AWAE_InitInp%NOutDisWindYZ, "OutDisWindX", "X coordinates of YZ planes for output of disturbed wind data across the low-resolution domain (m) [1 to NOutDisWindYZ] [unused for NOutDisWindYZ=0]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return ! XZ planes - CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindXZ, "NOutDisWindXZ", "Number of XZ planes for output of disturbed wind data across the low-resolution domain to .Low/DisXZ..t.vtk (-) [0 to 9]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return + CALL ReadVar( UnIn, InputFile, AWAE_InitInp%NOutDisWindXZ, "NOutDisWindXZ", "Number of XZ planes for output of disturbed wind data across the low-resolution domain to .Low/DisXZ..t.vtk (-) [0 to 999]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return call allocAry( AWAE_InitInp%OutDisWindY, AWAE_InitInp%NOutDisWindXZ, "OutDisWindY", ErrStat2, ErrMsg2 ); if (Failed()) return CALL ReadAry( UnIn, InputFile, AWAE_InitInp%OutDisWindY, AWAE_InitInp%NOutDisWindXZ, "OutDisWindY", "Y coordinates of XZ planes for output of disturbed wind data across the low-resolution domain (m) [1 to NOutDisWindXZ] [unused for NOutDisWindXZ=0]", ErrStat2, ErrMsg2, UnEc); if (Failed()) return @@ -1117,9 +1117,9 @@ SUBROUTINE Farm_ValidateInput( p, WD_InitInp, AWAE_InitInp, SC_InitInp, ErrStat, AWAE_InitInp%WrDisDT = p%DT_low * n_disDT_dt - if (AWAE_InitInp%NOutDisWindXY < 0 .or. AWAE_InitInp%NOutDisWindXY > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindXY must be in the range [0, 99].', ErrStat, ErrMsg, RoutineName ) - if (AWAE_InitInp%NOutDisWindYZ < 0 .or. AWAE_InitInp%NOutDisWindYZ > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindYZ must be in the range [0, 99].', ErrStat, ErrMsg, RoutineName ) - if (AWAE_InitInp%NOutDisWindXZ < 0 .or. AWAE_InitInp%NOutDisWindXZ > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindXZ must be in the range [0, 99].', ErrStat, ErrMsg, RoutineName ) + if (AWAE_InitInp%NOutDisWindXY < 0 .or. AWAE_InitInp%NOutDisWindXY > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindXY must be in the range [0, 999].', ErrStat, ErrMsg, RoutineName ) + if (AWAE_InitInp%NOutDisWindYZ < 0 .or. AWAE_InitInp%NOutDisWindYZ > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindYZ must be in the range [0, 999].', ErrStat, ErrMsg, RoutineName ) + if (AWAE_InitInp%NOutDisWindXZ < 0 .or. AWAE_InitInp%NOutDisWindXZ > maxOutputPlanes ) CALL SetErrStat( ErrID_Fatal, 'NOutDisWindXZ must be in the range [0, 999].', ErrStat, ErrMsg, RoutineName ) if (p%NOutDist < 0 .or. p%NOutDist > maxOutputPoints ) then CALL SetErrStat( ErrID_Fatal, 'NOutDist must be in the range [0, 9].', ErrStat, ErrMsg, RoutineName ) else diff --git a/glue-codes/openfast/CMakeLists.txt b/glue-codes/openfast/CMakeLists.txt index bc2e132339..a742b5972a 100644 --- a/glue-codes/openfast/CMakeLists.txt +++ b/glue-codes/openfast/CMakeLists.txt @@ -33,11 +33,11 @@ endif() install(TARGETS openfast RUNTIME DESTINATION bin) -if(BUILD_OPENFAST_CPP_DRIVER) - add_executable(openfast_cpp_driver src/FAST_Prog.cpp src/FastLibAPI.cpp) - target_link_libraries(openfast_cpp_driver openfastlib) +if(BUILD_OPENFAST_LIB_DRIVER) + add_executable(openfast_lib_driver src/FAST_Prog.cpp src/FastLibAPI.cpp) + target_link_libraries(openfast_lib_driver openfastlib) - install(TARGETS openfast_cpp_driver + install(TARGETS openfast_lib_driver RUNTIME DESTINATION bin) endif() diff --git a/modules/aerodyn/CMakeLists.txt b/modules/aerodyn/CMakeLists.txt index 859dd1e155..3ace5a80d3 100644 --- a/modules/aerodyn/CMakeLists.txt +++ b/modules/aerodyn/CMakeLists.txt @@ -101,7 +101,7 @@ target_link_libraries(unsteadyaero_driver basicaerolib lindynlib versioninfolib) add_library(aerodyn_inflow_c_binding SHARED src/AeroDyn_Inflow_C_Binding.f90 ) -target_link_libraries(aerodyn_inflow_c_binding adilib aerodyn_driver_subs versioninfolib) +target_link_libraries(aerodyn_inflow_c_binding aerodyn_driver_subs versioninfolib) if(APPLE OR UNIX) target_compile_definitions(aerodyn_inflow_c_binding PRIVATE IMPLICIT_DLLEXPORT) endif() diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index fe3cf33d9d..a0cae3d526 100644 --- a/modules/aerodyn/python-lib/aerodyn_inflow_library.py +++ b/modules/aerodyn/python-lib/aerodyn_inflow_library.py @@ -70,8 +70,8 @@ def __init__(self, library_path): self.ended = False # For error handling at end # Input file handling - self.ADinputPass = True # Assume passing of input file as a string - self.IfWinputPass = True # Assume passing of input file as a string + self.ADinputPass = 1 # Assume passing of input file as a string + self.IfWinputPass = 1 # Assume passing of input file as a string # Create buffers for class data self.abort_error_level = 4 @@ -107,6 +107,7 @@ def __init__(self, library_path): # VTK self.WrVTK = 0 # default of no vtk output self.WrVTK_Type = 1 # default of surface meshes + self.WrVTK_DT = 0.0 # default to all self.VTKNacDim = np.array([-2.5,-2.5,0,10,5,5], dtype="float32") # default nacelle dimension for VTK surface rendering [x0,y0,z0,Lx,Ly,Lz] (m) self.VTKHubRad = 1.5 # default hub radius for VTK surface rendering @@ -156,6 +157,7 @@ def __init__(self, library_path): # If HD writes a file (echo, summary, or other), use this for the # root of the file name. self.outRootName = "Output_ADIlib_default" + self.outVTKdir = "" # Set to specify a directory relative to the input files (created if doesn't exist) # _initialize_routines() ------------------------------------------------------------------------------------------------------------ def _initialize_routines(self): @@ -199,6 +201,7 @@ def _initialize_routines(self): POINTER(c_char_p), # IfW input file as string POINTER(c_int), # IfW input file string length POINTER(c_char), # OutRootName + POINTER(c_char), # OutVTKdir POINTER(c_float), # gravity POINTER(c_float), # defFldDens POINTER(c_float), # defKinVisc @@ -213,6 +216,7 @@ def _initialize_routines(self): POINTER(c_int), # storeHHVel POINTER(c_int), # WrVTK POINTER(c_int), # WrVTK_Type + POINTER(c_double), # WrVTK_DT -- 0 or negative to do every step POINTER(c_float), # VTKNacDim POINTER(c_float), # VTKHubRad POINTER(c_int), # wrOuts -- file format for writing outputs @@ -267,6 +271,15 @@ def _initialize_routines(self): self.ADI_C_GetRotorLoads.restype = c_int + self.ADI_C_GetDiskAvgVel.argtypes = [ + POINTER(c_int), # iturb + POINTER(c_float), # Disk average vel vector + POINTER(c_int), # ErrStat_C + POINTER(c_char) # ErrMsg_C + ] + self.ADI_C_GetDiskAvgVel.restype = c_int + + self.ADI_C_CalcOutput.argtypes = [ POINTER(c_double), # Time_C POINTER(c_float), # Output Channel Values @@ -370,6 +383,7 @@ def adi_init(self, AD_input_string_array, IfW_input_string_array): # Rootname for ADI output files (echo etc). _outRootName_c = create_string_buffer((self.outRootName.ljust(self.default_str_c_len)).encode('utf-8')) + _outVTKdir_c = create_string_buffer((self.outVTKdir.ljust(self.default_str_c_len)).encode('utf-8')) # Flatten arrays to pass # [x2,y1,z1, x2,y2,z2 ...] @@ -384,6 +398,7 @@ def adi_init(self, AD_input_string_array, IfW_input_string_array): c_char_p(IfW_input_string), # IN: IfW input file as string (or filename if IfWinputPass is false) byref(c_int(IfW_input_string_length)), # IN: IfW input file string length _outRootName_c, # IN: rootname for ADI file writing + _outVTKdir_c, # IN: directory for vtk output files (relative to input file) byref(c_float(self.gravity)), # IN: gravity byref(c_float(self.defFldDens)), # IN: defFldDens byref(c_float(self.defKinVisc)), # IN: defKinVisc @@ -398,6 +413,7 @@ def adi_init(self, AD_input_string_array, IfW_input_string_array): byref(c_int(self.storeHHVel)), # IN: storeHHVel byref(c_int(self.WrVTK)), # IN: WrVTK byref(c_int(self.WrVTK_Type)), # IN: WrVTK_Type + byref(c_double(self.WrVTK_DT)), # IN: WrVTK_DT VTKNacDim_c, # IN: VTKNacDim byref(c_float(self.VTKHubRad)), # IN: VTKHubRad byref(c_int(self.wrOuts)), # IN: wrOuts -- file format for writing outputs @@ -490,7 +506,7 @@ def adi_setrotormotion(self, iturb, \ self.check_error() - # adi_calcOutput ------------------------------------------------------------------------------------------------------------ + # adi_getrotorloads --------------------------------------------------------------------------------------------------------- def adi_getrotorloads(self, iturb, meshFrcMom, hhVel=None): # Resulting Forces/moments -- [Fx1,Fy1,Fz1,Mx1,My1,Mz1, Fx2,Fy2,Fz2,Mx2,My2,Mz2 ...] _meshFrc_flat_c = (c_float * (6 * self.numMeshPts))(0.0,) @@ -525,6 +541,28 @@ def adi_getrotorloads(self, iturb, meshFrcMom, hhVel=None): hhVel[1] = _hhVel_flat_c[1] hhVel[2] = _hhVel_flat_c[2] + + # adi_getdiskavgvel --------------------------------------------------------------------------------------------------------- + def adi_getdiskavgvel(self, iturb, diskAvgVel): + # Resulting disk average velocity [Vx,Vy,Vz] + _diskAvgVel_flat_c = (c_float * 3)(0.0,) + + # Run ADI_GetDiskAvgVel + self.ADI_C_GetDiskAvgVel( + c_int(iturb), # IN: iturb -- current turbine number + _diskAvgVel_flat_c, # OUT: disk average velocity [Vx, Vy, Vz] + byref(self.error_status_c), # OUT: ErrStat_C + self.error_message_c # OUT: ErrMsg_C + ) + + self.check_error() + + ## Disk average wind speed + diskAvgVel[0] = _diskAvgVel_flat_c[0] + diskAvgVel[1] = _diskAvgVel_flat_c[1] + diskAvgVel[2] = _diskAvgVel_flat_c[2] + + # adi_calcOutput ------------------------------------------------------------------------------------------------------------ def adi_calcOutput(self, time, outputChannelValues): @@ -907,6 +945,9 @@ def __init__(self,filename,numMeshPts): self.DbgFile.write(f_string.format(f_num+"Mx" )) self.DbgFile.write(f_string.format(f_num+"My" )) self.DbgFile.write(f_string.format(f_num+"Mz" )) + self.DbgFile.write(f_string.format(f_num+"DskAvgVx" )) + self.DbgFile.write(f_string.format(f_num+"DskAvgVy" )) + self.DbgFile.write(f_string.format(f_num+"DskAvgVz" )) self.DbgFile.write("\n") self.DbgFile.write(" (s) ") for i in range(1,self.numMeshPts+1): @@ -934,10 +975,13 @@ def __init__(self,filename,numMeshPts): self.DbgFile.write(f_string.format("(N-m)" )) self.DbgFile.write(f_string.format("(N-m)" )) self.DbgFile.write(f_string.format("(N-m)" )) + self.DbgFile.write(f_string.format("(m/s)" )) + self.DbgFile.write(f_string.format("(m/s)" )) + self.DbgFile.write(f_string.format("(m/s)" )) self.DbgFile.write("\n") self.opened = True - def write(self,t,meshPos,meshVel,meshAcc,meshFrc): + def write(self,t,meshPos,meshVel,meshAcc,meshFrc,DiskAvgVel): t_string = "{:10.4f}" f_string3 = "{:25.7e}"*3 f_string6 = "{:25.7e}"*6 @@ -947,6 +991,7 @@ def write(self,t,meshPos,meshVel,meshAcc,meshFrc): self.DbgFile.write(f_string6.format(*meshVel[i,:])) self.DbgFile.write(f_string6.format(*meshAcc[i,:])) self.DbgFile.write(f_string6.format(*meshFrc[i,:])) + self.DbgFile.write(f_string3.format(*DiskAvgVel[:])) self.DbgFile.write("\n") def end(self): diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index d43664041a..6ed9b86c50 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -1763,8 +1763,10 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat 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) - if (Failed()) return + do i=1,size(u) + call SetInputsForFVW(p, u(i), i, m, errStat2, errMsg2) + if (Failed()) return + enddo ! 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 ) if (Failed()) return @@ -1929,7 +1931,7 @@ subroutine AD_CalcWind_Rotor(t, u, FlowField, p, RotInflow, StartNode, ErrStat, contains logical function Failed() - call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'AD_CalcWind') + call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'AD_CalcWindRotor') Failed = errStat >= AbortErrLev end function Failed end subroutine @@ -1989,7 +1991,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, if (p%Wake_Mod == WakeMod_FVW) then ! 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 SetInputsForFVW(p, u, 1, m, errStat2, errMsg2) if(Failed()) return ! Calculate Outputs at time t CALL FVW_CalcOutput( t, m%FVW_u(1), p%FVW, x%FVW, xd%FVW, z%FVW, OtherState%FVW, m%FVW_y, m%FVW, ErrStat2, ErrMsg2 ) @@ -3574,10 +3576,11 @@ subroutine Calculate_MeshOrientation_LiftingLine(p, u, m, twist, toe, cant, ErrS end subroutine Calculate_MeshOrientation_LiftingLine !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets m%FVW_u(indx). -subroutine SetInputsForFVW(p, u, m, errStat, errMsg) +subroutine SetInputsForFVW(p, u, tIndx, m, errStat, errMsg) type(AD_ParameterType), intent(in ) :: p !< AD parameters - type(AD_InputType), intent(in ) :: u(:) !< AD Inputs at Time + type(AD_InputType), intent(in ) :: u !< AD Inputs at Time + integer(intKi), intent(in ) :: tIndx !< index of m%FVW_u() array 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 @@ -3585,7 +3588,6 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) real(R8Ki) :: x_hat_disk(3) real(R8Ki), allocatable :: thetaBladeNds(:,:) - integer(intKi) :: tIndx integer(intKi) :: iR ! Loop on rotors integer(intKi) :: j, k ! loop counter for blades integer(intKi) :: ErrStat2 @@ -3596,82 +3598,80 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) ErrStat = ErrID_None ErrMsg = "" - do tIndx=1,size(u) - do iR =1, size(p%rotors) - allocate(thetaBladeNds(p%rotors(iR)%NumBlNds, p%rotors(iR)%NumBlades)) - ! 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%rotors(iR), u(tIndx)%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), x_hat_disk) ! also sets m%V_diskAvg and m%V_dot_x - - ! Compute Orientation similar to BEM, only to have consistent outputs... - ! TODO TODO TODO All this below is mostly a calcOutput thing, we should move it somewhere else! - ! orientation annulus is only used for Outputs with OLAF, same for pitch and azimuth - if (p%rotors(iR)%AeroProjMod==APM_BEM_NoSweepPitchTwist) then - call Calculate_MeshOrientation_NoSweepPitchTwist(p%rotors(iR), u(tIndx)%rotors(iR), m%rotors(iR), thetaBladeNds, m%rotors(iR)%Toe, m%rotors(iR)%Cant, ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve - - elseif (p%rotors(iR)%AeroProjMod==APM_BEM_Polar) then - do k=1,p%rotors(iR)%numBlades - call Calculate_MeshOrientation_Rel2Hub(u(tIndx)%rotors(iR)%BladeMotion(k), u(tIndx)%rotors(iR)%HubMotion, x_hat_disk, m%rotors(iR)%orientationAnnulus(:,:,:,k)) - call TwistToeCant_FromLocalPolar(u(tIndx)%rotors(iR)%BladeMotion(k), m%rotors(iR)%orientationAnnulus(:,:,:,k), thetaBladeNds(:,k), m%rotors(iR)%Toe(:,k), m%rotors(iR)%Cant(:,k)) - enddo + do iR =1, size(p%rotors) + allocate(thetaBladeNds(p%rotors(iR)%NumBlNds, p%rotors(iR)%NumBlades)) + ! 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%rotors(iR), u%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), x_hat_disk) ! also sets m%V_diskAvg and m%V_dot_x + + ! Compute Orientation similar to BEM, only to have consistent outputs... + ! TODO TODO TODO All this below is mostly a calcOutput thing, we should move it somewhere else! + ! orientation annulus is only used for Outputs with OLAF, same for pitch and azimuth + if (p%rotors(iR)%AeroProjMod==APM_BEM_NoSweepPitchTwist) then + call Calculate_MeshOrientation_NoSweepPitchTwist(p%rotors(iR), u%rotors(iR), m%rotors(iR), thetaBladeNds, m%rotors(iR)%Toe, m%rotors(iR)%Cant, ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve + + elseif (p%rotors(iR)%AeroProjMod==APM_BEM_Polar) then + do k=1,p%rotors(iR)%numBlades + call Calculate_MeshOrientation_Rel2Hub(u%rotors(iR)%BladeMotion(k), u%rotors(iR)%HubMotion, x_hat_disk, m%rotors(iR)%orientationAnnulus(:,:,:,k)) + call TwistToeCant_FromLocalPolar(u%rotors(iR)%BladeMotion(k), m%rotors(iR)%orientationAnnulus(:,:,:,k), thetaBladeNds(:,k), m%rotors(iR)%Toe(:,k), m%rotors(iR)%Cant(:,k)) + enddo - else if (p%rotors(iR)%AeroProjMod==APM_LiftingLine) then - call Calculate_MeshOrientation_LiftingLine (p%rotors(iR),u(tIndx)%rotors(iR), m%rotors(iR), thetaBladeNds, m%rotors(iR)%Toe, m%rotors(iR)%Cant, ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve - else - call SetErrStat(ErrID_Fatal, 'Aero Projection Method not implemented' ,ErrStat, ErrMsg, RoutineName) + else if (p%rotors(iR)%AeroProjMod==APM_LiftingLine) then + call Calculate_MeshOrientation_LiftingLine (p%rotors(iR),u%rotors(iR), m%rotors(iR), thetaBladeNds, m%rotors(iR)%Toe, m%rotors(iR)%Cant, ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve + else + call SetErrStat(ErrID_Fatal, 'Aero Projection Method not implemented' ,ErrStat, ErrMsg, RoutineName) + endif + call StorePitchAndAzimuth(p%rotors(iR), u%rotors(iR), m%rotors(iR), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + 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%rotors(iR)%NumBlades + iW=p%FVW%Bld2Wings(iR,k) + + if ( u%rotors(iR)%BladeMotion(k)%nNodes /= m%FVW_u(tIndx)%WingsMesh(iW)%nNodes ) then + call SetErrStat(ErrID_Fatal,"WingsMesh contains different number of nodes than the BladeMotion mesh",ErrStat,ErrMsg,RoutineName) + return endif - call StorePitchAndAzimuth(p%rotors(iR), u(tIndx)%rotors(iR), m%rotors(iR), ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - 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%rotors(iR)%NumBlades - iW=p%FVW%Bld2Wings(iR,k) - - if ( u(tIndx)%rotors(iR)%BladeMotion(k)%nNodes /= m%FVW_u(tIndx)%WingsMesh(iW)%nNodes ) then - call SetErrStat(ErrID_Fatal,"WingsMesh contains different number of nodes than the BladeMotion mesh",ErrStat,ErrMsg,RoutineName) - return + m%FVW%W(iW)%PitchAndTwist(:) = thetaBladeNds(:,k) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade + m%FVW_u(tIndx)%WingsMesh(iW)%TranslationDisp = u%rotors(iR)%BladeMotion(k)%TranslationDisp + m%FVW_u(tIndx)%WingsMesh(iW)%Orientation = u%rotors(iR)%BladeMotion(k)%Orientation + m%FVW_u(tIndx)%WingsMesh(iW)%TranslationVel = u%rotors(iR)%BladeMotion(k)%TranslationVel + m%FVW_u(tIndx)%rotors(iR)%HubPosition = u%rotors(iR)%HubMotion%Position(:,1) + u%rotors(iR)%HubMotion%TranslationDisp(:,1) + m%FVW_u(tIndx)%rotors(iR)%HubOrientation = u%rotors(iR)%HubMotion%Orientation(:,:,1) + + ! Inputs for dynamic stall (see SetInputsForBEMT) + do j=1,p%rotors(iR)%NumBlNds + ! inputs for CUA, section pitch/torsion rate + m%FVW_u(tIndx)%W(iW)%omega_z(j) = dot_product( u%rotors(iR)%BladeMotion(k)%RotationVel( :,j), m%rotors(iR)%orientationAnnulus(3,:,j,k) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade + end do !j=nodes + enddo ! k blades + if (allocated(thetaBladeNds)) deallocate(thetaBladeNds) + enddo ! iR, rotors + + if (ALLOCATED(m%FVW_u(tIndx)%V_wind)) then + m%FVW_u(tIndx)%V_wind = m%Inflow(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%FVW%TwrShadowOnWake) then + do iR =1, size(p%rotors) + if (p%rotors(iR)%TwrPotent /= TwrPotent_none .or. p%rotors(iR)%TwrShadow /= TwrShadow_none) then + call TwrInflArray( p%rotors(iR), u%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), m%FVW%r_wind, m%FVW_u(tIndx)%V_wind, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return endif - m%FVW%W(iW)%PitchAndTwist(:) = thetaBladeNds(:,k) ! local pitch + twist (aerodyanmic + elastic) angle of the jth node in the kth blade - m%FVW_u(tIndx)%WingsMesh(iW)%TranslationDisp = u(tIndx)%rotors(iR)%BladeMotion(k)%TranslationDisp - m%FVW_u(tIndx)%WingsMesh(iW)%Orientation = u(tIndx)%rotors(iR)%BladeMotion(k)%Orientation - m%FVW_u(tIndx)%WingsMesh(iW)%TranslationVel = u(tIndx)%rotors(iR)%BladeMotion(k)%TranslationVel - m%FVW_u(tIndx)%rotors(iR)%HubPosition = u(tIndx)%rotors(iR)%HubMotion%Position(:,1) + u(tIndx)%rotors(iR)%HubMotion%TranslationDisp(:,1) - m%FVW_u(tIndx)%rotors(iR)%HubOrientation = u(tIndx)%rotors(iR)%HubMotion%Orientation(:,:,1) - - ! Inputs for dynamic stall (see SetInputsForBEMT) - do j=1,p%rotors(iR)%NumBlNds - ! inputs for CUA, section pitch/torsion rate - m%FVW_u(tIndx)%W(iW)%omega_z(j) = dot_product( u(tIndx)%rotors(iR)%BladeMotion(k)%RotationVel( :,j), m%rotors(iR)%orientationAnnulus(3,:,j,k) ) ! rotation of no-sweep-pitch coordinate system around z of the jth node in the kth blade - end do !j=nodes - enddo ! k blades - if (allocated(thetaBladeNds)) deallocate(thetaBladeNds) - enddo ! iR, rotors - - if (ALLOCATED(m%FVW_u(tIndx)%V_wind)) then - m%FVW_u(tIndx)%V_wind = m%Inflow(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%FVW%TwrShadowOnWake) then - do iR =1, size(p%rotors) - if (p%rotors(iR)%TwrPotent /= TwrPotent_none .or. p%rotors(iR)%TwrShadow /= TwrShadow_none) then - call TwrInflArray( p%rotors(iR), u(tIndx)%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), m%FVW%r_wind, m%FVW_u(tIndx)%V_wind, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >= AbortErrLev) return - endif - enddo - end if - endif - do iR =1, size(p%rotors) - ! Disturbed inflow for UA on Lifting line Mesh Points - call SetDisturbedInflow(p%rotors(iR), p, u(tIndx)%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), errStat2, errMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - do k=1,p%rotors(iR)%NumBlades - iW=p%FVW%Bld2Wings(iR,k) - m%FVW_u(tIndx)%W(iW)%Vwnd_LL(1:3,:) = m%rotors(iR)%DisturbedInflow(1:3,:,k) enddo + end if + endif + do iR =1, size(p%rotors) + ! Disturbed inflow for UA on Lifting line Mesh Points + call SetDisturbedInflow(p%rotors(iR), p, u%rotors(iR), m%Inflow(tIndx)%RotInflow(iR), m%rotors(iR), errStat2, errMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + do k=1,p%rotors(iR)%NumBlades + iW=p%FVW%Bld2Wings(iR,k) + m%FVW_u(tIndx)%W(iW)%Vwnd_LL(1:3,:) = m%rotors(iR)%DisturbedInflow(1:3,:,k) enddo enddo diff --git a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt index f36db0bc02..47c55804f2 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Driver_Registry.txt @@ -45,17 +45,18 @@ typedef ^ ^ character(25) Fmt_a typedef ^ ^ character(1) delim - - - "column delimiter" "-" typedef ^ ^ character(20) outFmt - - - "Format specifier" "-" typedef ^ ^ IntKi fileFmt - - - "Output format 1=Text, 2=Binary, 3=Both" "-" -typedef ^ ^ IntKi wrVTK - - - "0= no vtk, 1=init only, 2=animation" "-" +typedef ^ ^ IntKi WrVTK - - - "0= no vtk, 1=init only, 2=animation" "-" typedef ^ ^ IntKi WrVTK_Type - - - "Flag for VTK output type (1=surface, 2=line, 3=both)" - typedef ^ ^ character(1024) Root - - - "Output file rootname" "-" -typedef ^ ^ character(1024) VTK_OutFileRoot - - - "Output file rootname for vtk" "-" +typedef ^ ^ character(1024) VTK_OutFileRoot - - - "Output file rootname for vtk (includes directory)" "-" typedef ^ ^ character(ChanLen) WriteOutputHdr {:} - - "Channel headers" "-" typedef ^ ^ character(ChanLen) WriteOutputUnt {:} - - "Channel units" "-" typedef ^ ^ ReKi storage ::: - - "nTurbines x nChannel x nTime" typedef ^ ^ ReKi outLine : - - "Output line to be written to disk" typedef ^ ^ DvrVTK_SurfaceType VTK_surface : - - "Data for VTK surface visualization" -typedef ^ ^ INTEGER VTK_tWidth - - - "Width of number of files for leading zeros in file name format" - -typedef ^ ^ INTEGER n_VTKTime - - - "Number of time steps between writing VTK files" - +typedef ^ ^ IntKi VTK_tWidth - - - "Width of number of files for leading zeros in file name format" - +typedef ^ ^ IntKi n_VTKTime - - - "Number of time steps between writing VTK files" - +typedef ^ ^ DbKi VTK_DT - - - "Write VTK time step" - typedef ^ ^ SiKi VTKHubRad - - - "Hub radius for visualization" m typedef ^ ^ ReKi VTKNacDim 6 - - "Nacelle dimensions for visualization" m typedef ^ ^ SiKi VTKRefPoint 3 - - "RefPoint for VTK outputs" @@ -149,7 +150,7 @@ typedef ^ ^ IntKi iCase typedef ^ ^ ReKi timeSeries :: - - "Times series inputs when AnalysisType=1, 6 columns, Time, WndSpeed, ShearExp, RotSpd, Pitch, Yaw" "-" typedef ^ ^ IntKi iTimeSeries - - - "Stored index to optimize time interpolation" - typedef ^ ^ character(1024) root - - - "Output file rootname" "-" -typedef ^ ^ Dvr_Outputs out - - - "data for driver output file" "-" +typedef ^ ^ Dvr_Outputs out - - - "data for driver output file" "-" typedef ^ ^ ADI_IW_InputData IW_InitInp - - - "" - # ..... Data to wrap the driver .......................................................................................................... diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 0d3b1d295d..d609215127 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -469,7 +469,7 @@ subroutine Init_ADI_ForDriver(iCase, ADI, dvr, FED, dt, errStat, errMsg) InitInp%IW_InitInp%FilePassingMethod = 0_IntKi ! read input file instead of passed file data ! AeroDyn InitInp%AD%Gravity = 9.80665_ReKi - InitInp%AD%RootName = dvr%out%Root ! 'C:/Work/XFlow/' + InitInp%AD%RootName = dvr%out%Root InitInp%AD%InputFile = dvr%AD_InputFile InitInp%AD%MHK = dvr%MHK InitInp%AD%defFldDens = dvr%FldDens @@ -959,7 +959,7 @@ subroutine Dvr_ReadInputFile(fileName, dvr, errStat, errMsg ) call ParseVar(FileInfo_In, CurLine, "analysisType", dvr%analysisType, errStat2, errMsg2, unEc); if (Failed()) return call ParseVar(FileInfo_In, CurLine, "tMax" , dvr%tMax , errStat2, errMsg2, unEc); if (Failed()) return call ParseVar(FileInfo_In, CurLine, "dt" , dvr%dt , errStat2, errMsg2, unEc); if (Failed()) return - call ParseVar(FileInfo_In, CurLine, "AeroFile" , dvr%AD_InputFile, errStat2, errMsg2, unEc); if (Failed()) return + call ParseVar(FileInfo_In, CurLine, "AeroFile" , dvr%AD_InputFile, errStat2, errMsg2, unEc, IsPath=.true.); if (Failed()) return ! --- Environmental conditions call ParseCom(FileInfo_In, CurLine, Line, errStat2, errMsg2, unEc); if (Failed()) return @@ -974,7 +974,7 @@ subroutine Dvr_ReadInputFile(fileName, dvr, errStat, errMsg ) ! --- Inflow data call ParseCom(FileInfo_In, CurLine, Line, errStat2, errMsg2, unEc); if (Failed()) return call ParseVar(FileInfo_In, CurLine, "compInflow", dvr%IW_InitInp%compInflow , errStat2, errMsg2, unEc); if (Failed()) return - call ParseVar(FileInfo_In, CurLine, "InflowFile", dvr%IW_InitInp%InputFile, errStat2, errMsg2, unEc); if (Failed()) return + call ParseVar(FileInfo_In, CurLine, "InflowFile", dvr%IW_InitInp%InputFile, errStat2, errMsg2, unEc, IsPath=.true.); if (Failed()) return if (dvr%IW_InitInp%compInflow==0) then call ParseVar(FileInfo_In, CurLine, "HWindSpeed", dvr%IW_InitInp%HWindSpeed , errStat2, errMsg2, unEc); if (Failed()) return call ParseVar(FileInfo_In, CurLine, "RefHt" , dvr%IW_InitInp%RefHt , errStat2, errMsg2, unEc); if (Failed()) return @@ -1689,12 +1689,12 @@ subroutine Dvr_WriteOutputs(nt, t, dvr, out, yADI, errStat, errMsg) end subroutine Dvr_WriteOutputs !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets up the information needed for plotting VTK surfaces. -subroutine setVTKParameters(p_FAST, dvr, ADI, errStat, errMsg, dirname) - type(Dvr_Outputs), intent(inout) :: p_FAST !< The parameters of the glue code - type(Dvr_SimData), target, intent(inout) :: dvr ! intent(out) only so that we can save FmtWidth in dvr%out%ActualChanLen - type(ADI_Data), target, intent(in ) :: ADI ! Input data for initialization (intent out for getting AD WriteOutput names/units) - integer(IntKi), intent( out) :: errStat !< Error status of the operation - character(*), intent( out) :: errMsg !< Error message if errStat /= ErrID_None +subroutine setVTKParameters(DVR_Outs, dvr, ADI, errStat, errMsg, dirname) + type(Dvr_Outputs), intent(inout) :: DVR_Outs !< The parameters of the glue code + type(Dvr_SimData), target, intent(inout) :: dvr ! intent(out) only so that we can save FmtWidth in dvr%out%ActualChanLen + type(ADI_Data), target, intent(in ) :: ADI ! Input data for initialization (intent out for getting AD WriteOutput names/units) + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if errStat /= ErrID_None character(*), optional,intent(in ) :: dirname real(SiKi) :: RefPoint(3), RefLengths(2) real(SiKi) :: x, y @@ -1726,19 +1726,23 @@ subroutine setVTKParameters(p_FAST, dvr, ADI, errStat, errMsg, dirname) ! get the name of the output directory for vtk files (in a subdirectory called "vtk" of the output directory), and ! create the VTK directory if it does not exist - call GetPath ( p_FAST%root, p_FAST%VTK_OutFileRoot, vtkroot ) ! the returned p_FAST%VTK_OutFileRoot includes a file separator character at the end - p_FAST%VTK_OutFileRoot = trim(p_FAST%VTK_OutFileRoot) // trim(dir) - call MKDIR( trim(p_FAST%VTK_OutFileRoot) ) - p_FAST%VTK_OutFileRoot = trim( p_FAST%VTK_OutFileRoot ) // PathSep // trim(vtkroot) + call GetPath ( DVR_Outs%root, DVR_Outs%VTK_OutFileRoot, vtkroot ) ! the returned DVR_Outs%VTK_OutFileRoot includes a file separator character at the end + if (PathIsRelative(trim(dir))) then + DVR_Outs%VTK_OutFileRoot = trim(DVR_Outs%VTK_OutFileRoot) // trim(dir) + else + DVR_Outs%VTK_OutFileRoot = trim(dir) + endif + call MKDIR( trim(DVR_Outs%VTK_OutFileRoot) ) + DVR_Outs%VTK_OutFileRoot = trim( DVR_Outs%VTK_OutFileRoot ) // PathSep // trim(vtkroot) ! calculate the number of digits in 'y_FAST%NOutSteps' (Maximum number of output steps to be written) ! this will be used to pad the write-out step in the VTK filename with zeros in calls to MeshWrVTK() - p_FAST%VTK_tWidth = max(9, CEILING( log10( real(dvr%numSteps+1, ReKi) / p_FAST%n_VTKTime ) ) + 1) ! NOTE: at least 9, if user changes dt/and tmax + DVR_Outs%VTK_tWidth = max(9, CEILING( log10( real(dvr%numSteps+1, ReKi) / DVR_Outs%n_VTKTime ) ) + 1) ! NOTE: at least 9, if user changes dt/and tmax - if (allocated(p_FAST%VTK_Surface)) then + if (allocated(DVR_Outs%VTK_Surface)) then return ! The surfaces were already computed (for combined cases) endif - allocate(p_FAST%VTK_Surface(dvr%numTurbines)) + allocate(DVR_Outs%VTK_Surface(dvr%numTurbines)) ! --- Find dimensions for all objects to determine "Ground" and typical dimensions MaxBladeLength = 0 MaxTwrLength = 0 @@ -1779,7 +1783,7 @@ subroutine setVTKParameters(p_FAST, dvr, ADI, errStat, errMsg, dirname) enddo ! Loop on turbine ! Get radius for ground (blade length + hub radius): - GroundRad = MaxBladeLength + MaxTwrLength+ p_FAST%VTKHubRad + GroundRad = MaxBladeLength + MaxTwrLength+ DVR_Outs%VTKHubRad ! write the ground or seabed reference polygon: RefPoint(1:2) = dvr%WT(1)%originInit(1:2) do iWT=2,dvr%numTurbines @@ -1789,37 +1793,37 @@ subroutine setVTKParameters(p_FAST, dvr, ADI, errStat, errMsg, dirname) RefPoint(3) = 0.0_ReKi RefLengths = GroundRad + sqrt((WorldBoxMax(1)-WorldBoxMin(1))**2 + (WorldBoxMax(2)-WorldBoxMin(2))**2) - call WrVTK_Ground (RefPoint, RefLengths, trim(p_FAST%VTK_OutFileRoot) // '.GroundSurface', errStat2, errMsg2 ) + call WrVTK_Ground (RefPoint, RefLengths, trim(DVR_Outs%VTK_OutFileRoot) // '.GroundSurface', errStat2, errMsg2 ) ! --- Create surfaces for Nacelle, Base, Tower, Blades do iWT=1,dvr%numTurbines wt => dvr%wt(iWT) - p_FAST%VTK_Surface(iWT)%NumSectors = 25 + DVR_Outs%VTK_Surface(iWT)%NumSectors = 25 ! Create nacelle box - p_FAST%VTK_Surface(iWT)%NacelleBox(:,1) = (/ p_FAST%VTKNacDim(1) , p_FAST%VTKNacDim(2)+p_FAST%VTKNacDim(5), p_FAST%VTKNacDim(3) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,2) = (/ p_FAST%VTKNacDim(1)+p_FAST%VTKNacDim(4), p_FAST%VTKNacDim(2)+p_FAST%VTKNacDim(5), p_FAST%VTKNacDim(3) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,3) = (/ p_FAST%VTKNacDim(1)+p_FAST%VTKNacDim(4), p_FAST%VTKNacDim(2) , p_FAST%VTKNacDim(3) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,4) = (/ p_FAST%VTKNacDim(1) , p_FAST%VTKNacDim(2) , p_FAST%VTKNacDim(3) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,5) = (/ p_FAST%VTKNacDim(1) , p_FAST%VTKNacDim(2) , p_FAST%VTKNacDim(3)+p_FAST%VTKNacDim(6) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,6) = (/ p_FAST%VTKNacDim(1)+p_FAST%VTKNacDim(4), p_FAST%VTKNacDim(2) , p_FAST%VTKNacDim(3)+p_FAST%VTKNacDim(6) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,7) = (/ p_FAST%VTKNacDim(1)+p_FAST%VTKNacDim(4), p_FAST%VTKNacDim(2)+p_FAST%VTKNacDim(5), p_FAST%VTKNacDim(3)+p_FAST%VTKNacDim(6) /) - p_FAST%VTK_Surface(iWT)%NacelleBox(:,8) = (/ p_FAST%VTKNacDim(1) , p_FAST%VTKNacDim(2)+p_FAST%VTKNacDim(5), p_FAST%VTKNacDim(3)+p_FAST%VTKNacDim(6) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,1) = (/ DVR_Outs%VTKNacDim(1) , DVR_Outs%VTKNacDim(2)+DVR_Outs%VTKNacDim(5), DVR_Outs%VTKNacDim(3) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,2) = (/ DVR_Outs%VTKNacDim(1)+DVR_Outs%VTKNacDim(4), DVR_Outs%VTKNacDim(2)+DVR_Outs%VTKNacDim(5), DVR_Outs%VTKNacDim(3) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,3) = (/ DVR_Outs%VTKNacDim(1)+DVR_Outs%VTKNacDim(4), DVR_Outs%VTKNacDim(2) , DVR_Outs%VTKNacDim(3) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,4) = (/ DVR_Outs%VTKNacDim(1) , DVR_Outs%VTKNacDim(2) , DVR_Outs%VTKNacDim(3) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,5) = (/ DVR_Outs%VTKNacDim(1) , DVR_Outs%VTKNacDim(2) , DVR_Outs%VTKNacDim(3)+DVR_Outs%VTKNacDim(6) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,6) = (/ DVR_Outs%VTKNacDim(1)+DVR_Outs%VTKNacDim(4), DVR_Outs%VTKNacDim(2) , DVR_Outs%VTKNacDim(3)+DVR_Outs%VTKNacDim(6) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,7) = (/ DVR_Outs%VTKNacDim(1)+DVR_Outs%VTKNacDim(4), DVR_Outs%VTKNacDim(2)+DVR_Outs%VTKNacDim(5), DVR_Outs%VTKNacDim(3)+DVR_Outs%VTKNacDim(6) /) + DVR_Outs%VTK_Surface(iWT)%NacelleBox(:,8) = (/ DVR_Outs%VTKNacDim(1) , DVR_Outs%VTKNacDim(2)+DVR_Outs%VTKNacDim(5), DVR_Outs%VTKNacDim(3)+DVR_Outs%VTKNacDim(6) /) ! Create base box (using towerbase or nacelle dime) - BaseBoxDim = minval(p_FAST%VTKNacDim(4:6))/2 + BaseBoxDim = minval(DVR_Outs%VTKNacDim(4:6))/2 if (size(ADI%m%VTK_Surfaces(iWT)%TowerRad)>0) then BaseBoxDim = ADI%m%VTK_Surfaces(iWT)%TowerRad(1) endif - p_FAST%VTK_Surface(iWT)%BaseBox(:,1) = (/ -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,2) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,3) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim , -BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,4) = (/ -BaseBoxDim , -BaseBoxDim , -BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,5) = (/ -BaseBoxDim , -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,6) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,7) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim /) - p_FAST%VTK_Surface(iWT)%BaseBox(:,8) = (/ -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,1) = (/ -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,2) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,3) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim , -BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,4) = (/ -BaseBoxDim , -BaseBoxDim , -BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,5) = (/ -BaseBoxDim , -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,6) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,7) = (/ -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim /) + DVR_Outs%VTK_Surface(iWT)%BaseBox(:,8) = (/ -BaseBoxDim , -BaseBoxDim+2*BaseBoxDim, -BaseBoxDim+2*BaseBoxDim /) enddo ! iWT, turbines @@ -1827,12 +1831,12 @@ end subroutine SetVTKParameters !---------------------------------------------------------------------------------------------------------------------------------- !> 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, ADI, FED, p_FAST, VTK_count) +subroutine WrVTK_Surfaces(t_global, ADI, FED, DVR_Outs, VTK_count) use FVW_IO, only: WrVTK_FVW real(DbKi), intent(in ) :: t_global !< Current global time type(FED_Data), target, intent(in ) :: FED !< Elastic wind turbine data (Fake ElastoDyn) type(ADI_Data), intent(in ) :: ADI !< Input data for initialization (intent out for getting AD WriteOutput names/units) - type(Dvr_Outputs), intent(in ) :: p_FAST !< Parameters for the glue code + type(Dvr_Outputs), intent(in ) :: DVR_Outs !< Parameters for the glue code integer(IntKi) , intent(in ) :: VTK_count logical, parameter :: OutputFields = .FALSE. ! due to confusion about what fields mean on a surface, we are going to just output the basic meshes if people ask for fields integer(IntKi) :: errStat2 @@ -1843,7 +1847,7 @@ subroutine WrVTK_Surfaces(t_global, ADI, FED, p_FAST, VTK_count) type(RotFED), pointer :: y_ED ! Alias to shorten notation ! AeroDyn surfaces (Blades, Hub, Tower) - call AD_WrVTK_Surfaces(ADI%u(2)%AD, ADI%y%AD, p_FAST%VTKRefPoint, ADI%m%VTK_Surfaces, VTK_count, p_FAST%VTK_OutFileRoot, p_FAST%VTK_tWidth, 25, p_FAST%VTKHubRad) + call AD_WrVTK_Surfaces(ADI%u(2)%AD, ADI%y%AD, DVR_Outs%VTKRefPoint, ADI%m%VTK_Surfaces, VTK_count, DVR_Outs%VTK_OutFileRoot, DVR_Outs%VTK_tWidth, 25, DVR_Outs%VTKHubRad) ! Elastic info nWT = size(FED%WT) @@ -1856,25 +1860,25 @@ subroutine WrVTK_Surfaces(t_global, ADI, FED, p_FAST, VTK_count) y_ED => FED%WT(iWT) ! Base - call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, y_ED%PlatformPtMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.BaseSurface', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth , verts = p_FAST%VTK_Surface(iWT)%BaseBox) + call MeshWrVTK_PointSurface (DVR_Outs%VTKRefPoint, y_ED%PlatformPtMesh, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.BaseSurface', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth , verts = DVR_Outs%VTK_Surface(iWT)%BaseBox) if (y_ED%numBlades>0) then ! Nacelle - call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, y_ED%NacelleMotion, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.NacelleSurface', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth , verts = p_FAST%VTK_Surface(iWT)%NacelleBox) + call MeshWrVTK_PointSurface (DVR_Outs%VTKRefPoint, y_ED%NacelleMotion, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.NacelleSurface', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth , verts = DVR_Outs%VTK_Surface(iWT)%NacelleBox) endif - if (p_FAST%WrVTK>1) then + if (DVR_Outs%WrVTK>1) then ! --- animations ! Tower base - call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, y_ED%TwrPtMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseSurface', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth , & - NumSegments=p_FAST%VTK_Surface(iWT)%NumSectors, radius=p_FAST%VTKHubRad) + call MeshWrVTK_PointSurface (DVR_Outs%VTKRefPoint, y_ED%TwrPtMesh, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseSurface', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth , & + NumSegments=DVR_Outs%VTK_Surface(iWT)%NumSectors, radius=DVR_Outs%VTKHubRad) if (ADI%u(2)%AD%rotors(iWT)%TowerMotion%nNodes>0) then - call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, y_ED%TwrPtMeshAD, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseSurfaceAD', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth , & - NumSegments=p_FAST%VTK_Surface(iWT)%NumSectors, radius=p_FAST%VTKHubRad) + call MeshWrVTK_PointSurface (DVR_Outs%VTKRefPoint, y_ED%TwrPtMeshAD, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseSurfaceAD', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth , & + NumSegments=DVR_Outs%VTK_Surface(iWT)%NumSectors, radius=DVR_Outs%VTKHubRad) endif endif enddo @@ -1882,18 +1886,18 @@ subroutine WrVTK_Surfaces(t_global, ADI, FED, p_FAST, VTK_count) ! Free wake if (allocated(ADI%m%AD%FVW_u)) then if (allocated(ADI%m%AD%FVW_u(1)%WingsMesh)) then - call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(1)%AD%FVW, ADI%z(1)%AD%FVW, ADI%m%AD%FVW, trim(p_FAST%VTK_OutFileRoot)//'.FVW', VTK_count, p_FAST%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(1)%AD%FVW, ADI%z(1)%AD%FVW, ADI%m%AD%FVW, trim(DVR_Outs%VTK_OutFileRoot)//'.FVW', VTK_count, DVR_Outs%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords end if end if end subroutine WrVTK_Surfaces !> This routine writes a minimal subset of meshes with surfaces to VTK-formatted files. It doesn't bother with !! returning an error code. -subroutine WrVTK_Lines(t_global, ADI, FED, p_FAST, VTK_count) +subroutine WrVTK_Lines(t_global, ADI, FED, DVR_Outs, VTK_count) use FVW_IO, only: WrVTK_FVW REAL(DbKi), INTENT(IN ) :: t_global !< Current global time type(ADI_Data), intent(in ) :: ADI !< Input data for initialization (intent out for getting AD WriteOutput names/units) type(FED_Data), target, intent(in ) :: FED !< Elastic wind turbine data (Fake ElastoDyn) - TYPE(Dvr_Outputs), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(Dvr_Outputs), INTENT(IN ) :: DVR_Outs !< Parameters for the glue code INTEGER(IntKi) , INTENT(IN ) :: VTK_count logical, parameter :: OutputFields = .TRUE. INTEGER(IntKi) :: k @@ -1905,7 +1909,7 @@ subroutine WrVTK_Lines(t_global, ADI, FED, p_FAST, VTK_count) type(RotFED), pointer :: y_ED ! Alias to shorten notation ! AeroDyn surfaces (Blades, Tower) - call AD_WrVTK_LinesPoints(ADI%u(2)%AD, ADI%y%AD, p_FAST%VTKRefPoint, VTK_count, p_FAST%VTK_OutFileRoot, p_FAST%VTK_tWidth) + call AD_WrVTK_LinesPoints(ADI%u(2)%AD, ADI%y%AD, DVR_Outs%VTKRefPoint, VTK_count, DVR_Outs%VTK_OutFileRoot, DVR_Outs%VTK_tWidth) ! Elastic info nWT = size(FED%WT) @@ -1917,34 +1921,34 @@ subroutine WrVTK_Lines(t_global, ADI, FED, p_FAST, VTK_count) endif y_ED => FED%WT(iWT) - if (p_FAST%WrVTK_Type==2) then ! only if not doing surfaces + if (DVR_Outs%WrVTK_Type==2) then ! only if not doing surfaces ! Base - call MeshWrVTK_PointSurface (p_FAST%VTKRefPoint, y_ED%PlatformPtMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.BaseSurface', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth , verts = p_FAST%VTK_Surface(iWT)%BaseBox) + call MeshWrVTK_PointSurface (DVR_Outs%VTKRefPoint, y_ED%PlatformPtMesh, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.BaseSurface', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth , verts = DVR_Outs%VTK_Surface(iWT)%BaseBox) endif if (y_ED%numBlades>0) then ! Nacelle - call MeshWrVTK( p_FAST%VTKRefPoint, y_ED%NacelleMotion, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.Nacelle', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth ) + call MeshWrVTK( DVR_Outs%VTKRefPoint, y_ED%NacelleMotion, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.Nacelle', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth ) endif - if (p_FAST%WrVTK>1) then + if (DVR_Outs%WrVTK>1) then ! --- animations ! Tower base - call MeshWrVTK(p_FAST%VTKRefPoint, y_ED%TwrPtMesh, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.TwrBase', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth ) + call MeshWrVTK(DVR_Outs%VTKRefPoint, y_ED%TwrPtMesh, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.TwrBase', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth ) if (ADI%u(2)%AD%rotors(iWT)%TowerMotion%nNodes>0) then - call MeshWrVTK(p_FAST%VTKRefPoint, y_ED%TwrPtMeshAD, trim(p_FAST%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseAD', & - VTK_count, OutputFields, errStat2, errMsg2, p_FAST%VTK_tWidth ) + call MeshWrVTK(DVR_Outs%VTKRefPoint, y_ED%TwrPtMeshAD, trim(DVR_Outs%VTK_OutFileRoot)//trim(sWT)//'.TwrBaseAD', & + VTK_count, OutputFields, errStat2, errMsg2, DVR_Outs%VTK_tWidth ) endif endif enddo ! Free wake (only write this here if doing line meshes only -- FVW is written with surface outputs) - if (allocated(ADI%m%AD%FVW_u) .and. p_FAST%WrVTK_Type==2) then + if (allocated(ADI%m%AD%FVW_u) .and. DVR_Outs%WrVTK_Type==2) then if (allocated(ADI%m%AD%FVW_u(1)%WingsMesh)) then - call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(1)%AD%FVW, ADI%z(1)%AD%FVW, ADI%m%AD%FVW, trim(p_FAST%VTK_OutFileRoot)//'.FVW', VTK_count, p_FAST%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(1)%AD%FVW, ADI%z(1)%AD%FVW, ADI%m%AD%FVW, trim(DVR_Outs%VTK_OutFileRoot)//'.FVW', VTK_count, DVR_Outs%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords end if end if end subroutine WrVTK_Lines diff --git a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 index 8d3153e0a9..f1122aded8 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Types.f90 @@ -68,10 +68,10 @@ MODULE AeroDyn_Driver_Types character(1) :: delim !< column delimiter [-] character(20) :: outFmt !< Format specifier [-] INTEGER(IntKi) :: fileFmt = 0_IntKi !< Output format 1=Text, 2=Binary, 3=Both [-] - INTEGER(IntKi) :: wrVTK = 0_IntKi !< 0= no vtk, 1=init only, 2=animation [-] + INTEGER(IntKi) :: WrVTK = 0_IntKi !< 0= no vtk, 1=init only, 2=animation [-] INTEGER(IntKi) :: WrVTK_Type = 0_IntKi !< Flag for VTK output type (1=surface, 2=line, 3=both) [-] character(1024) :: Root !< Output file rootname [-] - character(1024) :: VTK_OutFileRoot !< Output file rootname for vtk [-] + character(1024) :: VTK_OutFileRoot !< Output file rootname for vtk (includes directory) [-] character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Channel headers [-] character(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Channel units [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: storage !< nTurbines x nChannel x nTime [-] @@ -79,6 +79,7 @@ MODULE AeroDyn_Driver_Types TYPE(DvrVTK_SurfaceType) , DIMENSION(:), ALLOCATABLE :: VTK_surface !< Data for VTK surface visualization [-] INTEGER(IntKi) :: VTK_tWidth = 0_IntKi !< Width of number of files for leading zeros in file name format [-] INTEGER(IntKi) :: n_VTKTime = 0_IntKi !< Number of time steps between writing VTK files [-] + REAL(DbKi) :: VTK_DT = 0.0_R8Ki !< Write VTK time step [-] REAL(SiKi) :: VTKHubRad = 0.0_R4Ki !< Hub radius for visualization [m] REAL(ReKi) , DIMENSION(1:6) :: VTKNacDim = 0.0_ReKi !< Nacelle dimensions for visualization [m] REAL(SiKi) , DIMENSION(1:3) :: VTKRefPoint = 0.0_R4Ki !< RefPoint for VTK outputs [-] @@ -346,7 +347,7 @@ subroutine AD_Dvr_CopyDvr_Outputs(SrcDvr_OutputsData, DstDvr_OutputsData, CtrlCo DstDvr_OutputsData%delim = SrcDvr_OutputsData%delim DstDvr_OutputsData%outFmt = SrcDvr_OutputsData%outFmt DstDvr_OutputsData%fileFmt = SrcDvr_OutputsData%fileFmt - DstDvr_OutputsData%wrVTK = SrcDvr_OutputsData%wrVTK + DstDvr_OutputsData%WrVTK = SrcDvr_OutputsData%WrVTK DstDvr_OutputsData%WrVTK_Type = SrcDvr_OutputsData%WrVTK_Type DstDvr_OutputsData%Root = SrcDvr_OutputsData%Root DstDvr_OutputsData%VTK_OutFileRoot = SrcDvr_OutputsData%VTK_OutFileRoot @@ -416,6 +417,7 @@ subroutine AD_Dvr_CopyDvr_Outputs(SrcDvr_OutputsData, DstDvr_OutputsData, CtrlCo end if DstDvr_OutputsData%VTK_tWidth = SrcDvr_OutputsData%VTK_tWidth DstDvr_OutputsData%n_VTKTime = SrcDvr_OutputsData%n_VTKTime + DstDvr_OutputsData%VTK_DT = SrcDvr_OutputsData%VTK_DT DstDvr_OutputsData%VTKHubRad = SrcDvr_OutputsData%VTKHubRad DstDvr_OutputsData%VTKNacDim = SrcDvr_OutputsData%VTKNacDim DstDvr_OutputsData%VTKRefPoint = SrcDvr_OutputsData%VTKRefPoint @@ -478,7 +480,7 @@ subroutine AD_Dvr_PackDvr_Outputs(RF, Indata) call RegPack(RF, InData%delim) call RegPack(RF, InData%outFmt) call RegPack(RF, InData%fileFmt) - call RegPack(RF, InData%wrVTK) + call RegPack(RF, InData%WrVTK) call RegPack(RF, InData%WrVTK_Type) call RegPack(RF, InData%Root) call RegPack(RF, InData%VTK_OutFileRoot) @@ -497,6 +499,7 @@ subroutine AD_Dvr_PackDvr_Outputs(RF, Indata) end if call RegPack(RF, InData%VTK_tWidth) call RegPack(RF, InData%n_VTKTime) + call RegPack(RF, InData%VTK_DT) call RegPack(RF, InData%VTKHubRad) call RegPack(RF, InData%VTKNacDim) call RegPack(RF, InData%VTKRefPoint) @@ -523,7 +526,7 @@ subroutine AD_Dvr_UnPackDvr_Outputs(RF, OutData) call RegUnpack(RF, OutData%delim); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%outFmt); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%fileFmt); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%wrVTK); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WrVTK); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%WrVTK_Type); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%Root); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%VTK_OutFileRoot); if (RegCheckErr(RF, RoutineName)) return @@ -546,6 +549,7 @@ subroutine AD_Dvr_UnPackDvr_Outputs(RF, OutData) end if call RegUnpack(RF, OutData%VTK_tWidth); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%n_VTKTime); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%VTK_DT); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%VTKHubRad); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%VTKNacDim); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%VTKRefPoint); if (RegCheckErr(RF, RoutineName)) return diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index fdf50bbef7..a3e56406a7 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -818,7 +818,7 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade call ParseVar( FileInfo_In, CurLine, "CompAA", InputFileData%CompAA, ErrStat2, ErrMsg2, UnEc ) if (Failed()) return ! AA_InputFile - Aeroacoustics input file - call ParseVar( FileInfo_In, CurLine, "AA_InputFile", InputFileData%AA_InputFile, ErrStat2, ErrMsg2, UnEc ) + call ParseVar( FileInfo_In, CurLine, "AA_InputFile", InputFileData%AA_InputFile, ErrStat2, ErrMsg2, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%AA_InputFile ) ) InputFileData%AA_InputFile = TRIM(PriPath)//TRIM(InputFileData%AA_InputFile) @@ -944,7 +944,7 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo CurLine = CurLine + 1 ! OLAFInputFileName - Input file for OLAF [used only when WakeMod=3] - call ParseVar( FileInfo_In, CurLine, "OLAFInputFileName", InputFileData%FVWFileName, ErrStat2, ErrMsg2, UnEc ) + call ParseVar( FileInfo_In, CurLine, "OLAFInputFileName", InputFileData%FVWFileName, ErrStat2, ErrMsg2, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%FVWFileName ) ) InputFileData%FVWFileName = TRIM(PriPath)//TRIM(InputFileData%FVWFileName) @@ -1080,7 +1080,7 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade ! NOTE: being nice with legacy input file. Uncomment in next release call ParseVar(FileInfo_In, CurLine, "TFinAero", InputFileData%rotors(iR)%TFinAero, ErrStat2, ErrMsg2, UnEc); if (ErrStat2==ErrID_None) then - call ParseVar(FileInfo_In, CurLine, "TFinFile", InputFileData%rotors(iR)%TFinFile, ErrStat2, ErrMsg2, UnEc); if (Failed()) return + call ParseVar(FileInfo_In, CurLine, "TFinFile", InputFileData%rotors(iR)%TFinFile, ErrStat2, ErrMsg2, UnEc, IsPath=.true.); if (Failed()) return IF ( PathIsRelative( InputFileData%rotors(iR)%TFinFile ) ) InputFileData%rotors(iR)%TFinFile = trim(PriPath) // trim(InputFileData%rotors(iR)%TFinFile) else call LegacyWarning('Tail Fin section (TFinAero, TFinFile) is missing from input file.') @@ -1445,13 +1445,11 @@ SUBROUTINE ReadBladeInputs ( ADBlFile, BladeKInputFileData, AeroProjMod, UnEc, c ErrMsg = "" UnIn = -1 + ! Open the input file for blade K. + !$OMP critical(filename) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - - - ! Open the input file for blade K. - CALL OpenFInpFile ( UnIn, ADBlFile, ErrStat2, ErrMsg2 ) + !$OMP end critical(filename) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN @@ -1754,8 +1752,10 @@ SUBROUTINE AD_PrintSum( InputFileData, p, p_AD, u, y, NumBlades, BladeInputFileD ! Open the summary file and give it a heading. + !$OMP critical(filename) CALL GetNewUnit( UnSu, ErrStat, ErrMsg ) CALL OpenFOutFile ( UnSu, TRIM( p%RootName )//'.sum', ErrStat, ErrMsg ) + !$OMP end critical(filename) IF ( ErrStat >= AbortErrLev ) RETURN ! Heading: diff --git a/modules/aerodyn/src/AeroDyn_Inflow.f90 b/modules/aerodyn/src/AeroDyn_Inflow.f90 index 5da3f6b8d6..3f212d78e3 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow.f90 @@ -388,6 +388,10 @@ subroutine ADI_InitInflowWind(Root, i_IW, u_AD, o_AD, IW, dt, InitOutData, errSt endif InitInData%RootName = trim(Root)//'.IfW' InitInData%MHK = i_IW%MHK + ! OLAF might be used in AD, in which case we need to allow out of bounds for some calcs. To do that + ! the average values for the entire wind profile must be calculated and stored (we don't know if OLAF + ! is used until after AD_Init below). + InitInData%BoxExceedAllow = .true. CALL InflowWind_Init( InitInData, IW%u, IW%p, & IW%x, IW%xd, IW%z, IW%OtherSt, & IW%y, IW%m, dt, InitOutData, errStat2, errMsg2 ) diff --git a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index b2523e14c4..48f0d4601f 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 @@ -24,6 +24,7 @@ MODULE AeroDyn_Inflow_C_BINDING USE AeroDyn_Inflow_Types USE AeroDyn_Driver_Types, only: Dvr_SimData, Dvr_Outputs USE AeroDyn_Driver_Subs, only: Dvr_InitializeOutputs, Dvr_WriteOutputs, SetVTKParameters !, WrVTK_Surfaces, WrVTK_Lines, WrVTK_Ground + USE IfW_FlowField, only: IfW_FlowField_GetVelAcc USE NWTC_Library USE VersionInfo @@ -39,6 +40,7 @@ MODULE AeroDyn_Inflow_C_BINDING PUBLIC :: ADI_C_SetupRotor ! Initial node positions etc for a rotor PUBLIC :: ADI_C_SetRotorMotion ! Set motions for a given rotor PUBLIC :: ADI_C_GetRotorLoads ! Retrieve loads for a given rotor + PUBLIC :: ADI_C_GetDiskAvgVel ! Get the disk average velocity for the rotor !------------------------------------------------------------------------------------ ! Version info for display @@ -96,7 +98,7 @@ MODULE AeroDyn_Inflow_C_BINDING integer(IntKi) :: InterpOrder !------------------------------ ! Primary ADI data derived data types - type(ADI_Data) :: ADI + type(ADI_Data), target :: ADI !< all ADI data (target for using pointers to simplify code) type(ADI_InitInputType) :: InitInp !< Initialization data type(ADI_InitOutputType) :: InitOutData !< Initial output data -- Names, units, and version info. type(ADI_InputType) :: ADI_u !< ADI inputs -- set by AD_SetInputMotion. Copied as needed (necessary for correction steps) @@ -125,17 +127,29 @@ MODULE AeroDyn_Inflow_C_BINDING ! the glue code. However, here we do not pass state information through the ! interface and therefore must store it here analogously to how it is handled ! in the OpenFAST glue code. - integer(IntKi) :: n_Global ! global timestep - integer(IntKi) :: n_VTK ! VTK timestep - real(DbKi) :: InputTimePrev ! input time of last UpdateStates call + integer(IntKi) :: n_Global ! global timestep + integer(IntKi) :: n_VTK ! VTK timestep + real(DbKi) :: InputTimePrev ! input time of last UpdateStates call + real(DbKi) :: InputTimePrev_Calc ! input time of last CalcOutput call ! Note that we are including the previous state info here (not done in OF this way) - integer(IntKi), parameter :: STATE_LAST = 0 ! Index for previous state (not needed in OF, but necessary here) - integer(IntKi), parameter :: STATE_CURR = 1 ! Index for current state - integer(IntKi), parameter :: STATE_PRED = 2 ! Index for predicted state + integer(IntKi), parameter :: STATE_LAST = 0 ! Index for previous state (not needed in OF, but necessary here) + integer(IntKi), parameter :: STATE_CURR = 1 ! Index for current state + integer(IntKi), parameter :: STATE_PRED = 2 ! Index for predicted state ! Note the indexing is different on inputs (no clue why, but thats how OF handles it) - integer(IntKi), parameter :: INPUT_LAST = 3 ! Index for previous input at t-dt - integer(IntKi), parameter :: INPUT_CURR = 2 ! Index for current input at t - integer(IntKi), parameter :: INPUT_PRED = 1 ! Index for predicted input at t+dt + integer(IntKi), parameter :: INPUT_LAST = 3 ! Index for previous input at t-dt + integer(IntKi), parameter :: INPUT_CURR = 2 ! Index for current input at t + integer(IntKi), parameter :: INPUT_PRED = 1 ! Index for predicted input at t+dt + + !------------------------------- + ! Variables for disk average velocity calculations + integer(IntKi), parameter :: NumPtsDiskAvg = 144 + type :: DiskAvgVelData_Type + real(ReKi) :: DiskWindPosRel(3,NumPtsDiskAvg) + real(ReKi) :: DiskWindPosAbs(3,NumPtsDiskAvg) + real(ReKi) :: DiskWindVel(3,NumPtsDiskAvg) + real(ReKi) :: DiskAvgVel(3) + end type DiskAvgVelData_Type + type(DiskAvgVelData_Type), allocatable :: DiskAvgVelVars(:) !------------------------------------------------------------------------------------ ! Meshes for motions and loads @@ -276,9 +290,9 @@ subroutine ADI_C_PreInit(NumTurbines_C, TransposeDCM_in, PointLoadOutput_in, Deb endif ! check valid debug level - if (DebugLevel < 0_IntKi .or. DebugLevel > 4_IntKi) then + if (DebugLevel < 0_IntKi) then ErrStat2 = ErrID_Fatal - ErrMsg2 = "Interface debug level must be between 0 and 4"//NewLine// & + ErrMsg2 = "Interface debug level must be 0 or greater"//NewLine// & " 0 - none"//NewLine// & " 1 - some summary info and variables passed through interface"//NewLine// & " 2 - above + all position/orientation info"//NewLine// & @@ -303,6 +317,10 @@ subroutine ADI_C_PreInit(NumTurbines_C, TransposeDCM_in, PointLoadOutput_in, Deb if (allocated(InitInp%AD%rotors)) deallocate(InitInp%AD%rotors) allocate(InitInp%AD%rotors(Sim%NumTurbines),stat=errStat2); if (Failed0('rotors')) return + ! allocate data storage for DiskAvgVel retrieval + if (allocated(DiskAvgVelVars)) deallocate(DiskAvgVelVars) + allocate(DiskAvgVelVars(Sim%NumTurbines), STAT=ErrStat2); if (Failed0('DiskAvgVelVars')) return + ! Allocate data storage for turbine info if (allocated(Sim%WT)) deallocate(Sim%WT) allocate(Sim%WT(Sim%NumTurbines),stat=errStat2); if (Failed0('wind turbines')) return @@ -383,11 +401,13 @@ end subroutine ADI_C_PreInit !=============================================================================================================== SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileStringLength_C, & IfWinputFilePassed, IfWinputFileString_C, IfWinputFileStringLength_C, OutRootName_C, & + OutVTKDir_C, & gravity_C, defFldDens_C, defKinVisc_C, defSpdSound_C, & defPatm_C, defPvap_C, WtrDpth_C, MSL2SWL_C, & InterpOrder_C, DT_C, TMax_C, & storeHHVel, & - WrVTK_in, WrVTK_inType, VTKNacDim_in, VTKHubRad_in, & + WrVTK_in, WrVTK_inType, WrVTK_inDT, & + VTKNacDim_in, VTKHubRad_in, & wrOuts_C, DT_Outs_C, & NumChannels_C, OutputChannelNames_C, OutputChannelUnits_C, & ErrStat_C, ErrMsg_C) BIND (C, NAME='ADI_C_Init') @@ -404,6 +424,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString type(c_ptr), intent(in ) :: IfWinputFileString_C !< Input file as a single string with lines deliniated by C_NULL_CHAR integer(c_int), intent(in ) :: IfWinputFileStringLength_C !< lenght of the input file string character(kind=c_char), intent(in ) :: OutRootName_C(IntfStrLen) !< Root name to use for echo files and other + character(kind=c_char), intent(in ) :: OutVTKDir_C(IntfStrLen) !< Directory to put all vtk output ! Environmental real(c_float), intent(in ) :: gravity_C !< Gravitational acceleration (m/s^2) real(c_float), intent(in ) :: defFldDens_C !< Air density (kg/m^3) @@ -423,6 +444,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString ! VTK integer(c_int), intent(in ) :: WrVTK_in !< Write VTK outputs [0: none, 1: init only, 2: animation] integer(c_int), intent(in ) :: WrVTK_inType !< Write VTK outputs as [1: surface, 2: lines, 3: both] + real(c_double), intent(in ) :: WrVTK_inDT !< Timestep between VTK writes real(c_float), intent(in ) :: VTKNacDim_in(6) !< Nacelle dimension passed in for VTK surface rendering [0,y0,z0,Lx,Ly,Lz] (m) real(c_float), intent(in ) :: VTKHubrad_in !< Hub radius for VTK surface rendering integer(c_int), intent(in ) :: wrOuts_C !< Write ADI output file @@ -444,6 +466,7 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString character(ErrMsgLen) :: ErrMsg !< aggregated error message integer(IntKi) :: ErrStat2 !< temporary error status from a call character(ErrMsgLen) :: ErrMsg2 !< temporary error message from a call + character(IntfStrLen) :: OutVTKdir !< Output directory for files (relative to current location) integer(IntKi) :: i,j,k !< generic index variables integer(IntKi) :: iWT !< current turbine number (iterate through during setup for ADI_Init call) integer(IntKi) :: AeroProjMod !< for checking that all turbines use the same AeroProjMod @@ -494,6 +517,10 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString i = INDEX(OutRootName,C_NULL_CHAR) - 1 ! if this has a c null character at the end... if ( i > 0 ) OutRootName = OutRootName(1:I) ! remove it + ! OutVTKdir -- output directory + OutVTKdir = TRANSFER( OutVTKdir_C, OutVTKdir ) + i = INDEX(OutVTKdir,C_NULL_CHAR) - 1 ! if this has a c null character at the end... + if ( i > 0 ) OutVTKdir = OutVTKdir(1:I) ! remove it ! For debugging the interface: if (DebugLevel > 0) then @@ -554,18 +581,19 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString Sim%root = trim(OutRootName) ! Timekeeping n_Global = 0_IntKi ! Assume we are on timestep 0 at start - n_VTK = -1_IntKi ! Set VTK output to T=0 at first call + n_VTK = -1_IntKi ! counter advance just before writing ! Interpolation order InterpOrder = int(InterpOrder_C, IntKi) ! VTK outputs WrOutputsData%WrVTK = int(WrVTK_in, IntKi) WrOutputsData%WrVTK_Type = int(WrVTK_inType, IntKi) + WrOutputsData%VTK_dt = real(WrVTK_inDT, DbKi) WrOutputsData%VTKNacDim = real(VTKNacDim_in, SiKi) WrOutputsData%VTKHubrad = real(VTKHubrad_in, SiKi) WrOutputsData%VTKRefPoint = (/ 0.0_ReKi, 0.0_ReKi, 0.0_ReKi /) !TODO: should this be an input? WrOutputsData%root = trim(OutRootName) - WrOutputsData%n_VTKTime = 1 ! output every timestep + WrOutputsData%n_VTKTime = 1 ! output every timestep ! Write outputs to file WrOutputsData%fileFmt = int(wrOuts_C, IntKi) @@ -641,7 +669,10 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString call SetupMotionLoadsInterfaceMeshes(); if (Failed()) return ! setup meshes if (WrOutputsData%WrVTK > 0_IntKi) then - call setVTKParameters(WrOutputsData, Sim, ADI, ErrStat2, ErrMsg2, 'vtk-ADI') + if (len_trim(OutVTKdir) <= 0) then + OutVTKdir = 'vtk-ADI' + endif + call setVTKParameters(WrOutputsData, Sim, ADI, ErrStat2, ErrMsg2, OutVTKdir) if (Failed()) return endif ! write meshes for this rotor @@ -652,21 +683,30 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString if (Failed()) return endif + ! Setup points for calculating disk average velocity + do iWT=1,Sim%NumTurbines + call SetDiskAvgPoints(iWT) + if (Failed()) return + enddo + !------------------------------------------------------------- ! Setup other prior timesteps ! We fill InputTimes with negative times, but the Input values are identical for each of those times; this allows ! us to use, e.g., quadratic interpolation that effectively acts as a zeroth-order extrapolation and first-order extrapolation ! for the first and second time steps. (The interpolation order in the ExtrapInput routines are determined as ! order = SIZE(Input) + ! Tracking of previous input times + ! Since we may run correction steps, there are some things we don't want to do !------------------------------------------------------------- do i=2,InterpOrder+1 call ADI_CopyInput (ADI%u(1), ADI%u(i), MESH_NEWCOPY, Errstat2, ErrMsg2) if (Failed()) return enddo do i = 1, InterpOrder + 1 - ADI%InputTimes(i) = 0.0_DbKi - (i - 1) * Sim%dT ! assume start at T=0 + ADI%InputTimes(i) = 0.0_DbKi - (i - 1) * Sim%dT ! assume start at T=0 enddo - InputTimePrev = ADI%InputTimes(1) - Sim%dT ! Initialize for UpdateStates + InputTimePrev = ADI%InputTimes(1) - Sim%dT ! Initialize for UpdateStates + InputTimePrev_Calc = ADI%InputTimes(1) - Sim%dT ! Initialize for CalcOutput !------------------------------------------------------------- ! copy of ADI inputs. AD_SetInputMotion will set this mesh. When CalcOutput is called, @@ -806,6 +846,19 @@ subroutine ValidateSetInputs(ErrStat3,ErrMsg3) call SetErrStat(ErrID_Warn,"Requested DT_Outs is not an integer multiple of DT. Changing DT_Outs to "//trim(Num2LStr(WrOutputsData%DT_Outs))//".",ErrStat3,ErrMsg3,RoutineName) endif endif + if (WrOutputsData%WrVTK > 1_IntKi) then ! only if writing during simulation is requested (ignore init or no outputs) + ! If a smaller timestep between outputs is requested than the simulation runs at, change to DT + if (WrOutputsData%VTK_DT < Sim%dT) then + WrOutputsData%VTK_DT = Sim%dT + call SetErrStat(ErrID_Warn,"Requested VTK_DT is smaller than timestep DT. Setting VTK_DT to DT.",ErrStat3,ErrMsg3,RoutineName) + endif + ! If not an integer multiple of DT, adjust + WrOutputsData%n_VTKtime = NINT( WrOutputsData%VTK_DT / Sim%dT ) + if (.NOT. EqualRealNos( WrOutputsData%VTK_DT, Sim%dT * WrOutputsData%n_VTKtime )) then + WrOutputsData%VTK_DT = real(WrOutputsData%n_VTKtime, DbKi) * Sim%dT + call SetErrStat(ErrID_Warn,"Requested VTK_DT is not an integer multiple of DT. Changing VTK_DT to "//trim(Num2LStr(WrOutputsData%VTK_DT))//".",ErrStat3,ErrMsg3,RoutineName) + endif + endif end subroutine ValidateSetInputs !> allocate data storage for file outputs @@ -853,6 +906,7 @@ subroutine ShowPassedData() call WrScr(" IfWinputFileString_C (ptr addr)"//trim(Num2LStr(LOC(IfWinputFileString_C))) ) call WrScr(" IfWinputFileStringLength_C "//trim(Num2LStr( IfWinputFileStringLength_C )) ) call WrScr(" OutRootName "//trim(OutRootName) ) + call WrScr(" OutVTKDir "//trim(OutVTKDir) ) call WrScr(" Environment variables") call WrScr(" gravity_C "//trim(Num2LStr( gravity_C )) ) call WrScr(" defFldDens_C "//trim(Num2LStr( defFldDens_C )) ) @@ -875,6 +929,7 @@ subroutine ShowPassedData() call WrScr(" storeHHVel "//TmpFlag ) call WrScr(" WrVTK_in "//trim(Num2LStr( WrVTK_in )) ) call WrScr(" WrVTK_inType "//trim(Num2LStr( WrVTK_inType )) ) + call WrScr(" WrVTK_inDT "//trim(Num2LStr( WrVTK_inDT )) ) call WrScr("-----------------------------------------------------------") end subroutine ShowPassedData @@ -954,6 +1009,24 @@ subroutine CheckNodes(iWT) ! - some checks on hub/nacelle being near middle of the rotor? Not sure if that matters end subroutine CheckNodes + !> Setup points for disk average velocity calculations + subroutine SetDiskAvgPoints(iWT) + integer(IntKi), intent(in) :: iWT + integer(IntKi) :: i,BlNds + real(ReKi) :: R,theta,BLength + ! Calculate relative points on disk (do this once up front to save computational time). + ! NOTE: this is in the XY plane, and will be multiplied by the hub orientation vector + BlNds = ADI%p%AD%rotors(iWT)%NumBlNds + BLength = TwoNorm(ADI%u(1)%AD%rotors(iWT)%BladeMotion(1)%Position(:,BlNds) - ADI%u(1)%AD%rotors(iWT)%HubMotion%Position(:,1)) + R = real(BLength,ReKi) * 0.7_reKi !70% radius + do i=1,NumPtsDiskAvg + theta = pi +(i-1)*TwoPi/NumPtsDiskAvg + DiskAvgVelVars(iWT)%DiskWindPosRel(1,i) = 0.0_ReKi ! Hub X (perpindicular to rotor plane) + DiskAvgVelVars(iWT)%DiskWindPosRel(2,i) = R*cos(theta) ! Hub Y + DiskAvgVelVars(iWT)%DiskWindPosRel(3,i) = R*sin(theta) ! Hub Z (in vertical plane when azimuth=0) + end do + end subroutine SetDiskAvgPoints + END SUBROUTINE ADI_C_Init @@ -1049,7 +1122,16 @@ SUBROUTINE ADI_C_CalcOutput(Time_C, & ! write outputs !------------------------------------------------------- ! Write VTK if requested (animation=2) - if (WrOutputsData%WrVTK > 1_IntKi) call WrVTK_Meshes(ADI%u(1)%AD%rotors(:),(/0.0_SiKi,0.0_SiKi,0.0_SiKi/),ErrStat2,ErrMsg2) + if (WrOutputsData%WrVTK > 1_IntKi) then + ! Check if writing this step (note this may overwrite if we rerun a step in a correction loop) + if ( mod( n_Global, WrOutputsData%n_VTKTime ) == 0 ) THEN + ! increment the current VTK output number if not a correction step, otherwise overwrite previous + if (.not. EqualRealNos( real(Time,DbKi), InputTimePrev_Calc ) ) then + n_VTK = n_VTK + 1_IntKi ! Increment for this write + endif + call WrVTK_Meshes(ADI%u(1)%AD%rotors(:),(/0.0_SiKi,0.0_SiKi,0.0_SiKi/),ErrStat2,ErrMsg2) + endif + endif if (WrOutputsData%fileFmt > idFmtNone) then !FIXME: need some way to overwrite the correction timesteps (for text file)! @@ -1059,6 +1141,9 @@ SUBROUTINE ADI_C_CalcOutput(Time_C, & ! Set error status call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + ! Store info what time we just ran calcs for + InputTimePrev_Calc = Time + CONTAINS logical function Failed() CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -1904,6 +1989,76 @@ end subroutine ShowPassedData end subroutine ADI_C_GetRotorLoads +!=============================================================================================================== +!--------------------------------------------- GetDiskAvgVel --------------------------------------------------- +!=============================================================================================================== +!> Get the disk average velocity for a single rotor (uses the IfW DiskAvgVel routine) +subroutine ADI_C_GetDiskAvgVel(iWT_C, & + DiskAvgVel_C, & + ErrStat_C, ErrMsg_C) BIND (C, NAME='ADI_C_GetDiskAvgVel') + implicit none +#ifndef IMPLICIT_DLLEXPORT +!DEC$ ATTRIBUTES DLLEXPORT :: ADI_C_GetDiskAvgVel +!GCC$ ATTRIBUTES DLLEXPORT :: ADI_C_GetDiskAvgVel +#endif + integer(c_int), intent(in ) :: iWT_C !< Wind turbine / rotor number + real(c_float), intent( out) :: DiskAvgVel_C(3) !< Wind speed vector for disk average [Vx,Vy,Vz] -- (m/s) (global) + integer(c_int), intent( out) :: ErrStat_C + character(kind=c_char), intent( out) :: ErrMsg_C(ErrMsgLen_C) + + ! Local variables + type(MeshType), pointer :: Hub ! HubMotion mesh pointer, for simplicity in code reading + integer(IntKi) :: iWT !< current wind turbine / rotor + integer(IntKi) :: i + integer(IntKi), parameter :: StartNode = 1 ! so all points are calculated + real(ReKi), allocatable :: NoAcc(:,:) ! Placeholder array not used when accelerations not required. + real(ReKi) :: DiskAvgVel(3) !< Wind speed vector for disk average [Vx,Vy,Vz] -- (m/s) (global) + integer(IntKi) :: ErrStat !< aggregated error status + character(ErrMsgLen) :: ErrMsg !< aggregated error message + character(*), parameter :: RoutineName = 'ADI_C_GetDiskAvgVel' !< for error handling + + ! Initialize error handling + ErrStat = ErrID_None + ErrMsg = "" + + ! For debugging the interface: + if (DebugLevel > 0) then + call ShowPassedData() + endif + + ! current turbine number + iWT = int(iWT_c, IntKi) + + ! pointer to make code more readable + Hub => ADI%u(1)%AD%rotors(iWT)%HubMotion + + ! Calculate Disk Avg Velocity + do i=1,NumPtsDiskAvg + DiskAvgVelVars(iWT)%DiskWindPosAbs(:,i) = real(Hub%Position(1:3,1)+Hub%TranslationDisp(1:3,1),ReKi) & + + matmul(real(Hub%Orientation(1:3,1:3,1),ReKi),DiskAvgVelVars(iWT)%DiskWindPosRel(:,i)) + enddo + call IfW_FlowField_GetVelAcc(ADI%m%IW%p%FlowField, StartNode, InputTimePrev_Calc, DiskAvgVelVars(iWT)%DiskWindPosAbs, DiskAvgVelVars(iWT)%DiskWindVel, NoAcc, ErrStat, ErrMsg) + + ! calculate average + DiskAvgVel = sum(DiskAvgVelVars(iWT)%DiskWindVel, dim=2) / REAL(NumPtsDiskAvg,SiKi) + DiskAvgVel_C = real(DiskAvgVel, c_float) + + ! Set error status + call SetErr(ErrStat,ErrMsg,ErrStat_C,ErrMsg_C) + +CONTAINS + !> This subroutine prints out all the variables that are passed in. Use this only + !! for debugging the interface on the Fortran side. + subroutine ShowPassedData() + call WrSCr("") + call WrScr("-----------------------------------------------------------") + call WrScr("Interface debugging: Variables passed in through interface") + call WrScr(" ADI_C_GetDiskAvgVel -- rotor "//trim(Num2LStr(iWT_c))) + call WrScr("-----------------------------------------------------------") + end subroutine ShowPassedData +end subroutine ADI_C_GetDiskAvgVel + + !=================================================================================================================================== ! Internal routines for setting meshes etc. !=================================================================================================================================== @@ -2254,7 +2409,7 @@ subroutine WrVTK_Points(ErrStat3,ErrMsg3) ! Blade point motion (structural mesh from driver) do iBlade=1,Sim%WT(iWT)%NumBlades - call MeshWrVTK(RefPoint, BldStrMotionMesh(iWT)%Mesh(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldStrMotionMesh'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + call MeshWrVTK(RefPoint, BldStrMotionMesh(iWT)%Mesh(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BldStrMotionMesh'//trim(num2lstr(iBlade)), n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return enddo @@ -2262,20 +2417,20 @@ subroutine WrVTK_Points(ErrStat3,ErrMsg3) if (allocated(rot_u(iWT)%BladeRootMotion)) then do iBlade=1,Sim%WT(iWT)%NumBlades if (rot_u(iWT)%BladeRootMotion(iBlade)%Committed) then - call MeshWrVTK(RefPoint, rot_u(iWT)%BladeRootMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + call MeshWrVTK(RefPoint, rot_u(iWT)%BladeRootMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.BladeRootMotion'//trim(num2lstr(iBlade)), n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return endif enddo endif ! Nacelle (structural point input - if ( rot_u(iWT)%NacelleMotion%Committed ) call MeshWrVTK(RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.NacelleMotion', n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + if ( rot_u(iWT)%NacelleMotion%Committed ) call MeshWrVTK(RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.NacelleMotion', n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return ! Free wake if (allocated(ADI%m%AD%FVW_u) .and. iWT==1) then if (allocated(ADI%m%AD%FVW_u(1)%WingsMesh)) then - call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(STATE_CURR)%AD%FVW, ADI%z(STATE_CURR)%AD%FVW, ADI%m%AD%FVW, trim(WrOutputsData%VTK_OutFileRoot)//'.FVW', n_Global, WrOutputsData%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords + call WrVTK_FVW(ADI%p%AD%FVW, ADI%x(STATE_CURR)%AD%FVW, ADI%z(STATE_CURR)%AD%FVW, ADI%m%AD%FVW, trim(WrOutputsData%VTK_OutFileRoot)//'.FVW', n_VTK, WrOutputsData%VTK_tWidth, bladeFrame=.FALSE.) ! bladeFrame==.FALSE. to output in global coords endif end if end subroutine WrVTK_Points @@ -2291,11 +2446,11 @@ subroutine WrVTK_Surfaces(ErrStat3,ErrMsg3) ErrMsg3 = '' ! TODO: use this routine when it is moved out of the driver and into ADI - ! call AD_WrVTK_Surfaces(ADI%u(1)%AD, ADI%y%AD, RefPoint, ADI%m%VTK_Surfaces, n_Global, WrOutputsData%Root, WrOutputsData%VTK_tWidth, 25, WrOutputsData%VTKHubRad) + ! call AD_WrVTK_Surfaces(ADI%u(1)%AD, ADI%y%AD, RefPoint, ADI%m%VTK_Surfaces, n_VTK, WrOutputsData%Root, WrOutputsData%VTK_tWidth, 25, WrOutputsData%VTKHubRad) ! Nacelle if ( rot_u(iWT)%NacelleMotion%Committed ) then - call MeshWrVTK_PointSurface (RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.NacelleSurface', n_Global, & + call MeshWrVTK_PointSurface (RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.NacelleSurface', n_VTK, & OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth, verts=WrOutputsData%VTK_Surface(iWT)%NacelleBox) if (ErrStat3 >= AbortErrLev) return endif @@ -2303,14 +2458,14 @@ subroutine WrVTK_Surfaces(ErrStat3,ErrMsg3) ! Tower if (rot_u(iWT)%TowerMotion%Committed) then call MeshWrVTK_Ln2Surface (RefPoint, rot_u(iWT)%TowerMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.TowerSurface', & - n_Global, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth, numSectors, ADI%m%VTK_Surfaces(iWT)%TowerRad ) + n_VTK, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth, numSectors, ADI%m%VTK_Surfaces(iWT)%TowerRad ) if (ErrStat3 >= AbortErrLev) return endif ! Hub if (rot_u(iWT)%HubMotion%Committed) then call MeshWrVTK_PointSurface (RefPoint, rot_u(iWT)%HubMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.HubSurface', & - n_Global, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth, & + n_VTK, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth, & NumSegments=numSectors, radius=WrOutputsData%VTKHubRad) if (ErrStat3 >= AbortErrLev) return endif @@ -2320,7 +2475,7 @@ subroutine WrVTK_Surfaces(ErrStat3,ErrMsg3) do iBlade=1,Sim%WT(iWT)%NumBlades if (rot_u(iWT)%BladeMotion(iBlade)%Committed) then call MeshWrVTK_Ln2Surface (RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade))//'Surface', & - n_Global, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth , verts=ADI%m%VTK_Surfaces(iWT)%BladeShape(iBlade)%AirfoilCoords, & + n_VTK, OutputFields, errStat3, errMsg3, WrOutputsData%VTK_tWidth , verts=ADI%m%VTK_Surfaces(iWT)%BladeShape(iBlade)%AirfoilCoords, & Sib=ADI%y%AD%rotors(iWT)%BladeLoad(iBlade) ) if (ErrStat3 >= AbortErrLev) return endif @@ -2336,22 +2491,22 @@ subroutine WrVTK_Lines(ErrStat3,ErrMsg3) ErrMsg3 = '' ! Tower - if (rot_u(iWT)%TowerMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%TowerMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Tower', n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + if (rot_u(iWT)%TowerMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%TowerMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Tower', n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return ! Nacelle meshes - if (rot_u(iWT)%NacelleMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Nacelle', n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + if (rot_u(iWT)%NacelleMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%NacelleMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Nacelle', n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return ! Hub - if (rot_u(iWT)%HubMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%HubMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Hub', n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + if (rot_u(iWT)%HubMotion%Committed) call MeshWrVTK(RefPoint, rot_u(iWT)%HubMotion, trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Hub', n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return ! Blades if (allocated(rot_u(iWT)%BladeMotion)) then do iBlade=1,Sim%WT(iWT)%NumBlades if (rot_u(iWT)%BladeMotion(iBlade)%Committed) then - call MeshWrVTK(RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade)), n_Global, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) + call MeshWrVTK(RefPoint, rot_u(iWT)%BladeMotion(iBlade), trim(WrOutputsData%VTK_OutFileRoot)//trim(sWT)//'.Blade'//trim(num2lstr(iBlade)), n_VTK, .true., ErrStat3, ErrMsg3, WrOutputsData%VTK_tWidth) if (ErrStat3 >= AbortErrLev) return endif enddo @@ -2446,6 +2601,8 @@ subroutine ClearTmpStorage() ! if (allocated(NacMotionMesh )) call ClearMeshArr1(NacMotionMesh ) ! if (allocated(NacLoadMesh )) call ClearMeshArr1(NacLoadMesh ) if (allocated(Map_BldStrMotion_2_AD_Blade )) call ClearMeshMapArr2(Map_BldStrMotion_2_AD_Blade ) + ! other stuff + if (allocated(DiskAvgVelVars)) deallocate(DiskAvgVelVars) contains subroutine ClearMeshArr1(MeshName) type(MeshType), allocatable :: MeshName(:) diff --git a/modules/aerodyn/src/AirfoilInfo.f90 b/modules/aerodyn/src/AirfoilInfo.f90 index 5cde187db8..2c6ab6af03 100644 --- a/modules/aerodyn/src/AirfoilInfo.f90 +++ b/modules/aerodyn/src/AirfoilInfo.f90 @@ -483,7 +483,7 @@ SUBROUTINE ReadAFfile ( InitInp, NumCoefsIn, p, ErrStat, ErrMsg, UnEc ) ENDIF ! Reading Boundary layer file for aeroacoustics - CALL ParseVar ( FileInfo, CurLine, 'BL_file' , p%BL_file , ErrStat2, ErrMsg2, UnEc ) + CALL ParseVar ( FileInfo, CurLine, 'BL_file' , p%BL_file , ErrStat2, ErrMsg2, UnEc, IsPath=.true. ) IF (ErrStat2 >= AbortErrLev) p%BL_file = "NOT_SET_IN_AIRFOIL_FILE" !CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( PathIsRelative( p%BL_file ) ) p%BL_file=trim(PriPath)//trim(p%BL_file) @@ -1927,13 +1927,12 @@ subroutine AFI_WrHeader(delim, FileName, unOutFile, ErrStat, ErrMsg) ChanName(i) = 'alphaBreakLower'; ChanUnit(i) = '(deg)'; i = i+1; ChanName(i) = 'CnBreakLower'; ChanUnit(i) = '(-)'; i = i+1; + !$OMP critical(filename) CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) - IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( unOutFile, trim(FileName), ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return - + if (ErrStat < AbortErrLev) then + CALL OpenFOutFile ( unOutFile, trim(FileName), ErrStat2, ErrMsg2 ) + endif + !$OMP end critical(filename) ! Generate file outputs @@ -2106,11 +2105,12 @@ subroutine AFI_WrTables(AFI_Params,UAMod,OutRootName) ! Write to file - + !$OMP critical(filename) CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) - IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( unOutFile, trim(OutRootName)//'.Coefs.'//trim(num2lstr(iTab))//'.out', ErrStat, ErrMsg ) + if (ErrStat < AbortErrLev) then + CALL OpenFOutFile ( unOutFile, trim(OutRootName)//'.Coefs.'//trim(num2lstr(iTab))//'.out', ErrStat, ErrMsg ) + endif + !$OMP end critical(filename) if (ErrStat >= AbortErrLev) then call WrScr(Trim(ErrMsg)) return diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index 08b83a2b10..673ba0eddf 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -1438,10 +1438,12 @@ subroutine UA_Init_Outputs(InitInp, p, y, InitOut, errStat, errMsg) ! --- Write to File if ((p%NumOuts > 0) .and. p%UA_OUTS==2) then call WrScr(' UA: Writing separate output file: '//trim(InitInp%OutRootName)//'.out') + !$OMP critical(filename) CALL GetNewUnit( p%unOutFile, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return - CALL OpenFOutFile ( p%unOutFile, trim(InitInp%OutRootName)//'.out', ErrStat2, ErrMsg2 ) + if (ErrStat2 < AbortErrLev) then + CALL OpenFOutFile ( p%unOutFile, trim(InitInp%OutRootName)//'.UA.out', ErrStat2, ErrMsg2 ) + endif + !$OMP end critical(filename) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -4092,7 +4094,7 @@ subroutine UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat, ErrMsg) call AFI_WrHeader(delim, trim(InitInp%OutRootName)//'.sum', unOutFile, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return - + !...................................................... ! Write the data for each table in each file !...................................................... diff --git a/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index 01ba5e3af0..cec3d20e3e 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -1443,7 +1443,7 @@ subroutine AWAE_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg character(ErrMsgLen) :: errMsg2 character(*), parameter :: RoutineName = 'AWAE_CalcOutput' integer(intKi) :: n, n_high - character(2) :: PlaneNumStr ! 2 digit number of the output plane + character(3) :: PlaneNumStr ! 2 digit number of the output plane CHARACTER(1024) :: FileName INTEGER(IntKi) :: Un ! unit number of opened file @@ -1473,7 +1473,7 @@ subroutine AWAE_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ! XY plane slices do k = 1,p%NOutDisWindXY - write(PlaneNumStr, '(i2.2)') k + write(PlaneNumStr, '(i3.3)') k call ExtractSlice( XYSlice, p%OutDisWindZ(k), p%Z0_low, p%nZ_low, p%nX_low, p%nY_low, p%dZ_low, m%Vdist_low_full, m%outVizXYPlane(:,:,:,1)) ! Create the output vtk file with naming /Low/DisXY.t.vtk FileName = trim(p%OutFileVTKRoot)//".Low.DisXY"//PlaneNumStr//"."//trim(Tstr)//".vtk" @@ -1483,7 +1483,7 @@ subroutine AWAE_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ! YZ plane slices do k = 1,p%NOutDisWindYZ - write(PlaneNumStr, '(i2.2)') k + write(PlaneNumStr, '(i3.3)') k call ExtractSlice( YZSlice, p%OutDisWindX(k), p%X0_low, p%nX_low, p%nY_low, p%nZ_low, p%dX_low, m%Vdist_low_full, m%outVizYZPlane(:,:,:,1)) ! Create the output vtk file with naming /Low/DisYZ.t.vtk FileName = trim(p%OutFileVTKRoot)//".Low.DisYZ"//PlaneNumStr//"."//trim(Tstr)//".vtk" @@ -1493,7 +1493,7 @@ subroutine AWAE_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ! XZ plane slices do k = 1,p%NOutDisWindXZ - write(PlaneNumStr, '(i2.2)') k + write(PlaneNumStr, '(i3.3)') k call ExtractSlice( XZSlice, p%OutDisWindY(k), p%Y0_low, p%nY_low, p%nX_low, p%nZ_low, p%dY_low, m%Vdist_low_full, m%outVizXZPlane(:,:,:,1)) ! Create the output vtk file with naming /Low/DisXZ.t.vtk FileName = trim(p%OutFileVTKRoot)//".Low.DisXZ"//PlaneNumStr//"."//trim(Tstr)//".vtk" diff --git a/modules/awae/src/AWAE_IO.f90 b/modules/awae/src/AWAE_IO.f90 index 1755aeac78..b51febcc61 100644 --- a/modules/awae/src/AWAE_IO.f90 +++ b/modules/awae/src/AWAE_IO.f90 @@ -505,8 +505,10 @@ SUBROUTINE AWAE_PrintSum( p, u, y, ErrStat, ErrMsg ) ! Open the summary file and give it a heading. + !$OMP critical(fileopen) CALL GetNewUnit( UnSu, ErrStat, ErrMsg ) CALL OpenFOutFile ( UnSu, TRIM( p%OutFileRoot )//'.sum', ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF ( ErrStat >= AbortErrLev ) RETURN diff --git a/modules/beamdyn/src/BeamDyn_IO.f90 b/modules/beamdyn/src/BeamDyn_IO.f90 index 29c37404e3..0b52e2fabe 100644 --- a/modules/beamdyn/src/BeamDyn_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_IO.f90 @@ -588,9 +588,11 @@ SUBROUTINE BD_ReadPrimaryFile(InputFile,InputFileData,OutFileRoot,UnEc,ErrStat,E CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !$OMP critical(filename) CALL GetNewUnit(UnIn,ErrStat2,ErrMsg2) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL OpenFInpFile(UnIn,InputFile,ErrStat2,ErrMsg2) + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) then call cleanup() @@ -1050,9 +1052,11 @@ SUBROUTINE BD_ReadBladeFile(BldFile,BladeInputFileData,UnEc,ErrStat,ErrMsg) ErrStat = ErrID_None ErrMsg = "" + !$OMP critical(filename) CALL GetNewUnit(UnIn,ErrStat2,ErrMsg2) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL OpenFInpFile (UnIn,BldFile,ErrStat2,ErrMsg2) + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) if (ErrStat >= AbortErrLev) then return @@ -1942,8 +1946,10 @@ SUBROUTINE BD_PrintSum( p, x, OtherState, m, InitInp, ErrStat, ErrMsg ) ! Open the summary file and give it a heading. + !$OMP critical(filename) CALL GetNewUnit( UnSu, ErrStat, ErrMsg ) CALL OpenFOutFile ( UnSu, TRIM( InitInp%RootName )//'.sum.yaml', ErrStat, ErrMsg ) + !$OMP end critical(filename) IF ( ErrStat >= AbortErrLev ) RETURN ! Heading: diff --git a/modules/elastodyn/src/ElastoDyn.f90 b/modules/elastodyn/src/ElastoDyn.f90 index cbfdace5c6..4bce771cd6 100644 --- a/modules/elastodyn/src/ElastoDyn.f90 +++ b/modules/elastodyn/src/ElastoDyn.f90 @@ -9759,10 +9759,12 @@ SUBROUTINE ED_PrintSum( p, OtherState, ErrStat, ErrMsg ) ! Open the summary file and give it a heading. + !$OMP critical(filename) CALL GetNewUnit( UnSu, ErrStat, ErrMsg ) - IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( UnSu, TRIM( p%RootName )//'.sum', ErrStat, ErrMsg ) + if (ErrStat < AbortErrLev) then + CALL OpenFOutFile ( UnSu, TRIM( p%RootName )//'.sum', ErrStat, ErrMsg ) + endif + !$OMP end critical(filename) IF ( ErrStat /= ErrID_None ) RETURN diff --git a/modules/elastodyn/src/ElastoDyn_IO.f90 b/modules/elastodyn/src/ElastoDyn_IO.f90 index 5e32e39bd5..7cadb7c7d9 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -2064,12 +2064,13 @@ SUBROUTINE ReadTowerFile( TwrFile, InputFileData, UnEc, ErrStat, ErrMsg ) ErrMsg = "" + !$OMP critical(filename) CALL GetNewUnit( UnIn, ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN - + IF ( ErrStat < AbortErrLev ) THEN ! Open the tower input file. - - CALL OpenFInpFile ( UnIn, TwrFile, ErrStat2, ErrMsg2 ) + CALL OpenFInpFile ( UnIn, TwrFile, ErrStat2, ErrMsg2 ) + ENDIF + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() @@ -2406,14 +2407,13 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile ! Get an available unit number for the file. - + !$OMP critical(filename) CALL GetNewUnit( UnIn, ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN - - + IF ( ErrStat < AbortErrLev ) THEN ! Open the Primary input file. - - CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) + CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) + ENDIF + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() diff --git a/modules/hydrodyn/src/HydroDyn_Output.f90 b/modules/hydrodyn/src/HydroDyn_Output.f90 index 45a7450afa..113e7048bf 100644 --- a/modules/hydrodyn/src/HydroDyn_Output.f90 +++ b/modules/hydrodyn/src/HydroDyn_Output.f90 @@ -797,10 +797,10 @@ SUBROUTINE HDOut_OpenSum( UnSum, SummaryName, HD_Prog, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - + !$OMP critical(fileopen) CALL GetNewUnit( UnSum ) - CALL OpenFOutFile ( UnSum, SummaryName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1123,9 +1123,11 @@ SUBROUTINE HDOut_OpenOutput( HydroDyn_ProgDesc, OutRootName, p, InitOut, ErrSta ! Open the file for output OutFileName = TRIM(OutRootName)//'.out' - CALL GetNewUnit( p%UnOutFile ) + !$OMP critical(fileopen) + CALL GetNewUnit( p%UnOutFile ) CALL OpenFOutFile ( p%UnOutFile, OutFileName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN diff --git a/modules/hydrodyn/src/WAMIT2.f90 b/modules/hydrodyn/src/WAMIT2.f90 index 8155bfa691..a1fe008229 100644 --- a/modules/hydrodyn/src/WAMIT2.f90 +++ b/modules/hydrodyn/src/WAMIT2.f90 @@ -3106,16 +3106,13 @@ SUBROUTINE Read_DataFile3D( InitInp, Filename3D, Data3D, ErrStat, Errmsg ) !------------------------------------------------------------------------------ ! Find a unit number to use + !$OMP critical(fileopen) CALL GetNewUnit(UnitDataFile,ErrStatTmp,ErrMsgTmp) - CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - UnitDataFile = -1 - CALL CleanUp() - RETURN - ENDIF - - ! Open the file - CALL OpenFInpFile( UnitDataFile, TRIM(Filename3D), ErrStat, ErrMsg ) ! Open file containing mean drift information + if (ErrStatTmp < AbortErrLev) then + ! Open the file + CALL OpenFInpFile( UnitDataFile, TRIM(Filename3D), ErrStat, ErrMsg ) ! Open file containing mean drift information + endif + !$OMP end critical(fileopen) CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName) IF ( ErrStat >= AbortErrLev ) THEN UnitDataFile = -1 @@ -3780,15 +3777,13 @@ SUBROUTINE Read_DataFile4D( InitInp, Filename4D, Data4D, ErrStat, Errmsg ) !------------------------------------------------------------------------------ ! Find a unit number to use + !$OMP critical(fileopen) CALL GetNewUnit(UnitDataFile,ErrStatTmp,ErrMsgTmp) - CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName) - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanUp() - RETURN - ENDIF - + if (ErrStatTmp < AbortErrLev) then ! Open the file - CALL OpenFInpFile( UnitDataFile, TRIM(Filename4D), ErrStatTmp, ErrMsgTmp ) ! Open file containing mean drift information + CALL OpenFInpFile( UnitDataFile, TRIM(Filename4D), ErrStatTmp, ErrMsgTmp ) ! Open file containing mean drift information + endif + !$OMP end critical(fileopen) CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName) IF ( ErrStat >= AbortErrLev ) THEN CLOSE( UnitDataFile ) diff --git a/modules/inflowwind/CMakeLists.txt b/modules/inflowwind/CMakeLists.txt index 8e5b3c2e34..1e9b3a3063 100644 --- a/modules/inflowwind/CMakeLists.txt +++ b/modules/inflowwind/CMakeLists.txt @@ -19,6 +19,7 @@ if (GENERATE_TYPES) generate_f90_types(src/InflowWind_IO.txt ${CMAKE_CURRENT_LIST_DIR}/src/InflowWind_IO_Types.f90 -noextrap) generate_f90_types(src/Lidar.txt ${CMAKE_CURRENT_LIST_DIR}/src/Lidar_Types.f90) generate_f90_types(src/InflowWind.txt ${CMAKE_CURRENT_LIST_DIR}/src/InflowWind_Types.f90) + generate_f90_types(src/InflowWind_Driver_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/InflowWind_Driver_Types.f90 -noextrap) endif() # InflowWind object library diff --git a/modules/inflowwind/src/IfW_FlowField.f90 b/modules/inflowwind/src/IfW_FlowField.f90 index 9861a9692c..546359d16e 100644 --- a/modules/inflowwind/src/IfW_FlowField.f90 +++ b/modules/inflowwind/src/IfW_FlowField.f90 @@ -1628,6 +1628,7 @@ subroutine Grid4DField_GetVel(G4D, Time, Position, Velocity, ErrStat, ErrMsg) real(ReKi) :: P(3, 16) ! Point values real(ReKi) :: tmp integer(IntKi) :: i + character(60) :: PtLoc ErrStat = ErrID_None ErrMsg = "" @@ -1664,11 +1665,12 @@ subroutine Grid4DField_GetVel(G4D, Time, Position, Velocity, ErrStat, ErrMsg) do i = 1, 4 if (Indx_Lo(i) <= 0) then Indx_Lo(i) = 1 - call SetErrStat(ErrID_Fatal, 'Outside the grid bounds.', ErrStat, ErrMsg, RoutineName) + write(PtLoc,'(A1,3(f8.2,A1))') '(',Position(1),',',Position(2),',',Position(3),')' + call SetErrStat(ErrID_Fatal, 'Outside the grid bounds: '//trim(PtLoc), ErrStat, ErrMsg, RoutineName) return elseif (Indx_Lo(i) >= G4D%n(i)) then - Indx_Lo(i) = max(G4D%n(i) - 1, 1) ! make sure it's a valid index - call SetErrStat(ErrID_Fatal, 'Outside the grid bounds.', ErrStat, ErrMsg, RoutineName) + write(PtLoc,'(A1,3(f8.2,A1))') '(',Position(1),',',Position(2),',',Position(3),')' + call SetErrStat(ErrID_Fatal, 'Outside the grid bounds: '//trim(PtLoc), ErrStat, ErrMsg, RoutineName) return end if Indx_Hi(i) = min(Indx_Lo(i) + 1, G4D%n(i)) ! make sure it's a valid index diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 14ac13d755..eb0951492e 100644 --- a/modules/inflowwind/src/InflowWind.f90 +++ b/modules/inflowwind/src/InflowWind.f90 @@ -176,6 +176,15 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons CALL InflowWind_ValidateInput( InitInp, InputFileData, TmpErrStat, TmpErrMsg ); if (Failed()) return + ! Disable Lidar if not allowed (FAST.Farm doesn't allow this) + if (.not. InitInp%LidarEnabled) then + if (p%lidar%SensorType /= SensorType_None) then + call WrScr(' WARNING: LiDAR cannot be used with this instance of InflowWind (not usable with FAST.Farm).') + call WrScr(' --> Disabling LiDAR.') + p%lidar%SensorType = SensorType_None + end if + endif + ! initialize sensor data: p%lidar%SensorType = InputFileData%SensorType IF (InputFileData%SensorType /= SensorType_None) THEN diff --git a/modules/inflowwind/src/InflowWind.txt b/modules/inflowwind/src/InflowWind.txt index 3dd63debae..e62c055276 100644 --- a/modules/inflowwind/src/InflowWind.txt +++ b/modules/inflowwind/src/InflowWind.txt @@ -101,6 +101,7 @@ typedef ^ ^ IntKi MHK typedef ^ ^ ReKi WtrDpth - - - "Water depth" m typedef ^ ^ ReKi MSL2SWL - - - "Mean sea level to still water level" m typedef ^ ^ LOGICAL BoxExceedAllow - .FALSE. - "Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim)" - +typedef ^ ^ LOGICAL LidarEnabled - .false. - "Enable LiDAR for this instance of InflowWind? (FAST.Farm, ADI, and InflowWind driver/library are not compatible)" - # Init Output diff --git a/modules/inflowwind/src/InflowWind_Driver.f90 b/modules/inflowwind/src/InflowWind_Driver.f90 index 2ca88e84f1..42b29d1d11 100644 --- a/modules/inflowwind/src/InflowWind_Driver.f90 +++ b/modules/inflowwind/src/InflowWind_Driver.f90 @@ -39,6 +39,9 @@ PROGRAM InflowWind_Driver TYPE( ProgDesc ), PARAMETER :: ProgInfo = ProgDesc("InflowWind_Driver","","") INTEGER(IntKi) :: IfWDriver_Verbose = 5 ! Verbose level. 0 = none, 5 = some, 10 = lots + ! output paths hard coded + CHARACTER(*), PARAMETER :: VTKsliceDir = "vtk" ! Directory to place the output VTK slices + ! Types needed here (from InflowWind module) TYPE(InflowWind_InitInputType) :: InflowWind_InitInp ! Data for initialization -- this is where the input info goes TYPE(InflowWind_InputType) :: InflowWind_u1 ! input -- contains xyz coords of interest -- set 1 @@ -116,8 +119,23 @@ PROGRAM InflowWind_Driver CALL CPU_TIME( Timer(1) ) ! Set some CLSettings to null/default values - CLSettings%ProgInfo = ProgInfo - Settings%ProgInfo = ProgInfo + CLSettings%ProgInfo = ProgInfo + Settings%ProgInfo = ProgInfo + ! Set the filenames to empty strings -- otherwise prints garbage with the -vv option + CLSettings%DvrIptFileName = '' + CLSettings%IfWIptFileName = '' + CLSettings%SummaryFileName = '' + CLSettings%PointsFileName = '' + CLSettings%WindGridOutput%Name = '' + CLSettings%FFTOutput%Name = '' + CLSettings%PointsVelOutput%Name = '' + Settings%DvrIptFileName = '' + Settings%IfWIptFileName = '' + Settings%SummaryFileName = '' + Settings%PointsFileName = '' + Settings%WindGridOutput%Name = '' + Settings%FFTOutput%Name = '' + Settings%PointsVelOutput%Name = '' !-------------------------------------------------------------------------------------------------------------------------------- !-=-=- Parse the command line inputs -=-=- @@ -419,92 +437,61 @@ PROGRAM InflowWind_Driver InflowWind_p%FlowField%Grid3D%BoxExceedAllowDrv = .true. end if - ! Make sure no errors occured that give us reason to terminate now. - IF ( ErrStat >= AbortErrLev ) THEN - CALL DriverCleanup() - CALL ProgAbort( ErrMsg ) - ELSEIF ( ErrStat /= ErrID_None ) THEN - IF ( IfWDriver_Verbose >= 7_IntKi ) THEN - CALL WrScr(NewLine//' InflowWind_Init returned: ErrStat: '//TRIM(Num2LStr(ErrStat))// & - NewLine//' ErrMsg: '//TRIM(ErrMsg)//NewLine) - ELSEIF ( ErrStat >= ErrID_Warn ) THEN - CALL ProgWarn( ErrMsg ) - ELSE - CALL WrScr(TRIM(ErrMsg)) - ENDIF - ENDIF - + call CheckCallErr('InflowWind_Init') - ! Let user know we returned from the InflowWind code if verbose - IF ( IfWDriver_Verbose >= 5_IntKi ) CALL WrScr(NewLine//'InflowWind_Init CALL returned without errors.'//NewLine) - ! Convert InflowWind file to HAWC format IF (SettingsFlags%WrHAWC) THEN CALL IfW_WriteHAWC( InflowWind_p%FlowField, InflowWind_InitInp%RootName, ErrStat, ErrMsg ) - IF (ErrStat > ErrID_None) THEN - CALL WrScr( TRIM(ErrMsg) ) - IF ( ErrStat >= AbortErrLev ) THEN - CALL DriverCleanup() - CALL ProgAbort( ErrMsg ) - ELSEIF ( IfWDriver_Verbose >= 7_IntKi ) THEN - CALL WrScr(NewLine//' IfW_WriteHAWC returned: ErrStat: '//TRIM(Num2LStr(ErrStat))) - END IF - ELSE IF ( IfWDriver_Verbose >= 5_IntKi ) THEN - CALL WrScr(NewLine//'IfW_WriteHAWC CALL returned without errors.'//NewLine) - END IF + call CheckCallErr('IfW_WriteHAWC') END IF ! Convert InflowWind file to Native Bladed format IF (SettingsFlags%WrBladed) THEN CALL IfW_WriteBladed( InflowWind_p%FlowField, InflowWind_InitInp%RootName, ErrStat, ErrMsg ) - IF (ErrStat > ErrID_None) THEN - CALL WrScr( TRIM(ErrMsg) ) - IF ( ErrStat >= AbortErrLev ) THEN - CALL DriverCleanup() - CALL ProgAbort( ErrMsg ) - ELSEIF ( IfWDriver_Verbose >= 7_IntKi ) THEN - CALL WrScr(NewLine//' InflowWind_Convert2Bladed returned: ErrStat: '//TRIM(Num2LStr(ErrStat))) - END IF - ELSE IF ( IfWDriver_Verbose >= 5_IntKi ) THEN - CALL WrScr(NewLine//'InflowWind_Convert2Bladed CALL returned without errors.'//NewLine) - END IF + call CheckCallErr('IfW_WriteBladed') END IF + IF (SettingsFlags%WrVTK) THEN CALL IfW_WriteVTK( InflowWind_p%FlowField, InflowWind_InitInp%RootName, ErrStat, ErrMsg ) - IF (ErrStat > ErrID_None) THEN - CALL WrScr( TRIM(ErrMsg) ) - IF ( ErrStat >= AbortErrLev ) THEN - CALL DriverCleanup() - CALL ProgAbort( ErrMsg ) - ELSEIF ( IfWDriver_Verbose >= 7_IntKi ) THEN - CALL WrScr(NewLine//' IfW_WriteVTK returned: ErrStat: '//TRIM(Num2LStr(ErrStat))) - END IF - ELSE IF ( IfWDriver_Verbose >= 5_IntKi ) THEN - CALL WrScr(NewLine//'IfW_WriteVTK CALL returned without errors.'//NewLine) - END IF - + call CheckCallErr('IfW_WriteVTK') END IF IF (SettingsFlags%WrUniform) THEN CALL IfW_WriteUniform( InflowWind_p%FlowField, InflowWind_InitInp%RootName, ErrStat, ErrMsg ) - IF (ErrStat > ErrID_None) THEN - CALL WrScr( TRIM(ErrMsg) ) - IF ( ErrStat >= AbortErrLev ) THEN - CALL DriverCleanup() - CALL ProgAbort( ErrMsg ) - ELSEIF ( IfWDriver_Verbose >= 7_IntKi ) THEN - CALL WrScr(NewLine//' IfW_WriteUniform returned: ErrStat: '//TRIM(Num2LStr(ErrStat))) - END IF - ELSE IF ( IfWDriver_Verbose >= 5_IntKi ) THEN - CALL WrScr(NewLine//'IfW_WriteUniform CALL returned without errors.'//NewLine) - END IF + call CheckCallErr('IfW_WriteUniform') END IF + + IF (Settings%NOutWindXY>0) THEN + do i=1,Settings%NOutWindXY + CALL IfW_WriteXYslice( InflowWind_p%FlowField, InflowWind_InitInp%RootName, VTKsliceDir, Settings%OutWindZ(i), ErrStat, ErrMsg ) + call CheckCallErr('IfW_WriteXYslice'//trim(Num2LStr(i))) + enddo + END IF + + +!FIXME: future developent +! IF (Settings%NOutWindXZ>0) THEN +! do i=1,Settings%NOutWindXZ +! CALL IfW_WriteXZslice( InflowWind_p%FlowField, InflowWind_InitInp%RootName, VTKsliceDir, Settings%OutWindY(i), ErrStat, ErrMsg ) +! call CheckCallErr('IfW_WriteXZslice'//trim(Num2LStr(i))) +! enddo +! END IF + + +! IF (Settings%NOutWindYZ>0) THEN +! do i=1,Settings%NOutWindYZ +! CALL IfW_WriteYZslice( InflowWind_p%FlowField, InflowWind_InitInp%RootName, VTKsliceDir, Settings%OutWindX(i), ErrStat, ErrMsg ) +! call CheckCallErr('IfW_WriteYZslice'//trim(Num2LStr(i))) +! enddo +! END IF + + !-------------------------------------------------------------------------------------------------------------------------------- !-=-=- Other Setup -=-=- !-------------------------------------------------------------------------------------------------------------------------------- @@ -942,6 +929,22 @@ SUBROUTINE DriverCleanup() END SUBROUTINE DriverCleanup + subroutine CheckCallErr(RoutineName) + character(*), intent(in) :: RoutineName + if (ErrStat > ErrID_None) then + call WrScr( trim(ErrMsg) ) + if ( ErrStat >= AbortErrLev ) then + call DriverCleanup() + call ProgAbort( ErrMsg ) + elseif ( IfWDriver_Verbose >= 7_IntKi ) then + call WrScr(NewLine//' '//trim(RoutineName)//' returned: ErrStat: '//TRIM(Num2LStr(ErrStat))) + endif + elseif ( IfWDriver_Verbose >= 5_IntKi ) then + CALL WrScr(NewLine//trim(RoutineName)//' CALL returned without errors.'//NewLine) + endif + end subroutine CheckCallErr + + END PROGRAM InflowWind_Driver diff --git a/modules/inflowwind/src/InflowWind_Driver_Registry.txt b/modules/inflowwind/src/InflowWind_Driver_Registry.txt new file mode 100644 index 0000000000..3863019d77 --- /dev/null +++ b/modules/inflowwind/src/InflowWind_Driver_Registry.txt @@ -0,0 +1,91 @@ +#---------------------------------------------------------------------------------------------------------------------------------- +# Registry for IfW_Interp, creates MODULE IfW_Interp_Types +# Module IfW_Interp_Types contains all of the user-defined types needed in IfW_FF. It also contains copy, destroy, pack, and +# unpack routines associated with each defined data types. +#---------------------------------------------------------------------------------------------------------------------------------- +# keyword +#---------------------------------------------------------------------------------------------------------------------------------- + +include Registry_NWTC_Library.txt + +#---------------------------------------------------------------------------------------------------------------------------------- +typedef InflowWind_Driver OutputFile character(1024) Name - "" - "Filename for output from points read in from points file" - +typedef ^ ^ integer Unit - -1 - "Unit number for the output file for the Points file output" - +typedef ^ ^ logical Initialized - .false. - "Flag indicating that file has been initialized" - + +# This contains flags to note if the settings were made. This same data structure is +# used both during the driver input file and the command line options. +# +# NOTE: The WindFileType is only set if it is given as a command line option. Otherwise +# it is handled internally by InflowWInd. +# +# NOTE: The wind direction is specified by the InflowWind input file. +#---------------------------------------------------------------------------------------------------------------------------------- +typedef InflowWind_Driver IfWDriver_Flags logical DvrIptFile - .false. - "Was an input file name given on the command line?" - +typedef ^ ^ logical IfWIptFile - .false. - "Was an InflowWind input file requested?" - +typedef ^ ^ logical Summary - .false. - "create a summary at command line? (data extents in the wind file)" - +typedef ^ ^ logical SummaryFile - .false. - "create a summary file of the output?" - +typedef ^ ^ logical TStart - .false. - "specified a start time" - +typedef ^ ^ logical NumTimeSteps - .false. - "specified a number of timesteps to process" - +typedef ^ ^ logical NumTimeStepsDefault - .false. - "specified a 'DEFAULT' for number of timesteps to process" - +typedef ^ ^ logical DT - .false. - "specified a resolution in time" - +typedef ^ ^ logical DTDefault - .false. - "specified a 'DEFAULT' for the time resolution" - + +typedef ^ ^ logical FFTcalc - .false. - "do an FFT" - + +typedef ^ ^ logical WindGrid - .false. - "Requested output of wind data on a grid -- input file option only" - +typedef ^ ^ logical XRange - .false. - "specified a range of x -- command line option only -- stored as GridCtrCoord and GridDelta" - +typedef ^ ^ logical YRange - .false. - "specified a range of y -- command line option only -- stored as GridCtrCoord and GridDelta" - +typedef ^ ^ logical ZRange - .false. - "specified a range of z -- command line option only -- stored as GridCtrCoord and GridDelta" - +typedef ^ ^ logical Dx - .false. - "specified a resolution in x -- command line option only, 0.0 otherwise" - +typedef ^ ^ logical Dy - .false. - "speficied a resolution in y" - +typedef ^ ^ logical Dz - .false. - "specified a resolution in z" - + +typedef ^ ^ logical PointsFile - .false. - "points filename to read in" - +typedef ^ ^ logical OutputAccel - .false. - "flag to calculate and output wind acceleration in addition to velocity" - + +typedef ^ ^ logical Verbose - .false. - "Verbose error reporting" - +typedef ^ ^ logical VVerbose - .false. - "Very Verbose error reporting" - +typedef ^ ^ logical BoxExceedAllowF - .false. - "set flag to allow exceeding wind box boundaries for FF files (for diagnostic purposes)" - + +typedef ^ ^ logical WrHAWC - .false. - "Requested file conversion to HAWC2 format?" - +typedef ^ ^ logical WrBladed - .false. - "Requested file conversion to Bladed format?" - +typedef ^ ^ logical WrVTK - .false. - "Requested file output as VTK?" - +typedef ^ ^ logical WrUniform - .false. - "Requested file output as Uniform wind format?" - + +typedef ^ ^ logical XYslice - .false. - "Take XY slice at one elevation" - + + + +# This contains all the settings (possible passed in arguments). +#---------------------------------------------------------------------------------------------------------------------------------- +typedef InflowWind_Driver IfWDriver_Settings character(1024) DvrIptFileName - "" - "Driver input file name" - +typedef ^ ^ character(1024) IfWIptFileName - "" - "Filename of InflowWind input file to read (if no driver input file)" - +typedef ^ ^ character(1024) SummaryFileName - "" - "Filename for the summary information output" - + +typedef ^ ^ character(1024) PointsFileName - "" - "Filename of points file to read in" - + +typedef ^ ^ IntKi NumTimeSteps - 0 - "Number of timesteps" - +typedef ^ ^ DbKi DT - 0.0_DbKi - "resolution of time" s +typedef ^ ^ DbKi TStart - 0.0_DbKi - "range of time -- end time converted from TRange (command line option only)" s + +typedef ^ ^ ReKi FFTcoord(1:3) - 0.0_ReKi - "(x,y,z) coordinate to do an FFT at" (m) + +typedef ^ ^ ReKi GridDelta(1:3) - 0.0_ReKi - "(GridDx,GridDy,GridDz) -- grid point spacing" (m) +typedef ^ ^ IntKi GridN(1:3) - 1_IntKi - "(GridNx,GridNy,GridNz) -- number of grid points" - + +typedef ^ ^ ReKi XRange(1:2) - 0.0_ReKi - "Range in the x-direction for the gridded data" (m) +typedef ^ ^ ReKi YRange(1:2) - 0.0_ReKi - "Range in the y-direction for the gridded data" (m) +typedef ^ ^ ReKi ZRange(1:2) - 0.0_ReKi - "Range in the z-direction for the gridded data" (m) + +typedef ^ ^ ProgDesc ProgInfo - - - "Program info" - +typedef ^ ^ OutputFile WindGridOutput - - - "Wind grid file handling" - +typedef ^ ^ OutputFile FFTOutput - - - "FFT file handling" - +typedef ^ ^ OutputFile PointsVelOutput - - - "Points output velocity file handling" - + +typedef ^ ^ IntKi NOutWindXY - 0 - "Number of XY planes for output .XY.t.vtk [0 to 9]" - +typedef ^ ^ ReKi OutWindZ : - - "Z coordinates of XY planes for output [1 to NOutWindXY] [unused for NOutWindXY=0]" (m) +typedef ^ ^ IntKi NOutWindXZ - 0 - "Number of YZ planes for output .YZ.t.vtk [0 to 9]" - +typedef ^ ^ ReKi OutWindY : - - "Y coordinates of YZ planes for output [1 to NOutWindYZ] [unused for NOutWindYZ=0]" (m) +typedef ^ ^ IntKi NOutWindYZ - 0 - "Number of YZ planes for output .YZ.t.vtk [0 to 9]" - +typedef ^ ^ ReKi OutWindX : - - "X coordinates of YZ planes for output [1 to NOutWindYZ] [unused for NOutWindYZ=0]" (m) diff --git a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 index 186b3435df..98d7fdf293 100644 --- a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 @@ -734,18 +734,12 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat ! Initialize the echo file unit to -1 which is the default to prevent echoing, we will alter this based on user input UnEchoLocal = -1 - FileName = TRIM(DvrFileName) + ErrStat = ErrID_None + ErrMsg = "" CALL GetNewUnit( UnIn ) - CALL OpenFInpFile( UnIn, FileName, ErrStatTmp, ErrMsgTmp ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,' Failed to open InflowWind Driver input file: '//FileName, & - ErrStat,ErrMsg,RoutineName) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL OpenFInpFile( UnIn, FileName, ErrStatTmp, ErrMsgTmp ); if (Failed()) return CALL WrScr( 'Opening InflowWind Driver input file: '//FileName ) @@ -754,30 +748,9 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat !------------------------------------------------------------------------------------------------- ! File header !------------------------------------------------------------------------------------------------- - - CALL ReadCom( UnIn, FileName,' InflowWind Driver input file header line 1', ErrStatTmp, ErrMsgTmp ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CLOSE( UnIn ) - RETURN - ENDIF - - - CALL ReadCom( UnIn, FileName, 'InflowWind Driver input file header line 2', ErrStatTmp, ErrMsgTmp ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CLOSE( UnIn ) - RETURN - ENDIF - - - ! Echo Input Files. - CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadCom( UnIn, FileName,' InflowWind Driver input file header line 1', ErrStatTmp, ErrMsgTmp ); if (Failed()) return + CALL ReadCom( UnIn, FileName, 'InflowWind Driver input file header line 2', ErrStatTmp, ErrMsgTmp ); if (Failed()) return + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp ); if (Failed()) return ! If we are Echoing the input then we should re-read the first three lines so that we can echo them @@ -788,44 +761,15 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat EchoFileName = TRIM(FileName)//'.ech' CALL GetNewUnit( UnEchoLocal ) - CALL OpenEcho ( UnEchoLocal, EchoFileName, ErrStatTmp, ErrMsgTmp, ProgInfo ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL OpenEcho ( UnEchoLocal, EchoFileName, ErrStatTmp, ErrMsgTmp, ProgInfo ); if (Failed()) return REWIND(UnIn) ! Reread and echo - CALL ReadCom( UnIn, FileName,' InflowWind Driver input file header line 1', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - - - CALL ReadCom( UnIn, FileName, 'InflowWind Driver input file header line 2', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - - - ! Echo Input Files. - CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadCom( UnIn, FileName,' InflowWind Driver input file header line 1', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadCom( UnIn, FileName, 'InflowWind Driver input file header line 2', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return @@ -835,78 +779,30 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat !------------------------------------------------------------------------------------------------- ! Driver setup section !------------------------------------------------------------------------------------------------- - - ! Header - CALL ReadCom( UnIn, FileName,' Driver setup section, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL ReadCom( UnIn, FileName,' Driver setup section, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Name of InflowWind input file - CALL ReadVar( UnIn, FileName,DvrSettings%IfWIptFileName,'IfWIptFileName',' InflowWind input filename', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ELSE - DvrFlags%IfWIptFile = .TRUE. - ENDIF - + CALL ReadVar( UnIn, FileName,DvrSettings%IfWIptFileName,'IfWIptFileName',' InflowWind input filename', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + DvrFlags%IfWIptFile = .TRUE. IF ( PathIsRelative( DvrSettings%IfWIptFileName ) ) DvrSettings%IfWIptFileName = TRIM(PriPath)//TRIM(DvrSettings%IfWIptFileName) !------------------------------------------------------------------------------------------------- ! File Conversion Options section !------------------------------------------------------------------------------------------------- - - ! Header - CALL ReadCom( UnIn, FileName,'File Conversion Options Section Header', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - - ! WrHAWC - CALL ReadVar( UnIn, FileName, DvrFlags%WrHAWC, 'WrHAWC', 'Convert wind data to HAWC2 format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + CALL ReadCom( UnIn, FileName,'File Conversion Options Section Header', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName, DvrFlags%WrHAWC, 'WrHAWC', 'Convert wind data to HAWC2 format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName, DvrFlags%WrBladed, 'WrBladed', 'Convert wind data to Bladed format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName, DvrFlags%WrVTK, 'WrVTK', 'Convert wind data to VTK format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName, DvrFlags%WrUniform, 'WrUniform','Convert wind data to Uniform Wind format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return - ! WrBladed - CALL ReadVar( UnIn, FileName, DvrFlags%WrBladed, 'WrBladed', 'Convert wind data to Bladed format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - - ! WrVTK - CALL ReadVar( UnIn, FileName, DvrFlags%WrVTK, 'WrVTK', 'Convert wind data to VTK format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - - ! WrUniform - CALL ReadVar( UnIn, FileName, DvrFlags%WrUniform, 'WrUniform', 'Convert wind data to Uniform Wind format?', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - - IF ( ErrStat >= AbortErrLev ) THEN - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - !------------------------------------------------------------------------------------------------- ! Tests of Interpolation Options section !------------------------------------------------------------------------------------------------- - CALL ReadCom( UnIn, FileName,'Tests of Interpolation Options Section Header', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - CALL SetErrStat(ErrStatTmp, ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - + CALL ReadCom( UnIn, FileName,'Tests of Interpolation Options Section Header', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Number of timesteps - CALL ReadVar( UnIn, FileName,NumTimeStepsChr,'NumTimeStepsChr',' Character string for number of timesteps to read.', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadVar( UnIn, FileName,NumTimeStepsChr,'NumTimeStepsChr',' Number of timesteps to read.', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Check if we asked for the DEFAULT (use what is in the file) CALL Conv2UC( NumTimeStepsChr ) @@ -918,8 +814,7 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat ! make sure that it was appropriately interpretted. READ (NumTimeStepsChr,*,IOSTAT=IOS) DvrSettings%NumTimeSteps IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. - CALL CheckIOS ( IOS, '', 'NumTimeSteps',NumType, ErrStatTmp, ErrMsgTmp ) - RETURN + CALL CheckIOS ( IOS, '', 'NumTimeSteps',NumType, ErrStatTmp, ErrMsgTmp ); if (Failed()) return ELSE ! Was ok, so set the flags DvrFlags%NumTimeSteps = .TRUE. DvrFlags%NumTimeStepsDefault = .FALSE. @@ -928,27 +823,11 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat ! TStart -- start time - CALL ReadVar( UnIn, FileName,DvrSettings%TStart,'TStart',' Time in wind file to start parsing.', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ELSE - DvrFlags%TStart = .TRUE. - ENDIF - + CALL ReadVar( UnIn, FileName,DvrSettings%TStart,'TStart',' Time in wind file to start parsing.', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + DvrFlags%TStart = .TRUE. ! DT -- Timestep size for the driver to take (or DEFAULT for what the file contains) - CALL ReadVar( UnIn, FileName,DTChr,'DTChr',' Character string for Timestep size for the driver to take (or DEFAULT for what the file contains).', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadVar( UnIn, FileName,DTChr,'DTChr',' Character string for Timestep', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Check if we asked for the DEFAULT (use what is in the file) CALL Conv2UC( DTChr ) @@ -960,8 +839,7 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat ! make sure that it was appropriately interpretted. READ (DTChr,*,IOSTAT=IOS) DvrSettings%DT IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. - CALL CheckIOS ( IOS, '', 'DT',NumType, ErrStatTmp, ErrMsgTmp ) - RETURN + CALL CheckIOS ( IOS, '', 'DT',NumType, ErrStatTmp, ErrMsgTmp ); if (Failed()) return ELSE ! Was ok, so set the flags DvrFlags%DT = .TRUE. DvrFlags%DTDefault = .FALSE. @@ -969,213 +847,75 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat ENDIF - ! Summarize the extents in the windfile - CALL ReadVar( UnIn, FileName,DvrFlags%Summary,'Summary',' Summarize data extents in the windfile', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN -! ELSE -! DvrFlags%Summary = .TRUE. - ENDIF - - - ! Summarize everything in a summary file/ - CALL ReadVar( UnIn, FileName,DvrFlags%SummaryFile,'SummaryFile',' Summarize the results in a .sum file', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN -! ELSE -! DvrFlags%SummaryFile = .TRUE. - ENDIF + ! Summary info + CALL ReadVar( UnIn, FileName,DvrFlags%Summary, 'Summary', ' Summarize data extents in the windfile', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName,DvrFlags%SummaryFile,'SummaryFile',' Summarize the results in a .sum file', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Flag to allow sampling outside grid - CALL ReadVar( UnIn, FileName,DvrFlags%BoxExceedAllowF,'BoxExceedAllow',' Allow point sampling outside grid', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadVar( UnIn, FileName,DvrFlags%BoxExceedAllowF,'BoxExceedAllow',' Allow point sampling outside grid', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + #ifdef UNUSED_INPUTFILE_LINES !------------------------------------------------------------------------------------------------- ! FFT calculations !------------------------------------------------------------------------------------------------- - - ! Header - CALL ReadCom( UnIn, FileName,' FFT calculations, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - - - ! FFTcalc -- FFTcalc of the windfield needed. - CALL ReadVar( UnIn, FileName,DvrFlags%FFTcalc,'FFTcalc',' Perform an FFT?', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL ReadCom( UnIn, FileName,' FFT calculations, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName,DvrFlags%FFTcalc,'FFTcalc',' Perform an FFT?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Read the coordinate for the FFT if the flag is set, otherwise skip the line IF ( DvrFlags%FFTcalc ) THEN ! FFTcoord -- The coordinates to perform the FFT at - CALL ReadAry ( UnIn, FileName, DvrSettings%FFTcoord, 3, 'FFTcoord', & - 'FFT coordinate', ErrStatTmp, ErrMsgTmp, UnEchoLocal) - IF ( ErrStat /= ErrID_None ) THEN - CALL SetErrStat( ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadAry ( UnIn, FileName, DvrSettings%FFTcoord, 3, 'FFTcoord', 'FFT coordinate', ErrStatTmp, ErrMsgTmp, UnEchoLocal); if (Failed()) return ELSE - CALL ReadCom( UnIn, FileName,' Skipping the FFT coordinate since not doint an FFT.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadCom( UnIn, FileName,' Skipping the FFT coordinate since not doint an FFT.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ENDIF - #endif + !------------------------------------------------------------------------------------------------- ! points file input !------------------------------------------------------------------------------------------------- - - ! Header line - CALL ReadCom( UnIn, FileName,' Points file input, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - - - ! PointsFile -- Read a points file - CALL ReadVar( UnIn, FileName,DvrFlags%PointsFile,'PointsFile',' Read a points file?', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - - - ! Points input file (unused if .not. DvrFlags%PointsFile) - CALL ReadVar( UnIn, FileName,DvrSettings%PointsFileName,'PointsFileName',' Points file input filename', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL ReadCom( UnIn, FileName,' Points file input, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName,DvrFlags%PointsFile, 'PointsFile', ' Read a points file?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadVar( UnIn, FileName,DvrSettings%PointsFileName,'PointsFileName',' Points file input filename', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return IF ( PathIsRelative( DvrSettings%PointsFileName ) ) DvrSettings%PointsFileName = TRIM(PriPath)//TRIM(DvrSettings%PointsFileName) ! CalcAccel - calculate wind acceleration (unused if .not. DvrFlags%PointsFile) - CALL ReadVar( UnIn, FileName,DvrFlags%OutputAccel, 'CalcAccel', ' Calc and output wind acceleration', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadVar( UnIn, FileName,DvrFlags%OutputAccel, 'CalcAccel', ' Calc and output wind acceleration', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + !------------------------------------------------------------------------------------------------- ! gridded data output !------------------------------------------------------------------------------------------------- - - ! Header - CALL ReadCom( UnIn, FileName,' Gridded data output, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - + CALL ReadCom( UnIn, FileName,' Gridded data output, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! WindGrid -- Gridded data output - CALL ReadVar( UnIn, FileName,DvrFlags%WindGrid,'WindGrid',' Output a grid of data?', & - ErrStatTmp,ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadVar( UnIn, FileName,DvrFlags%WindGrid,'WindGrid',' Output a grid of data?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return - ! Read the coordinate for the FFT if the flag is set, otherwise skip the line + ! Read the coordinate for the WindGrid if the flag is set, otherwise skip the line IF ( DvrFlags%WindGrid ) THEN ! GridCtrCoord -- The coordinates to center the gridded data at - CALL ReadAry ( UnIn, FileName, GridCtrCoord, 3, 'GridCtrCoord', & - 'Coordinate of the center of the gridded data', ErrStatTmp, ErrMsgTmp, UnEchoLocal) - IF ( ErrStat /= ErrID_None ) THEN - CALL SetErrStat( ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadAry ( UnIn, FileName, GridCtrCoord, 3, 'GridCtrCoord', 'Coordinate of the center of the gridded data', ErrStatTmp, ErrMsgTmp, UnEchoLocal); if (Failed()) return ! Read the DY and DZ stepsize - CALL ReadAry ( UnIn, FileName, TmpRealAr3, 3, 'GridDX, GridDY, GridDZ', & - 'GridDX, GridDY, GridDZ', ErrStatTmp, ErrMsgTmp, UnEchoLocal) - IF ( ErrStat /= ErrID_None ) THEN - CALL SetErrStat( ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadAry ( UnIn, FileName, TmpRealAr3, 3, 'GridDX, GridDY, GridDZ', 'GridDX, GridDY, GridDZ', ErrStatTmp, ErrMsgTmp, UnEchoLocal); if (Failed()) return ! Save the DY and DZ values - DvrSettings%GridDelta(1) = abs(TmpRealAr3(1)) ! X direction - DvrSettings%GridDelta(2) = abs(TmpRealAr3(2)) ! Y direction - DvrSettings%GridDelta(3) = abs(TmpRealAr3(3)) ! Z direction + DvrSettings%GridDelta(1:3) = abs(TmpRealAr3(1:3)) DvrFlags%Dx = .TRUE. ! read in value for the X direction gridding DvrFlags%Dy = .TRUE. ! read in value for the Y direction gridding DvrFlags%Dz = .TRUE. ! read in value for the Z direction gridding ! Read the number of points in the Y and Z directions - CALL ReadAry ( UnIn, FileName, TmpIntAr3, 3, 'GridNx, GridNY, GridNZ', & - 'GridNx, GridNY, GridNZ', ErrStatTmp, ErrMsgTmp, UnEchoLocal) - IF ( ErrStat /= ErrID_None ) THEN - CALL SetErrStat( ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadAry ( UnIn, FileName, DvrSettings%GridN, 3, 'GridNx, GridNY, GridNZ', 'GridNx, GridNY, GridNZ', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ! Save the GridNY and GridNZ values - DvrSettings%GridN(1) = TmpIntAr3(1) ! X direction - DvrSettings%GridN(2) = TmpIntAr3(2) ! Y direction - DvrSettings%GridN(3) = TmpIntAr3(3) ! Z direction - DvrFlags%XRange = .TRUE. ! read in value for the X direction gridding - DvrFlags%YRange = .TRUE. ! read in value for the Y direction gridding - DvrFlags%ZRange = .TRUE. ! read in value for the Z direction gridding - + DvrFlags%XRange = .TRUE. ! read in value for the X direction gridding + DvrFlags%YRange = .TRUE. ! read in value for the Y direction gridding + DvrFlags%ZRange = .TRUE. ! read in value for the Z direction gridding ! Check that valid values of Dx, Dy, and Dz were read in. @@ -1269,10 +1009,8 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat DvrFlags%ZRange = .TRUE. ENDIF - ELSE ! read these lines as comments (actually, we don't need to read them) - DvrSettings%GridDelta = 0.0_ReKi DvrFlags%Dx = .FALSE. DvrFlags%Dy = .FALSE. @@ -1284,34 +1022,48 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat DvrFlags%ZRange = .FALSE. ! Skip the next three entries of the gridded data section. - CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF - CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) - IF ( ErrStatTmp /= ErrID_None ) THEN - CALL SetErrStat(ErrID_Fatal,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) - RETURN - ENDIF + CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + CALL ReadCom( UnIn, FileName,' Skipping the gridded data section since not calculating it.', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return ENDIF + !------------------------------------------------------------------------------------------------- + ! VTK output slices + !------------------------------------------------------------------------------------------------- + CALL ReadCom( UnIn, FileName,' VTK output slices, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ); if (Failed()) return + + ! NOutWindXY -- Number of XY planes for output .XY.t.vtk (-) [0 to 9] + CALL ReadVar( UnIn, FileName,DvrSettings%NOutWindXY, 'NOutWindXY','Number of VTK slices in XY?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + if (DvrSettings%NOutWindXY > 0_IntKi) then + CALL AllocAry( DvrSettings%OutWindZ, DvrSettings%NOutWindXY, "Z coordinates of XY planes for output", ErrStatTmp,ErrMsgTmp ); if (Failed()) return + CALL ReadAry( UnIn, FileName,DvrSettings%OutWindZ,DvrSettings%NOutWindXY,'OutWindZ','Z coordinates', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return + else + CALL ReadCom( UnIn, FileName,' Skipping OutWindZ', ErrStatTmp,ErrMsgTmp,UnEchoLocal); if (Failed()) return + endif + +!FIXME: future development +! ! NOutWindXZ -- Number of XZ planes for output .XZ.t.vtk (-) [0 to 9] +! CALL ReadVar( UnIn, FileName,DvrSettings%NOutWindXZ, 'NOutWindXZ','Number of VTK slices in XZ?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return +! if (DvrSettings%NOutWindXZ > 0_IntKi) then +! CALL AllocAry( DvrSettings%OutWindY, DvrSettings%NOutWindXZ, "Y coordinates of XZ planes for output",ErrStatTmp,ErrMsgTmp ); if (Failed()) return +! CALL ReadAry( UnIn, FileName,DvrSettings%OutWindY,DvrSettings%NOutWindXZ,'OutWindY','Y coordinates' ,ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return +! else +! CALL ReadCom( UnIn, FileName,' Skipping OutWindY', ErrStatTmp,ErrMsgTmp,UnEchoLocal); if (Failed()) return +! endif +! +! ! NOutWindYZ -- Number of YZ planes for output .YZ.t.vtk (-) [0 to 9] +! CALL ReadVar( UnIn, FileName,DvrSettings%NOutWindYZ, 'NOutWindYZ','Number of VTK slices in YZ?', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return +! if (DvrSettings%NOutWindYZ > 0_IntKi) then +! CALL AllocAry( DvrSettings%OutWindX, DvrSettings%NOutWindYZ, "X coordinates of YZ planes for output", ErrStatTmp,ErrMsgTmp ); if (Failed()) return +! CALL ReadAry( UnIn, FileName,DvrSettings%OutWindX,DvrSettings%NOutWindYZ,'OutWindX','X coordinates', ErrStatTmp,ErrMsgTmp, UnEchoLocal ); if (Failed()) return +! else +! CALL ReadCom( UnIn, FileName,' Skipping OutWindX', ErrStatTmp,ErrMsgTmp,UnEchoLocal); if (Failed()) return +! endif + ! Close the echo and input file - CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) - CLOSE( UnIn ) + CALL Cleanup() CONTAINS @@ -1319,17 +1071,19 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat !---------------------------------------------------------------------------------------------------- !> The routine cleans up the module echo file and resets the NWTC_Library, reattaching it to !! any existing echo information - SUBROUTINE CleanupEchoFile( EchoFlag, UnEcho) - LOGICAL, INTENT(IN ) :: EchoFlag ! local version of echo flag - INTEGER(IntKi), INTENT(IN ) :: UnEcho ! echo unit number - - ! Close this module's echo file - IF ( EchoFlag ) THEN - CLOSE(UnEcho) + subroutine Cleanup() + ! Close this module's echo file + IF ( EchoFileContents ) THEN + CLOSE(UnEchoLocal) ENDIF - END SUBROUTINE CleanupEchoFile - - + if (UnIn > 1) close(UnIn) + end subroutine Cleanup + !------------------------------------------------------------------------------------------------- + logical function Failed() + CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + if (Failed) CALL Cleanup() + end function Failed END SUBROUTINE ReadDvrIptFile @@ -2623,6 +2377,50 @@ subroutine IfW_WriteVTK(FF, FileRootName, ErrStat, ErrMsg) end subroutine IfW_WriteVTK +subroutine IfW_WriteXYslice(FF, FileRootName, vtk_dir, XYslice_height, ErrStat, ErrMsg) + type(FlowFieldType), intent(in ) :: FF !< Parameters + character(*), intent(in ) :: FileRootName !< RootName for output files + character(*), intent(in ) :: vtk_dir !< Directory for vtk slice outputs + real(ReKi), intent(in ) :: XYslice_height + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + character(*), parameter :: RoutineName = "IfW_WriteXYslice" + type(Grid3DFieldType) :: G3D + integer(IntKi) :: unit + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat = ErrID_None + ErrMsg = "" + + ! Get new unit for writing file + call GetNewUnit(unit, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + + ! Switch based on field type + select case (FF%FieldType) + + case (Uniform_FieldType) + call Uniform_to_Grid3D(FF%Uniform, FF%VelInterpCubic, G3D, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat < AbortErrLev) then + call Grid3D_WriteVTKsliceXY(G3D, FileRootName, vtk_dir, XYslice_height, unit, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end if + + case (Grid3D_FieldType) + call Grid3D_WriteVTKsliceXY(FF%Grid3D, FileRootName, vtk_dir, XYslice_height, unit, ErrStat, ErrMsg) + + case default + ErrStat = ErrID_Warn + ErrMsg = RoutineName//': Field type '//TRIM(Num2LStr(FF%FieldType))// & + ' cannot be converted to VTK format.' + end select +end subroutine IfW_WriteXYslice + + !> This routine exists only to support the development of the module. It will not be needed after the module is complete. SUBROUTINE printSettings( DvrFlags, DvrSettings ) ! The arguments @@ -2671,6 +2469,25 @@ SUBROUTINE printSettings( DvrFlags, DvrSettings ) CALL WrScr(' FFTOutputInit: '//FLAG(DvrSettings%FFTOutput%Initialized)// ' Unit #: '//TRIM(Num2LStr(DvrSettings%FFTOutput%Unit))) CALL WrScr(' PointsVelOutputInit: '//FLAG(DvrSettings%PointsVelOutput%Initialized)// ' Unit #: '//TRIM(Num2LStr(DvrSettings%PointsVelOutput%Unit))) CALL WrScr(' PointsAccOutputInit: '//FLAG(DvrSettings%PointsVelOutput%Initialized)// ' Unit #: '//TRIM(Num2LStr(DvrSettings%PointsVelOutput%Unit))) + call WrScr(' NOutWindXY: '//trim(Num2LStr(DvrSettings%NOutWindXY))) + if (DvrSettings%NOutWindXY>0) then + do i=1,DvrSettings%NOutWindXY + call WrScr(' z location '//trim(Num2LStr(i))//': '//trim(Num2LStr(DvrSettings%OutWindZ(i)))) + enddo + endif + call WrScr(' NOutWindXZ: '//trim(Num2LStr(DvrSettings%NOutWindXZ))) + if (DvrSettings%NOutWindXZ>0) then + do i=1,DvrSettings%NOutWindXZ + call WrScr(' y location '//trim(Num2LStr(i))//': '//trim(Num2LStr(DvrSettings%OutWindY(i)))) + enddo + endif + call WrScr(' NOutWindYZ: '//trim(Num2LStr(DvrSettings%NOutWindYZ))) + if (DvrSettings%NOutWindYZ>0) then + do i=1,DvrSettings%NOutWindYZ + call WrScr(' x location '//trim(Num2LStr(i))//': '//trim(Num2LStr(DvrSettings%OutWindX(i)))) + enddo + endif + END SUBROUTINE printSettings diff --git a/modules/inflowwind/src/InflowWind_Driver_Types.f90 b/modules/inflowwind/src/InflowWind_Driver_Types.f90 index 669303cf60..6768f63819 100644 --- a/modules/inflowwind/src/InflowWind_Driver_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Driver_Types.f90 @@ -1,111 +1,433 @@ -!********************************************************************************************************************************** +!STARTOFREGISTRYGENERATEDFILE 'InflowWind_Driver_Types.f90' ! -! MODULE: IfW_Driver_Types - This module contains types used by the InflowWind Driver program to store arguments passed in +! WARNING This file is generated automatically by the FAST registry. +! Do not edit. Your changes to this file will be lost. ! -! The types listed here are used within the InflowWind Driver program to store the settings. These settings are read in as -! command line arguments, then stored within these types. +! FAST Registry +!********************************************************************************************************************************* +! InflowWind_Driver_Types +!................................................................................................................................. +! This file is part of InflowWind_Driver. ! -!********************************************************************************************************************************** +! Copyright (C) 2012-2016 National Renewable Energy Laboratory ! -!.................................................................................................................................. -! LICENSING -! Copyright (C) 2015 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 ! -! This file is part of InflowWind. +! http://www.apache.org/licenses/LICENSE-2.0 ! -! InflowWind is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as -! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. ! -! This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty -! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ! -! You should have received a copy of the GNU General Public License along with InflowWind. -! If not, see . +! 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 InflowWind_Driver. 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 InflowWind_Driver_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE NWTC_Library +IMPLICIT NONE +! ========= OutputFile ======= + TYPE, PUBLIC :: OutputFile + character(1024) :: Name !< Filename for output from points read in from points file [-] + INTEGER(IntKi) :: Unit = -1 !< Unit number for the output file for the Points file output [-] + LOGICAL :: Initialized = .false. !< Flag indicating that file has been initialized [-] + END TYPE OutputFile +! ======================= +! ========= IfWDriver_Flags ======= + TYPE, PUBLIC :: IfWDriver_Flags + LOGICAL :: DvrIptFile = .false. !< Was an input file name given on the command line? [-] + LOGICAL :: IfWIptFile = .false. !< Was an InflowWind input file requested? [-] + LOGICAL :: Summary = .false. !< create a summary at command line? (data extents in the wind file) [-] + LOGICAL :: SummaryFile = .false. !< create a summary file of the output? [-] + LOGICAL :: TStart = .false. !< specified a start time [-] + LOGICAL :: NumTimeSteps = .false. !< specified a number of timesteps to process [-] + LOGICAL :: NumTimeStepsDefault = .false. !< specified a 'DEFAULT' for number of timesteps to process [-] + LOGICAL :: DT = .false. !< specified a resolution in time [-] + LOGICAL :: DTDefault = .false. !< specified a 'DEFAULT' for the time resolution [-] + LOGICAL :: FFTcalc = .false. !< do an FFT [-] + LOGICAL :: WindGrid = .false. !< Requested output of wind data on a grid -- input file option only [-] + LOGICAL :: XRange = .false. !< specified a range of x -- command line option only -- stored as GridCtrCoord and GridDelta [-] + LOGICAL :: YRange = .false. !< specified a range of y -- command line option only -- stored as GridCtrCoord and GridDelta [-] + LOGICAL :: ZRange = .false. !< specified a range of z -- command line option only -- stored as GridCtrCoord and GridDelta [-] + LOGICAL :: Dx = .false. !< specified a resolution in x -- command line option only, 0.0 otherwise [-] + LOGICAL :: Dy = .false. !< speficied a resolution in y [-] + LOGICAL :: Dz = .false. !< specified a resolution in z [-] + LOGICAL :: PointsFile = .false. !< points filename to read in [-] + LOGICAL :: OutputAccel = .false. !< flag to calculate and output wind acceleration in addition to velocity [-] + LOGICAL :: Verbose = .false. !< Verbose error reporting [-] + LOGICAL :: VVerbose = .false. !< Very Verbose error reporting [-] + LOGICAL :: BoxExceedAllowF = .false. !< set flag to allow exceeding wind box boundaries for FF files (for diagnostic purposes) [-] + LOGICAL :: WrHAWC = .false. !< Requested file conversion to HAWC2 format? [-] + LOGICAL :: WrBladed = .false. !< Requested file conversion to Bladed format? [-] + LOGICAL :: WrVTK = .false. !< Requested file output as VTK? [-] + LOGICAL :: WrUniform = .false. !< Requested file output as Uniform wind format? [-] + LOGICAL :: XYslice = .false. !< Take XY slice at one elevation [-] + END TYPE IfWDriver_Flags +! ======================= +! ========= IfWDriver_Settings ======= + TYPE, PUBLIC :: IfWDriver_Settings + character(1024) :: DvrIptFileName !< Driver input file name [-] + character(1024) :: IfWIptFileName !< Filename of InflowWind input file to read (if no driver input file) [-] + character(1024) :: SummaryFileName !< Filename for the summary information output [-] + character(1024) :: PointsFileName !< Filename of points file to read in [-] + INTEGER(IntKi) :: NumTimeSteps = 0 !< Number of timesteps [-] + REAL(DbKi) :: DT = 0.0_DbKi !< resolution of time [s] + REAL(DbKi) :: TStart = 0.0_DbKi !< range of time -- end time converted from TRange (command line option only) [s] + REAL(ReKi) :: FFTcoord(1:3) = 0.0_ReKi !< (x,y,z) coordinate to do an FFT at [(m)] + REAL(ReKi) :: GridDelta(1:3) = 0.0_ReKi !< (GridDx,GridDy,GridDz) -- grid point spacing [(m)] + INTEGER(IntKi) :: GridN(1:3) = 1_IntKi !< (GridNx,GridNy,GridNz) -- number of grid points [-] + REAL(ReKi) :: XRange(1:2) = 0.0_ReKi !< Range in the x-direction for the gridded data [(m)] + REAL(ReKi) :: YRange(1:2) = 0.0_ReKi !< Range in the y-direction for the gridded data [(m)] + REAL(ReKi) :: ZRange(1:2) = 0.0_ReKi !< Range in the z-direction for the gridded data [(m)] + TYPE(ProgDesc) :: ProgInfo !< Program info [-] + TYPE(OutputFile) :: WindGridOutput !< Wind grid file handling [-] + TYPE(OutputFile) :: FFTOutput !< FFT file handling [-] + TYPE(OutputFile) :: PointsVelOutput !< Points output velocity file handling [-] + INTEGER(IntKi) :: NOutWindXY = 0 !< Number of XY planes for output .XY.t.vtk [0 to 9] [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: OutWindZ !< Z coordinates of XY planes for output [1 to NOutWindXY] [unused for NOutWindXY=0] [(m)] + INTEGER(IntKi) :: NOutWindXZ = 0 !< Number of YZ planes for output .YZ.t.vtk [0 to 9] [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: OutWindY !< Y coordinates of YZ planes for output [1 to NOutWindYZ] [unused for NOutWindYZ=0] [(m)] + INTEGER(IntKi) :: NOutWindYZ = 0 !< Number of YZ planes for output .YZ.t.vtk [0 to 9] [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: OutWindX !< X coordinates of YZ planes for output [1 to NOutWindYZ] [unused for NOutWindYZ=0] [(m)] + END TYPE IfWDriver_Settings +! ======================= +CONTAINS - USE NWTC_Library - USE InflowWind_Types - - IMPLICIT NONE - - TYPE OutputFile - LOGICAL :: Initialized = .FALSE. !< Flag indicating that file has been initialized - CHARACTER(1024) :: Name = "" !< Filename for output from points read in from points file - INTEGER(IntKi) :: Unit = -1 !< Unit number for the output file for the Points file output - END TYPE - - !> This contains flags to note if the settings were made. This same data structure is - !! used both during the driver input file and the command line options. - !! - !! NOTE: The WindFileType is only set if it is given as a command line option. Otherwise - !! it is handled internally by InflowWInd. - !! - !! NOTE: The wind direction is specified by the InflowWind input file. - TYPE :: IfWDriver_Flags - LOGICAL :: DvrIptFile = .FALSE. !< Was an input file name given on the command line? - LOGICAL :: IfWIptFile = .FALSE. !< Was an InflowWind input file requested? - LOGICAL :: Summary = .FALSE. !< create a summary at command line? (data extents in the wind file) - LOGICAL :: SummaryFile = .FALSE. !< create a summary file of the output? - LOGICAL :: TStart = .FALSE. !< specified a start time - LOGICAL :: NumTimeSteps = .FALSE. !< specified a number of timesteps to process - LOGICAL :: NumTimeStepsDefault = .FALSE. !< specified a 'DEFAULT' for number of timesteps to process - LOGICAL :: DT = .FALSE. !< specified a resolution in time - LOGICAL :: DTDefault = .FALSE. !< specified a 'DEFAULT' for the time resolution - - LOGICAL :: FFTcalc = .FALSE. !< do an FFT - - LOGICAL :: WindGrid = .FALSE. !< Requested output of wind data on a grid -- input file option only - LOGICAL :: XRange = .FALSE. !< specified a range of x -- command line option only -- stored as GridCtrCoord and GridDelta - LOGICAL :: YRange = .FALSE. !< specified a range of y -- command line option only -- stored as GridCtrCoord and GridDelta - LOGICAL :: ZRange = .FALSE. !< specified a range of z -- command line option only -- stored as GridCtrCoord and GridDelta - LOGICAL :: Dx = .FALSE. !< specified a resolution in x -- command line option only, 0.0 otherwise - LOGICAL :: Dy = .FALSE. !< speficied a resolution in y - LOGICAL :: Dz = .FALSE. !< specified a resolution in z - - LOGICAL :: PointsFile = .FALSE. !< points filename to read in - LOGICAL :: OutputAccel = .FALSE. !< flag to calculate and output wind acceleration in addition to velocity - - LOGICAL :: Verbose = .FALSE. !< Verbose error reporting - LOGICAL :: VVerbose = .FALSE. !< Very Verbose error reporting - LOGICAL :: BoxExceedAllowF = .FALSE. !< set flag to allow exceeding wind box boundaries for FF files (for diagnostic purposes) +subroutine InflowWind_Driver_CopyOutputFile(SrcOutputFileData, DstOutputFileData, CtrlCode, ErrStat, ErrMsg) + type(OutputFile), intent(in) :: SrcOutputFileData + type(OutputFile), intent(inout) :: DstOutputFileData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'InflowWind_Driver_CopyOutputFile' + ErrStat = ErrID_None + ErrMsg = '' + DstOutputFileData%Name = SrcOutputFileData%Name + DstOutputFileData%Unit = SrcOutputFileData%Unit + DstOutputFileData%Initialized = SrcOutputFileData%Initialized +end subroutine - LOGICAL :: WrHAWC = .FALSE. !< Requested file conversion to HAWC2 format? - LOGICAL :: WrBladed = .FALSE. !< Requested file conversion to Bladed format? - LOGICAL :: WrVTK = .FALSE. !< Requested file output as VTK? - LOGICAL :: WrUniform = .FALSE. !< Requested file output as Uniform wind format? - END TYPE IfWDriver_Flags +subroutine InflowWind_Driver_DestroyOutputFile(OutputFileData, ErrStat, ErrMsg) + type(OutputFile), intent(inout) :: OutputFileData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'InflowWind_Driver_DestroyOutputFile' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine +subroutine InflowWind_Driver_PackOutputFile(RF, Indata) + type(RegFile), intent(inout) :: RF + type(OutputFile), intent(in) :: InData + character(*), parameter :: RoutineName = 'InflowWind_Driver_PackOutputFile' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%Name) + call RegPack(RF, InData%Unit) + call RegPack(RF, InData%Initialized) + if (RegCheckErr(RF, RoutineName)) return +end subroutine - ! This contains all the settings (possible passed in arguments). - TYPE :: IfWDriver_Settings - CHARACTER(1024) :: DvrIptFileName = "" !< Driver input file name - CHARACTER(1024) :: IfWIptFileName = "" !< Filename of InflowWind input file to read (if no driver input file) - CHARACTER(1024) :: SummaryFileName = "" !< Filename for the summary information output +subroutine InflowWind_Driver_UnPackOutputFile(RF, OutData) + type(RegFile), intent(inout) :: RF + type(OutputFile), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'InflowWind_Driver_UnPackOutputFile' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%Name); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Unit); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Initialized); if (RegCheckErr(RF, RoutineName)) return +end subroutine - CHARACTER(1024) :: PointsFileName = "" !< Filename of points file to read in - - INTEGER(IntKi) :: NumTimeSteps = 0 !< Number of timesteps - REAL(DbKi) :: DT = 0.0_DbKi !< resolution of time - REAL(DbKi) :: TStart = 0.0_DbKi !< range of time -- end time converted from TRange (command line option only) +subroutine InflowWind_Driver_CopyIfWDriver_Flags(SrcIfWDriver_FlagsData, DstIfWDriver_FlagsData, CtrlCode, ErrStat, ErrMsg) + type(IfWDriver_Flags), intent(in) :: SrcIfWDriver_FlagsData + type(IfWDriver_Flags), intent(inout) :: DstIfWDriver_FlagsData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'InflowWind_Driver_CopyIfWDriver_Flags' + ErrStat = ErrID_None + ErrMsg = '' + DstIfWDriver_FlagsData%DvrIptFile = SrcIfWDriver_FlagsData%DvrIptFile + DstIfWDriver_FlagsData%IfWIptFile = SrcIfWDriver_FlagsData%IfWIptFile + DstIfWDriver_FlagsData%Summary = SrcIfWDriver_FlagsData%Summary + DstIfWDriver_FlagsData%SummaryFile = SrcIfWDriver_FlagsData%SummaryFile + DstIfWDriver_FlagsData%TStart = SrcIfWDriver_FlagsData%TStart + DstIfWDriver_FlagsData%NumTimeSteps = SrcIfWDriver_FlagsData%NumTimeSteps + DstIfWDriver_FlagsData%NumTimeStepsDefault = SrcIfWDriver_FlagsData%NumTimeStepsDefault + DstIfWDriver_FlagsData%DT = SrcIfWDriver_FlagsData%DT + DstIfWDriver_FlagsData%DTDefault = SrcIfWDriver_FlagsData%DTDefault + DstIfWDriver_FlagsData%FFTcalc = SrcIfWDriver_FlagsData%FFTcalc + DstIfWDriver_FlagsData%WindGrid = SrcIfWDriver_FlagsData%WindGrid + DstIfWDriver_FlagsData%XRange = SrcIfWDriver_FlagsData%XRange + DstIfWDriver_FlagsData%YRange = SrcIfWDriver_FlagsData%YRange + DstIfWDriver_FlagsData%ZRange = SrcIfWDriver_FlagsData%ZRange + DstIfWDriver_FlagsData%Dx = SrcIfWDriver_FlagsData%Dx + DstIfWDriver_FlagsData%Dy = SrcIfWDriver_FlagsData%Dy + DstIfWDriver_FlagsData%Dz = SrcIfWDriver_FlagsData%Dz + DstIfWDriver_FlagsData%PointsFile = SrcIfWDriver_FlagsData%PointsFile + DstIfWDriver_FlagsData%OutputAccel = SrcIfWDriver_FlagsData%OutputAccel + DstIfWDriver_FlagsData%Verbose = SrcIfWDriver_FlagsData%Verbose + DstIfWDriver_FlagsData%VVerbose = SrcIfWDriver_FlagsData%VVerbose + DstIfWDriver_FlagsData%BoxExceedAllowF = SrcIfWDriver_FlagsData%BoxExceedAllowF + DstIfWDriver_FlagsData%WrHAWC = SrcIfWDriver_FlagsData%WrHAWC + DstIfWDriver_FlagsData%WrBladed = SrcIfWDriver_FlagsData%WrBladed + DstIfWDriver_FlagsData%WrVTK = SrcIfWDriver_FlagsData%WrVTK + DstIfWDriver_FlagsData%WrUniform = SrcIfWDriver_FlagsData%WrUniform + DstIfWDriver_FlagsData%XYslice = SrcIfWDriver_FlagsData%XYslice +end subroutine - REAL(ReKi) :: FFTcoord(1:3) = 0.0_ReKi !< (x,y,z) coordinate to do an FFT at +subroutine InflowWind_Driver_DestroyIfWDriver_Flags(IfWDriver_FlagsData, ErrStat, ErrMsg) + type(IfWDriver_Flags), intent(inout) :: IfWDriver_FlagsData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'InflowWind_Driver_DestroyIfWDriver_Flags' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine - REAL(ReKi) :: GridDelta(1:3) = 0.0_ReKi !< (GridDx,GridDy,GridDz) -- grid point spacing - INTEGER(IntKi) :: GridN(1:3) = 1_IntKi !< (GridNx,GridNy,GridNz) -- number of grid points +subroutine InflowWind_Driver_PackIfWDriver_Flags(RF, Indata) + type(RegFile), intent(inout) :: RF + type(IfWDriver_Flags), intent(in) :: InData + character(*), parameter :: RoutineName = 'InflowWind_Driver_PackIfWDriver_Flags' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%DvrIptFile) + call RegPack(RF, InData%IfWIptFile) + call RegPack(RF, InData%Summary) + call RegPack(RF, InData%SummaryFile) + call RegPack(RF, InData%TStart) + call RegPack(RF, InData%NumTimeSteps) + call RegPack(RF, InData%NumTimeStepsDefault) + call RegPack(RF, InData%DT) + call RegPack(RF, InData%DTDefault) + call RegPack(RF, InData%FFTcalc) + call RegPack(RF, InData%WindGrid) + call RegPack(RF, InData%XRange) + call RegPack(RF, InData%YRange) + call RegPack(RF, InData%ZRange) + call RegPack(RF, InData%Dx) + call RegPack(RF, InData%Dy) + call RegPack(RF, InData%Dz) + call RegPack(RF, InData%PointsFile) + call RegPack(RF, InData%OutputAccel) + call RegPack(RF, InData%Verbose) + call RegPack(RF, InData%VVerbose) + call RegPack(RF, InData%BoxExceedAllowF) + call RegPack(RF, InData%WrHAWC) + call RegPack(RF, InData%WrBladed) + call RegPack(RF, InData%WrVTK) + call RegPack(RF, InData%WrUniform) + call RegPack(RF, InData%XYslice) + if (RegCheckErr(RF, RoutineName)) return +end subroutine - REAL(ReKi) :: XRange(1:2) = 0.0_ReKi !< Range in the x-direction for the gridded data - REAL(ReKi) :: YRange(1:2) = 0.0_ReKi !< Range in the y-direction for the gridded data - REAL(ReKi) :: ZRange(1:2) = 0.0_ReKi !< Range in the z-direction for the gridded data +subroutine InflowWind_Driver_UnPackIfWDriver_Flags(RF, OutData) + type(RegFile), intent(inout) :: RF + type(IfWDriver_Flags), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'InflowWind_Driver_UnPackIfWDriver_Flags' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%DvrIptFile); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%IfWIptFile); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Summary); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%SummaryFile); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TStart); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NumTimeSteps); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NumTimeStepsDefault); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%DT); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%DTDefault); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%FFTcalc); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WindGrid); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%XRange); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YRange); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%ZRange); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Dx); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Dy); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Dz); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%PointsFile); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%OutputAccel); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Verbose); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%VVerbose); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%BoxExceedAllowF); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WrHAWC); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WrBladed); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WrVTK); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WrUniform); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%XYslice); if (RegCheckErr(RF, RoutineName)) return +end subroutine - TYPE(ProgDesc) :: ProgInfo !< Program info - TYPE(OutputFile) :: WindGridOutput - TYPE(OutputFile) :: FFTOutput - TYPE(OutputFile) :: PointsVelOutput +subroutine InflowWind_Driver_CopyIfWDriver_Settings(SrcIfWDriver_SettingsData, DstIfWDriver_SettingsData, CtrlCode, ErrStat, ErrMsg) + type(IfWDriver_Settings), intent(in) :: SrcIfWDriver_SettingsData + type(IfWDriver_Settings), intent(inout) :: DstIfWDriver_SettingsData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'InflowWind_Driver_CopyIfWDriver_Settings' + ErrStat = ErrID_None + ErrMsg = '' + DstIfWDriver_SettingsData%DvrIptFileName = SrcIfWDriver_SettingsData%DvrIptFileName + DstIfWDriver_SettingsData%IfWIptFileName = SrcIfWDriver_SettingsData%IfWIptFileName + DstIfWDriver_SettingsData%SummaryFileName = SrcIfWDriver_SettingsData%SummaryFileName + DstIfWDriver_SettingsData%PointsFileName = SrcIfWDriver_SettingsData%PointsFileName + DstIfWDriver_SettingsData%NumTimeSteps = SrcIfWDriver_SettingsData%NumTimeSteps + DstIfWDriver_SettingsData%DT = SrcIfWDriver_SettingsData%DT + DstIfWDriver_SettingsData%TStart = SrcIfWDriver_SettingsData%TStart + DstIfWDriver_SettingsData%FFTcoord(1:3) = SrcIfWDriver_SettingsData%FFTcoord(1:3) + DstIfWDriver_SettingsData%GridDelta(1:3) = SrcIfWDriver_SettingsData%GridDelta(1:3) + DstIfWDriver_SettingsData%GridN(1:3) = SrcIfWDriver_SettingsData%GridN(1:3) + DstIfWDriver_SettingsData%XRange(1:2) = SrcIfWDriver_SettingsData%XRange(1:2) + DstIfWDriver_SettingsData%YRange(1:2) = SrcIfWDriver_SettingsData%YRange(1:2) + DstIfWDriver_SettingsData%ZRange(1:2) = SrcIfWDriver_SettingsData%ZRange(1:2) + call NWTC_Library_CopyProgDesc(SrcIfWDriver_SettingsData%ProgInfo, DstIfWDriver_SettingsData%ProgInfo, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + call InflowWind_Driver_CopyOutputFile(SrcIfWDriver_SettingsData%WindGridOutput, DstIfWDriver_SettingsData%WindGridOutput, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + call InflowWind_Driver_CopyOutputFile(SrcIfWDriver_SettingsData%FFTOutput, DstIfWDriver_SettingsData%FFTOutput, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + call InflowWind_Driver_CopyOutputFile(SrcIfWDriver_SettingsData%PointsVelOutput, DstIfWDriver_SettingsData%PointsVelOutput, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + DstIfWDriver_SettingsData%NOutWindXY = SrcIfWDriver_SettingsData%NOutWindXY + if (allocated(SrcIfWDriver_SettingsData%OutWindZ)) then + LB(1:1) = lbound(SrcIfWDriver_SettingsData%OutWindZ) + UB(1:1) = ubound(SrcIfWDriver_SettingsData%OutWindZ) + if (.not. allocated(DstIfWDriver_SettingsData%OutWindZ)) then + allocate(DstIfWDriver_SettingsData%OutWindZ(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstIfWDriver_SettingsData%OutWindZ.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstIfWDriver_SettingsData%OutWindZ = SrcIfWDriver_SettingsData%OutWindZ + end if + DstIfWDriver_SettingsData%NOutWindXZ = SrcIfWDriver_SettingsData%NOutWindXZ + if (allocated(SrcIfWDriver_SettingsData%OutWindY)) then + LB(1:1) = lbound(SrcIfWDriver_SettingsData%OutWindY) + UB(1:1) = ubound(SrcIfWDriver_SettingsData%OutWindY) + if (.not. allocated(DstIfWDriver_SettingsData%OutWindY)) then + allocate(DstIfWDriver_SettingsData%OutWindY(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstIfWDriver_SettingsData%OutWindY.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstIfWDriver_SettingsData%OutWindY = SrcIfWDriver_SettingsData%OutWindY + end if + DstIfWDriver_SettingsData%NOutWindYZ = SrcIfWDriver_SettingsData%NOutWindYZ + if (allocated(SrcIfWDriver_SettingsData%OutWindX)) then + LB(1:1) = lbound(SrcIfWDriver_SettingsData%OutWindX) + UB(1:1) = ubound(SrcIfWDriver_SettingsData%OutWindX) + if (.not. allocated(DstIfWDriver_SettingsData%OutWindX)) then + allocate(DstIfWDriver_SettingsData%OutWindX(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstIfWDriver_SettingsData%OutWindX.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstIfWDriver_SettingsData%OutWindX = SrcIfWDriver_SettingsData%OutWindX + end if +end subroutine - END TYPE IfWDriver_Settings +subroutine InflowWind_Driver_DestroyIfWDriver_Settings(IfWDriver_SettingsData, ErrStat, ErrMsg) + type(IfWDriver_Settings), intent(inout) :: IfWDriver_SettingsData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'InflowWind_Driver_DestroyIfWDriver_Settings' + ErrStat = ErrID_None + ErrMsg = '' + call NWTC_Library_DestroyProgDesc(IfWDriver_SettingsData%ProgInfo, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call InflowWind_Driver_DestroyOutputFile(IfWDriver_SettingsData%WindGridOutput, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call InflowWind_Driver_DestroyOutputFile(IfWDriver_SettingsData%FFTOutput, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call InflowWind_Driver_DestroyOutputFile(IfWDriver_SettingsData%PointsVelOutput, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (allocated(IfWDriver_SettingsData%OutWindZ)) then + deallocate(IfWDriver_SettingsData%OutWindZ) + end if + if (allocated(IfWDriver_SettingsData%OutWindY)) then + deallocate(IfWDriver_SettingsData%OutWindY) + end if + if (allocated(IfWDriver_SettingsData%OutWindX)) then + deallocate(IfWDriver_SettingsData%OutWindX) + end if +end subroutine +subroutine InflowWind_Driver_PackIfWDriver_Settings(RF, Indata) + type(RegFile), intent(inout) :: RF + type(IfWDriver_Settings), intent(in) :: InData + character(*), parameter :: RoutineName = 'InflowWind_Driver_PackIfWDriver_Settings' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%DvrIptFileName) + call RegPack(RF, InData%IfWIptFileName) + call RegPack(RF, InData%SummaryFileName) + call RegPack(RF, InData%PointsFileName) + call RegPack(RF, InData%NumTimeSteps) + call RegPack(RF, InData%DT) + call RegPack(RF, InData%TStart) + call RegPack(RF, InData%FFTcoord(1:3)) + call RegPack(RF, InData%GridDelta(1:3)) + call RegPack(RF, InData%GridN(1:3)) + call RegPack(RF, InData%XRange(1:2)) + call RegPack(RF, InData%YRange(1:2)) + call RegPack(RF, InData%ZRange(1:2)) + call NWTC_Library_PackProgDesc(RF, InData%ProgInfo) + call InflowWind_Driver_PackOutputFile(RF, InData%WindGridOutput) + call InflowWind_Driver_PackOutputFile(RF, InData%FFTOutput) + call InflowWind_Driver_PackOutputFile(RF, InData%PointsVelOutput) + call RegPack(RF, InData%NOutWindXY) + call RegPackAlloc(RF, InData%OutWindZ) + call RegPack(RF, InData%NOutWindXZ) + call RegPackAlloc(RF, InData%OutWindY) + call RegPack(RF, InData%NOutWindYZ) + call RegPackAlloc(RF, InData%OutWindX) + if (RegCheckErr(RF, RoutineName)) return +end subroutine +subroutine InflowWind_Driver_UnPackIfWDriver_Settings(RF, OutData) + type(RegFile), intent(inout) :: RF + type(IfWDriver_Settings), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'InflowWind_Driver_UnPackIfWDriver_Settings' + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%DvrIptFileName); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%IfWIptFileName); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%SummaryFileName); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%PointsFileName); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NumTimeSteps); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%DT); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%TStart); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%FFTcoord(1:3)); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GridDelta(1:3)); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GridN(1:3)); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%XRange(1:2)); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%YRange(1:2)); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%ZRange(1:2)); if (RegCheckErr(RF, RoutineName)) return + call NWTC_Library_UnpackProgDesc(RF, OutData%ProgInfo) ! ProgInfo + call InflowWind_Driver_UnpackOutputFile(RF, OutData%WindGridOutput) ! WindGridOutput + call InflowWind_Driver_UnpackOutputFile(RF, OutData%FFTOutput) ! FFTOutput + call InflowWind_Driver_UnpackOutputFile(RF, OutData%PointsVelOutput) ! PointsVelOutput + call RegUnpack(RF, OutData%NOutWindXY); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%OutWindZ); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NOutWindXZ); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%OutWindY); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NOutWindYZ); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%OutWindX); if (RegCheckErr(RF, RoutineName)) return +end subroutine END MODULE InflowWind_Driver_Types +!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/inflowwind/src/InflowWind_IO.f90 b/modules/inflowwind/src/InflowWind_IO.f90 index 35fbd4d6dc..48c0875081 100644 --- a/modules/inflowwind/src/InflowWind_IO.f90 +++ b/modules/inflowwind/src/InflowWind_IO.f90 @@ -39,7 +39,8 @@ module InflowWind_IO public :: Uniform_WriteHH, & Grid3D_WriteBladed, & Grid3D_WriteHAWC, & - Grid3D_WriteVTK + Grid3D_WriteVTK, & + Grid3D_WriteVTKsliceXY type(ProgDesc), parameter :: InflowWind_IO_Ver = ProgDesc('InflowWind_IO', '', '') @@ -537,12 +538,13 @@ subroutine IfW_TurbSim_Init(InitInp, SumFileUnit, G3D, FileDat, ErrStat, ErrMsg) !---------------------------------------------------------------------------- ! Get a unit number to use for the wind file + !$OMP critical(fileopen) call GetNewUnit(WindFileUnit, TmpErrStat, TmpErrMsg) - call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return - - ! Open binary file - call OpenBInpFile(WindFileUnit, TRIM(InitInp%WindFileName), TmpErrStat, TmpErrMsg) + if (TmpErrStat < AbortErrLev) then + ! Open binary file + call OpenBInpFile(WindFileUnit, TRIM(InitInp%WindFileName), TmpErrStat, TmpErrMsg) + endif + !$OMP end critical(fileopen) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -902,16 +904,17 @@ subroutine IfW_HAWC_Init(InitInp, SumFileUnit, G3D, FileDat, ErrStat, ErrMsg) TRIM(Num2LStr(G3D%GridBase + G3D%ZHWid*2))// & ' m above ground) with a characteristic wind speed of '//TRIM(Num2LStr(G3D%MeanWS))//' m/s. ') - ! Get a unit number to use for the wind file - call GetNewUnit(WindFileUnit, TmpErrStat, TmpErrMsg) - call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return - ! Loop through wind components (X, Y, Z) do IC = 1, G3D%NComp - ! Open wind file for this component - call OpenBInpFile(WindFileUnit, InitInp%WindFileName(IC), TmpErrStat, TmpErrMsg) + ! Get a unit number to use for the wind file + !$OMP critical(fileopen) + call GetNewUnit(WindFileUnit, TmpErrStat, TmpErrMsg) + if (TmpErrStat < AbortErrLev) then + ! Open wind file for this component + call OpenBInpFile(WindFileUnit, InitInp%WindFileName(IC), TmpErrStat, TmpErrMsg) + endif + !$OMP end critical(fileopen) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -1141,16 +1144,18 @@ subroutine IfW_Bladed_Init(InitInp, SumFileUnit, InitOut, G3D, FileDat, ErrStat, end if ! Get a unit number to use + !$OMP critical(fileopen) call GetNewUnit(UnitWind, TmpErrStat, TmpErrMsg) - call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) return + if (TmpErrStat < AbortErrLev) then !---------------------------------------------------------------------------- ! Open the binary file, read its "header" (first 2-byte integer) to ! determine what format binary file it is, and close it. !---------------------------------------------------------------------------- - call OpenBInpFile(UnitWind, TRIM(BinFileName), TmpErrStat, TmpErrMsg) + call OpenBInpFile(UnitWind, TRIM(BinFileName), TmpErrStat, TmpErrMsg) + endif + !$OMP end critical(fileopen) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -2943,4 +2948,87 @@ subroutine Grid3D_WriteHAWC(G3D, FileRootName, unit, ErrStat, ErrMsg) end subroutine Grid3D_WriteHAWC + +!> This subroutine writes a VTK slice in the XY plane at a designated height (rounds to nearest point) +!! This feature is mostly useful for testing when a grid is needed for comparison elsewhere +subroutine Grid3D_WriteVTKsliceXY(G3D, FileRootName, vtk_dir, XYslice_height, unit, ErrStat, ErrMsg) + type(Grid3DFieldType), intent(in ) :: G3D !< Parameters + character(*), intent(in ) :: FileRootName !< RootName for output files + character(*), intent(in ) :: vtk_dir !< directory for vtk file for output files + real(ReKi), intent(in ) :: XYslice_height + integer(IntKi), intent(in ) :: unit !< Error status of the operation + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + character(*), parameter :: RoutineName = 'Grid3D_WriteVTKsliceXY' + character(1024) :: RootPathName + character(1024) :: FileName + character(3) :: ht_str + character(8) :: t_str, t_fmt + integer :: it, ix, iy, iz, twidth + real(ReKi) :: time !< time for this slice + real(ReKi) :: ht !< nearest grid slice elevation + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + + ErrStat = ErrID_None + ErrMsg = "" + + call GetPath(FileRootName, RootPathName) + RootPathName = trim(RootPathName)//PathSep//vtk_dir + call MkDir(trim(RootPathName)) ! make this directory if it doesn't already exist + + ! get indices for this slice + iz = nint((G3D%GridBase + XYslice_height)*G3D%InvDZ) + ht = real(iz,ReKi) / G3D%InvDZ + G3D%GridBase ! nearest height index + write(ht_str,'(i0.3)') nint(ht) + + ! get width of string for time + twidth=ceiling(log10(real(G3D%NSteps))) + t_fmt='(i0.'//trim(Num2LStr(twidth))//')' + + ! check for errors in slice height + if (iz <= 0_IntKi .or. iz > G3D%NZGrids) then + call SetErrStat(ErrID_Warn,"No grid points near XY slice height of "//trim(num2lstr(XYslice_height))//". Skipping writing slice file.",ErrStat,ErrMsg,RoutineName) + return + endif + + ! Loop through time steps + do it = 1, G3D%NSteps + time = real(it - 1, ReKi)*G3D%DTime + + ! time string + write(t_str,t_fmt) it + + ! Create the output vtk file with naming /vtk/DisYZ.t.vtk + FileName = trim(RootPathName)//PathSep//"DisXY.Z"//ht_str//".t"//trim(t_str)//".vtp" + + ! see WrVTK_SP_header + call OpenFOutFile(unit, TRIM(FileName), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + + write (unit, '(A)') '# vtk DataFile Version 3.0' + write (unit, '(A)') "InflowWind XY Slice at T= "//trim(num2lstr(time))//" s" + write (unit, '(A)') 'ASCII' + write (unit, '(A)') 'DATASET STRUCTURED_POINTS' + + ! Note: gridVals must be stored such that the left-most dimension is X + ! and the right-most dimension is Z (see WrVTK_SP_vectors3D) + write (unit, '(A,3(i5,1X))') 'DIMENSIONS ', G3D%NSteps, G3D%NYGrids, 1 + write (unit, '(A,3(f10.2,1X))') 'ORIGIN ', G3D%InitXPosition+time*G3D%MeanWS, -G3D%YHWid, ht + write (unit, '(A,3(f10.2,1X))') 'SPACING ', -G3D%Dtime*G3D%MeanWS, 1.0_ReKi/G3D%InvDY, 0.0_ReKi + write (unit, '(A,i9)') 'POINT_DATA ', G3D%NSteps*G3D%NYGrids + write (unit, '(A)') 'VECTORS DisXY float' + + do iy = 1, G3D%NYGrids + do ix = 1, G3D%NSteps ! time and X are interchangeable + write (unit, '(3(f10.2,1X))') G3D%Vel(:, iy, iz, ix) + end do + end do + + close (unit) + enddo +end subroutine Grid3D_WriteVTKsliceXY + end module InflowWind_IO diff --git a/modules/inflowwind/src/InflowWind_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index 72421f99c1..2fe7c9149a 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -317,7 +317,7 @@ SUBROUTINE InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, In !------------------------------------------------------------------------------------------------- CurLine = CurLine + 1 ! Skip section break - CALL ParseVar( InFileInfo, CurLine, "FileName_Uni", InputFileData%Uniform_FileName, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FileName_Uni", InputFileData%Uniform_FileName, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%Uniform_FileName ) ) InputFileData%Uniform_FileName = TRIM(PriPath)//TRIM(InputFileData%Uniform_FileName) IF ( FixedWindFileRootName ) THEN ! .TRUE. when FAST.Farm uses multiple instances of InflowWind for ambient wind data @@ -339,7 +339,7 @@ SUBROUTINE InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, In !------------------------------------------------------------------------------------------------- CurLine = CurLine + 1 ! Skip section break - CALL ParseVar( InFileInfo, CurLine, "FileName_BTS", InputFileData%TSFF_FileName, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FileName_BTS", InputFileData%TSFF_FileName, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%TSFF_FileName ) ) InputFileData%TSFF_FileName = TRIM(PriPath)//TRIM(InputFileData%TSFF_FileName) IF ( FixedWindFileRootName ) THEN ! .TRUE. when FAST.Farm uses multiple instances of InflowWind for ambient wind data @@ -355,7 +355,7 @@ SUBROUTINE InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, In !------------------------------------------------------------------------------------------------- CurLine = CurLine + 1 ! Skip section break - CALL ParseVar( InFileInfo, CurLine, "FilenameRoot", InputFileData%BladedFF_FileName, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FilenameRoot", InputFileData%BladedFF_FileName, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%BladedFF_FileName ) ) InputFileData%BladedFF_FileName = TRIM(PriPath)//TRIM(InputFileData%BladedFF_FileName) @@ -383,15 +383,15 @@ SUBROUTINE InflowWind_ParseInputFileInfo( InputFileData, InFileInfo, PriPath, In !------------------------------------------------------------------------------------------------- CurLine = CurLine + 1 ! Skip section break - CALL ParseVar( InFileInfo, CurLine, "FileName_u", InputFileData%HAWC_FileName_u, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FileName_u", InputFileData%HAWC_FileName_u, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%HAWC_FileName_u ) ) InputFileData%HAWC_FileName_u = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_u) - CALL ParseVar( InFileInfo, CurLine, "FileName_v", InputFileData%HAWC_FileName_v, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FileName_v", InputFileData%HAWC_FileName_v, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%HAWC_FileName_v ) ) InputFileData%HAWC_FileName_v = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_v) - CALL ParseVar( InFileInfo, CurLine, "FileName_w", InputFileData%HAWC_FileName_w, TmpErrStat, TmpErrMsg, UnEc ) + CALL ParseVar( InFileInfo, CurLine, "FileName_w", InputFileData%HAWC_FileName_w, TmpErrStat, TmpErrMsg, UnEc, IsPath=.true. ) if (Failed()) return IF ( PathIsRelative( InputFileData%HAWC_FileName_w ) ) InputFileData%HAWC_FileName_w = TRIM(PriPath)//TRIM(InputFileData%HAWC_FileName_w) @@ -952,6 +952,7 @@ SUBROUTINE InflowWind_SetParameters( InitInp, InputFileData, p, m, ErrStat, ErrM ! Temporary variables INTEGER(IntKi) :: TmpErrStat !< Temporary error status for subroutine and function calls CHARACTER(ErrMsgLen) :: TmpErrMsg !< Temporary error message for subroutine and function calls + integer(IntKi) :: NumPtsAvg !< Number of points to use for disk average vel (1 if no radius) ! Local variables INTEGER(IntKi) :: I !< Generic counter @@ -1011,28 +1012,34 @@ SUBROUTINE InflowWind_SetParameters( InitInp, InputFileData, p, m, ErrStat, ErrM CALL AllocAry( m%y_Hub%VelocityUVW, 3, 1, "Array of velocities for hub values", TmpErrStat, TmpErrMsg ) CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - CALL AllocAry( m%u_Avg%PositionXYZ, 3, IfW_NumPtsAvg, "Array of positions for rotor-averaged values", TmpErrStat, TmpErrMsg ) + ! Disk Velocity calculations + if (InitInp%RadAvg < 0.0_ReKi) then + NumPtsAvg = 1_IntKi ! Use only hub point + else + NumPtsAvg = IfW_NumPtsAvg ! Use a field of points for disk average calculations + endif + + CALL AllocAry( m%u_Avg%PositionXYZ, 3, NumPtsAvg, "Array of positions for rotor-averaged values", TmpErrStat, TmpErrMsg ) CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - CALL AllocAry( m%y_Avg%VelocityUVW, 3, IfW_NumPtsAvg, "Array of velocities for rotor-averaged values", TmpErrStat, TmpErrMsg ) + CALL AllocAry( m%y_Avg%VelocityUVW, 3, NumPtsAvg, "Array of velocities for rotor-averaged values", TmpErrStat, TmpErrMsg ) CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) - CALL AllocAry( p%PositionAvg, 3, IfW_NumPtsAvg, "Array of positions for computing average wind speed", TmpErrStat, TmpErrMsg ) + CALL AllocAry( p%PositionAvg, 3, NumPtsAvg, "Array of positions for computing average wind speed", TmpErrStat, TmpErrMsg ) CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) IF ( ErrStat>= AbortErrLev ) RETURN if (InitInp%RadAvg < 0.0_ReKi) then - R = max(1.0_ReKi, InputFileData%Uniform_RefLength)/2.0_ReKi ! We'll use this as a guess for the rotor radius + p%PositionAvg = 0.0_ReKi ! Use only hub else - R = InitInp%RadAvg + ! Calculate a ring of points at 70 rotor radius + R = InitInp%RadAvg * 0.7_ReKi !70% radius + do i=1,NumPtsAvg + theta = pi +(i-1)*TwoPi/NumPtsAvg + p%PositionAvg(1,i) = 0.0_ReKi ! Hub X (perpindicular to rotor plane) + p%PositionAvg(2,i) = R*cos(theta) ! Hub Y + p%PositionAvg(3,i) = R*sin(theta) ! Hub Z (in vertical plane when azimuth=0) + end do end if - R = R * 0.7_ReKi !70% radius - - do i=1,IfW_NumPtsAvg - theta = pi +(i-1)*TwoPi/IfW_NumPtsAvg - p%PositionAvg(1,i) = R*cos(theta) - p%PositionAvg(2,i) = R*sin(theta) - p%PositionAvg(3,i) = 0.0_ReKi - end do p%OutputAccel = InitInp%OutputAccel @@ -1553,8 +1560,10 @@ SUBROUTINE InflowWind_OpenSumFile( SumFileUnit, SummaryName, IfW_Prog, WindType, ErrMsg = "" SumFileUnit = -1 + !$OMP critical(fileopen) CALL GetNewUnit( SumFileUnit ) CALL OpenFOutFile ( SumFileUnit, SummaryName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1676,7 +1685,7 @@ SUBROUTINE InflowWind_GetRotorSpatialAverage( Time, InputData, p, x, xd, z, Othe m%u_Avg%HubPosition = InputData%HubPosition m%u_Avg%HubOrientation = InputData%HubOrientation - do i = 1, IfW_NumPtsAvg + do i=1,size(m%u_Avg%PositionXYZ,DIM=2) m%u_Avg%PositionXYZ(:,i) = InputData%HubPosition + & matmul(InputData%HubOrientation,p%PositionAvg(:,i)) end do diff --git a/modules/inflowwind/src/InflowWind_Types.f90 b/modules/inflowwind/src/InflowWind_Types.f90 index 529267f23d..ba6f8c0584 100644 --- a/modules/inflowwind/src/InflowWind_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Types.f90 @@ -120,6 +120,7 @@ MODULE InflowWind_Types REAL(ReKi) :: WtrDpth = 0.0_ReKi !< Water depth [m] REAL(ReKi) :: MSL2SWL = 0.0_ReKi !< Mean sea level to still water level [m] LOGICAL :: BoxExceedAllow = .FALSE. !< Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim) [-] + LOGICAL :: LidarEnabled = .false. !< Enable LiDAR for this instance of InflowWind? (FAST.Farm, ADI, and InflowWind driver/library are not compatible) [-] END TYPE InflowWind_InitInputType ! ======================= ! ========= InflowWind_InitOutputType ======= @@ -527,6 +528,7 @@ subroutine InflowWind_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode DstInitInputData%WtrDpth = SrcInitInputData%WtrDpth DstInitInputData%MSL2SWL = SrcInitInputData%MSL2SWL DstInitInputData%BoxExceedAllow = SrcInitInputData%BoxExceedAllow + DstInitInputData%LidarEnabled = SrcInitInputData%LidarEnabled end subroutine subroutine InflowWind_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -575,6 +577,7 @@ subroutine InflowWind_PackInitInput(RF, Indata) call RegPack(RF, InData%WtrDpth) call RegPack(RF, InData%MSL2SWL) call RegPack(RF, InData%BoxExceedAllow) + call RegPack(RF, InData%LidarEnabled) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -603,6 +606,7 @@ subroutine InflowWind_UnPackInitInput(RF, OutData) call RegUnpack(RF, OutData%WtrDpth); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%MSL2SWL); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%BoxExceedAllow); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%LidarEnabled); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine InflowWind_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index e2b42cc264..8c8f522d04 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -62,7 +62,7 @@ MODULE NWTC_IO CHARACTER(99) :: ProgVer = ' ' !< The version (including date) of the calling program. DO NOT USE THIS IN NEW PROGRAMS CHARACTER(1), PARAMETER :: Tab = CHAR( 9 ) !< The tab character. CHARACTER(*), PARAMETER :: CommChars = '!#%' !< Comment characters that mark the end of useful input - INTEGER(IntKi), PARAMETER :: NWTC_SizeOfNumWord = 200 !< maximum length of the words containing numeric input (for ParseVar routines) + INTEGER(IntKi), PARAMETER :: NWTC_SizeOfNumWord = 256 !< maximum length of the words containing numeric input (for ParseVar routines) ! Parameters for writing to echo files (in this module only) @@ -2060,7 +2060,7 @@ END SUBROUTINE GetTokens !! It uses spaces, tabs, commas, semicolons, single quotes, and double quotes ("whitespace") !! as word separators. If there aren't NumWords in the line, the remaining array elements will remain empty. !! Use CountWords (nwtc_io::countwords) to count the number of words in a line. - SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) + SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) ! Argument declarations. @@ -2069,68 +2069,95 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) CHARACTER(*), INTENT(IN) :: Line !< The string to search. CHARACTER(*), INTENT(OUT) :: Words(NumWords) !< The array of found words. INTEGER, OPTIONAL, INTENT(OUT) :: NumFound !< The number of words found + LOGICAL, OPTIONAL, INTENT(IN) :: IgnoreQuotes !< Flag to ignore quotes (process as whitespace) - ! Local declarations. - - INTEGER :: Ch ! Character position within the string. - INTEGER :: IW ! Word index. - INTEGER :: NextWhite ! The location of the next whitespace in the string. - + INTEGER :: iWord ! Word index. + INTEGER :: i ! Character index in line. + INTEGER :: iChar ! Character index in word. + CHARACTER(len=1) :: Char ! Current character + LOGICAL :: InQuotes ! Flag indicating text is within quotes + LOGICAL :: IgnoreQuotesLoc ! Local flag to ignore quotes + ! Initialize number of words found to zero if present + if (present(NumFound)) NumFound = 0 - ! Let's prefill the array with blanks. + ! If no text on line, return + if (len_trim(Line) == 0) return - DO IW=1,NumWords - Words(IW) = ' ' - END DO ! IW + ! If ignore quotes is present, set local flag, otherwise true + if (present(IgnoreQuotes)) then + IgnoreQuotesLoc = IgnoreQuotes + else + IgnoreQuotesLoc = .true. + end if - IW = 0 + ! Let's prefill the array with blanks + do iWord = 1, NumWords + Words(iWord) = ' ' + end do + ! Initialize word index to first word + iWord = 1 - ! Let's make sure we have text on this line. - - IF ( LEN_TRIM( Line ) > 0 ) THEN - - ! Parse words separated by any combination of spaces, tabs, commas, - ! semicolons, single quotes, and double quotes ("whitespace"). - - Ch = 0 - - DO - - NextWhite = SCAN( Line(Ch+1:) , ' ,;''"'//Tab ) - - IF ( NextWhite > 1 ) THEN - - IW = IW + 1 - Words(IW) = Line(Ch+1:Ch+NextWhite-1) - if (NextWhite > len(words(iw)) ) then - call ProgWarn('Error reading field from file. There are too many characters in the input file to store in the field. Value may be truncated.') - end if - - IF ( IW == NumWords ) EXIT - - Ch = Ch + NextWhite - - ELSE IF ( NextWhite == 1 ) THEN - - Ch = Ch + 1 + ! Initialize index within word + iChar = 0 + + ! Initialize in quotes to false + InQuotes = .false. + + ! Loop through characters in line + do i = 1, len_trim(line) + + ! Get current character + Char = Line(i:i) + + ! Select based on character + select case (Char) + case ('"', "'") ! Double quotes, single quotes + if (IgnoreQuotesLoc .or. InQuotes) then + InQuotes = .false. + if (iChar > 0) then + ! If requested number of words found, exit; otherwise, new word + if (iWord == NumWords) exit + iWord = iWord + 1 + iChar = 0 + end if + else + InQuotes = .true. + end if + cycle + + ! Word separator + case (',', ';', ' ', Tab) ! Comma, semicolon, space, tab + ! If in quotes, keep these in word + if (.not. InQuotes) then + if (iChar > 0) then + ! If requested number of words found, exit; otherwise, new word + if (iWord == NumWords) exit + iWord = iWord + 1 + iChar = 0 + end if + cycle + end if - CYCLE + end select - ELSE + ! Increment character index + iChar = iChar + 1 - EXIT + ! If index is larger than length of word, continue + if (iChar > len(words(iWord))) then + call ProgWarn('Error reading field from file. There are too many characters in the input file to store in the field. Value may be truncated. '//Line) + cycle + end if - END IF + ! Add character to word + Words(iWord)(iChar:iChar) = Char - END DO - - END IF + end do - IF (PRESENT(NumFound)) NumFound = IW + if (present(NumFound)) NumFound = iWord - RETURN END SUBROUTINE GetWords !======================================================================= !> This subroutine is used to compare a header line (`HeaderLine`) with a list of column names. @@ -2467,6 +2494,7 @@ SUBROUTINE OpenEcho ( Un, OutFile, ErrStat, ErrMsg, ProgVer ) ! Get a unit number for the echo file: + !$OMP critical(fileopenNWTCio) IF ( Un < 0 ) THEN CALL GetNewUnit( Un, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2,ErrStat, ErrMsg, RoutineName ) @@ -2477,6 +2505,7 @@ SUBROUTINE OpenEcho ( Un, OutFile, ErrStat, ErrMsg, ProgVer ) CALL OpenFOutFile( Un, OutFile, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2,ErrStat, ErrMsg, RoutineName ) + !$OMP end critical(fileopenNWTCio) IF ( ErrStat >= AbortErrLev ) RETURN @@ -2958,7 +2987,7 @@ END SUBROUTINE ParseCom !! !! WARNING: This routine assumes the "words" containing the variable name and value are <= 20 characters. \n !! Use ParseVar (nwtc_io::parsevar) instead of directly calling a specific routine in the generic interface. - SUBROUTINE ParseChVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseChVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnEc, IsPath ) ! Arguments declarations. @@ -2967,6 +2996,7 @@ SUBROUTINE ParseChVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi), INTENT(INOUT) :: LineNum !< The number of the line to parse. INTEGER, INTENT(IN), OPTIONAL :: UnEc !< I/O unit for echo file. If present and > 0, write to UnEc. + LOGICAL, INTENT(IN), OPTIONAL :: IsPath !< Flag indicating that string is a path. CHARACTER(*), INTENT(OUT) :: Var !< The variable to receive the input value. CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if ErrStat /= 0. @@ -2979,6 +3009,7 @@ SUBROUTINE ParseChVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. INTEGER(IntKi) :: NameIndx ! The index into the Words array that points to the variable name. + LOGICAL :: IgnoreQuotes CHARACTER(NWTC_SizeOfNumWord) :: Words (2) ! The two "words" parsed from the line. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -2998,8 +3029,12 @@ SUBROUTINE ParseChVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE RETURN END IF - - CALL GetWords ( FileInfo%Lines(LineNum), Words, 2 ) ! Read the first two words in Line. + if (present(IsPath)) then + IgnoreQuotes = .not. IsPath + else + IgnoreQuotes = .true. + end if + CALL GetWords ( FileInfo%Lines(LineNum), Words, 2, IgnoreQuotes=IgnoreQuotes ) ! Read the first two words in Line. IF ( Words(2) == '' .and. (LEN_TRIM(ExpVarName) > 0) ) THEN CALL SetErrStat ( ErrID_Fatal, 'A fatal error occurred when parsing data from "' & //TRIM( FileInfo%FileList(FileInfo%FileIndx(LineNum)) )//'".'//NewLine// & @@ -4697,11 +4732,13 @@ RECURSIVE SUBROUTINE ReadComFile ( FileInfo, FileIndx, AryInd, StartLine, LastLi RETURN END IF + !$OMP critical(fileopenNWTCio) CALL GetNewUnit ( UnIn, ErrStatLcl, ErrMsg2 ) CALL SetErrStat( ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL OpenFInpFile ( UnIn, FileInfo%FileList(FileIndx), ErrStatLcl, ErrMsg2 ) CALL SetErrStat( ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !$OMP end critical(fileopenNWTCio) IF ( ErrStat >= AbortErrLev ) RETURN @@ -6631,9 +6668,11 @@ RECURSIVE SUBROUTINE ScanComFile ( FirstFile, ThisFile, LastFile, StartLine, Las ! Open the input file. UnIn = -1 + !$OMP critical(fileopenNWTCio) CALL GetNewUnit ( UnIn, ErrStatLcl, ErrMsg2 ) CALL OpenFInpFile ( UnIn, Filename, ErrStatLcl, ErrMsg2 ) + !$OMP end critical(fileopenNWTCio) IF ( ErrStatLcl /= 0 ) THEN CALL SetErrStat( ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL Cleanup() @@ -6941,6 +6980,7 @@ SUBROUTINE WrBinFAST(FileName, FileID, DescStr, ChanName, ChanUnit, TimeData, Al ! Generate the unit number for the binary file UnIn = 0 + !$OMP critical(fileopenNWTCio) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -6950,6 +6990,7 @@ SUBROUTINE WrBinFAST(FileName, FileID, DescStr, ChanName, ChanUnit, TimeData, Al CALL OpenBOutFile ( UnIn, TRIM(FileName), ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + !$OMP end critical(fileopenNWTCio) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() RETURN diff --git a/modules/nwtc-library/src/VTK.f90 b/modules/nwtc-library/src/VTK.f90 index 19f3d967a9..a407c9d770 100644 --- a/modules/nwtc-library/src/VTK.f90 +++ b/modules/nwtc-library/src/VTK.f90 @@ -93,8 +93,10 @@ SUBROUTINE WrVTK_header( FileName, NumberOfPoints, NumberOfLines, NumberOfPolys, INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs + !$OMP critical(fileopen) CALL GetNewUnit( Un, ErrStat, ErrMsg ) CALL OpenFOutFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) + !$OMP end critical(fileopen) if (ErrStat >= AbortErrLev) return ! Write a VTP mesh file (Polygonal VTK file) with positions and polygons (surfaces) @@ -157,10 +159,10 @@ SUBROUTINE ReadVTK_SP_info( FileName, descr, dims, origin, gridSpacing, vecLabel closeOnReturn = .FALSE. END IF - !$OMP critical + !$OMP critical(fileopen) CALL GetNewUnit( Un, ErrStat, ErrMsg ) CALL OpenFInpFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) - !$OMP end critical + !$OMP end critical(fileopen) if (ErrStat >= AbortErrLev) return CALL ReadCom( Un, FileName, 'File header: Module Version (line 1)', ErrStat2, ErrMsg2, 0 ) @@ -359,10 +361,10 @@ SUBROUTINE WrVTK_SP_header( FileName, descr, Un, ErrStat, ErrMsg ) INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs - !$OMP critical + !$OMP critical(fileopen) CALL GetNewUnit( Un, ErrStat, ErrMsg ) CALL OpenFOutFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) - !$OMP end critical + !$OMP end critical(fileopen) if (ErrStat >= AbortErrLev) return WRITE(Un,'(A)') '# vtk DataFile Version 3.0' @@ -450,6 +452,7 @@ logical function vtk_new_ascii_file(filename,label,mvtk) logical :: b if (.not. mvtk%bFileOpen) then + !$OMP critical(fileopen) CALL GetNewUnit( mvtk%vtk_unit ) if (mvtk%bBinary) then ! Fortran 2003 stream, otherwise intel fortran ! @@ -465,6 +468,7 @@ logical function vtk_new_ascii_file(filename,label,mvtk) else open(mvtk%vtk_unit,file=trim(adjustl(filename)),iostat=iostatvar,action="write",status='replace') endif + !$OMP end critical(fileopen) if (iostatvar == 0) then if (mvtk%bBinary) then write(mvtk%vtk_unit)'# vtk DataFile Version 3.0'//NewLine diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 83c0e525f9..90d292fe79 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -1715,8 +1715,10 @@ SUBROUTINE ED_HD_InputOutputSolve( this_time, p_FAST, calcJacobian & #ifdef OUTPUT_ADDEDMASS UnAM = -1 + !$OMP critical(fileopen) CALL GetNewUnit( UnAM, ErrStat, ErrMsg ) CALL OpenFOutFile( UnAM, TRIM(p_FAST%OutFileRoot)//'.AddedMassMatrix', ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL CleanUp() @@ -1729,8 +1731,10 @@ SUBROUTINE ED_HD_InputOutputSolve( this_time, p_FAST, calcJacobian & #endif #ifdef OUTPUT_JACOBIAN UnJac = -1 + !$OMP critical(fileopen) CALL GetNewUnit( UnJac, ErrStat2, ErrMsg2 ) CALL OpenFOutFile( UnJac, TRIM(p_FAST%OutFileRoot)//'.'//TRIM(num2lstr(this_time))//'.Jacobian2', ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL CleanUp() @@ -2490,8 +2494,10 @@ SUBROUTINE FullOpt1_InputOutputSolve( this_time, p_FAST, calcJacobian & #ifdef OUTPUT_ADDEDMASS IF (p_FAST%CompHydro == Module_HD ) THEN UnAM = -1 + !$OMP critical(fileopen) CALL GetNewUnit( UnAM, ErrStat2, ErrMsg2 ) CALL OpenFOutFile( UnAM, TRIM(p_FAST%OutFileRoot)//'.AddedMassMatrix', ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) RETURN @@ -2503,8 +2509,10 @@ SUBROUTINE FullOpt1_InputOutputSolve( this_time, p_FAST, calcJacobian & #endif #ifdef OUTPUT_JACOBIAN UnJac = -1 + !$OMP critical(fileopen) CALL GetNewUnit( UnJac, ErrStat2, ErrMsg2 ) CALL OpenFOutFile( UnJac, TRIM(p_FAST%OutFileRoot)//'.'//TRIM(num2lstr(this_time))//'.Jacobian', ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) RETURN @@ -5065,8 +5073,10 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca #ifdef OUTPUT_MASS_MATRIX if (n_t_global == 0 .and. p_FAST%CompElast /= Module_SED) then UnMM = -1 + !$OMP critical(fileopen) CALL GetNewUnit( UnMM, ErrStat2, ErrMsg2 ) CALL OpenFOutFile( UnMM, TRIM(p_FAST%OutFileRoot)//'.EDMassMatrix', ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) RETURN CALL WrMatrix(ED%m%AugMat,UnMM, p_FAST%OutFmt) diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 816441536e..67cde541c4 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -495,6 +495,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, SED, BD, S END IF ! lidar + Init%InData_IfW%LidarEnabled = .true. ! allowed with OF, but not FF Init%InData_IfW%lidar%Tmax = p_FAST%TMax if (p_FAST%CompElast == Module_SED) then Init%InData_IfW%lidar%HubPosition = SED%y%HubPtMotion%Position(:,1) @@ -520,6 +521,13 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, SED, BD, S Init%InData_IfW%Use4Dext = .false. END IF + ! OLAF might be used in AD, in which case we need to allow out of bounds for some calcs. To do that + ! the average values for the entire wind profile must be calculated and stored (we don't know if OLAF + ! is used until after AD_Init below). + if (p_FAST%CompAero == Module_AD) then + Init%InData_IfW%BoxExceedAllow = .true. + endif + CALL InflowWind_Init( Init%InData_IfW, IfW%Input(1), IfW%p, IfW%x(STATE_CURR), IfW%xd(STATE_CURR), IfW%z(STATE_CURR), & IfW%OtherSt(STATE_CURR), IfW%y, IfW%m, p_FAST%dt_module( MODULE_IfW ), Init%OutData_IfW, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -2679,11 +2687,14 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) y_FAST%ActualChanLen = max( y_FAST%ActualChanLen, LEN_TRIM(y_FAST%ChannelUnits(I)) ) ENDDO ! I - CALL GetNewUnit( y_FAST%UnOu, ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN - CALL OpenFOutFile ( y_FAST%UnOu, TRIM(p_FAST%OutFileRoot)//'.out', ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN + !$OMP critical(fileopen) + CALL GetNewUnit( y_FAST%UnOu, ErrStat, ErrMsg ) + IF ( ErrStat < AbortErrLev ) then + CALL OpenFOutFile ( y_FAST%UnOu, TRIM(p_FAST%OutFileRoot)//'.out', ErrStat, ErrMsg ) + ENDIF + !$OMP end critical(fileopen) + IF ( ErrStat >= AbortErrLev ) RETURN ! Add some file information: @@ -2815,18 +2826,18 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrS ! Get an available unit number for the file. + !$OMP critical(fileopen) CALL GetNewUnit( UnIn, ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN - - + if ( ErrStat < AbortErrLev ) then ! Open the Primary input file. - - CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) + CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) - if ( ErrStat >= AbortErrLev ) then - call cleanup() - RETURN - end if + endif + !$OMP end critical(fileopen) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if p%NumSSCases = 0 p%RotSpeedInit = 0.0_ReKi @@ -4845,11 +4856,13 @@ SUBROUTINE FAST_WrSum( p_FAST, y_FAST, MeshMapData, ErrStat, ErrMsg ) ! Get a unit number and open the file: + !$OMP critical(fileopen) CALL GetNewUnit( y_FAST%UnSum, ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN - - CALL OpenFOutFile ( y_FAST%UnSum, TRIM(p_FAST%OutFileRoot)//'.sum', ErrStat, ErrMsg ) - IF ( ErrStat >= AbortErrLev ) RETURN + if ( ErrStat < AbortErrLev ) then + CALL OpenFOutFile ( y_FAST%UnSum, TRIM(p_FAST%OutFileRoot)//'.sum', ErrStat, ErrMsg ) + endif + !$OMP end critical(fileopen) + IF ( ErrStat >= AbortErrLev ) RETURN ! Add some file information: @@ -9181,8 +9194,10 @@ SUBROUTINE WriteInputMeshesToFile(u_ED, u_AD, u_SD, u_HD, u_MAP, u_BD, FileName, ! Open the binary output file: unOut=-1 + !$OMP critical(fileopen) CALL GetNewUnit( unOut, ErrStat, ErrMsg ) CALL OpenBOutFile ( unOut, TRIM(FileName), ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat /= ErrID_None) RETURN ! note that I'm not doing anything with the errors here, so it won't tell @@ -9261,9 +9276,11 @@ SUBROUTINE WriteMotionMeshesToFile(time, y_ED, u_SD, y_SD, u_HD, u_MAP, y_BD, u_ ! Open the binary output file and write a header: if (unOut<0) then + !$OMP critical(fileopen) CALL GetNewUnit( unOut, ErrStat, ErrMsg ) CALL OpenBOutFile ( unOut, TRIM(FileName), ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat /= ErrID_None) RETURN ! Add a file identification number (in case we ever have to change this): @@ -10073,10 +10090,12 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, IF ( unOut < 0 ) THEN - CALL GetNewUnit(unOut, ErrStat2, ErrMsg2) - CALL OpenBOutFile (unOut, FileName, ErrStat2, ErrMsg2) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev) then + !$OMP critical(fileopen) + CALL GetNewUnit( unOut, ErrStat2, ErrMsg2 ) + CALL OpenBOutFile ( unOut, FileName, ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev ) then IF (.NOT. PRESENT(Unit)) THEN CLOSE(unOut) unOut = -1 @@ -10226,11 +10245,12 @@ SUBROUTINE FAST_RestoreFromCheckpoint_T(t_initial, n_t_global, NumTurbines, Turb IF ( unIn < 0 ) THEN + !$OMP critical(fileopen) CALL GetNewUnit( unIn, ErrStat2, ErrMsg2 ) - - CALL OpenBInpFile(unIn, FileName, ErrStat2, ErrMsg2) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - if (ErrStat >= AbortErrLev ) return + CALL OpenBInpFile ( unIn, FileName, ErrStat2, ErrMsg2) + !$OMP end critical(fileopen) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev ) RETURN READ (unIn, IOSTAT=ErrStat2) AbortErrLev ! Abort error level READ (unIn, IOSTAT=ErrStat2) NumTurbines ! Number of turbines @@ -10602,9 +10622,11 @@ SUBROUTINE ReadModeShapeMatlabFile(p_FAST, ErrStat, ErrMsg) ErrMsg = "" ! Open data file. + !$OMP critical(fileopen) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) CALL OpenBInpFile ( UnIn, trim(p_FAST%VTK_modes%MatlabFileName), ErrStat2, ErrMsg2 ) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN @@ -10728,9 +10750,11 @@ SUBROUTINE ReadModeShapeFile(p_FAST, InputFile, ErrStat, ErrMsg, checkpointOnly) CALL GetPath( InputFile, PriPath ) ! Input files will be relative to the path where the primary input file is located. ! Open data file. + !$OMP critical(fileopen) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN diff --git a/modules/seastate/src/SeaState_Input.f90 b/modules/seastate/src/SeaState_Input.f90 index 71daf185e9..0ddedbaffc 100644 --- a/modules/seastate/src/SeaState_Input.f90 +++ b/modules/seastate/src/SeaState_Input.f90 @@ -271,7 +271,7 @@ subroutine SeaSt_ParseInput( InputFileName, OutRootName, defWtrDens, defWtrDpth, if (Failed()) return; ! WvKinFile - call ParseVar( FileInfo_In, CurLine, 'WvKinFile', InputFileData%Waves%WvKinFile, ErrStat2, ErrMsg2, UnEc ) + call ParseVar( FileInfo_In, CurLine, 'WvKinFile', InputFileData%Waves%WvKinFile, ErrStat2, ErrMsg2, UnEc, IsPath=.true. ) if (Failed()) return; !------------------------------------------------------------------------------------------------- diff --git a/modules/seastate/src/SeaState_Output.f90 b/modules/seastate/src/SeaState_Output.f90 index 96ff2d0f06..dc202ce5a6 100644 --- a/modules/seastate/src/SeaState_Output.f90 +++ b/modules/seastate/src/SeaState_Output.f90 @@ -280,10 +280,12 @@ SUBROUTINE SeaStOut_WriteWvKinFiles( Rootname, SeaSt_Prog, WaveField, WaveDT, X_ DO iFile = 1,7 - CALL GetNewUnit( UnWv ) WvName = TRIM(Rootname) // TRIM(extension(iFile)) + !$OMP critical(fileopen) + CALL GetNewUnit( UnWv ) CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN call WriteWvKinHeader( UnWv, iFile, Delim, SeaSt_Prog, waveDT, -z_gridPts(1), NGrid, deltaGrid ) @@ -330,11 +332,11 @@ SUBROUTINE SeaStOut_WriteWvKinFiles( Rootname, SeaSt_Prog, WaveField, WaveDT, X_ END DO ! WaveElevation Grid - - CALL GetNewUnit( UnWv ) - WvName = TRIM(Rootname) // '.Elev' + !$OMP critical(fileopen) + CALL GetNewUnit( UnWv ) CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -444,13 +446,15 @@ subroutine SeaStOut_WriteWaveElev0( Rootname, NStepWave, NGrid, WaveElev1, WaveE ErrMsg = "" Frmt = '(F12.4,ES12.4e2)' Frmt2 = '(2(A12))' - CALL GetNewUnit( UnWv ) WvName = TRIM(Rootname) // '.Elev' i = NGrid(1) / 2 + 1 j = NGrid(2) / 2 + 1 + !$OMP critical(fileopen) + CALL GetNewUnit( UnWv ) CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN ! WRITE (UnWv,'(A)', IOSTAT=ErrStat) 'This wave elevation (0,0) file was generated by '//TRIM( SeaSt_Prog%Name )//& ! ' '//TRIM( SeaSt_Prog%Ver )//' on '//CurDate()//' at '//CurTime()//'.' @@ -718,9 +722,11 @@ SUBROUTINE SeaStOut_OpenOutput( SeaSt_ProgDesc, OutRootName, p, InitOut, ErrSta ! Open the file for output OutFileName = TRIM(OutRootName)//'.out' + + !$OMP critical(fileopen) CALL GetNewUnit( p%UnOutFile ) - CALL OpenFOutFile ( p%UnOutFile, OutFileName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1011,9 +1017,11 @@ SUBROUTINE SeaStOut_WrSummaryFile(InitInp, InputFileData, p, ErrStat, ErrMsg ) SummaryName = trim(InitInp%OutRootName)//'.sum' UnSum = -1 - CALL GetNewUnit( UnSum ) + !$OMP critical(fileopen) + CALL GetNewUnit( UnSum ) CALL OpenFOutFile ( UnSum, SummaryName, ErrStat2, ErrMsg2 ) + !$OMP end critical(fileopen) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) IF (ErrStat >=AbortErrLev) RETURN diff --git a/modules/seastate/src/UserWaves.f90 b/modules/seastate/src/UserWaves.f90 index 12eed126e0..4dbb0c79b2 100644 --- a/modules/seastate/src/UserWaves.f90 +++ b/modules/seastate/src/UserWaves.f90 @@ -144,14 +144,14 @@ SUBROUTINE WaveElev_ReadFile ( InitInp, WaveElevData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - ! Get a unit number for reading in the file - CALL GetNewUnit( WaveElevUnit ) - ! Assemble the filename for the wave elevation data. WaveElevData%FileName = TRIM(InitInp%WvKinFile)//'.Elev' ! Open the file containing the wave elevation timeseries + !$OMP critical(fileopen) + CALL GetNewUnit( WaveElevUnit ) CALL OpenFInpFile( WaveElevUnit, WaveElevData%FileName, ErrStatTmp, ErrMsgTmp ) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat,ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CLOSE ( WaveElevUnit ) @@ -492,11 +492,13 @@ SUBROUTINE UserWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) ! Read the first file and set the initial values of the DO iFile = 1,7 - CALL GetNewUnit( UnWv ) FileName = TRIM(InitInp%WvKinFile) // TRIM(extension(iFile)) + !$OMP critical(fileopen) + CALL GetNewUnit( UnWv ) CALL OpenFInpFile ( UnWv, FileName, ErrStatTmp, ErrMsgTmp ) + !$OMP end critical(fileopen) IF ( ErrStatTmp /= 0 ) THEN ErrMsgTmp = 'Failed to open wave kinematics file, ' // TRIM(FileName) CALL SetErrStat( ErrID_Fatal, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) @@ -552,11 +554,13 @@ SUBROUTINE UserWaves_Init ( InitInp, InitOut, WaveField, ErrStat, ErrMsg ) end do ! WaveElev - CALL GetNewUnit( UnWv ) FileName = TRIM(InitInp%WvKinFile) // '.Elev' + !$OMP critical(fileopen) + CALL GetNewUnit( UnWv ) CALL OpenFInpFile ( UnWv, FileName, ErrStatTmp, ErrMsgTmp ) + !$OMP end critical(fileopen) IF ( ErrStatTmp /= 0 ) THEN ErrMsgTmp = 'Failed to open wave elevation file, ' // TRIM(FileName) CALL SetErrStat( ErrID_Fatal, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) @@ -691,14 +695,14 @@ SUBROUTINE WaveComp_ReadFile ( InitInp, WaveDOmega, WaveCompData, ErrStat, ErrMs ErrStat = ErrID_None ErrMsg = "" - ! Get a unit number for reading in the file - CALL GetNewUnit( WaveCompUnit ) - ! Assemble the filename for the wave component data. WaveCompData%FileName = TRIM(InitInp%WvKinFile) ! Open the file containing the list of wave components + !$OMP critical(fileopen) + CALL GetNewUnit( WaveCompUnit ) CALL OpenFInpFile( WaveCompUnit, WaveCompData%FileName, ErrStatTmp, ErrMsgTmp ) + !$OMP end critical(fileopen) CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat,ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL CleanUpError() diff --git a/modules/servodyn/src/ServoDyn_IO.f90 b/modules/servodyn/src/ServoDyn_IO.f90 index cb900579ec..13d607f6eb 100644 --- a/modules/servodyn/src/ServoDyn_IO.f90 +++ b/modules/servodyn/src/ServoDyn_IO.f90 @@ -1332,15 +1332,15 @@ subroutine ParseInputFileInfo( PriPath, InputFile, OutFileRoot, FileInfo_In, Inp if ( InputFileData%Echo ) WRITE(UnEcho, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo CurLine = CurLine + 1 ! DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] - call ParseVar( FileInfo_In, CurLine, 'DLL_FileName', InputFileData%DLL_FileName, ErrStat2, ErrMsg2, UnEcho ) + call ParseVar( FileInfo_In, CurLine, 'DLL_FileName', InputFileData%DLL_FileName, ErrStat2, ErrMsg2, UnEcho, IsPath=.true. ) if (Failed()) return; IF ( PathIsRelative( InputFileData%DLL_FileName ) ) InputFileData%DLL_FileName = TRIM(PriPath)//TRIM(InputFileData%DLL_FileName) ! DLL_InFile - Name of input file sent to the DLL (-) [used only with Bladed Interface] - call ParseVar( FileInfo_In, CurLine, 'DLL_InFile', InputFileData%DLL_InFile, ErrStat2, ErrMsg2, UnEcho ) + call ParseVar( FileInfo_In, CurLine, 'DLL_InFile', InputFileData%DLL_InFile, ErrStat2, ErrMsg2, UnEcho, IsPath=.true. ) if (Failed()) return; IF ( PathIsRelative( InputFileData%DLL_InFile ) ) InputFileData%DLL_InFile = TRIM(PriPath)//TRIM(InputFileData%DLL_InFile) ! DLL_ProcName - Name of procedure in DLL to be called (-) [case sensitive; used only with DLL Interface] - call ParseVar( FileInfo_In, CurLine, 'DLL_ProcName', InputFileData%DLL_ProcName, ErrStat2, ErrMsg2, UnEcho ) + call ParseVar( FileInfo_In, CurLine, 'DLL_ProcName', InputFileData%DLL_ProcName, ErrStat2, ErrMsg2, UnEcho, IsPath=.true. ) if (Failed()) return; ! DLL_DT - Communication interval for dynamic library (s) (or "default") [used only with Bladed Interface] call ParseVarWDefault( FileInfo_In, CurLine, 'DLL_DT', InputFileData%DLL_DT, InputFileData%DT, ErrStat2, ErrMsg2, UnEcho ) @@ -2400,8 +2400,10 @@ subroutine InitializeSummaryFile(InputFileData,OutfileRoot,UnSum,ErrStat,ErrMsg) ErrStat = ErrID_None ErrMsg = '' if ( InputFileData%SumPrint ) then + !$OMP critical(fileopen) call GetNewUnit( UnSum ) CALL OpenEcho ( UnSum, TRIM(OutFileRoot)//'.sum', ErrStat2, ErrMsg2 ) + !$OMP end critical(fileopen) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) IF (ErrStat >= AbortErrLev) RETURN else diff --git a/modules/servodyn/src/StrucCtrl.f90 b/modules/servodyn/src/StrucCtrl.f90 index 60c9efd530..0c0cea0da6 100644 --- a/modules/servodyn/src/StrucCtrl.f90 +++ b/modules/servodyn/src/StrucCtrl.f90 @@ -2115,7 +2115,7 @@ SUBROUTINE StC_ParseInputFileInfo( PriPath, InputFile, RootName, NumMeshPts, Fil call ParseVar( FileInfo_In, Curline, 'PrescribedForcesCoordSys', InputFileData%PrescribedForcesCoordSys, ErrStat2, ErrMsg2 ) If (Failed()) return; ! Prescribed input time series - call ParseVar( FileInfo_In, Curline, 'PrescribedForcesFile', InputFileData%PrescribedForcesFile, ErrStat2, ErrMsg2 ) + call ParseVar( FileInfo_In, Curline, 'PrescribedForcesFile', InputFileData%PrescribedForcesFile, ErrStat2, ErrMsg2, IsPath=.true. ) if (Failed()) return; if ( PathIsRelative( InputFileData%PrescribedForcesFile ) ) InputFileData%PrescribedForcesFile = TRIM(PriPath)//TRIM(InputFileData%PrescribedForcesFile) diff --git a/modules/subdyn/src/SubDyn.f90 b/modules/subdyn/src/SubDyn.f90 index eff2ca3a23..c9c62ed92c 100644 --- a/modules/subdyn/src/SubDyn.f90 +++ b/modules/subdyn/src/SubDyn.f90 @@ -934,9 +934,11 @@ SUBROUTINE SD_Input(SDInputFile, Init, p, ErrStat,ErrMsg) UnEc = -1 Echo = .FALSE. +!$OMP critical(fileopen) CALL GetNewUnit( UnIn ) CALL OpenFInpfile(UnIn, TRIM(SDInputFile), ErrStat2, ErrMsg2) +!$OMP end critical(fileopen) IF ( ErrStat2 /= ErrID_None ) THEN Call Fatal('Could not open SubDyn input file') @@ -3624,6 +3626,7 @@ END SUBROUTINE OutModes !> Write the common part of the JSON file (Nodes, Connectivity, Element prop) +!FIXME: error handling is broken here!!! SUBROUTINE WriteJSONCommon(FileName, Init, p, m, InitInput, FileKind, UnSum, ErrStat, ErrMsg) use JSON, only: json_write_array TYPE(SD_InitType), INTENT(INOUT) :: Init !< Input data for initialization routine @@ -3645,8 +3648,10 @@ SUBROUTINE WriteJSONCommon(FileName, Init, p, m, InitInput, FileKind, UnSum, Err ! --- Create file and get unit UnSum = -1 ! we haven't opened the summary file, yet. + !$OMP critical(fileopen) call GetNewUnit( UnSum ) call OpenFOutFile ( UnSum, FileName, ErrStat2, ErrMsg2 ) + !$OMP end critical(fileopen) write(UnSum, '(A)')'{' ! --- Misc diff --git a/openfast_python/openfast_io/turbsim_file.py b/openfast_python/openfast_io/turbsim_file.py index 2756fff7be..9cd6ed1e88 100644 --- a/openfast_python/openfast_io/turbsim_file.py +++ b/openfast_python/openfast_io/turbsim_file.py @@ -5,6 +5,7 @@ """ import pandas as pd import numpy as np +import argparse import os import struct import time @@ -16,13 +17,13 @@ File=dict class TurbSimFile(File): - """ + """ Read/write a TurbSim turbulence file (.bts). The object behaves as a dictionary. Main keys --------- - 'u': velocity field, shape (3 x nt x ny x nz) - - 'y', 'z', 't': space and time coordinates + - 'y', 'z', 't': space and time coordinates - 'dt', 'ID', 'info' - 'zTwr', 'uTwr': tower coordinates and field if present (3 x nt x nTwr) - 'zHub', 'uHub': height and velocity at a reference point (usually not hub) @@ -36,7 +37,7 @@ class TurbSimFile(File): ts = TurbSimFile('Turb.bts') print(ts.keys()) - print(ts['u'].shape) + print(ts['u'].shape) """ @@ -55,7 +56,7 @@ def __init__(self,filename=None, **kwargs): self.read(filename, **kwargs) def read(self, filename=None, header_only=False): - """ read BTS file, with field: + """ read BTS file, with field: u (3 x nt x ny x nz) uTwr (3 x nt x nTwr) """ @@ -69,7 +70,7 @@ def read(self, filename=None, header_only=False): raise EmptyFileError('File is empty:',self.filename) scl = np.zeros(3, np.float32); off = np.zeros(3, np.float32) - with open(self.filename, mode='rb') as f: + with open(self.filename, mode='rb') as f: # Reading header info ID, nz, ny, nTwr, nt = struct.unpack('0) @@ -95,7 +96,7 @@ def read(self, filename=None, header_only=False): self['info'] = info self['ID'] = ID self['dt'] = dt - self['y'] = np.arange(ny)*dy + self['y'] = np.arange(ny)*dy self['y'] -= np.mean(self['y']) # y always centered on 0 self['z'] = np.arange(nz)*dz +zBottom self['t'] = np.arange(nt)*dt @@ -104,7 +105,7 @@ def read(self, filename=None, header_only=False): self['uHub'] = uHub def write(self, filename=None): - """ + """ write a BTS file, using the following keys: 'u','z','y','t','uTwr' u (3 x nt x ny x nz) uTwr (3 x nt x nTwr) @@ -151,7 +152,7 @@ def write(self, filename=None): # Providing estimates of uHub and zHub even if these fields are not used zHub,uHub, bHub = self.hubValues() - with open(self.filename, mode='wb') as f: + with open(self.filename, mode='wb') as f: f.write(struct.pack('