Skip to content

Commit

Permalink
Merge pull request #1949 from OpenFAST/rc-3.5.2
Browse files Browse the repository at this point in the history
Release 3.5.2
  • Loading branch information
andrew-platt authored Jan 18, 2024
2 parents 6a6511a + da0ad54 commit 4b6337f
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 15 deletions.
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ endif()
option(BUILD_TESTING "Build the testing tree." OFF)
if(BUILD_TESTING)
option(CODECOVERAGE "Enable infrastructure for measuring code coverage." OFF)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -DUNIT_TEST")
option(BUILD_UNIT_TESTING "Enable unit testing" ON)
if(BUILD_UNIT_TESTING)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -DUNIT_TEST")
endif()
endif()

# Setup Fortran Compiler options based on architecture/compiler
Expand Down Expand Up @@ -276,8 +279,10 @@ if(BUILD_TESTING)
add_subdirectory(reg_tests)

# unit tests
if(NOT (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Flang"))
add_subdirectory(unit_tests)
if(BUILD_UNIT_TESTING)
if(NOT (${CMAKE_Fortran_COMPILER_ID} STREQUAL "Flang"))
add_subdirectory(unit_tests)
endif()
endif()
endif()

Expand Down
70 changes: 70 additions & 0 deletions docs/changelogs/v3.5.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
**Feature or improvement description**
Pull request to merge `rc-3.5.2` into `main` and create a tagged release for v3.5.2.

See the milestone and project pages for additional information

https://github.com/OpenFAST/openfast/milestone/12

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 tag
- [ ] Compile executables for Windows builds
- [ ] FAST_SFunc.mexw64
- [ ] OpenFAST-Simulink_x64.dll
- [ ] openfast_x64.exe
- [ ] DISCON.dll (x64)
- [ ] AeroDyn_Driver
- [ ] AeroDyn_Inflow_C_Binding
- [ ] BeamDyn_Driver
- [ ] HydroDyn_Driver
- [ ] HydroDyn_C_Binding (x64)
- [ ] InflowWind_Driver
- [ ] IfW_C_Binding (x64)
- [ ] MoorDyn_Driver
- [ ] FAST.Farm (x64)

# Changelog

## General

### Build systems

#1948 Pass Python_EXECUTABLE to pfunit, add error check on Python version


## Module changes

### AeroDyn

#1913 ADI: memory leak in ADI_UpdateStates

### AWAE

#1963 FAST.Farm, Mod_AmbWind=3: add error if HR grid not centered on turbine in Y dimension

### HydroDyn

#1872 Fix segfault in HD when no outputs specified



## Regression tests

#1886 Update floating MHK case input files



## Input file changes

No input files change with this release, as this only includes minor bugfixes.

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.2 (example input files from the regression testing)

2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.1'
release = u'v3.5.2'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
5 changes: 3 additions & 2 deletions docs/source/testing/unit_test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Unit testing in OpenFAST modules is accomplished through `pFUnit <https://github
This framework provides a Fortran abstraction to the popular
`xUnit <https://en.wikipedia.org/wiki/XUnit>`__ structure. pFUnit is compiled
along with OpenFAST through CMake when the CMake variable ``BUILD_TESTING`` is
turned on.
turned on (default off) and the CMake variable ``BUILD_UNIT_TESTING`` is on
(turned on by default when ``BUILD_TEST`` is on).

The BeamDyn and NWTC Library modules contain some sample unit tests and should
serve as a reference for future development and testing.
Expand All @@ -21,7 +22,7 @@ Dependencies
------------
The following packages are required for unit testing:

- Python 3.7+
- Python 3.7+, <3.12
- CMake
- pFUnit - Included in OpenFAST repo through a git-submodule

Expand Down
8 changes: 7 additions & 1 deletion docs/source/user/api_change.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ 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.1 to OpenFAST v3.5.2
----------------------------------

No input file changes were made.


OpenFAST v3.5.0 to OpenFAST v3.5.1
----------------------------------

No input files changes were made. Some input files now include additional
No input file changes were made. Some input files now include additional
output channels: AeroDyn nodal outputs for another coordinate system, new
MoorDyn output names (Connect changed to Point).

Expand Down
5 changes: 5 additions & 0 deletions modules/aerodyn/src/AeroDyn_Inflow.f90
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,15 @@ subroutine ADI_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errSta
! Get state variables at next step: INPUT at step nt - 1, OUTPUT at step nt
call AD_UpdateStates(t, n, u_AD(:), utimes(:), p%AD, x%AD, xd%AD, z%AD, OtherState%AD, m%AD, errStat2, errMsg2); if(Failed()) return

call CleanUp()

contains

subroutine CleanUp()
!call ADI_DestroyConstrState(z_guess, errStat2, errMsg2); if(Failed()) return
do it=1,size(utimes)
call AD_DestroyInput(u_AD(it), errStat2, errMsg2); if(Failed()) return
enddo
end subroutine

logical function Failed()
Expand Down
1 change: 1 addition & 0 deletions modules/aerodyn/src/FVW.f90
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@ end subroutine RollBackPreviousTimeStep

subroutine CleanUp()
call FVW_DestroyConstrState(z_guess, ErrStat2, ErrMsg2); if(Failed()) return
call FVW_DestroyInput(uInterp, ErrStat2, ErrMsg2); if(Failed()) return
end subroutine

logical function Failed()
Expand Down
106 changes: 100 additions & 6 deletions modules/awae/src/AWAE.f90
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO

type(AWAE_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine
type(AWAE_InputType), intent( out) :: u !< An initial guess for the input; input mesh must be defined
type(AWAE_ParameterType), intent( out) :: p !< Parameters
type(AWAE_ParameterType),target,intent( out) :: p !< Parameters
type(AWAE_ContinuousStateType), intent( out) :: x !< Initial continuous states
type(AWAE_DiscreteStateType), intent( out) :: xd !< Initial discrete states
type(AWAE_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states
Expand All @@ -821,7 +821,7 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO
character(ErrMsgLen) :: errMsg2 ! temporary error message
character(*), parameter :: RoutineName = 'AWAE_Init'
type(InflowWind_InitInputType) :: IfW_InitInp
type(InflowWind_InitOutputType) :: IfW_InitOut
type(InflowWind_InitOutputType), target :: IfW_InitOut
! Initialize variables for this routine

errStat = ErrID_None
Expand Down Expand Up @@ -1053,25 +1053,32 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO
do nt = 1,p%NumTurbines

IfW_InitInp%TurbineID = nt

call WrScr(NewLine//'Initializing high-resolution grid for Turbine '//trim(Num2Lstr(nt)))
call InflowWind_Init( IfW_InitInp, m%u_IfW_High, p%IfW(nt), x%IfW(nt), xd%IfW(nt), z%IfW(nt), OtherState%IfW(nt), m%y_IfW_High, m%IfW(nt), Interval, IfW_InitOut, ErrStat2, ErrMsg2 )
call SetErrStat ( errStat2, errMsg2, errStat, errMsg, RoutineName )
if (errStat2 >= AbortErrLev) then
if (errStat >= AbortErrLev) then
return
end if

! Check that the high resolution grid placement is correct
! The InflowWind grid location is exactly centered on the TurbPos location in the Y direction. The high resolution grid
! must exactly match the sizing and location of the InflowWind grid. We are only going to check the Y and Z locations
! for now and throw an error if these don't match appropriately.
call CheckModAmb3Boundaries()

end do
if (errStat >= AbortErrLev) return

end if

! Set the position inputs once for the low-resolution grid
m%u_IfW_Low%PositionXYZ = p%Grid_low
! Set the hub position and orientation to pass to IfW (IfW always calculates hub and disk avg vel)
! Set the hub position and orientation to pass to IfW (FIXME: IfW always calculates hub and disk avg vel. Change this after IfW pointers fully enabled.)
m%u_IfW_Low%HubPosition = (/ p%X0_low + 0.5*p%nX_low*p%dX_low, p%Y0_low + 0.5*p%nY_low*p%dY_low, p%Z0_low + 0.5*p%nZ_low*p%dZ_low /)
call Eye(m%u_IfW_Low%HubOrientation,ErrStat2,ErrMsg2)

! Initialize the high-resolution grid inputs and outputs
IF ( .NOT. ALLOCATED( m%u_IfW_High%PositionXYZ ) ) THEN
IF ( .NOT. ALLOCATED( m%u_IfW_High%PositionXYZ ) ) THEN
call AllocAry(m%u_IfW_High%PositionXYZ, 3, p%nX_high*p%nY_high*p%nZ_high, 'm%u_IfW_High%PositionXYZ', ErrStat2, ErrMsg2)
call SetErrStat ( errStat2, errMsg2, errStat, errMsg, RoutineName )
call AllocAry(m%y_IfW_High%VelocityUVW, 3, p%nX_high*p%nY_high*p%nZ_high, 'm%y_IfW_High%VelocityUVW', ErrStat2, ErrMsg2)
Expand Down Expand Up @@ -1258,6 +1265,93 @@ subroutine AWAE_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO



contains
subroutine CheckModAmb3Boundaries()
real(ReKi) :: Dxyz
real(ReKi) :: ff_lim(2)
real(ReKi) :: hr_lim(2)
real(ReKi), parameter :: GridTol = 1.0E-3 ! Tolerance from IfW for checking the high-res grid (Mod_AmbWind=3 only).
type(FlowFieldType), pointer :: ff ! alias to shorten notation to fullfield
type(WindFileDat), pointer :: wfi ! alias to shorten notation to WindFileInfo
character(1024) :: tmpMsg

ff => p%IfW(nt)%FlowField
wfi => IfW_InitOut%WindFileInfo

tmpMsg = NewLine//NewLine//'Turbine '//trim(Num2LStr(nt))//' -- Mod_AmbWind=3 requires the FAST.Farm high-res grid '// &
'is entirely contained within the flow-field from InflowWind. '//NewLine//' Try setting:'//NewLine

! check Z limits, if ZRange is limited (we don't care what kind of wind)
if (wfi%ZRange_Limited) then
! flow field limits (with grid tolerance)
ff_lim(1) = p%WT_Position(3,nt) + wfi%ZRange(1) - GridTol
ff_lim(2) = p%WT_Position(3,nt) + wfi%ZRange(2) + GridTol
! high-res Z limits
hr_lim(1) = p%Z0_High(nt)
hr_lim(2) = p%Z0_High(nt) + (real(p%nZ_high,ReKi)-1.0_ReKi)*p%dZ_high(nt)
if ((hr_lim(1) < ff_lim(1)) .or. &
(hr_lim(2) > ff_lim(2)) ) then
ErrStat2 = ErrID_Fatal
ErrMsg2 = trim(tmpMsg)// &
' Z0_high = '//trim(Num2LStr(p%WT_Position(3,nt)+wfi%ZRange(1)))
if (allocated(ff%Grid3D%Vel)) then
Dxyz = abs(wfi%ZRange(2)-wfi%ZRange(1))/(real(p%nZ_high,ReKi)-1.0_ReKi)
ErrMsg2=trim(ErrMsg2)//NewLine//' dZ_High = '//trim(Num2LStr(Dxyz))
call SetErrStat ( errStat2, errMsg2, errStat, errMsg, RoutineName )
endif
ErrMsg2=NewLine//' for Turbine '//trim(Num2LStr(nt))
endif
endif

! check FlowField Y limits if range limited. Depends on orientation of winds.
if (wfi%YRange_Limited) then
! wind X aligned with high-res X
if ((.not. ff%RotateWindBox) .or. EqualRealNos(abs(ff%PropagationDir),Pi)) then
! flow field limits (with grid tolerance)
ff_lim(1) = p%WT_Position(2,nt) + wfi%YRange(1) - GridTol
ff_lim(2) = p%WT_Position(2,nt) + wfi%YRange(2) + GridTol
! high-res Y limits
hr_lim(1) = p%Y0_High(nt)
hr_lim(2) = p%Y0_High(nt) + (real(p%nY_high,ReKi)-1.0_ReKi)*p%dY_high(nt)
if ((hr_lim(1) < ff_lim(1)) .or. &
(hr_lim(2) > ff_lim(2)) ) then
ErrStat2 = ErrID_Fatal
ErrMsg2 = trim(tmpMsg)// &
' Y0_high = '//trim(Num2LStr(p%WT_Position(2,nt)+wfi%YRange(1)))
if (allocated(ff%Grid3D%Vel)) then
Dxyz = abs(wfi%YRange(2)-wfi%YRange(1))/(real(p%nY_high,ReKi)-1.0_ReKi)
ErrMsg2=trim(ErrMsg2)//NewLine//' dY_High = '//trim(Num2LStr(Dxyz))
call SetErrStat ( errStat2, errMsg2, errStat, errMsg, RoutineName )
endif
ErrMsg2=NewLine//' for Turbine '//trim(Num2LStr(nt))
endif

! wind X aligned with high-res Y
elseif (EqualRealNos(abs(ff%PropagationDir),PiBy2)) then
! flow field limits (with grid tolerance)
ff_lim(1) = p%WT_Position(1,nt) + wfi%YRange(1) - GridTol
ff_lim(2) = p%WT_Position(1,nt) + wfi%YRange(2) + GridTol
! high-res X limits
hr_lim(1) = p%X0_High(nt)
hr_lim(2) = p%X0_High(nt) + (real(p%nX_high,ReKi)-1.0_ReKi)*p%dX_high(nt)
if ((hr_lim(1) < ff_lim(1)) .or. &
(hr_lim(2) > ff_lim(2)) ) then
ErrStat2 = ErrID_Fatal
ErrMsg2 = trim(tmpMsg)// &
' X0_high = '//trim(Num2LStr(p%WT_Position(1,nt)+wfi%YRange(1)))
if (allocated(ff%Grid3D%Vel)) then
Dxyz = abs(wfi%YRange(2)-wfi%YRange(1))/(real(p%nX_high,ReKi)-1.0_ReKi)
ErrMsg2=trim(ErrMsg2)//NewLine//' dX_High = '//trim(Num2LStr(Dxyz))
call SetErrStat ( errStat2, errMsg2, errStat, errMsg, RoutineName )
endif
ErrMsg2=NewLine//' for Turbine '//trim(Num2LStr(nt))
endif
elseif (.not. EqualRealNos(ff%PropagationDir,0.0_ReKi)) then ! wind not aligned with X or Y. This is not allowed at present
ErrStat2 = ErrID_Fatal
ErrMsg2 = NewLine//NewLine//'Turbine '//trim(Num2LStr(nt))//' -- Mod_AmbWind=3 requires InflowWind propagation direction alignment with X or Y (0, 90, 180, 270 degrees).'
endif
endif
end subroutine CheckModAmb3Boundaries


end subroutine AWAE_Init
Expand Down
13 changes: 12 additions & 1 deletion modules/hydrodyn/src/HydroDyn_Input.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3105,7 +3105,18 @@ SUBROUTINE HydroDynInput_ProcessInitData( InitInp, Interval, InputFileData, ErrS
IF (ErrStat >= AbortErrLev ) RETURN

DEALLOCATE(foundMask)


ELSE

! Set number of outputs to zero
InputFileData%NumOuts = 0
InputFileData%Waves2%NumOuts = 0
InputFileData%Morison%NumOuts = 0

! Allocate outlist with zero length
call AllocAry(InputFileData%OutList, 0, "InputFileData%OutList", ErrStat2, ErrMsg2);
call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName)

END IF
! Now that we have the sub-lists organized, lets do some additional validation.

Expand Down
2 changes: 1 addition & 1 deletion reg_tests/r-test
Submodule r-test updated 22 files
+32 −32 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_AeroDyn15_Blade.dat
+5 −5 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.AD.sum
+1 −1 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.ED.sum
+2 −2 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.IfW.sum
+11 −11 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.log
+1,502 −1,502 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.out
+ glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.outb
+1 −1 glue-codes/openfast/MHK_RM1_Fixed/MHK_RM1_Fixed.sum
+32 −32 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_AeroDyn15_Blade.dat
+2 −2 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.AD.sum
+1 −1 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.ED.sum
+18,138 −18,138 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.HD.sum
+2 −2 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.IfW.sum
+2,001 −2,001 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.MD.out
+13 −17 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.log
+202 −202 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.out
+ glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.outb
+1 −1 glue-codes/openfast/MHK_RM1_Floating/MHK_RM1_Floating.sum
+32 −32 modules/aerodyn/ad_MHK_RM1_Fixed/MHK_RM1_AeroDyn15_Blade.dat
+ modules/aerodyn/ad_MHK_RM1_Fixed/ad_driver.outb
+32 −32 modules/aerodyn/ad_MHK_RM1_Floating/MHK_RM1_AeroDyn15_Blade.dat
+ modules/aerodyn/ad_MHK_RM1_Floating/ad_driver.outb
10 changes: 10 additions & 0 deletions unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ project(OpenFAST_UnitTest Fortran)

include(CTest)

if(NOT ${Python_Interpreter_FOUND})
message(FATAL_ERROR "CMake did not find a Python interpreter. Python is required for unit tests." )
endif()
if (${Python_VERSION} VERSION_GREATER_EQUAL "3.12.0")
message(FATAL_ERROR "Unit testing with pfunit not currently possible with Python 3.12 or greater." )
endif()



### pfunit
include(ExternalProject)

Expand All @@ -41,6 +50,7 @@ ExternalProject_Add(pfunit
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/pfunit
-DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}
-DPYTHON_EXECUTABLE=${Python_EXECUTABLE}
-DROBUST=OFF
BUILD_BYPRODUCTS
${PFUNIT_LIB_PATH}
Expand Down

0 comments on commit 4b6337f

Please sign in to comment.