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/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/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index d43664041a..585a5af5ee 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 @@ -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_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 0d3b1d295d..7501857cef 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -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 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/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/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_IO.f90 b/modules/inflowwind/src/InflowWind_IO.f90 index 35fbd4d6dc..5f9150ce8f 100644 --- a/modules/inflowwind/src/InflowWind_IO.f90 +++ b/modules/inflowwind/src/InflowWind_IO.f90 @@ -537,12 +537,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 +903,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 +1143,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 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..29133e7b43 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) @@ -2679,11 +2680,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 +2819,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 +4849,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 +9187,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 +9269,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 +10083,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 +10238,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 +10615,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 +10743,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/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/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 26cbe15910..d5da53087d 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -42,7 +42,7 @@ option(CTEST_NO_RUN_FLAG "Complete the regression test comparison but do not ex # Set the OpenFAST executable configuration option and default set(CTEST_OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST executable to use in testing.") -if(BUILD_OPENFAST_CPP_API) +if(BUILD_OPENFAST_CPP_DRIVER) # Set the OpenFAST executable configuration option and default set(CTEST_OPENFASTCPP_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast-cpp/openfastcpp${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST C++ executable to use in testing.") endif() diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 8d48adcc3e..4d90af3db3 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -104,7 +104,7 @@ endfunction(of_aeromap_regression) function(of_fastlib_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastRegressionCase.py") - set(OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast_cpp_driver") + set(OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast_lib_driver") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") # extra flag in call to "regression" on next line sets the ${TESTDIR} @@ -347,11 +347,11 @@ if(BUILD_OPENFAST_CPP_DRIVER) of_cpp_interface_regression("5MW_Restart_cpp" "openfast;fastlib;cpp;restart") endif() -# OpenFAST C++ Driver test for OpenFAST Library +# OpenFAST Driver test for OpenFAST C++ Library # This tests the FAST Library and FAST_Library.h -if(BUILD_OPENFAST_CPP_DRIVER) +if(BUILD_OPENFAST_LIB_DRIVER) of_fastlib_regression("AWT_YFree_WSt" "fastlib;elastodyn;aerodyn;servodyn") -endif(BUILD_OPENFAST_CPP_DRIVER) +endif() # OpenFAST Python API test of_regression_py("5MW_Land_DLL_WTurb_py" "openfast;fastlib;python;elastodyn;aerodyn;servodyn") diff --git a/reg_tests/r-test b/reg_tests/r-test index b3824f2d3a..e609fa995a 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit b3824f2d3a4cd4cb826aa4ac95b6e39a99e66d43 +Subproject commit e609fa995afee18f1f2f55aa2e0255b830fd7f8d