diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 00e1d954c4..a7cca28d9d 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -227,8 +227,9 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! Local variables - integer(IntKi) :: i ! loop counter + integer(IntKi) :: i,k ! loop counter integer(IntKi) :: iR ! loop on rotors + integer(IntKi) :: nNodesVelRot ! number of nodes associated with the rotor that need wind velocity (for CFD coupling) integer(IntKi) :: errStat2 ! temporary error status of the operation character(ErrMsgLen) :: errMsg2 ! temporary error message @@ -500,6 +501,18 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut end do end if + ! number of nodes velocity is required at (for coupling to cfd) + InitOut%nNodesVel = 0 + do iR = 1, nRotors + if (u%rotors(iR)%HubMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%HubMotion%nNodes + do k = 1,size(u%rotors(iR)%BladeMotion) + if (u%rotors(iR)%BladeMotion(k)%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%BladeMotion(k)%nNodes + enddo + if (u%rotors(iR)%TowerMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%TowerMotion%nNodes + if (u%rotors(iR)%NacelleMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%NacelleMotion%nNodes + if (u%rotors(iR)%TFinMotion%committed) InitOut%nNodesVel = InitOut%nNodesVel + u%rotors(iR)%TFinMotion%nNodes + enddo + !............................................................................................ ! Initialize Jacobian: !............................................................................................ diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 618b6540d6..8a615e8b4e 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -141,6 +141,7 @@ typedef ^ RotInitOutputType ReKi TwrDiam {:} - - "Diameter of tower at node" m typedef ^ InitOutputType RotInitOutputType rotors {:} - - "Rotor init output type" - typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - +typedef ^ InitOutputType IntKi nNodesVel - - - "number of nodes velocity values are needed at (for ExtLoads coupling)" - # ..... Input file data ........................................................................................................... # ..... Primary Input file data ................................................................................................... diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index fa691fffed..f8ab54496e 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -169,6 +169,7 @@ MODULE AeroDyn_Types TYPE, PUBLIC :: AD_InitOutputType TYPE(RotInitOutputType) , DIMENSION(:), ALLOCATABLE :: rotors !< Rotor init output type [-] TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] + INTEGER(IntKi) :: nNodesVel = 0_IntKi !< number of nodes velocity values are needed at (for ExtLoads coupling) [-] END TYPE AD_InitOutputType ! ======================= ! ========= RotInputFile ======= @@ -1673,6 +1674,7 @@ subroutine AD_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, Err call NWTC_Library_CopyProgDesc(SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + DstInitOutputData%nNodesVel = SrcInitOutputData%nNodesVel end subroutine subroutine AD_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) @@ -1716,6 +1718,7 @@ subroutine AD_PackInitOutput(RF, Indata) end do end if call NWTC_Library_PackProgDesc(RF, InData%Ver) + call RegPack(RF, InData%nNodesVel) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -1742,6 +1745,7 @@ subroutine AD_UnPackInitOutput(RF, OutData) end do end if call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver + call RegUnpack(RF, OutData%nNodesVel); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyRotInputFile(SrcRotInputFileData, DstRotInputFileData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/extloads/CMakeLists.txt b/modules/extloads/CMakeLists.txt index b649f69557..43baa634f6 100644 --- a/modules/extloads/CMakeLists.txt +++ b/modules/extloads/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(extloadslib STATIC target_include_directories(extloadslib PUBLIC $ ) -target_link_libraries(extloadslib beamdynlib nwtclibs versioninfolib) +target_link_libraries(extloadslib beamdynlib nwtclibs versioninfolib ifwlib) set_target_properties(extloadslib PROPERTIES PUBLIC_HEADER "src/ExtLoadsDX_Types.h") install(TARGETS extloadslib diff --git a/modules/extloads/src/ExtLoads.f90 b/modules/extloads/src/ExtLoads.f90 index 86ae0c85d3..03b4404407 100644 --- a/modules/extloads/src/ExtLoads.f90 +++ b/modules/extloads/src/ExtLoads.f90 @@ -26,7 +26,10 @@ module ExtLoads use NWTC_Library use ExtLoads_Types - + use IfW_FlowField + use InflowWind_IO_Types + use InflowWind_IO + implicit none private @@ -40,7 +43,7 @@ module ExtLoads public :: ExtLd_CalcOutput ! Routine for computing outputs public :: ExtLd_ConvertOpDataForOpenFAST ! Routine to convert Output data for OpenFAST public :: ExtLd_ConvertInpDataForExtProg ! Routine to convert Input data for external programs - + contains !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets the initialization output data structure, which contains data to be returned to the calling program (e.g., @@ -86,21 +89,21 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM type(ExtLd_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated; type(ExtLd_MiscVarType), intent( out) :: m !< Miscellaneous variables type(ExtLd_ParameterType), intent( out) :: p !< Parameter variables - !! only the output mesh is initialized) - real(DbKi), intent(inout) :: interval !< Coupling interval in seconds: the rate that - !! (1) ExtLd_UpdateStates() is called in loose coupling & - !! (2) ExtLd_UpdateDiscState() is called in tight coupling. - !! Input is the suggested time from the glue code; - !! Output is the actual coupling interval that will be used - !! by the glue code. + !! only the output mesh is initialized) + real(DbKi), intent(inout) :: interval !< Coupling interval in seconds: the rate that + !! (1) ExtLd_UpdateStates() is called in loose coupling & + !! (2) ExtLd_UpdateDiscState() is called in tight coupling. + !! Input is the suggested time from the glue code; + !! Output is the actual coupling interval that will be used + !! by the glue code. type(ExtLd_InitOutputType), intent( out) :: InitOut !< Output for initialization routine - integer(IntKi), intent( out) :: errStat !< Error status of the operation - character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None ! Local variables integer(IntKi) :: i ! loop counter - + type(Points_InitInputType) :: Points_InitInput integer(IntKi) :: errStat2 ! temporary error status of the operation character(ErrMsgLen) :: errMsg2 ! temporary error message @@ -118,10 +121,7 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM p%NumBlds = InitInp%NumBlades call AllocAry(p%NumBldNds, p%NumBlds, 'NumBldNds', ErrStat2,ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return p%NumBldNds(:) = InitInp%NumBldNodes(:) p%nTotBldNds = sum(p%NumBldNds(:)) p%NumTwrNds = InitInp%NumTwrNds @@ -142,10 +142,7 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM call Init_u( u, p, InitInp, errStat2, errMsg2 ) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return ! Initialize discrete states @@ -159,11 +156,27 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM !............................................................................................ call Init_y(y, u, m, p, errStat2, errMsg2) ! do this after input meshes have been initialized call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) then - call Cleanup() - return - end if + if (ErrStat >= AbortErrLev) return + !............................................................................................ + ! Initialize InflowWind FlowField + !............................................................................................ + if (associated(m%FlowField)) deallocate(m%FlowField) + allocate(m%FlowField, stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat( ErrID_Fatal, 'Error allocating m%FlowField', ErrStat, ErrMsg, RoutineName ) + return + end if + + ! Initialize flowfield points type + m%FlowField%FieldType = Point_FieldType + Points_InitInput%NumWindPoints = InitInp%nNodesVel + call IfW_Points_Init(Points_InitInput, m%FlowField%Points, ErrStat2, ErrMsg2); if (Failed()) return + + ! Set pointer to flow field in InitOut + InitOut%FlowField => m%FlowField + + write(*,*) 'Initializing InitOut ' !............................................................................................ @@ -172,13 +185,13 @@ subroutine ExtLd_Init( InitInp, u, xd, p, y, m, interval, InitOut, ErrStat, ErrM call ExtLd_SetInitOut(p, InitOut, errStat2, errMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - call Cleanup() contains - subroutine Cleanup() - - end subroutine Cleanup - + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + end subroutine ExtLd_Init !---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes ExtLoads meshes and output array variables for use during the simulation. diff --git a/modules/extloads/src/ExtLoads_Registry.txt b/modules/extloads/src/ExtLoads_Registry.txt index d70ba74433..5f3af5384d 100644 --- a/modules/extloads/src/ExtLoads_Registry.txt +++ b/modules/extloads/src/ExtLoads_Registry.txt @@ -15,6 +15,7 @@ ################################################################################################################################### # ...... Include files (definitions from NWTC Library) ............................................................................ include Registry_NWTC_Library.txt +include IfW_FlowField.txt usefrom ExtLoadsDX_Registry.txt # ..... Initialization data ....................................................................................................... @@ -43,12 +44,14 @@ typedef ^ InitInputType ReKi BldChord {:}{:} typedef ^ InitInputType ReKi BldRloc {:}{:} - - "Radial location of each node along the blade" m typedef ^ InitInputType ReKi TwrDia {:} - - "Tower diameter (NumTwrNodes)" m typedef ^ InitInputType ReKi TwrHloc {:} - - "Height location of each node along the tower" m +typedef ^ InitInputType IntKi nNodesVel - - - "Number of nodes velocity data is needed from (for sizing array)" - # Define outputs from the initialization routine here: typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputUnt {:} - - "Units of the output-to-file channels" - typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - typedef ^ InitOutputType ReKi AirDens - - - "Air density" kg/m^3 +typedef ^ InitOutputType FlowFieldType *FlowField - - - "Pointer of flow field data type" - # ..... States .................................................................................................................... # Define continuous (differentiable) states here: @@ -58,8 +61,9 @@ typedef ^ ContinuousStateType ReKi blah - - - "Someth typedef ^ DiscreteStateType ReKi blah - - - "Something" - #Defin misc variables here -typedef ^ MiscVarType ReKi az - - - "Current azimuth" - -typedef ^ MiscVarType ReKi phi_cfd - - - "Blending ratio of load from external driver [0-1]" - +typedef ^ MiscVarType ReKi az - - - "Current azimuth" - +typedef ^ MiscVarType ReKi phi_cfd - - - "Blending ratio of load from external driver [0-1]" - +typedef ^ MiscVarType FlowFieldType &FlowField - - - "Flow field data type" - # Define constraint states here: typedef ^ ConstraintStateType ReKi blah - - - "Something" - diff --git a/modules/extloads/src/ExtLoads_Types.f90 b/modules/extloads/src/ExtLoads_Types.f90 index 1a7e775232..dcb14a5afe 100644 --- a/modules/extloads/src/ExtLoads_Types.f90 +++ b/modules/extloads/src/ExtLoads_Types.f90 @@ -31,6 +31,7 @@ !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. MODULE ExtLoads_Types !--------------------------------------------------------------------------------------------------------------------------------- +USE IfW_FlowField_Types USE ExtLoadsDX_Types USE NWTC_Library IMPLICIT NONE @@ -60,6 +61,7 @@ MODULE ExtLoads_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BldRloc !< Radial location of each node along the blade [m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrDia !< Tower diameter (NumTwrNodes) [m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TwrHloc !< Height location of each node along the tower [m] + INTEGER(IntKi) :: nNodesVel = 0_IntKi !< Number of nodes velocity data is needed from (for sizing array) [-] END TYPE ExtLd_InitInputType ! ======================= ! ========= ExtLd_InitOutputType ======= @@ -68,6 +70,7 @@ MODULE ExtLoads_Types CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Units of the output-to-file channels [-] TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] REAL(ReKi) :: AirDens = 0.0_ReKi !< Air density [kg/m^3] + TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Pointer of flow field data type [-] END TYPE ExtLd_InitOutputType ! ======================= ! ========= ExtLd_ContinuousStateType ======= @@ -84,6 +87,7 @@ MODULE ExtLoads_Types TYPE, PUBLIC :: ExtLd_MiscVarType REAL(ReKi) :: az = 0.0_ReKi !< Current azimuth [-] REAL(ReKi) :: phi_cfd = 0.0_ReKi !< Blending ratio of load from external driver [0-1] [-] + TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Flow field data type [-] END TYPE ExtLd_MiscVarType ! ======================= ! ========= ExtLd_ConstraintStateType ======= @@ -290,6 +294,7 @@ subroutine ExtLd_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, Err end if DstInitInputData%TwrHloc = SrcInitInputData%TwrHloc end if + DstInitInputData%nNodesVel = SrcInitInputData%nNodesVel end subroutine subroutine ExtLd_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -363,6 +368,7 @@ subroutine ExtLd_PackInitInput(RF, Indata) call RegPackAlloc(RF, InData%BldRloc) call RegPackAlloc(RF, InData%TwrDia) call RegPackAlloc(RF, InData%TwrHloc) + call RegPack(RF, InData%nNodesVel) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -398,6 +404,7 @@ subroutine ExtLd_UnPackInitInput(RF, OutData) call RegUnpackAlloc(RF, OutData%BldRloc); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%TwrDia); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%TwrHloc); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%nNodesVel); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine ExtLd_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) @@ -440,6 +447,7 @@ subroutine ExtLd_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return DstInitOutputData%AirDens = SrcInitOutputData%AirDens + DstInitOutputData%FlowField => SrcInitOutputData%FlowField end subroutine subroutine ExtLd_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) @@ -459,17 +467,26 @@ subroutine ExtLd_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) end if call NWTC_Library_DestroyProgDesc(InitOutputData%Ver, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + nullify(InitOutputData%FlowField) end subroutine subroutine ExtLd_PackInitOutput(RF, Indata) type(RegFile), intent(inout) :: RF type(ExtLd_InitOutputType), intent(in) :: InData character(*), parameter :: RoutineName = 'ExtLd_PackInitOutput' + logical :: PtrInIndex if (RF%ErrStat >= AbortErrLev) return call RegPackAlloc(RF, InData%WriteOutputHdr) call RegPackAlloc(RF, InData%WriteOutputUnt) call NWTC_Library_PackProgDesc(RF, InData%Ver) call RegPack(RF, InData%AirDens) + call RegPack(RF, associated(InData%FlowField)) + if (associated(InData%FlowField)) then + call RegPackPointer(RF, c_loc(InData%FlowField), PtrInIndex) + if (.not. PtrInIndex) then + call IfW_FlowField_PackFlowFieldType(RF, InData%FlowField) + end if + end if if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -480,11 +497,31 @@ subroutine ExtLd_UnPackInitOutput(RF, OutData) integer(B8Ki) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc + integer(B8Ki) :: PtrIdx + type(c_ptr) :: Ptr if (RF%ErrStat /= ErrID_None) return call RegUnpackAlloc(RF, OutData%WriteOutputHdr); if (RegCheckErr(RF, RoutineName)) return call RegUnpackAlloc(RF, OutData%WriteOutputUnt); if (RegCheckErr(RF, RoutineName)) return call NWTC_Library_UnpackProgDesc(RF, OutData%Ver) ! Ver call RegUnpack(RF, OutData%AirDens); if (RegCheckErr(RF, RoutineName)) return + if (associated(OutData%FlowField)) deallocate(OutData%FlowField) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackPointer(RF, Ptr, PtrIdx); if (RegCheckErr(RF, RoutineName)) return + if (c_associated(Ptr)) then + call c_f_pointer(Ptr, OutData%FlowField) + else + allocate(OutData%FlowField,stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%FlowField.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + RF%Pointers(PtrIdx) = c_loc(OutData%FlowField) + call IfW_FlowField_UnpackFlowFieldType(RF, OutData%FlowField) ! FlowField + end if + else + OutData%FlowField => null() + end if end subroutine subroutine ExtLd_CopyContState(SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg) @@ -569,29 +606,60 @@ subroutine ExtLd_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg + integer(B8Ki) :: LB(0), UB(0) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'ExtLd_CopyMisc' ErrStat = ErrID_None ErrMsg = '' DstMiscData%az = SrcMiscData%az DstMiscData%phi_cfd = SrcMiscData%phi_cfd + if (associated(SrcMiscData%FlowField)) then + if (.not. associated(DstMiscData%FlowField)) then + allocate(DstMiscData%FlowField, stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%FlowField.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + call IfW_FlowField_CopyFlowFieldType(SrcMiscData%FlowField, DstMiscData%FlowField, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end if end subroutine subroutine ExtLd_DestroyMisc(MiscData, ErrStat, ErrMsg) type(ExtLd_MiscVarType), intent(inout) :: MiscData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'ExtLd_DestroyMisc' ErrStat = ErrID_None ErrMsg = '' + if (associated(MiscData%FlowField)) then + call IfW_FlowField_DestroyFlowFieldType(MiscData%FlowField, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + deallocate(MiscData%FlowField) + MiscData%FlowField => null() + end if end subroutine subroutine ExtLd_PackMisc(RF, Indata) type(RegFile), intent(inout) :: RF type(ExtLd_MiscVarType), intent(in) :: InData character(*), parameter :: RoutineName = 'ExtLd_PackMisc' + logical :: PtrInIndex if (RF%ErrStat >= AbortErrLev) return call RegPack(RF, InData%az) call RegPack(RF, InData%phi_cfd) + call RegPack(RF, associated(InData%FlowField)) + if (associated(InData%FlowField)) then + call RegPackPointer(RF, c_loc(InData%FlowField), PtrInIndex) + if (.not. PtrInIndex) then + call IfW_FlowField_PackFlowFieldType(RF, InData%FlowField) + end if + end if if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -599,9 +667,32 @@ subroutine ExtLd_UnPackMisc(RF, OutData) type(RegFile), intent(inout) :: RF type(ExtLd_MiscVarType), intent(inout) :: OutData character(*), parameter :: RoutineName = 'ExtLd_UnPackMisc' + integer(B8Ki) :: LB(0), UB(0) + integer(IntKi) :: stat + logical :: IsAllocAssoc + integer(B8Ki) :: PtrIdx + type(c_ptr) :: Ptr if (RF%ErrStat /= ErrID_None) return call RegUnpack(RF, OutData%az); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%phi_cfd); if (RegCheckErr(RF, RoutineName)) return + if (associated(OutData%FlowField)) deallocate(OutData%FlowField) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackPointer(RF, Ptr, PtrIdx); if (RegCheckErr(RF, RoutineName)) return + if (c_associated(Ptr)) then + call c_f_pointer(Ptr, OutData%FlowField) + else + allocate(OutData%FlowField,stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%FlowField.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + RF%Pointers(PtrIdx) = c_loc(OutData%FlowField) + call IfW_FlowField_UnpackFlowFieldType(RF, OutData%FlowField) ! FlowField + end if + else + OutData%FlowField => null() + end if end subroutine subroutine ExtLd_CopyConstrState(SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 60c51e1a08..78e7340ff3 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -531,9 +531,6 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_A Node = Node + 1 u_IfW%PositionXYZ(:,Node) = u_AD14%Twr_InputMarkers%TranslationDisp(:,J) + u_AD14%Twr_InputMarkers%Position(:,J) END DO - - ELSEIF (p_FAST%CompAero == MODULE_AD) THEN - END IF @@ -551,55 +548,81 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_A END SUBROUTINE IfW_InputSolve !---------------------------------------------------------------------------------------------------------------------------------- -!---------------------------------------------------------------------------------------------------------------------------------- -!FIXME: ExtLoads does needs to use the new method for setting the values in the IfW pointers -SUBROUTINE AD_InputSolve_IfW_ExtLoads( p_FAST, u_AD, p_ExtLd, ErrStat, ErrMsg ) - - type(FAST_ParameterType), intent(in) :: p_FAST !< FAST parameter data - type(AD_InputType), intent(inout) :: u_AD !< The inputs to AeroDyn - type(ExtLd_ParameterType), intent(in) :: p_ExtLd !< Parameters of ExtLoads - integer(IntKi) :: ErrStat !< Error status of the operation - character(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None - - !local variables - real(ReKi) :: z !< Local 'z' coordinate - real(ReKi) :: mean_vel !< Local mean velocity - real(ReKi) :: pi !< Our favorite number - integer(IntKi) :: j,k !< Local counter variables - integer(IntKi) :: NumBl !< Number of blades - integer(IntKi) :: Nnodes !< Number of nodes - - ErrStat = ErrID_None - ErrMsg = '' - -! pi = acos(-1.0) -! NumBl = size(u_AD%rotors(1)%InflowOnBlade,3) -! Nnodes = size(u_AD%rotors(1)%InflowOnBlade,2) -! -! do k=1,NumBl -! do j=1,Nnodes -! !Get position first -! z = u_AD%rotors(1)%BladeMotion(k)%Position(3,j) + u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) -! mean_vel = p_ExtLd%vel_mean * ( (z/p_ExtLd%z_ref) ** p_ExtLd%shear_exp) -! u_AD%rotors(1)%InflowOnBlade(1,j,k) = -mean_vel * sin(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnBlade(2,j,k) = -mean_vel * cos(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnBlade(3,j,k) = 0.0 -! end do -! end do -! -! if ( allocated(u_AD%rotors(1)%InflowOnTower) ) then -! Nnodes = size(u_AD%rotors(1)%InflowOnTower,2) -! do j=1,Nnodes -! !Get position first -! z = u_AD%rotors(1)%TowerMotion%Position(3,j) + u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) -! mean_vel = p_ExtLd%vel_mean * ( (z/p_ExtLd%z_ref) ** p_ExtLd%shear_exp) -! u_AD%rotors(1)%InflowOnTower(1,j) = -mean_vel * sin(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnTower(2,j) = -mean_vel * cos(p_ExtLd%wind_dir * pi / 180.0) -! u_AD%rotors(1)%InflowOnTower(3,j) = 0.0 -! end do -! end if +SUBROUTINE ExtLd_UpdateFlowField( p_FAST, u_AD, ExtLd, ErrStat, ErrMsg ) + type(FAST_ParameterType), intent(in) :: p_FAST !< FAST parameter data + type(AD_InputType), intent(in ) :: u_AD !< The inputs to AeroDyn + type(ExtLoads_Data), intent(in ) :: ExtLd !< ExtLoads data + integer(IntKi) :: ErrStat !< Error status of the operation + character(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + !local variables + real(ReKi) :: z !< Local 'z' coordinate + real(ReKi) :: pi !< Our favorite number + integer(IntKi) :: j,k !< Local counter variables + integer(IntKi) :: NumBl !< Number of blades + integer(IntKi) :: iPt !< Point in the flow field array. Make sure this order corresponds to what AD15 uses!!!!!! + -END SUBROUTINE AD_InputSolve_IfW_ExtLoads + ErrStat = ErrID_None + ErrMsg = '' + + NumBl = size(u_AD%rotors(1)%BladeMotion) + + iPt=1 + + ! Hub + if (u_AD%rotors(1)%HubMotion%committed) then + ! height + z = u_AD%rotors(1)%HubMotion%Position(3,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + + ! Blades + do k=1,NumBl + do j=1,u_AD%rotors(1)%BladeMotion(k)%nNodes + ! height + z = u_AD%rotors(1)%BladeMotion(k)%Position(3,j) + u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + call SetWind(iPt,z); iPt = iPt + 1 + end do + end do + + ! Tower + if ( allocated(u_AD%rotors(1)%InflowOnTower) ) then + do j=1,u_AD%rotors(1)%TowerMotion%nNodes + ! height + z = u_AD%rotors(1)%TowerMotion%Position(3,j) + u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) + call SetWind(iPt,z); iPt = iPt + 1 + end do + end if + + ! Nacelle + if (u_AD%rotors(1)%NacelleMotion%committed) then + ! height + z = u_AD%rotors(1)%NacelleMotion%Position(3,1) + u_AD%rotors(1)%NacelleMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + + ! Tailfin + if (u_AD%rotors(1)%TFinMotion%committed) then + ! height + z = u_AD%rotors(1)%TFinMotion%Position(3,1) + u_AD%rotors(1)%TFinMotion%TranslationDisp(3,1) + call SetWind(iPt,z); iPt = iPt + 1 + endif + +contains + function mean_vel(z_h) + real(ReKi) :: z_h !< height + real(ReKi) :: mean_vel !< mean velocity at height z_h + mean_vel = ExtLd%p%vel_mean * ( (z_h/ExtLd%p%z_ref) ** ExtLd%p%shear_exp) + end function + subroutine SetWind(i,z_h) + integer(IntKi) :: i ! point num + real(ReKi) :: z_h !< height + ExtLd%m%FlowField%Points%Vel(iPt,1) = -mean_vel(z_h) * sin(ExtLd%p%wind_dir * pi / 180.0) + ExtLd%m%FlowField%Points%Vel(iPt,2) = -mean_vel(z_h) * cos(ExtLd%p%wind_dir * pi / 180.0) + ExtLd%m%FlowField%Points%Vel(iPt,3) = 0.0 + end subroutine +END SUBROUTINE ExtLd_UpdateFlowField @@ -5143,7 +5166,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca CALL AD_InputSolve_NoIfW( p_FAST, AD%Input(1), SrvD%y, ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - CALL AD_InputSolve_IfW_ExtLoads( p_FAST, AD%Input(1), ExtLd%p, ErrStat2, ErrMsg2 ) + CALL ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL ExtLd_InputSolve_NoIfW( p_FAST, ExtLd%u, ExtLd%p, ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) @@ -5518,7 +5541,7 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data - TYPE(ExtLoads_Data), INTENT(INOUT) :: ExtLD !< ExtLoads data + TYPE(ExtLoads_Data), INTENT(INOUT) :: ExtLd !< ExtLoads data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5569,6 +5592,12 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, CALL AD14_InputSolve_IfW( p_FAST, AD14%Input(1), IfW%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ELSE IF (p_FAST%CompAero == Module_ExtLd ) THEN + + ! The outputs from ExternalInflow need to be transfered to the FlowField for use by AeroDyn, this seems like the right place + call ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END IF @@ -5655,7 +5684,7 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, CALL SetErrStat(ErrID_Fatal,'p_FAST%CompInflow option not setup to work with ExtLoads module.',ErrStat,ErrMsg,RoutineName) ENDIF - CALL AD_InputSolve_IfW_ExtLoads( p_FAST, AD%Input(1), ExtLd%p, ErrStat2, ErrMsg2 ) + CALL ExtLd_UpdateFlowField( p_FAST, AD%Input(1), ExtLd, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL AD_CalcOutput( this_time, AD%Input(1), AD%p, AD%x(this_state), AD%xd(this_state), AD%z(this_state), & diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 3cb106fbac..d44166a3c0 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -613,6 +613,9 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AirDens = Init%OutData_ExtLd%AirDens + ! Set pointer to flowfield + IF (p_FAST%CompAero == Module_AD) AD%p%FlowField => Init%OutData_ExtLd%FlowField + END IF END IF @@ -654,13 +657,6 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, IF ( p_FAST%CompAero == Module_AD14 ) THEN Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints + NumBl * AD14%Input(1)%InputMarkers(1)%NNodes + AD14%Input(1)%Twr_InputMarkers%NNodes - ELSEIF ( p_FAST%CompAero == Module_AD ) THEN - ! Number of Wind points from AeroDyn, see AeroDyn.f90 - Init%InData_IfW%NumWindPoints = Init%InData_IfW%NumWindPoints - ! Wake -- we allow the wake positions to exceed the wind box - if (allocated(AD%OtherSt(STATE_CURR)%WakeLocationPoints)) then - Init%InData_IfW%BoxExceedAllow = .true. - endif END IF ! lidar @@ -4664,6 +4660,10 @@ SUBROUTINE ExtLd_SetInitInput(InitInData_ExtLd, InitOutData_ED, y_ED, InitOutDat deallocate(AD_etaNodes) end if + ! Total number of nodes velocity is needed at + InitInData_ExtLd%nNodesVel = InitOutData_AD%nNodesVel + + RETURN END SUBROUTINE ExtLd_SetInitInput