Skip to content

Commit

Permalink
Merge pull request #1995 from andrew-platt/m/3.5.2_to_dev
Browse files Browse the repository at this point in the history
Merge main to dev
  • Loading branch information
andrew-platt authored Jan 19, 2024
2 parents 8259ce1 + a1c9418 commit 9ef15a7
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 20 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 @@ -278,8 +281,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 @@ -137,7 +137,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
9 changes: 7 additions & 2 deletions docs/source/user/api_change.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The line number corresponds to the resulting line number after all changes are i
Thus, be sure to implement each in order so that subsequent line numbers are correct.


OpenFAST v3.5.1 to OpenFAST dev
OpenFAST v3.5.2 to OpenFAST dev
----------------------------------

The HydroDyn module was split into HydroDyn and SeaState. This results in a
Expand All @@ -33,11 +33,16 @@ SubDyn 59\*
\*Exact line number depends on number of entries in various preceeding tables.


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 @@ -1054,25 +1054,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 @@ -1259,6 +1266,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
7 changes: 7 additions & 0 deletions modules/hydrodyn/src/HydroDyn_Input.f90
Original file line number Diff line number Diff line change
Expand Up @@ -2415,8 +2415,15 @@ SUBROUTINE HydroDynInput_ProcessInitData( InitInp, Interval, InputFileData, ErrS

DEALLOCATE(foundMask)
ELSE

! Set number of outputs to zero
InputFileData%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
Loading

0 comments on commit 9ef15a7

Please sign in to comment.