From bbded1bf7484f23781730f3bc91527fad4a51293 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Mon, 4 Nov 2024 14:05:24 +0000 Subject: [PATCH 01/49] CMAKE_INSTALL_PREFIX was incorrectly being prepended to the install directory for the ftnmod folder which caused it to be in the wrong place when importing OpenFAST as a library in AMR-Wind --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2dc54651d..3299153263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,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" ) From 309832aa26edc2ecf8e895958886773b2cc14226 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 4 Nov 2024 10:06:00 -0700 Subject: [PATCH 02/49] Docker: typo was preventing docker build upload to GH --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 180969d6fa..b94a541b10 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -77,7 +77,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 From a6268d3cb4d18e186555b557273baa14720e3a85 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Tue, 5 Nov 2024 16:46:57 +0000 Subject: [PATCH 03/49] Remove OpenMP statements from AeroDyn_Inflow.f90 because it causes compilation to fail when using the Intel oneAPI 2024.1.0 compiler --- modules/aerodyn/src/AeroDyn_Inflow.f90 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn_Inflow.f90 b/modules/aerodyn/src/AeroDyn_Inflow.f90 index 6dd7773665..17ad2f4bbc 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow.f90 @@ -488,16 +488,12 @@ subroutine ADI_CalcOutput_IW(t, u_IfW, IW, errStat, errMsg) call InflowWind_CalcOutput(t, u_IfW, IW%p, IW%x, IW%xd, IW%z, IW%OtherSt, IW%y, IW%m, errStat2, errMsg2) call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'ADI_CalcOutput_IW') else - !$OMP PARALLEL DEFAULT(SHARED) - !$OMP DO PRIVATE(j,z) schedule(runtime) do j=1,size(u_IfW%PositionXYZ,2) z = u_IfW%PositionXYZ(3,j) IW%y%VelocityUVW(1,j) = IW%HWindSpeed*(z/IW%RefHt)**IW%PLExp IW%y%VelocityUVW(2,j) = 0.0_ReKi !V IW%y%VelocityUVW(3,j) = 0.0_ReKi !W end do - !$OMP END DO - !$OMP END PARALLEL endif end subroutine ADI_CalcOutput_IW !---------------------------------------------------------------------------------------------------------------------------------- From ee1726c348941662371b9823e4420c2464c9dc96 Mon Sep 17 00:00:00 2001 From: Mayank Chetan Date: Wed, 6 Nov 2024 15:30:12 -0700 Subject: [PATCH 04/49] change to tag tracking --- .github/workflows/deploy.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b94a541b10..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 From 3acba023b3280424a7abbdc9706f6b0b8f00b2eb Mon Sep 17 00:00:00 2001 From: Mayank Chetan Date: Fri, 8 Nov 2024 11:08:40 -0700 Subject: [PATCH 05/49] repository name must be lowercase --- .github/workflows/build-docker-image-manual.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 15bafa4d4830749b6cff6fa0f89278f7fd1c5180 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 14 Nov 2024 16:36:26 -0700 Subject: [PATCH 06/49] AD bugfix: Segmentation fault with ifx When OLAF was used with the AeroDyn Driver compiled with ifx (IFX) 2023.2.0 20230622 (release only), there would be a segmentation fault when SetInputsForFVW was called. The root issue was that passing an array of `u` as `(/u/)` doesn't work correctly with this compiler. So to work around this, the SetInputsForFVW routine was reworked to only operate on a single `u`. In my opinion this is a hack of a solution to accomodate a compiler bug. --- modules/aerodyn/src/AeroDyn.f90 | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index e631ea3fcb..658f12bce5 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -1623,8 +1623,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) - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + do i=1,size(u) + call SetInputsForFVW(p, u(i), i, m, errStat2, errMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + 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 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1696,7 +1698,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, if (p%WakeMod == 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) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ! Calculate Outputs at time t CALL FVW_CalcOutput( t, m%FVW_u(1), p%FVW, x%FVW, xd%FVW, z%FVW, OtherState%FVW, m%FVW_y, m%FVW, ErrStat2, ErrMsg2 ) @@ -3091,10 +3093,11 @@ subroutine Calculate_MeshOrientation_LiftingLine(p, u, m, thetaBladeNds, toeBlad 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 @@ -3102,7 +3105,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 @@ -3113,55 +3115,54 @@ 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%rotors(iR), x_hat_disk) ! also sets m%V_diskAvg and m%V_dot_x + call DiskAvgValues(p%rotors(iR), u%rotors(iR), m%rotors(iR), x_hat_disk) ! also sets m%V_diskAvg and m%V_dot_x if (p%rotors(iR)%AeroProjMod==APM_BEM_NoSweepPitchTwist) then - call Calculate_MeshOrientation_NoSweepPitchTwist(p%rotors(iR),u(tIndx)%rotors(iR), m%rotors(iR), thetaBladeNds,ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve + call Calculate_MeshOrientation_NoSweepPitchTwist(p%rotors(iR),u%rotors(iR), m%rotors(iR), thetaBladeNds,ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve else if (p%rotors(iR)%AeroProjMod==APM_LiftingLine) then - call Calculate_MeshOrientation_LiftingLine (p%rotors(iR),u(tIndx)%rotors(iR), m%rotors(iR), thetaBladeNds,ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve + call Calculate_MeshOrientation_LiftingLine (p%rotors(iR),u%rotors(iR), m%rotors(iR), thetaBladeNds,ErrStat=ErrStat2,ErrMsg=ErrMsg2) ! sets m%orientationAnnulus, m%Curve endif - call StorePitchAndAzimuth(p%rotors(iR), u(tIndx)%rotors(iR), m%rotors(iR), ErrStat2, ErrMsg2) + 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(tIndx)%rotors(iR)%BladeMotion(k)%nNodes /= m%FVW_u(tIndx)%WingsMesh(iW)%nNodes ) then + + 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 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) - + 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(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 + 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 = u(tIndx)%InflowWakeVel + m%FVW_u(tIndx)%V_wind = u%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%rotors(iR), m%FVW%r_wind, m%FVW_u(tIndx)%V_wind, ErrStat2, ErrMsg2 ) + call TwrInflArray( p%rotors(iR), u%rotors(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 @@ -3170,14 +3171,13 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) endif do iR =1, size(p%rotors) ! Disturbed inflow for UA on Lifting line Mesh Points - call SetDisturbedInflow(p%rotors(iR), p, u(tIndx)%rotors(iR), m%rotors(iR), errStat2, errMsg2) + call SetDisturbedInflow(p%rotors(iR), p, u%rotors(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 - enddo end subroutine SetInputsForFVW !---------------------------------------------------------------------------------------------------------------------------------- From d4ea5ffb8df45b0228c33aab651dfb5b9ddb7b2d Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 15 Nov 2024 14:40:48 -0700 Subject: [PATCH 07/49] ADI bugfix: BoxExceed was not enabled for OLAF with ADI Neither the C-bindings nor AD driver could use the BoxExceedAllow option with OLAF --- modules/aerodyn/src/AeroDyn_Inflow.f90 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn_Inflow.f90 b/modules/aerodyn/src/AeroDyn_Inflow.f90 index 17ad2f4bbc..c83971db0b 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow.f90 @@ -4,7 +4,7 @@ module AeroDyn_Inflow use NWTC_Library use AeroDyn_Inflow_Types use AeroDyn_Types - use AeroDyn, only: AD_Init, AD_ReInit, AD_CalcOutput, AD_UpdateStates, AD_End + use AeroDyn, only: AD_Init, AD_ReInit, AD_CalcOutput, AD_UpdateStates, AD_End, AD_BoxExceedPointsIdx use AeroDyn, only: AD_NumWindPoints, AD_GetExternalWind, AD_SetExternalWindPositions use AeroDyn_IO, only: AD_SetVTKSurface use InflowWind, only: InflowWind_Init, InflowWind_CalcOutput, InflowWind_End @@ -344,6 +344,11 @@ subroutine ADI_InitInflowWind(Root, i_IW, u_AD, o_AD, IW, dt, InitOutData, errSt InitInData%InputFileName = i_IW%InputFile InitInData%Linearize = i_IW%Linearize InitInData%UseInputFile = i_IW%UseInputFile + ! Box exceed allow for OLAF poitns + if (allocated(o_AD%WakeLocationPoints)) then + InitInData%BoxExceedAllowF = .true. + InitInData%BoxExceedAllowIdx = min(InitInData%BoxExceedAllowIdx, AD_BoxExceedPointsIdx(u_AD, o_AD)) + endif if (.not. i_IW%UseInputFile) then call NWTC_Library_Copyfileinfotype( i_IW%PassedFileData, InitInData%PassedFileData, MESH_NEWCOPY, errStat2, errMsg2 ); if (Failed()) return endif From 901e3b325a42dc7768c75846aa22bd908690e1d0 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 22 Nov 2024 15:12:36 -0700 Subject: [PATCH 08/49] Incorrect initial value for `BoxExceedAllowIdx` This was introduced in PR #2518. The result was that anytime the driver was used with OLAF, all points were allowed outside the box, not just the wake as intended. --- modules/aerodyn/src/AeroDyn_Inflow.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn_Inflow.f90 b/modules/aerodyn/src/AeroDyn_Inflow.f90 index c83971db0b..0418fa019b 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow.f90 @@ -347,7 +347,7 @@ subroutine ADI_InitInflowWind(Root, i_IW, u_AD, o_AD, IW, dt, InitOutData, errSt ! Box exceed allow for OLAF poitns if (allocated(o_AD%WakeLocationPoints)) then InitInData%BoxExceedAllowF = .true. - InitInData%BoxExceedAllowIdx = min(InitInData%BoxExceedAllowIdx, AD_BoxExceedPointsIdx(u_AD, o_AD)) + InitInData%BoxExceedAllowIdx = AD_BoxExceedPointsIdx(u_AD, o_AD) endif if (.not. i_IW%UseInputFile) then call NWTC_Library_Copyfileinfotype( i_IW%PassedFileData, InitInData%PassedFileData, MESH_NEWCOPY, errStat2, errMsg2 ); if (Failed()) return From 5bbddd98e934ad61fbd3900fcface1ec94841886 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 22 Nov 2024 15:18:31 -0700 Subject: [PATCH 09/49] Fix error in BoxExceedAllowIdx in glue code IfW defaults this to -1, so if OLAF is used it would simply pass -1 for the index rather than the correct location from the AD_BoxExceedPointsIdx routine. --- modules/openfast-library/src/FAST_Subs.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 7fc3954ec9..e23cfe2e04 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -578,7 +578,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! Wake -- we allow the wake positions to exceed the wind box if (allocated(AD%OtherSt(STATE_CURR)%WakeLocationPoints)) then Init%InData_IfW%BoxExceedAllowF = .true. - Init%InData_IfW%BoxExceedAllowIdx = min(Init%InData_IfW%BoxExceedAllowIdx, AD_BoxExceedPointsIdx(AD%Input(1), AD%OtherSt(STATE_CURR))) + Init%InData_IfW%BoxExceedAllowIdx = AD_BoxExceedPointsIdx(AD%Input(1), AD%OtherSt(STATE_CURR)) endif END IF From 239316f415234380ce149a2ef8c7d01d5b9a5305 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sat, 23 Nov 2024 16:48:08 -0700 Subject: [PATCH 10/49] bugfix: IfW rotor points for disk average incorrect The calculations for the rotor disk average wind speed use a set of point projected on the disk perpindular to the hub at ~0.7 rotor radius in the hub YZ plane. However, the indices for this calculation were incorrect and projected the points onto disk in the hub XY plane. This was discovered after one of the cases used in the curled wake paper failed to run correctly with 3.5.4 for a turbine very close to the back edge of the high resolution domain. Also added some additional information about the location of points causing outside box bound errors. --- modules/inflowwind/src/IfW_FlowField.f90 | 8 +++++--- modules/inflowwind/src/InflowWind_Subs.f90 | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/inflowwind/src/IfW_FlowField.f90 b/modules/inflowwind/src/IfW_FlowField.f90 index a71b75dffc..d20e1815d5 100644 --- a/modules/inflowwind/src/IfW_FlowField.f90 +++ b/modules/inflowwind/src/IfW_FlowField.f90 @@ -1591,6 +1591,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 = "" @@ -1627,11 +1628,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_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index de910b24c8..8b5a18b0c6 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -1047,9 +1047,9 @@ SUBROUTINE InflowWind_SetParameters( InitInp, InputFileData, p, m, ErrStat, ErrM 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 + 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 p%OutputAccel = InitInp%OutputAccel From ce8351ea2fbb356ae105d6e38ae00a630268c305 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 25 Nov 2024 13:05:51 -0700 Subject: [PATCH 11/49] IfW: use single point for disk average if no radius given --- modules/inflowwind/src/InflowWind_Subs.f90 | 39 +++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/modules/inflowwind/src/InflowWind_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index 8b5a18b0c6..c8349ffbd3 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -967,6 +967,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 @@ -1029,28 +1030,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) = 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 p%OutputAccel = InitInp%OutputAccel @@ -1709,17 +1716,17 @@ SUBROUTINE InflowWind_GetSpatialAverage( Time, InputData, p, x, xd, z, OtherStat 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) = matmul(InputData%HubOrientation,p%PositionAvg(:,i)) + InputData%HubPosition end do CALL CalculateOutput( Time, m%u_Avg, p, x, xd, z, OtherStates, m%y_Avg, m, FillWrOut, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - do i=1,IfW_NumPtsAvg + do i=1,size(m%u_Avg%PositionXYZ,DIM=2) MeanVelocity = MeanVelocity + m%y_Avg%VelocityUVW(:,i) end do - MeanVelocity = MeanVelocity / REAL(IfW_NumPtsAvg,ReKi) + MeanVelocity = MeanVelocity / REAL(size(m%u_Avg%PositionXYZ,DIM=2),ReKi) RETURN From 28c15b043687229ecc46890470a4fde955a283d7 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 25 Nov 2024 13:37:53 -0700 Subject: [PATCH 12/49] Update AD14 cases using disk average velocity --- reg_tests/r-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reg_tests/r-test b/reg_tests/r-test index f282c79af7..a820ba376e 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit f282c79af7152d20ec7becb7a7c9edbf65cca71c +Subproject commit a820ba376e4f38413e01cacf461eaf5eb3c21154 From 84537f7d017aeef70170c4b1e89a87b5e61fb73c Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 25 Nov 2024 15:27:41 -0700 Subject: [PATCH 13/49] FF: increase number of output planes to 999 --- glue-codes/fast-farm/src/FAST_Farm_Subs.f90 | 14 +++++++------- modules/awae/src/AWAE.f90 | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 1ee45ea21e..0727b70b07 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -44,7 +44,7 @@ MODULE FAST_Farm_Subs integer, parameter :: maxOutputPoints = 9 - integer, parameter :: maxOutputPlanes = 99 ! Allow up to 99 outpt planes + integer, parameter :: maxOutputPlanes = 999 ! Allow up to 999 outpt planes CONTAINS @@ -1140,7 +1140,7 @@ SUBROUTINE Farm_ReadPrimaryFile( InputFile, p, WD_InitInp, AWAE_InitInp, SC_Init end if ! NOutDisWindXY - Number of XY planes for output of disturbed wind data across the low-resolution domain to .Low.DisXY..t.vtk (-) [0 to 9]: - 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) + 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) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if ( ErrStat >= AbortErrLev ) then call cleanup() @@ -1163,7 +1163,7 @@ SUBROUTINE Farm_ReadPrimaryFile( InputFile, p, WD_InitInp, AWAE_InitInp, SC_Init end if ! NOutDisWindYZ - Number of YZ planes for output of disturbed wind data across the low-resolution domain to .Low.DisYZ..t.vtk (-) [0 to 9]: - 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 99]", ErrStat2, ErrMsg2, UnEc) + 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) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if ( ErrStat >= AbortErrLev ) then call cleanup() @@ -1186,7 +1186,7 @@ SUBROUTINE Farm_ReadPrimaryFile( InputFile, p, WD_InitInp, AWAE_InitInp, SC_Init end if ! NOutDisWindXZ - Number of XZ planes for output of disturbed wind data across the low-resolution domain to .Low/DisXZ..t.vtk (-) [0 to 9]: - 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 99]", ErrStat2, ErrMsg2, UnEc) + 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) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if ( ErrStat >= AbortErrLev ) then call cleanup() @@ -1546,9 +1546,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/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index 86c882e235..29fc543112 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -1613,7 +1613,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 @@ -1651,7 +1651,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" @@ -1665,7 +1665,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" @@ -1679,7 +1679,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" From 17ac3c7658bcfcfb71ba3d07ea3b68cc808a8e20 Mon Sep 17 00:00:00 2001 From: Andy Platt Date: Tue, 26 Nov 2024 08:57:24 -0700 Subject: [PATCH 14/49] AWAE: update comment Co-authored-by: Derek Slaughter --- modules/awae/src/AWAE.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index 29fc543112..5a19a7315c 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -1613,7 +1613,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(3) :: PlaneNumStr ! 2 digit number of the output plane + character(3) :: PlaneNumStr ! 3 digit number of the output plane CHARACTER(1024) :: FileName INTEGER(IntKi) :: Un ! unit number of opened file From ada86f4b8d5c106a73ec5771408f73270ca4be63 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Tue, 26 Nov 2024 16:11:22 +0000 Subject: [PATCH 15/49] Add BUILD_OPENFAST_CFD_DRIVER to build C++ driver for CFD interface (AMR-Wind/Nalu-Wind) --- .github/workflows/automated-dev-tests.yml | 1 + CMakeLists.txt | 1 + glue-codes/openfast-cpp/CMakeLists.txt | 2 +- reg_tests/CTestList.cmake | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 7ca5d3dffa..1b370ab80a 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -199,6 +199,7 @@ jobs: -DBUILD_FASTFARM:BOOL=ON \ -DBUILD_OPENFAST_CPP_API:BOOL=ON \ -DBUILD_OPENFAST_CPP_DRIVER:BOOL=ON \ + -DBUILD_OPENFAST_CFD_DRIVER:BOOL=ON \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3299153263..88cdeb08e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ 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_CFD_DRIVER "Enable building OpenFAST CFD driver using C++ CFD 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) diff --git a/glue-codes/openfast-cpp/CMakeLists.txt b/glue-codes/openfast-cpp/CMakeLists.txt index 6405e48cc6..f85f91e1e1 100644 --- a/glue-codes/openfast-cpp/CMakeLists.txt +++ b/glue-codes/openfast-cpp/CMakeLists.txt @@ -56,7 +56,7 @@ install(TARGETS openfastcpplib ) # Build driver if requested -if (BUILD_OPENFAST_CPP_DRIVER) +if (BUILD_OPENFAST_CFD_DRIVER) find_package(yaml-cpp REQUIRED) add_executable(openfastcpp src/FAST_Prog.cpp) diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 360133f860..b9c6dbf882 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -285,7 +285,7 @@ of_regression("MHK_RM1_Floating" "openfast;elastodyn;aerod of_regression("Tailfin_FreeYaw1DOF_PolarBased" "openfast;elastodyn;aerodyn15") # OpenFAST C++ API test -if(BUILD_OPENFAST_CPP_API) +if(BUILD_OPENFAST_CFD_DRIVER) of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;fastlib;cpp") endif() From dbfff8cddec3f797a2205997c4a746b486aa33f0 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Tue, 26 Nov 2024 17:03:07 +0000 Subject: [PATCH 16/49] Use CPP driver for CFD and LIB for the openfastlib C++ interface --- .github/workflows/automated-dev-tests.yml | 2 +- glue-codes/openfast-cpp/CMakeLists.txt | 2 +- glue-codes/openfast/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 1b370ab80a..92402268bf 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -198,8 +198,8 @@ 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_OPENFAST_CFD_DRIVER:BOOL=ON \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ diff --git a/glue-codes/openfast-cpp/CMakeLists.txt b/glue-codes/openfast-cpp/CMakeLists.txt index f85f91e1e1..6405e48cc6 100644 --- a/glue-codes/openfast-cpp/CMakeLists.txt +++ b/glue-codes/openfast-cpp/CMakeLists.txt @@ -56,7 +56,7 @@ install(TARGETS openfastcpplib ) # Build driver if requested -if (BUILD_OPENFAST_CFD_DRIVER) +if (BUILD_OPENFAST_CPP_DRIVER) find_package(yaml-cpp REQUIRED) add_executable(openfastcpp src/FAST_Prog.cpp) diff --git a/glue-codes/openfast/CMakeLists.txt b/glue-codes/openfast/CMakeLists.txt index bc2e132339..402a790f69 100644 --- a/glue-codes/openfast/CMakeLists.txt +++ b/glue-codes/openfast/CMakeLists.txt @@ -33,7 +33,7 @@ endif() install(TARGETS openfast RUNTIME DESTINATION bin) -if(BUILD_OPENFAST_CPP_DRIVER) +if(BUILD_OPENFAST_LIB_DRIVER) add_executable(openfast_cpp_driver src/FAST_Prog.cpp src/FastLibAPI.cpp) target_link_libraries(openfast_cpp_driver openfastlib) From 9df336380a139f1359622ec4f3a761b3a320c503 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Tue, 26 Nov 2024 17:31:28 +0000 Subject: [PATCH 17/49] Missed an instance of BUILD_OPENFAST_LIB_DRIVER --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88cdeb08e2..0bd22f12a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,8 +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_CFD_DRIVER "Enable building OpenFAST CFD driver using C++ CFD 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) From 4943c199f30ccc00fe8ee610620951d606236188 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 27 Nov 2024 16:24:22 -0700 Subject: [PATCH 18/49] Update r-test pointer --- reg_tests/r-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reg_tests/r-test b/reg_tests/r-test index a820ba376e..d9691df033 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit a820ba376e4f38413e01cacf461eaf5eb3c21154 +Subproject commit d9691df0339bbc718c63e1de8a1aaa642e978398 From 61549fcc2d9d638d74df6fa7eb304841a1447478 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Dec 2024 14:38:32 -0700 Subject: [PATCH 19/49] Add `!$OMP critical` directives around some GetNewUnit/Open*File calls --- modules/aerodyn/src/AeroDyn_IO.f90 | 4 ++ modules/aerodyn/src/UnsteadyAero.f90 | 16 ++++--- modules/awae/src/AWAE_IO.f90 | 2 + modules/beamdyn/src/BeamDyn_IO.f90 | 6 +++ modules/elastodyn/src/ElastoDyn.f90 | 8 ++-- modules/elastodyn/src/ElastoDyn_IO.f90 | 39 +++++++-------- modules/hydrodyn/src/HydroDyn_Output.f90 | 8 ++++ modules/hydrodyn/src/Morison_Output.f90 | 2 + modules/hydrodyn/src/WAMIT2.f90 | 37 +++++---------- modules/inflowwind/src/InflowWind_IO.f90 | 34 +++++++------ modules/inflowwind/src/InflowWind_Subs.f90 | 2 + modules/nwtc-library/src/NWTC_IO.f90 | 8 ++++ modules/nwtc-library/src/VTK.f90 | 12 +++-- modules/openfast-library/src/FAST_Solver.f90 | 10 ++++ modules/openfast-library/src/FAST_Subs.f90 | 50 +++++++++++++------- modules/servodyn/src/ServoDyn_IO.f90 | 2 + modules/subdyn/src/SubDyn.f90 | 5 ++ 17 files changed, 155 insertions(+), 90 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 24e56b0ab2..532fc55d2e 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -1080,6 +1080,7 @@ SUBROUTINE ReadBladeInputs ( ADBlFile, BladeKInputFileData, AeroProjMod, UnEc, E ErrMsg = "" UnIn = -1 + !$OMP critical(filename) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -1087,6 +1088,7 @@ SUBROUTINE ReadBladeInputs ( ADBlFile, BladeKInputFileData, AeroProjMod, UnEc, E ! 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 @@ -1324,8 +1326,10 @@ SUBROUTINE AD_PrintSum( InputFileData, p, p_AD, u, y, ErrStat, ErrMsg ) ! 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/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index 84f0addf1c..a6686580f4 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -1328,10 +1328,12 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & p%Delim ='' if (p%NumOuts > 0) then + !$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)//'.UA.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 @@ -3685,10 +3687,12 @@ subroutine UA_WriteAFIParamsToFile(InitInp, AFInfo, ErrStat, ErrMsg) ChanName(i) = 'c_Rate'; ChanUnit(i) = '(-/rad)'; i = i+1; ChanName(i) = 'c_RateUpper'; ChanUnit(i) = '(-/rad)'; i = i+1; + !$OMP critical(filename) CALL GetNewUnit( unOutFile, ErrStat, ErrMsg ) - IF ( ErrStat /= ErrID_None ) RETURN - - CALL OpenFOutFile ( unOutFile, trim(InitInp%OutRootName)//'.UA.sum', ErrStat2, ErrMsg2 ) + if (ErrStat < AbortErrLev) then + CALL OpenFOutFile ( unOutFile, trim(InitInp%OutRootName)//'.UA.sum', ErrStat2, ErrMsg2 ) + endif + !$OMP end critical(filename) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return diff --git a/modules/awae/src/AWAE_IO.f90 b/modules/awae/src/AWAE_IO.f90 index 5d89f40978..a4b2720cf3 100644 --- a/modules/awae/src/AWAE_IO.f90 +++ b/modules/awae/src/AWAE_IO.f90 @@ -548,8 +548,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 15ed92d7d6..d50d333122 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() @@ -1048,9 +1050,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 @@ -1940,8 +1944,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 28db59d3d5..061dbb3c11 100644 --- a/modules/elastodyn/src/ElastoDyn.f90 +++ b/modules/elastodyn/src/ElastoDyn.f90 @@ -9634,10 +9634,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 698c57fe12..6e793c5c02 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -1582,12 +1582,13 @@ SUBROUTINE ReadBladeFile ( BldFile, BladeKInputFileData, UnEc, ErrStat, ErrMsg ) ErrMsg = "" UnIn = -1 + !$OMP critical(filename) CALL GetNewUnit( UnIn, ErrStat2, ErrMsg2 ) - - + IF (ErrStat2 < AbortErrLev) THEN ! Open the input file for blade K. - - CALL OpenFInpFile ( UnIn, BldFile, ErrStat2, ErrMsg2 ) + CALL OpenFInpFile ( UnIn, BldFile, ErrStat2, ErrMsg2 ) + ENDIF + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() @@ -1888,13 +1889,13 @@ SUBROUTINE ReadBladeMeshFileAD( BladeKInputFileMesh, MeshFile, UnEc, ErrStat, Er ! 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 AeroDyn input file. - - CALL OpenFInpFile ( UnIn, MeshFile, ErrStat2, ErrMsg2 ) + CALL OpenFInpFile ( UnIn, MeshFile, ErrStat2, ErrMsg2 ) + ENDIF + !$OMP end critical(filename) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( ErrStat >= AbortErrLev ) THEN CALL Cleanup() @@ -2179,12 +2180,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() @@ -2521,14 +2523,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 a48f6429ef..39addf3406 100644 --- a/modules/hydrodyn/src/HydroDyn_Output.f90 +++ b/modules/hydrodyn/src/HydroDyn_Output.f90 @@ -979,9 +979,11 @@ SUBROUTINE HDOut_OpenSum( UnSum, SummaryName, HD_Prog, ErrStat, ErrMsg ) ErrMsg = "" + !$OMP critical(fileopen) CALL GetNewUnit( UnSum ) CALL OpenFOutFile ( UnSum, SummaryName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1033,10 +1035,12 @@ SUBROUTINE HDOut_WriteWvKinFiles( Rootname, HD_Prog, NStepWave, NNodes, NWaveEle DO iFile = 1,7 + !$OMP critical(fileopen) CALL GetNewUnit( UnWv ) WvName = Rootname // TRIM(extension(iFile)) CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1084,10 +1088,12 @@ SUBROUTINE HDOut_WriteWvKinFiles( Rootname, HD_Prog, NStepWave, NNodes, NWaveEle IF ( NWaveElev > 0 ) THEN + !$OMP critical(fileopen) CALL GetNewUnit( UnWv ) WvName = Rootname // '.Elev' CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) + !$OMP end critical(fileopen) IF (ErrStat >=AbortErrLev) RETURN @@ -1463,9 +1469,11 @@ SUBROUTINE HDOut_OpenOutput( HydroDyn_ProgDesc, OutRootName, p, InitOut, ErrSta ! Open the file for output OutFileName = TRIM(OutRootName)//'.HD.out' + !$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/Morison_Output.f90 b/modules/hydrodyn/src/Morison_Output.f90 index 4ec1db451a..d98a4565d2 100644 --- a/modules/hydrodyn/src/Morison_Output.f90 +++ b/modules/hydrodyn/src/Morison_Output.f90 @@ -6610,9 +6610,11 @@ SUBROUTINE MrsnOut_OpenOutput( ProgName, OutRootName, p, InitOut, ErrStat, ErrM ! Open the file for output OutFileName = TRIM(OutRootName)//'.MRSN.out' + !$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 47653312a2..8cfe1026b2 100644 --- a/modules/hydrodyn/src/WAMIT2.f90 +++ b/modules/hydrodyn/src/WAMIT2.f90 @@ -3649,20 +3649,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 - IF (ALLOCATED(TmpRealArr)) DEALLOCATE(TmpRealArr,STAT=ErrStatTmp) - IF (ALLOCATED(RawData3D)) DEALLOCATE(RawData3D,STAT=ErrStatTmp) - IF (ALLOCATED(RawData3DTmp)) DEALLOCATE(RawData3DTmp,STAT=ErrStatTmp) - IF (ALLOCATED(TmpDataRow)) DEALLOCATE(TmpDataRow,STAT=ErrStatTmp) - IF (ALLOCATED(TmpWvFreq1)) DEALLOCATE(TmpWvFreq1,STAT=ErrStatTmp) - 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 CLOSE( UnitDataFile ) @@ -4423,21 +4416,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 - IF (ALLOCATED(RawData4D)) DEALLOCATE(RawData4D,STAT=ErrStatTmp) - IF (ALLOCATED(RawData4DTmp)) DEALLOCATE(RawData4DTmp,STAT=ErrStatTmp) - IF (ALLOCATED(TmpRealArr)) DEALLOCATE(TmpRealArr,STAT=ErrStatTmp) - IF (ALLOCATED(TmpDataRow)) DEALLOCATE(TmpDataRow,STAT=ErrStatTmp) - IF (ALLOCATED(TmpWvFreq1)) DEALLOCATE(TmpWvFreq1,STAT=ErrStatTmp) - IF (ALLOCATED(TmpWvFreq2)) DEALLOCATE(TmpWvFreq2,STAT=ErrStatTmp) - CALL CleanUp - RETURN - ENDIF - + if (ErrStatTmp < AbortErrLev) then ! Open the file - CALL OpenFInpFile( UnitDataFile, TRIM(Filename4D), ErrStat, ErrMsg ) ! Open file containing mean drift information + CALL OpenFInpFile( UnitDataFile, TRIM(Filename4D), ErrStat, ErrMsg ) ! 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/InflowWind_IO.f90 b/modules/inflowwind/src/InflowWind_IO.f90 index e1b0f64547..b74a2e5143 100644 --- a/modules/inflowwind/src/InflowWind_IO.f90 +++ b/modules/inflowwind/src/InflowWind_IO.f90 @@ -518,12 +518,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 @@ -883,16 +884,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 @@ -1132,16 +1134,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 c8349ffbd3..e99dae4377 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -1575,8 +1575,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 diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 931aaf76e7..656f46840d 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2409,6 +2409,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 ) @@ -2419,6 +2420,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 @@ -4615,11 +4617,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 @@ -6410,9 +6414,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() @@ -6720,6 +6726,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 ) @@ -6729,6 +6736,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 fb57a5781b..0083582caf 100644 --- a/modules/nwtc-library/src/VTK.f90 +++ b/modules/nwtc-library/src/VTK.f90 @@ -94,8 +94,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) @@ -158,10 +160,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 ) @@ -360,10 +362,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' @@ -451,6 +453,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 ! @@ -466,6 +469,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 1f6653285c..01138be3f1 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -1839,8 +1839,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() @@ -1853,8 +1855,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() @@ -2608,8 +2612,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 @@ -2621,8 +2627,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 @@ -5095,8 +5103,10 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca #ifdef OUTPUT_MASS_MATRIX if (n_t_global == 0) 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 e23cfe2e04..9e0af8c935 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -2280,11 +2280,13 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) y_FAST%OutFmt_a = trim(y_FAST%OutFmt_a)//','//trim(num2lstr(y_FAST%ActualChanLen - p_FAST%FmtWidth))//'x' end if + !$OMP critical(fileopen) 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 + 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: @@ -2415,18 +2417,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 ! Read the lines up/including to the "Echo" simulation control variable @@ -3929,11 +3931,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: @@ -6173,8 +6177,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 @@ -6252,9 +6258,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): @@ -7045,8 +7053,10 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, IF ( unOut < 0 ) 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 call cleanup() @@ -7213,9 +7223,11 @@ 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) + !$OMP end critical(fileopen) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev ) RETURN @@ -7617,9 +7629,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 @@ -7743,9 +7757,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..373440979a 100644 --- a/modules/servodyn/src/ServoDyn_IO.f90 +++ b/modules/servodyn/src/ServoDyn_IO.f90 @@ -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/subdyn/src/SubDyn.f90 b/modules/subdyn/src/SubDyn.f90 index 1258379d05..e2f7bc7e8d 100644 --- a/modules/subdyn/src/SubDyn.f90 +++ b/modules/subdyn/src/SubDyn.f90 @@ -866,9 +866,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') @@ -3470,6 +3472,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 @@ -3491,8 +3494,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 From 6bacfca574416e1837e9fd0ad99b6e251059c0c1 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Wed, 11 Dec 2024 21:53:38 +0000 Subject: [PATCH 20/49] Modify NWTC_IO's GetWords function to handle quoted strings properly --- modules/nwtc-library/src/NWTC_IO.f90 | 117 +++++++++++++++------------ 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 931aaf76e7..a248bf54f6 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) @@ -2068,70 +2068,87 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) INTEGER, INTENT(IN) :: NumWords !< The maximum number of words to look for (and size of Words) CHARACTER(*), INTENT(IN) :: Line !< The string to search. - CHARACTER(*), INTENT(OUT) :: Words(NumWords) !< The array of found words. + CHARACTER(*), INTENT(OUT) :: Words(:) !< The array of found words. INTEGER, OPTIONAL, INTENT(OUT) :: NumFound !< The number of words found - ! 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 + ! If no text on line, return + if (len_trim(Line) == 0) return + ! Let's prefill the array with blanks. + do iWord = 1, NumWords + Words(iWord) = ' ' + end do - ! Let's prefill the array with blanks. - - DO IW=1,NumWords - Words(IW) = ' ' - END DO ! IW + ! Initialize number of words found to zero if present + if (present(NumFound)) NumFound = 0 - IW = 0 + ! If no text on line, return + if (len_trim(Line) == 0) return + ! 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 (InQuotes) then + InQuotes = .false. + if (iChar > 0) then + iWord = iWord + 1 + iChar = 0 + end if + else + InQuotes = .true. + end if + cycle + + case (' ', ',', ';', Tab) ! Whitespace, comma, semicolon + if (.not. InQuotes) then + if (iChar > 0) then + iWord = iWord + 1 + iChar = 0 + end if + cycle + end if + end select - CYCLE + ! If sufficient words have been collected, exit loop + if (iWord > NumWords) exit - 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.') + 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 routine converts an ASCII array of integers into an equivalent string From 4c6aad12795000b63cbdd82d1e398d5259df4c73 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Wed, 11 Dec 2024 21:55:42 +0000 Subject: [PATCH 21/49] Use NumWords for length of array --- modules/nwtc-library/src/NWTC_IO.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index a248bf54f6..e9a2da6958 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2068,7 +2068,7 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) INTEGER, INTENT(IN) :: NumWords !< The maximum number of words to look for (and size of Words) CHARACTER(*), INTENT(IN) :: Line !< The string to search. - CHARACTER(*), INTENT(OUT) :: Words(:) !< The array of found words. + CHARACTER(*), INTENT(OUT) :: Words(NumWords) !< The array of found words. INTEGER, OPTIONAL, INTENT(OUT) :: NumFound !< The number of words found INTEGER :: iWord ! Word index. From 7ffff7ebc09ca02f946cdc329fed1ad4e91a11e6 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Thu, 12 Dec 2024 15:29:58 +0000 Subject: [PATCH 22/49] GetWords: always break on ',' and ';' --- modules/nwtc-library/src/NWTC_IO.f90 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index e9a2da6958..500dcde4fc 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2120,7 +2120,8 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) end if cycle - case (' ', ',', ';', Tab) ! Whitespace, comma, semicolon + case (' ', Tab) ! Whitespace + ! If between quotes, keep whitespace; otherwise separate words if (.not. InQuotes) then if (iChar > 0) then iWord = iWord + 1 @@ -2128,6 +2129,14 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) end if cycle end if + + case (',', ';') ! Comma, semicolon + ! Always separate words on these characters + if (iChar > 0) then + iWord = iWord + 1 + iChar = 0 + end if + cycle end select ! If sufficient words have been collected, exit loop @@ -2138,7 +2147,7 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) ! 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.') + 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 From 892756db5d0b86480d74fb2ee832b38a1b7984d8 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Thu, 12 Dec 2024 16:46:57 +0000 Subject: [PATCH 23/49] Add IgnoreQuotes arg to GetWords and add IsPath arg to ParseChVar --- modules/nwtc-library/src/NWTC_IO.f90 | 34 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 500dcde4fc..602fad45da 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2061,7 +2061,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. @@ -2070,16 +2070,25 @@ 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(OUT) :: IgnoreQuotes !< Flag to ignore quotes (process as whitespace) 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 ! If no text on line, return if (len_trim(Line) == 0) return + ! If ignore quotes is present, set local flag, otherwise true + if (present(IgnoreQuotes)) then + IgnoreQuotesLoc = IgnoreQuotes + else + IgnoreQuotesLoc = .true. + end if + ! Let's prefill the array with blanks. do iWord = 1, NumWords Words(iWord) = ' ' @@ -2109,9 +2118,11 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) ! Select based on character select case (Char) case ('"', "'") ! Double quotes, single quotes - if (InQuotes) then + if (IgnoreQuotesLoc .or. InQuotes) then InQuotes = .false. if (iChar > 0) then + ! If requested number of words found, exit + if (iWord == NumWords) exit iWord = iWord + 1 iChar = 0 end if @@ -2124,6 +2135,8 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) ! If between quotes, keep whitespace; otherwise separate words if (.not. InQuotes) then if (iChar > 0) then + ! If requested number of words found, exit + if (iWord == NumWords) exit iWord = iWord + 1 iChar = 0 end if @@ -2133,15 +2146,14 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound ) case (',', ';') ! Comma, semicolon ! Always separate words on these characters if (iChar > 0) then + ! If requested number of words found, exit + if (iWord == NumWords) exit iWord = iWord + 1 iChar = 0 end if cycle end select - ! If sufficient words have been collected, exit loop - if (iWord > NumWords) exit - ! Increment character index iChar = iChar + 1 @@ -2910,7 +2922,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. @@ -2919,6 +2931,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. @@ -2931,6 +2944,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 @@ -2950,8 +2964,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// & From f77571df724e24c505ba2f5d3dd27444f129451f Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Thu, 12 Dec 2024 16:47:19 +0000 Subject: [PATCH 24/49] Add IsPath=.true. where ParseVar is used to parse a file path --- modules/aerodyn/src/AeroDyn_Driver_Subs.f90 | 4 ++-- modules/aerodyn/src/AeroDyn_IO.f90 | 6 +++--- modules/aerodyn/src/AirfoilInfo.f90 | 2 +- modules/hydrodyn/src/HydroDyn_Input.f90 | 2 +- modules/inflowwind/src/InflowWind_Subs.f90 | 12 ++++++------ modules/servodyn/src/ServoDyn_IO.f90 | 6 +++--- modules/servodyn/src/StrucCtrl.f90 | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 8227a8252a..a43ae3356a 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -958,7 +958,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 @@ -973,7 +973,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 24e56b0ab2..815e147458 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -730,7 +730,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) @@ -802,7 +802,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) @@ -906,7 +906,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 InputFileData%rotors(iR)%TFinFile = trim(PriPath) // trim(InputFileData%rotors(iR)%TFinFile) else call LegacyWarning('Tail Fin section (TFinAero, TFinFile) is missing from input file.') diff --git a/modules/aerodyn/src/AirfoilInfo.f90 b/modules/aerodyn/src/AirfoilInfo.f90 index 477d46ca50..7d3d0742e7 100644 --- a/modules/aerodyn/src/AirfoilInfo.f90 +++ b/modules/aerodyn/src/AirfoilInfo.f90 @@ -479,7 +479,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) diff --git a/modules/hydrodyn/src/HydroDyn_Input.f90 b/modules/hydrodyn/src/HydroDyn_Input.f90 index a9fe940189..8c5cd4dab5 100644 --- a/modules/hydrodyn/src/HydroDyn_Input.f90 +++ b/modules/hydrodyn/src/HydroDyn_Input.f90 @@ -359,7 +359,7 @@ SUBROUTINE HydroDyn_ParseInput( InputFileName, OutRootName, defWtrDens, defWtrDp 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; ! NWaveElev diff --git a/modules/inflowwind/src/InflowWind_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index c8349ffbd3..4f4169a1fc 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) diff --git a/modules/servodyn/src/ServoDyn_IO.f90 b/modules/servodyn/src/ServoDyn_IO.f90 index cb900579ec..1cbee9c9ef 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 ) 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) From fce5c223ae0d01a4eed18ecb90f0a9aa92a0dc89 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Thu, 12 Dec 2024 21:47:52 +0000 Subject: [PATCH 25/49] Allow , and ; in quoted words --- modules/nwtc-library/src/NWTC_IO.f90 | 29 +++++++++------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 602fad45da..b69b375d2b 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2079,6 +2079,9 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) 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 + ! If no text on line, return if (len_trim(Line) == 0) return @@ -2089,17 +2092,11 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) IgnoreQuotesLoc = .true. end if - ! Let's prefill the array with blanks. + ! Let's prefill the array with blanks do iWord = 1, NumWords Words(iWord) = ' ' end do - ! Initialize number of words found to zero if present - if (present(NumFound)) NumFound = 0 - - ! If no text on line, return - if (len_trim(Line) == 0) return - ! Initialize word index to first word iWord = 1 @@ -2121,7 +2118,7 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) if (IgnoreQuotesLoc .or. InQuotes) then InQuotes = .false. if (iChar > 0) then - ! If requested number of words found, exit + ! If requested number of words found, exit; otherwise, new word if (iWord == NumWords) exit iWord = iWord + 1 iChar = 0 @@ -2131,11 +2128,12 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) end if cycle - case (' ', Tab) ! Whitespace - ! If between quotes, keep whitespace; otherwise separate words + ! 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 + ! If requested number of words found, exit; otherwise, new word if (iWord == NumWords) exit iWord = iWord + 1 iChar = 0 @@ -2143,15 +2141,6 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) cycle end if - case (',', ';') ! Comma, semicolon - ! Always separate words on these characters - if (iChar > 0) then - ! If requested number of words found, exit - if (iWord == NumWords) exit - iWord = iWord + 1 - iChar = 0 - end if - cycle end select ! Increment character index From a62d8772ee378d1ebb44a8f8c3d5beae9e8293d6 Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Mon, 16 Dec 2024 17:57:17 +0000 Subject: [PATCH 26/49] Use INTENT(IN) for IgnoreQuotes in GetWords (NWTC_IO) --- modules/nwtc-library/src/NWTC_IO.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index b69b375d2b..25565afe9b 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -2070,7 +2070,7 @@ SUBROUTINE GetWords ( Line, Words, NumWords, NumFound, IgnoreQuotes ) 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(OUT) :: IgnoreQuotes !< Flag to ignore quotes (process as whitespace) + LOGICAL, OPTIONAL, INTENT(IN) :: IgnoreQuotes !< Flag to ignore quotes (process as whitespace) INTEGER :: iWord ! Word index. INTEGER :: i ! Character index in line. From 0e99c524043c8dfedc5200a025811d4513364acf Mon Sep 17 00:00:00 2001 From: Derek Slaughter Date: Tue, 17 Dec 2024 15:12:41 +0000 Subject: [PATCH 27/49] Change openfast_cpp_driver to openfast_lib_driver to better separate openfast-cpp from the OpenFAST library C++ driver --- .github/workflows/automated-dev-tests.yml | 2 +- glue-codes/openfast/CMakeLists.txt | 6 +++--- reg_tests/CMakeLists.txt | 2 +- reg_tests/CTestList.cmake | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 92402268bf..9028693e2a 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -243,7 +243,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/glue-codes/openfast/CMakeLists.txt b/glue-codes/openfast/CMakeLists.txt index 402a790f69..a742b5972a 100644 --- a/glue-codes/openfast/CMakeLists.txt +++ b/glue-codes/openfast/CMakeLists.txt @@ -34,10 +34,10 @@ install(TARGETS openfast RUNTIME DESTINATION bin) if(BUILD_OPENFAST_LIB_DRIVER) - add_executable(openfast_cpp_driver src/FAST_Prog.cpp src/FastLibAPI.cpp) - target_link_libraries(openfast_cpp_driver openfastlib) + 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/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 268e188f9d..70cbf67176 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 b9c6dbf882..163fa4f35f 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -85,7 +85,7 @@ endfunction(of_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") regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} "${TESTNAME}_fastlib" "${LABEL}" ${TESTNAME}) @@ -285,15 +285,15 @@ of_regression("MHK_RM1_Floating" "openfast;elastodyn;aerod of_regression("Tailfin_FreeYaw1DOF_PolarBased" "openfast;elastodyn;aerodyn15") # OpenFAST C++ API test -if(BUILD_OPENFAST_CFD_DRIVER) +if(BUILD_OPENFAST_CPP_DRIVER) of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;fastlib;cpp") 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;aerodyn15;servodyn") -endif(BUILD_OPENFAST_CPP_DRIVER) +endif() # OpenFAST Python API test of_regression_py("5MW_Land_DLL_WTurb_py" "openfast;fastlib;python;elastodyn;aerodyn15;servodyn") From 8193c7a732aa9af48d57449b88618d04d0c19fef Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 14:48:49 -0700 Subject: [PATCH 28/49] Disable LiDAR in IfW at FAST.Farm level --- modules/inflowwind/src/InflowWind.f90 | 11 ++++++++++- modules/inflowwind/src/InflowWind.txt | 1 + modules/inflowwind/src/InflowWind_Types.f90 | 7 +++++++ modules/openfast-library/src/FAST_Subs.f90 | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 103ddb948b..9c0c0276f6 100644 --- a/modules/inflowwind/src/InflowWind.f90 +++ b/modules/inflowwind/src/InflowWind.f90 @@ -224,7 +224,16 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons p%lidar%PulseSpacing = InputFileData%PulseSpacing p%lidar%URefLid = InputFileData%URefLid p%lidar%ConsiderHubMotion = InputFileData%ConsiderHubMotion - + + ! Disable Lidar if not allowed (FAST.Farm doesn't allow this) + if (InitInp%LidarDisable) 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 + CALL Lidar_Init( InitInp, InputGuess, p, ContStates, DiscStates, ConstrStateGuess, OtherStates, & y, m, TimeInterval, InitOutData, TmpErrStat, TmpErrMsg ) diff --git a/modules/inflowwind/src/InflowWind.txt b/modules/inflowwind/src/InflowWind.txt index 3ab0940982..5fbe8e6c0e 100644 --- a/modules/inflowwind/src/InflowWind.txt +++ b/modules/inflowwind/src/InflowWind.txt @@ -101,6 +101,7 @@ typedef ^ ^ ReKi WtrDpth typedef ^ ^ ReKi MSL2SWL - - - "Mean sea level to still water level" m typedef ^ ^ IntKi BoxExceedAllowIdx - -1 - "Extrapolate winds outside box starting at this index (for OLAF wakes and LidarSim)" - typedef ^ ^ LOGICAL BoxExceedAllowF - .FALSE. - "Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim)" - +typedef ^ ^ LOGICAL LidarDisable - .true. - "Disable LiDAR for this instance of InflowWind? (FAST.Farm not compatible)" - # Init Output diff --git a/modules/inflowwind/src/InflowWind_Types.f90 b/modules/inflowwind/src/InflowWind_Types.f90 index 605bfe2228..8ac1bfc93f 100644 --- a/modules/inflowwind/src/InflowWind_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Types.f90 @@ -119,6 +119,7 @@ MODULE InflowWind_Types REAL(ReKi) :: MSL2SWL !< Mean sea level to still water level [m] INTEGER(IntKi) :: BoxExceedAllowIdx = -1 !< Extrapolate winds outside box starting at this index (for OLAF wakes and LidarSim) [-] LOGICAL :: BoxExceedAllowF = .FALSE. !< Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim) [-] + LOGICAL :: LidarDisable = .true. !< Disable LiDAR for this instance of InflowWind? (FAST.Farm not compatible) [-] END TYPE InflowWind_InitInputType ! ======================= ! ========= InflowWind_InitOutputType ======= @@ -1110,6 +1111,7 @@ SUBROUTINE InflowWind_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCod DstInitInputData%MSL2SWL = SrcInitInputData%MSL2SWL DstInitInputData%BoxExceedAllowIdx = SrcInitInputData%BoxExceedAllowIdx DstInitInputData%BoxExceedAllowF = SrcInitInputData%BoxExceedAllowF + DstInitInputData%LidarDisable = SrcInitInputData%LidarDisable END SUBROUTINE InflowWind_CopyInitInput SUBROUTINE InflowWind_DestroyInitInput( InitInputData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -1263,6 +1265,7 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Re_BufSz = Re_BufSz + 1 ! MSL2SWL Int_BufSz = Int_BufSz + 1 ! BoxExceedAllowIdx Int_BufSz = Int_BufSz + 1 ! BoxExceedAllowF + Int_BufSz = Int_BufSz + 1 ! LidarDisable IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1438,6 +1441,8 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = TRANSFER(InData%BoxExceedAllowF, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%LidarDisable, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE InflowWind_PackInitInput SUBROUTINE InflowWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -1662,6 +1667,8 @@ SUBROUTINE InflowWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS Int_Xferred = Int_Xferred + 1 OutData%BoxExceedAllowF = TRANSFER(IntKiBuf(Int_Xferred), OutData%BoxExceedAllowF) Int_Xferred = Int_Xferred + 1 + OutData%LidarDisable = TRANSFER(IntKiBuf(Int_Xferred), OutData%LidarDisable) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE InflowWind_UnPackInitInput SUBROUTINE InflowWind_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 9e0af8c935..09f532a022 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -583,6 +583,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, END IF ! lidar + Init%InData_IfW%LidarDisable = .false. ! allowed with OF, but not FF Init%InData_IfW%lidar%Tmax = p_FAST%TMax Init%InData_IfW%lidar%HubPosition = ED%y%HubPtMotion%Position(:,1) From 5c30c4233999af01b46bca7f88296efda271c954 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 15:45:40 -0700 Subject: [PATCH 29/49] Update release notes and changelog for 3.5.5 --- docs/changelogs/v3.5.5.md | 105 ++++++++++++++++++++++++++++++++ docs/conf.py | 2 +- docs/source/user/api_change.rst | 6 ++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 docs/changelogs/v3.5.5.md diff --git a/docs/changelogs/v3.5.5.md b/docs/changelogs/v3.5.5.md new file mode 100644 index 0000000000..8043f3a3bd --- /dev/null +++ b/docs/changelogs/v3.5.5.md @@ -0,0 +1,105 @@ +**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 performance + + + +## 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 f1b3d9f221..a1ce010114 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -130,7 +130,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 cf16f2fe4c..242ab07a03 100644 --- a/docs/source/user/api_change.rst +++ b/docs/source/user/api_change.rst @@ -9,6 +9,12 @@ The changes are tabulated according to the module input file, line number, and f The line number corresponds to the resulting line number after all changes are implemented. Thus, be sure to implement each in order so that subsequent line numbers are correct. +OpenFAST v3.5.4 to OpenFAST v3.5.5 +---------------------------------- + +No input file changes were made. + + OpenFAST v3.5.3 to OpenFAST v3.5.4 ---------------------------------- From c553ffcdb83f72d6df792966376032a0ffaa18c1 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 8 Nov 2024 13:09:33 -0700 Subject: [PATCH 30/49] AD: variable name change in ad_dvr_subs for clarity --- modules/aerodyn/src/AeroDyn_Driver_Subs.f90 | 126 ++++++++++---------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 0d3b1d295d..ddba204fd4 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -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,19 @@ 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 + DVR_Outs%VTK_OutFileRoot = trim(DVR_Outs%VTK_OutFileRoot) // trim(dir) + 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 +1779,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 +1789,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 +1827,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 +1843,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 +1856,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 +1882,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 +1905,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 +1917,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 From 7a0fd2d2c5928dad0b47701ee20356c85a42cae9 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 20:22:27 -0700 Subject: [PATCH 31/49] AD: remove redundant library from CMakeLists.txt --- modules/aerodyn/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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() From 9ad219779fa58acf0adca0fb0a3f861bf6023b93 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 20:28:22 -0700 Subject: [PATCH 32/49] ADI_c: add WrVTK_DT input for skipping timesteps for VTK outputs --- .../python-lib/aerodyn_inflow_library.py | 3 + .../aerodyn/src/AeroDyn_Driver_Registry.txt | 11 +-- modules/aerodyn/src/AeroDyn_Driver_Subs.f90 | 2 +- modules/aerodyn/src/AeroDyn_Driver_Types.f90 | 14 +-- .../aerodyn/src/AeroDyn_Inflow_C_Binding.f90 | 89 +++++++++++++------ reg_tests/r-test | 2 +- 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index fe3cf33d9d..859265342e 100644 --- a/modules/aerodyn/python-lib/aerodyn_inflow_library.py +++ b/modules/aerodyn/python-lib/aerodyn_inflow_library.py @@ -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 @@ -213,6 +214,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 @@ -398,6 +400,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 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 ddba204fd4..da8cd4bb04 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 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_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index b2523e14c4..c0a3276997 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 @@ -125,17 +125,18 @@ 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 !------------------------------------------------------------------------------------ ! Meshes for motions and loads @@ -387,7 +388,8 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString 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') @@ -423,6 +425,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 @@ -554,18 +557,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) @@ -658,15 +662,18 @@ SUBROUTINE ADI_C_Init( ADinputFilePassed, ADinputFileString_C, ADinputFileString ! 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 +813,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 @@ -875,6 +895,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 @@ -1049,7 +1070,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 +1089,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 ) @@ -2254,7 +2287,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 +2295,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 +2324,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 +2336,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 +2353,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 +2369,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 diff --git a/reg_tests/r-test b/reg_tests/r-test index b3824f2d3a..4e4a8e461d 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit b3824f2d3a4cd4cb826aa4ac95b6e39a99e66d43 +Subproject commit 4e4a8e461d04fb41e59ce92a7175871a000a891b From ffbaba9eaf1c0f41824fc4bbb9344668321985a0 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 21:11:28 -0700 Subject: [PATCH 33/49] ADI_c: add vtk output directory to interface --- .../aerodyn/python-lib/aerodyn_inflow_library.py | 4 ++++ modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index 859265342e..eed6155ca6 100644 --- a/modules/aerodyn/python-lib/aerodyn_inflow_library.py +++ b/modules/aerodyn/python-lib/aerodyn_inflow_library.py @@ -157,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): @@ -200,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 @@ -372,6 +374,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 ...] @@ -386,6 +389,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 diff --git a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index c0a3276997..e8de9efdd4 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 @@ -384,6 +384,7 @@ 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, & @@ -406,6 +407,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) @@ -447,6 +449,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 @@ -497,6 +500,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 @@ -645,7 +652,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 @@ -873,6 +883,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 )) ) From 15cad72dab3afea045757d8e5c3b76393737db8f Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 18 Dec 2024 21:24:21 -0700 Subject: [PATCH 34/49] ADI_c: handle absolute or relative vtk output paths --- modules/aerodyn/src/AeroDyn_Driver_Subs.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index da8cd4bb04..27cc9ba0f6 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -1727,7 +1727,11 @@ subroutine setVTKParameters(DVR_Outs, 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 ( DVR_Outs%root, DVR_Outs%VTK_OutFileRoot, vtkroot ) ! the returned DVR_Outs%VTK_OutFileRoot includes a file separator character at the end - DVR_Outs%VTK_OutFileRoot = trim(DVR_Outs%VTK_OutFileRoot) // trim(dir) + 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) From 1ac5f8966c8c66fcf89bd277855c36dfa1cdc1f4 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 19 Dec 2024 00:25:02 -0700 Subject: [PATCH 35/49] ADI: add GetDiskAvgVel routine --- .../aerodyn/src/AeroDyn_Inflow_C_Binding.f90 | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index e8de9efdd4..7c319f031b 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) @@ -138,6 +140,17 @@ MODULE AeroDyn_Inflow_C_BINDING 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 ! Meshes are used within AD to handle all motions and loads. Rather than directly @@ -304,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 @@ -666,6 +683,12 @@ 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 @@ -986,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 @@ -1948,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. !=================================================================================================================================== @@ -2490,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(:) From d4d680158b7f198b04cee7aafd992c964c345b7a Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 19 Dec 2024 00:25:28 -0700 Subject: [PATCH 36/49] ADsk: correction to disk average velocity equations See PR #2532 for details --- modules/aerodisk/src/AeroDisk.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/aerodisk/src/AeroDisk.f90 b/modules/aerodisk/src/AeroDisk.f90 index 13de16bfbd..e6257ac2d7 100644 --- a/modules/aerodisk/src/AeroDisk.f90 +++ b/modules/aerodisk/src/AeroDisk.f90 @@ -172,9 +172,9 @@ subroutine SetDiskAvgPoints(ErrStat3,ErrMsg3) R = real(p%RotorRad,ReKi) * 0.7_reKi !70% radius do i=1,ADsk_NumPtsDiskAvg theta = pi +(i-1)*TwoPi/ADsk_NumPtsDiskAvg - p%DiskWindPosRel(1,i) = R*cos(theta) - p%DiskWindPosRel(2,i) = R*sin(theta) - p%DiskWindPosRel(3,i) = 0.0_ReKi + p%DiskWindPosRel(1,i) = 0.0_ReKi ! Hub X (perpindicular to rotor plane) + p%DiskWindPosRel(2,i) = R*cos(theta) ! Hub Y + p%DiskWindPosRel(3,i) = R*sin(theta) ! Hub Z (in vertical plane when azimuth=0) end do end subroutine SetDiskAvgPoints From 2052f625cfffe8e1d431fa329e9e2df437bcc0fa Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 19 Dec 2024 09:05:02 -0700 Subject: [PATCH 37/49] ADI: add GetDiskAvgVel to regression test --- .../python-lib/aerodyn_inflow_library.py | 42 ++++++++++++++++++- reg_tests/r-test | 2 +- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index eed6155ca6..22e4a87303 100644 --- a/modules/aerodyn/python-lib/aerodyn_inflow_library.py +++ b/modules/aerodyn/python-lib/aerodyn_inflow_library.py @@ -271,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 @@ -497,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,) @@ -532,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): @@ -914,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): @@ -941,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 @@ -954,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/reg_tests/r-test b/reg_tests/r-test index 4e4a8e461d..03c239dc79 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 4e4a8e461d04fb41e59ce92a7175871a000a891b +Subproject commit 03c239dc79b7c1e493701bb2ea909d3ec89bd274 From a8fe70e498f7827bc6fdda4c8e34247427ddb08b Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 19 Dec 2024 09:40:06 -0700 Subject: [PATCH 38/49] IfW: change logic flag for LidarEnabled --- modules/inflowwind/src/InflowWind.f90 | 2 +- modules/inflowwind/src/InflowWind.txt | 2 +- modules/inflowwind/src/InflowWind_Types.f90 | 10 +++++----- modules/openfast-library/src/FAST_Subs.f90 | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 9c0c0276f6..a0ddc5e713 100644 --- a/modules/inflowwind/src/InflowWind.f90 +++ b/modules/inflowwind/src/InflowWind.f90 @@ -226,7 +226,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons p%lidar%ConsiderHubMotion = InputFileData%ConsiderHubMotion ! Disable Lidar if not allowed (FAST.Farm doesn't allow this) - if (InitInp%LidarDisable) then + 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.') diff --git a/modules/inflowwind/src/InflowWind.txt b/modules/inflowwind/src/InflowWind.txt index 5fbe8e6c0e..c4ea6c56e3 100644 --- a/modules/inflowwind/src/InflowWind.txt +++ b/modules/inflowwind/src/InflowWind.txt @@ -101,7 +101,7 @@ typedef ^ ^ ReKi WtrDpth typedef ^ ^ ReKi MSL2SWL - - - "Mean sea level to still water level" m typedef ^ ^ IntKi BoxExceedAllowIdx - -1 - "Extrapolate winds outside box starting at this index (for OLAF wakes and LidarSim)" - typedef ^ ^ LOGICAL BoxExceedAllowF - .FALSE. - "Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim)" - -typedef ^ ^ LOGICAL LidarDisable - .true. - "Disable LiDAR for this instance of InflowWind? (FAST.Farm not compatible)" - +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_Types.f90 b/modules/inflowwind/src/InflowWind_Types.f90 index 8ac1bfc93f..a4384becf7 100644 --- a/modules/inflowwind/src/InflowWind_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Types.f90 @@ -119,7 +119,7 @@ MODULE InflowWind_Types REAL(ReKi) :: MSL2SWL !< Mean sea level to still water level [m] INTEGER(IntKi) :: BoxExceedAllowIdx = -1 !< Extrapolate winds outside box starting at this index (for OLAF wakes and LidarSim) [-] LOGICAL :: BoxExceedAllowF = .FALSE. !< Flag to allow Extrapolation winds outside box starting at this index (for OLAF wakes and LidarSim) [-] - LOGICAL :: LidarDisable = .true. !< Disable LiDAR for this instance of InflowWind? (FAST.Farm not compatible) [-] + 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 ======= @@ -1111,7 +1111,7 @@ SUBROUTINE InflowWind_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCod DstInitInputData%MSL2SWL = SrcInitInputData%MSL2SWL DstInitInputData%BoxExceedAllowIdx = SrcInitInputData%BoxExceedAllowIdx DstInitInputData%BoxExceedAllowF = SrcInitInputData%BoxExceedAllowF - DstInitInputData%LidarDisable = SrcInitInputData%LidarDisable + DstInitInputData%LidarEnabled = SrcInitInputData%LidarEnabled END SUBROUTINE InflowWind_CopyInitInput SUBROUTINE InflowWind_DestroyInitInput( InitInputData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -1265,7 +1265,7 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Re_BufSz = Re_BufSz + 1 ! MSL2SWL Int_BufSz = Int_BufSz + 1 ! BoxExceedAllowIdx Int_BufSz = Int_BufSz + 1 ! BoxExceedAllowF - Int_BufSz = Int_BufSz + 1 ! LidarDisable + Int_BufSz = Int_BufSz + 1 ! LidarEnabled IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1441,7 +1441,7 @@ SUBROUTINE InflowWind_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = TRANSFER(InData%BoxExceedAllowF, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%LidarDisable, IntKiBuf(1)) + IntKiBuf(Int_Xferred) = TRANSFER(InData%LidarEnabled, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 END SUBROUTINE InflowWind_PackInitInput @@ -1667,7 +1667,7 @@ SUBROUTINE InflowWind_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS Int_Xferred = Int_Xferred + 1 OutData%BoxExceedAllowF = TRANSFER(IntKiBuf(Int_Xferred), OutData%BoxExceedAllowF) Int_Xferred = Int_Xferred + 1 - OutData%LidarDisable = TRANSFER(IntKiBuf(Int_Xferred), OutData%LidarDisable) + OutData%LidarEnabled = TRANSFER(IntKiBuf(Int_Xferred), OutData%LidarEnabled) Int_Xferred = Int_Xferred + 1 END SUBROUTINE InflowWind_UnPackInitInput diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 09f532a022..7aec9c44f6 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -583,7 +583,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, END IF ! lidar - Init%InData_IfW%LidarDisable = .false. ! allowed with OF, but not FF + Init%InData_IfW%LidarEnabled = .true. ! allowed with OF, but not FF Init%InData_IfW%lidar%Tmax = p_FAST%TMax Init%InData_IfW%lidar%HubPosition = ED%y%HubPtMotion%Position(:,1) From 0b4a550e2e6b1b23f7e0ac58afd7772622c3e22e Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 19 Dec 2024 11:55:29 -0700 Subject: [PATCH 39/49] Update v3.5.5.md with summary --- docs/changelogs/v3.5.5.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelogs/v3.5.5.md b/docs/changelogs/v3.5.5.md index 8043f3a3bd..0ac516dbc0 100644 --- a/docs/changelogs/v3.5.5.md +++ b/docs/changelogs/v3.5.5.md @@ -42,7 +42,9 @@ See GitHub Actions ## Overview -This release includes performance +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. From 2a84dde5e3d2cd3daa58e80482b543caab0beef5 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquenot Date: Sat, 21 Dec 2024 16:10:21 +0100 Subject: [PATCH 40/49] :pencil: Replaced np.sqrt with square comparison to speed up comparison --- openfast_python/openfast_io/turbsim_file.py | 34 ++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openfast_python/openfast_io/turbsim_file.py b/openfast_python/openfast_io/turbsim_file.py index 2756fff7be..2e8acf4add 100644 --- a/openfast_python/openfast_io/turbsim_file.py +++ b/openfast_python/openfast_io/turbsim_file.py @@ -16,13 +16,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 +36,7 @@ class TurbSimFile(File): ts = TurbSimFile('Turb.bts') print(ts.keys()) - print(ts['u'].shape) + print(ts['u'].shape) """ @@ -55,7 +55,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 +69,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 +95,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 +104,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 +151,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(' Date: Sat, 21 Dec 2024 16:16:05 +0100 Subject: [PATCH 41/49] :wrench: Used list comprehension to speed u_rot creation --- openfast_python/openfast_io/turbsim_file.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openfast_python/openfast_io/turbsim_file.py b/openfast_python/openfast_io/turbsim_file.py index 2e8acf4add..26c60daeac 100644 --- a/openfast_python/openfast_io/turbsim_file.py +++ b/openfast_python/openfast_io/turbsim_file.py @@ -308,9 +308,7 @@ def compute_rot_avg(self, R): yy, zz = np.meshgrid(self['y'], self['z']) rotor_ind = (yy**2 + (zz - z_hub)**2) < R**2 - u_rot = [] - for u_plane in u_: - u_rot.append(u_plane[rotor_ind].mean()) + u_rot = [u_plane[rotor_ind].mean() for u_plane in u_] self['rot_avg'][i,:] = u_rot From 1b97110a2354d935eaf53a6a5c0d9abf3aaaf4c2 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquenot Date: Sat, 21 Dec 2024 16:18:20 +0100 Subject: [PATCH 42/49] :wrench: Removed unused variables and wrongly declared --- openfast_python/openfast_io/turbsim_file.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openfast_python/openfast_io/turbsim_file.py b/openfast_python/openfast_io/turbsim_file.py index 26c60daeac..e852ea838d 100644 --- a/openfast_python/openfast_io/turbsim_file.py +++ b/openfast_python/openfast_io/turbsim_file.py @@ -264,8 +264,6 @@ def __repr__(self): def toDataFrame(self): dfs={} - ny = len(self['y']) - nz = len(self['y']) # Index at mid box iy,iz = self._iMid() From ab386f4003c77c6c05dc7cec3336ee1803710a8c Mon Sep 17 00:00:00 2001 From: Guillaume Jacquenot Date: Sat, 21 Dec 2024 17:04:12 +0100 Subject: [PATCH 43/49] :sparkle: Added a dedicated entrypoint --- openfast_python/openfast_io/turbsim_file.py | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/openfast_python/openfast_io/turbsim_file.py b/openfast_python/openfast_io/turbsim_file.py index e852ea838d..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 @@ -311,5 +312,27 @@ def compute_rot_avg(self, R): self['rot_avg'][i,:] = u_rot +def main(): + # Create argument parser + parser = argparse.ArgumentParser( + description="Read an OpenFAST .bts wind field files") + parser.add_argument( + "input_file", + type=str, + help="Path to the input .bts file." + ) + + # Parse arguments + args = parser.parse_args() + + # Process input and output files + input_file = args.input_file + # ts = TurbSimFile('../_tests/TurbSim.bts') + ts = TurbSimFile(input_file) + df = ts.toDataFrame() + print(df['VertProfile'].info()) + print(df['MidLine'].info()) + + if __name__=='__main__': - ts = TurbSimFile('../_tests/TurbSim.bts') + main() From acf173968b21b0ea8cc4bf3e099fa88f34872f60 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sat, 21 Dec 2024 16:25:47 -0700 Subject: [PATCH 44/49] SeaState: Add `OMP critical` around file open `!$ OMP critical` directives were added to all other modules in the 3.5.5 updates, but new modules don't include these --- modules/seastate/src/SeaState_Input.f90 | 2 +- modules/seastate/src/SeaState_Output.f90 | 22 +++++++++++++++------- modules/seastate/src/UserWaves.f90 | 20 ++++++++++++-------- 3 files changed, 28 insertions(+), 16 deletions(-) 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() From cad9c8456a3b629adce8f5679d189cde1db328e6 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sun, 22 Dec 2024 14:30:06 -0700 Subject: [PATCH 45/49] ADsk: update reg test results after correcting DiskAvgVel --- reg_tests/r-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reg_tests/r-test b/reg_tests/r-test index b3824f2d3a..ba6813f1f2 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit b3824f2d3a4cd4cb826aa4ac95b6e39a99e66d43 +Subproject commit ba6813f1f241411eef2783f29fa644c5080a1d8a From 355419ced651d37799133d46b7ceb4cc5791b4a9 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sun, 22 Dec 2024 17:43:34 -0700 Subject: [PATCH 46/49] IfW: if AD is used, set BoxExceedAllow to true Ideally, we would set this after we initialize AD and decide based on if OLAF is used. But IfW is initialized before AD now, so we don't know if OLAF will need this info. --- modules/aerodyn/src/AeroDyn.f90 | 2 +- modules/aerodyn/src/AeroDyn_Inflow.f90 | 4 ++++ modules/openfast-library/src/FAST_Subs.f90 | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index d43664041a..7109a5f2a0 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -1929,7 +1929,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 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/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 816441536e..9a8db0b26c 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -520,6 +520,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) From 841bb9c222d59b4da3d6baab3005c58efbae0d2c Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sun, 22 Dec 2024 20:37:28 -0700 Subject: [PATCH 47/49] ADI python: fix type for a logical flag --- modules/aerodyn/python-lib/aerodyn_inflow_library.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/aerodyn/python-lib/aerodyn_inflow_library.py b/modules/aerodyn/python-lib/aerodyn_inflow_library.py index 22e4a87303..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 From 19ba345c01943609f950ddff80d8241b77e2a601 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Sun, 22 Dec 2024 21:23:55 -0700 Subject: [PATCH 48/49] ADI_c: update comment on debuglevel --- modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 index 7c319f031b..48f0d4601f 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_C_Binding.f90 @@ -290,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// & From 57c559902467d8a0a671155bb8fc8663cada62ae Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 23 Dec 2024 09:46:48 -0700 Subject: [PATCH 49/49] Update pointer to r-test dev --- reg_tests/r-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reg_tests/r-test b/reg_tests/r-test index b586d4ca96..abf2b8fbb9 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit b586d4ca9638e05770d8f7b91a5aaa085ca500ee +Subproject commit abf2b8fbb90efab593b4fd3547bfd356b1c22677