From 7311b54ac1ed40dd5820668ea9537a5408185416 Mon Sep 17 00:00:00 2001 From: luwang00 Date: Thu, 16 Apr 2026 17:11:21 -0600 Subject: [PATCH 1/4] Initial implementation of AD generalized support structure loads --- modules/aerodyn/src/AeroDyn.f90 | 435 ++++++++++- modules/aerodyn/src/AeroDyn_IO.f90 | 84 ++- modules/aerodyn/src/AeroDyn_Inflow_Types.f90 | 40 +- modules/aerodyn/src/AeroDyn_Registry.txt | 50 +- modules/aerodyn/src/AeroDyn_Types.f90 | 706 +++++++++++++++++- modules/openfast-library/src/FAST_Mapping.f90 | 21 + 6 files changed, 1282 insertions(+), 54 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index f78f205523..38a2a3de9e 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -442,7 +442,18 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! Set pointer to FlowField data if (associated(InitInp%FlowField)) p%FlowField => InitInp%FlowField - + ! Initialize general support structure parameters + call Init_GSParam(InputFileData%GS, p%GS, InputFileData%AirDens, InitInp%MHK, InitInp%WtrDpth, errStat2, errMsg2 ) + if (Failed()) return; + if (nRotors >= 1_IntKi) then + p%rotors(1)%GSAero = p%GS%GSAero + p%rotors(1)%GSDrag = p%GS%GSDrag ! Only rotor 1 handles GS drag force + end if + do iR = 2, nRotors + p%rotors(iR)%GSAero = p%GS%GSAero + p%rotors(iR)%GSDrag = .false. ! Only rotor 1 handles GS drag force + enddo + !............................................................................................ ! Define and initialize inputs here !............................................................................................ @@ -546,6 +557,13 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut if (Failed()) return enddo + !............................................................................................ + ! Initialize m%Inflow%GSInflow for tracking wind inflow + !............................................................................................ + call AllocAry( m%Inflow(1)%GSInflow%InflowVel, 3_IntKi, p%GS%NNodes, 'GSInflow%InflowVel', ErrStat2, ErrMsg2 ) + if (Failed()) return + m%Inflow(1)%GSInflow%InflowVel = 0.0_ReKi + ! Duplicte Inflow(1) (must be done after Init_OLAF) call AD_CopyInflowType(m%Inflow(1), m%Inflow(2), MESH_NEWCOPY, ErrStat2, ErrMsg2) if (Failed()) return @@ -1062,6 +1080,18 @@ subroutine Init_y(y, u, p, errStat, errMsg) errStat = ErrID_None errMsg = "" + if (p%GSDrag) then + call MeshCopy ( SrcMesh = u%GSMotion & + , DestMesh = y%GSLoad & + , CtrlCode = MESH_SIBLING & + , IOS = COMPONENT_OUTPUT & + , force = .TRUE. & + , moment = .TRUE. & + , ErrStat = ErrStat2 & + , ErrMess = ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) RETURN + end if if (p%NumTwrNds > 0 .and. (p%TwrAero /= TwrAero_None .or. p%MHK /= MHK_None)) then @@ -1172,12 +1202,17 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er ! Local variables real(reKi) :: position(3) ! node reference position real(reKi) :: positionL(3) ! node local position + real(ReKi) :: p1(3) ! node reference position + real(ReKi) :: p2(3) ! node reference position real(R8Ki) :: theta(3) ! Euler angles real(R8Ki) :: orientation(3,3) ! node reference orientation real(R8Ki) :: orientationL(3,3) ! node local orientation + real(ReKi) :: s ! normalized distance along a GS member integer(intKi) :: j ! counter for nodes integer(intKi) :: k ! counter for blades + integer(intKi) :: nnodes ! number of nodes of a GS member + integer(intKi) :: nodeCntr ! node counter integer(intKi) :: ErrStat2 ! temporary Error status character(ErrMsgLen) :: ErrMsg2 ! temporary Error message @@ -1192,11 +1227,74 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) if (errStat >= AbortErrLev) return - - + u%UserProp = 0.0_ReKi - - ! Meshes for motion inputs (ElastoDyn and/or BeamDyn) + + ! Meshes for motion inputs (ElastoDyn, SubDyn, and/or BeamDyn) + !................ + ! general support structure + !................ + if (p%GSAero .or. p%GSDrag) then + + call MeshCreate ( BlankMesh = u%GSMotion & + ,IOS = COMPONENT_INPUT & + ,Nnodes = p_AD%GS%NNodes & + ,ErrStat = ErrStat2 & + ,ErrMess = ErrMsg2 & + ,Orientation = .true. & ! Might be ok to remove Orientation later + ,TranslationDisp = .true. & + ,TranslationVel = .true. & + ) + if (failed()) return + + ! Add GS joints to the mesh first + nodeCntr = 0_IntKi + do j=1,p_AD%GS%NJoints + position = p_AD%GS%Joints(j)%position ! z offset for MHK_FixedBottom was already done in Init_GSParam + nodeCntr = nodeCntr + 1_IntKi + call MeshPositionNode(u%GSMotion, nodeCntr, position, errStat2, errMsg2) ! orientation is identity by default + if (failed()) return + end do !j + + ! Add member interior nodes to the mesh next + do j=1,p_AD%GS%NMembers + nnodes = p_AD%GS%Members(j)%NElements + 1_IntKi + p1 = p_AD%GS%Joints(p_AD%GS%Members(j)%NodeIndx( 1))%position + p2 = p_AD%GS%Joints(p_AD%GS%Members(j)%NodeIndx(nnodes))%position + do k=2_IntKi,nnodes-1_IntKi + s = real(k-1_IntKi,ReKi)/real(nnodes-1_IntKi,ReKi) + position = p1 * (1.0_ReKi-s) + p2 * s + nodeCntr = nodeCntr + 1_IntKi + call MeshPositionNode(u%GSMotion, nodeCntr, position, errStat2, errMsg2) ! orientation is identity by default + if (failed()) return + end do + ! ! create line2 elements + ! do k=1,nnodes-1_IntKi + ! call MeshConstructElement( u%GSMotion, ELEMENT_LINE2, errStat2, errMsg2, & + ! p1=p_AD%GS%Members(j)%NodeIndx( k), & + ! p2=p_AD%GS%Members(j)%NodeIndx(k+1) ) + ! call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + ! end do + end do + + do j=1,nodeCntr + call MeshConstructElement( u%GSMotion & + ,ELEMENT_POINT & + ,errStat2 & + ,errMsg2 & + ,j & + ) + if (failed()) return + end do + + call MeshCommit(u%GSMotion, errStat2, errMsg2 ); if (failed()) return + + ! Is it necessary to initalize u%GSMotion%Orientation? + u%GSMotion%TranslationDisp = 0.0_R8Ki + u%GSMotion%TranslationVel = 0.0_ReKi + + end if + !................ ! tower !................ @@ -1973,6 +2071,9 @@ subroutine AD_CalcWind(t, u, FLowField, p, m, o, Inflow, ErrStat, ErrMsg) if(Failed()) return enddo + call AD_CalcWind_GS(t, u%rotors(1), FlowField, p%GS, p, m, Inflow%GSInflow, StartNode, ErrStat2, ErrMsg2) + if(Failed()) return + ! OLAF points if (allocated(o%WakeLocationPoints) .and. allocated(Inflow%InflowWakeVel)) then ! If rotor is MHK, add water depth to z coordinate @@ -1987,7 +2088,8 @@ subroutine AD_CalcWind(t, u, FLowField, p, m, o, Inflow, ErrStat, ErrMsg) StartNode, t, & o%WakeLocationPoints, & Inflow%InflowWakeVel, & - NoAcc, ErrStat2, ErrMsg2) + NoAcc, ErrStat2, ErrMsg2, & + BoxExceedAllow=.true.) if(Failed()) return else call IfW_FlowField_GetVelAcc(FlowField, StartNode, t, & @@ -2143,11 +2245,63 @@ subroutine AD_CalcWind_Rotor(t, u, FlowField, p, p_AD, m, RotInflow, StartNode, contains logical function Failed() - call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'AD_CalcWindRotor') + call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'AD_CalcWind_Rotor') Failed = errStat >= AbortErrLev end function Failed end subroutine +subroutine AD_CalcWind_GS(t, u, FlowField, p, p_AD, m, GSInflow, StartNode, ErrStat, ErrMsg) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(RotInputType), intent(in ) :: u !< Inputs at Time t + type(FlowFieldType),pointer, intent(in ) :: FlowField !< Pointer to IfW flowfield + type(GSParameterType), intent(in ) :: p !< Parameters + type(AD_ParameterType), intent(in ) :: p_AD !< AD parameters + type(AD_MiscVarType), intent(inout) :: m !< Misc/optimization variables + type(ElemInflowType),target, intent(inout) :: GSInflow !< calculated inflow + integer(IntKi), intent(inout) :: StartNode !< starting node for rotor wind + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + integer(intKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + real(ReKi) :: PosOffset(3) + real(ReKi), allocatable :: NoAcc(:,:) + + ErrStat = ErrID_None + ErrMsg = "" + + if (p%GSAero.or.p%GSDrag) then + ! If rotor is MHK, add water depth to z coordinate + if (p%MHK /= MHK_None) then + PosOffset = [0.0_ReKi, 0.0_ReKi, p%WtrDpth] + else + PosOffset = 0.0_ReKi + end if + if (p%MHK /= MHK_None .and. p_AD%CompSeaSt) then ! MHK turbines with waves + call WaveField_GetWaveVelAcc_AD(p_AD%WaveField, m%WaveField_m, & + StartNode, t, & + real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & + GSInflow%InflowVel, & + NoAcc, ErrStat2, ErrMsg2, & + BoxExceedAllow=.true.) + if(Failed()) return + else + call IfW_FlowField_GetVelAcc(FlowField, StartNode, t, & + real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & + GSInflow%InflowVel, & + NoAcc, ErrStat2, ErrMsg2, & + BoxExceedAllow=.true., PosOffset=PosOffset) + if(Failed()) return + end if + StartNode = StartNode + p%NNodes + end if + +contains + logical function Failed() + call SetErrStat(errStat2, errMsg2, errStat, errMsg, 'AD_CalcWind_GS') + Failed = errStat >= AbortErrLev + end function Failed +end subroutine !---------------------------------------------------------------------------------------------------------------------------------- !> Routine for computing outputs, used in both loose and tight coupling. @@ -2195,7 +2349,7 @@ subroutine AD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, ! SetInputs, Calc BEM Outputs and Twr Outputs do iR=1,size(p%rotors) - call RotCalcOutput(t, u%rotors(iR), m%Inflow(1)%RotInflow(iR), p%rotors(iR), p, x%rotors(iR), & + call RotCalcOutput(t, u%rotors(iR), m%Inflow(1)%RotInflow(iR), m%Inflow(1)%GSInflow, p%rotors(iR), p, x%rotors(iR), & xd%rotors(iR), z%rotors(iR), OtherState%rotors(iR), & y%rotors(iR), m%rotors(iR), m, iR, ErrStat2, ErrMsg2, .false.) if(Failed()) return @@ -2234,7 +2388,7 @@ logical function Failed() end function Failed end subroutine AD_CalcOutput !---------------------------------------------------------------------------------------------------------------------------------- -subroutine RotCalcOutput( t, u, RotInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRot, ErrStat, ErrMsg, NeedWriteOutput) +subroutine RotCalcOutput( t, u, RotInflow, GSInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRot, ErrStat, ErrMsg, NeedWriteOutput) ! NOTE: no matter how many channels are selected for output, all of the outputs are calculated ! All of the calculated output channels are placed into the m%AllOuts(:), while the channels selected for outputs are ! placed in the y%WriteOutput(:) array. @@ -2243,6 +2397,7 @@ subroutine RotCalcOutput( t, u, RotInflow, p, p_AD, x, xd, z, OtherState, y, m, REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds TYPE(RotInputType), INTENT(IN ) :: u !< Inputs at Time t TYPE(RotInflowType), INTENT(IN ) :: RotInflow !< Rotor Inflow at Time t + TYPE(ElemInflowType), INTENT(IN ) :: GSInflow !< General support structure Inflow at Time t TYPE(RotParameterType), INTENT(IN ) :: p !< Parameters TYPE(AD_ParameterType), INTENT(IN ) :: p_AD !< Parameters TYPE(RotContinuousStateType), INTENT(IN ) :: x !< Continuous states at t @@ -2299,12 +2454,16 @@ subroutine RotCalcOutput( t, u, RotInflow, p, p_AD, x, xd, z, OtherState, y, m, end if endif - if ( p%TwrAero /= TwrAero_none ) then call ADTwr_CalcOutput(p, u, RotInflow, m, y, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif + if (p%GSDrag) then + call ADGS_CalcOutput(p_AD%GS, u, GSInflow, m, y, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif + ! initialize nacelle mesh loads y%NacelleLoad%Force = 0.0_ReKi y%NacelleLoad%Moment = 0.0_ReKi @@ -5123,7 +5282,158 @@ subroutine Cleanup() end subroutine Cleanup END SUBROUTINE Init_BEMTmodule +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine initializes the FVW module from within AeroDyn. +SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMsg ) + type(GSInputFile), intent(in ) :: InputFileData + type(GSParameterType), intent(inout) :: p + real(ReKi), intent(in ) :: Density + integer(IntKi), intent(in ) :: MHK + real(ReKi), intent(in ) :: WtrDpth + integer(IntKi), intent( out) :: errStat !< Error status of the operation + character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + + integer(IntKi) :: iMem, iJoint, iNode + integer(IntKi) :: j1, j2, j1Indx, j2Indx + integer(IntKi) :: memID + integer(IntKi) :: numDiv + real(ReKi) :: j1Pos(3), j2Pos(3) + real(ReKi) :: memLength, s + logical, allocatable :: JointUsed(:) + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'Init_GSParam' + + ErrStat = ErrID_None + ErrMsg = "" + + if (InputFileData%NMembers==0_IntKi) then + p%GSAero = .false. + p%GSDrag = .false. + p%Density = 0.0_ReKi + p%MHK = MHK + p%WtrDpth = WtrDpth + p%NJoints = 0_IntKi + p%NNodes = 0_IntKi + p%NMembers = 0_IntKi + return + end if + + ! Default GSAero and GSDrag to true for now; can be based on user input later + p%GSAero = .true. + p%GSDrag = .true. + p%Density = Density + p%NMembers = InputFileData%NMembers + p%NJoints = InputFileData%NJoints + p%NNodes = InputFileData%NJoints ! Total number of nodes (joints + interior nodes); incremented below + + allocate( p%Members(InputFileData%NMembers), STAT = ErrStat2) + if ( ErrStat2 /= 0 ) then + errMsg = RoutineName//': Error allocating space for the members array. ' + errStat = ErrID_Fatal + call Cleanup() + return + end if + allocate( p%Joints(InputFileData%NJoints), STAT = ErrStat2) + if ( ErrStat2 /= 0 ) then + errMsg = RoutineName//': Error allocating space for the joints array. ' + errStat = ErrID_Fatal + call Cleanup() + return + end if + call AllocAry( JointUsed, InputFileData%NJoints, 'temporary logical array to track which joint is used', ErrStat2, ErrMsg2 ) + if (Failed()) return + JointUsed = .false. + + do iJoint = 1,InputFileData%NJoints + p%Joints(iJoint)%JointID = InputFileData%InpJoints(iJoint)%JointID + p%Joints(iJoint)%position = InputFileData%InpJoints(iJoint)%position + if (MHK == MHK_FixedBottom) then + p%Joints(iJoint)%position(3) = p%Joints(iJoint)%position(3) - WtrDpth + end if + end do + + do iMem = 1,InputFileData%NMembers + memID = InputFileData%InpMembers(iMem)%MemberID + p%Members(iMem)%MemberID = memID + + j1 = InputFileData%InpMembers(iMem)%MJointID1 + j2 = InputFileData%InpMembers(iMem)%MJointID2 + j1Indx = -1_IntKi + j2Indx = -1_IntKi + do iJoint = 1,InputFileData%NJoints + if (InputFileData%InpJoints(iJoint)%JointID == j1) j1Indx = iJoint + if (InputFileData%InpJoints(iJoint)%JointID == j2) j2Indx = iJoint + enddo + if (j1Indx<0_IntKi) then + ErrStat = ErrID_Fatal + ErrMsg = RoutineName//': MJointID1 of member with ID '//trim(num2lstr(memID))//' not found in the joint table. ' + call Cleanup() + return + endif + JointUsed(j1Indx) = .true. + if (j2Indx<0_IntKi) then + ErrStat = ErrID_Fatal + ErrMsg = RoutineName//': MJointID2 of member with ID '//trim(num2lstr(memID))//' not found in the joint table. ' + call Cleanup() + return + endif + JointUsed(j2Indx) = .true. + + j1Pos = InputFileData%InpJoints(j1Indx)%Position + j2Pos = InputFileData%InpJoints(j2Indx)%Position + memLength = TwoNorm(j2Pos-j1Pos) + if (memLength==0.0_ReKi) then + ErrStat = ErrID_Fatal + ErrMsg = RoutineName//': Member with ID '//trim(num2lstr(memID))//' has zero length. ' + call Cleanup() + return + endif + numDiv = ceiling( memLength / InputFileData%InpMembers(iMem)%MDivSize ) + p%members(iMem)%RefLength = memLength + p%members(iMem)%NElements = numDiv + p%members(iMem)%dl = memLength/numDiv + + call AllocAry( p%members(iMem)%NodeIndx, numDiv+1_IntKi, 'Index of each of the member nodes in the global node list', ErrStat2, ErrMsg2 ) + if (Failed()) return + p%members(iMem)%NodeIndx(1) = j1Indx + p%members(iMem)%NodeIndx(numDiv+1_IntKi) = j2Indx + do iNode = 2,numDiv + p%members(iMem)%NodeIndx(iNode) = p%NNodes + iNode - 1_IntKi + enddo + p%NNodes = p%NNodes + numDiv - 1_IntKi + + call AllocAry( p%members(iMem)%R, numDiv+1_IntKi, 'Radius of each member nodes', ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( p%members(iMem)%Cd, numDiv+1_IntKi, 'Drag coefficient of each member nodes', ErrStat2, ErrMsg2 ); if (Failed()) return + call AllocAry( p%members(iMem)%TI, numDiv+1_IntKi, 'Turbulence intensity of each member nodes', ErrStat2, ErrMsg2 ); if (Failed()) return + do iNode = 1,numDiv+1_IntKi + s = real(iNode-1_IntKi,ReKi) / real(numDiv,ReKi) + p%members(iMem)%R(iNode) = InputFileData%InpMembers(iMem)%MDiam1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MDiam2 * s + p%members(iMem)%Cd(iNode) = InputFileData%InpMembers(iMem)%MCd1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MCd2 * s + p%members(iMem)%TI(iNode) = InputFileData%InpMembers(iMem)%MTI1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MTI2 * s + enddo + end do + + if ( any(.not.JointUsed) ) then + ErrStat = ErrID_Fatal + ErrMsg = RoutineName//': All joints in the general support structure joint table must be referenced by at least one member. ' + call Cleanup() + return + end if + + call Cleanup() +contains + subroutine Cleanup() + if (allocated(JointUsed)) deallocate(JointUsed) + end subroutine Cleanup + + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed +END SUBROUTINE !---------------------------------------------------------------------------------------------------------------------------------- !> This routine initializes the FVW module from within AeroDyn. SUBROUTINE Init_OLAF( InputFileData, u_AD, u, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) @@ -5463,6 +5773,65 @@ SUBROUTINE ADTwr_CalcOutput(p, u, RotInflow, m, y, ErrStat, ErrMsg ) END SUBROUTINE ADTwr_CalcOutput !---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine calculates the general support structure loads for the AeroDyn GSLoad output mesh. +SUBROUTINE ADGS_CalcOutput(p, u, GSInflow, m, y, ErrStat, ErrMsg ) + + TYPE(RotInputType), INTENT(IN ) :: u !< Inputs at Time t + TYPE(ElemInflowType), INTENT(IN ) :: GSInflow !< Inflow at Time t + TYPE(GSParameterType), INTENT(IN ) :: p !< Parameters + TYPE(RotMiscVarType), INTENT(INOUT) :: m !< Misc/optimization variables + TYPE(RotOutputType), INTENT(INOUT) :: y !< Outputs computed at t + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: j, j1, j2, iMem + real(ReKi) :: q1(3), q2(3) + real(ReKi) :: V_rel(3), V_mag ! relative wind speed on a tower node + real(ReKi) :: pos1(3) + real(ReKi) :: pos2(3) + real(ReKi) :: k(3) + real(ReKi) :: dl + character(*), parameter :: RoutineName = 'ADGS_CalcOutput' + + ErrStat = ErrID_None + ErrMsg = "" + + IF (.not.p%GSDrag) RETURN + + y%GSLoad%Force = 0.0_ReKi + y%GSLoad%moment = 0.0_ReKi + do iMem = 1,p%NMembers + associate( mem => p%Members(iMem)) + do j=1,mem%NElements + + j1 = mem%NodeIndx(j ) + j2 = mem%NodeIndx(j+1) + pos1 = u%GSMotion%position(:,j1) + u%GSMotion%TranslationDisp(:,j1) + pos2 = u%GSMotion%position(:,j2) + u%GSMotion%TranslationDisp(:,j2) + k = pos2-pos1 + dl = TwoNorm(k) + if (dl==0.0_ReKi) cycle ! Zero length element; shouldn't happen, but just in case. + k = k/dl + + V_rel = GSInflow%InflowVel(:,j1) - u%GSMotion%TranslationVel(:,j1) ! Total relative wind speed at GS node + V_rel = V_rel - dot_product(V_rel,k)*k ! Transverse component of relative wind speed + V_mag = TwoNorm(V_rel) + q1 = mem%Cd(j ) * p%Density * mem%R(j ) * 0.5_ReKi * dl * V_mag * V_rel + + V_rel = GSInflow%InflowVel(:,j2) - u%GSMotion%TranslationVel(:,j2) ! Total relative wind speed at GS node + V_rel = V_rel - dot_product(V_rel,k)*k ! Transverse component of relative wind speed + V_mag = TwoNorm(V_rel) + q2 = mem%Cd(j+1) * p%Density * mem%R(j+1) * 0.5_ReKi * dl * V_mag * V_rel + + y%GSLoad%force(:,j1) = y%GSLoad%force(:,j1) + q1 + y%GSLoad%force(:,j2) = y%GSLoad%force(:,j2) + q2 + + end do + end associate + end do + +END SUBROUTINE ADGS_CalcOutput +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine checks for invalid inputs to the tower influence models. SUBROUTINE CheckTwrInfl(u, ErrStat, ErrMsg ) @@ -6175,6 +6544,13 @@ subroutine AD_InitVars(iR, u, p, x, z, OtherState, y, m, InitOut, InputFileData, Mesh=u%TowerMotion, & Perturbs=[PerturbTower, Perturb, PerturbTower, PerturbTower]) + ! Add general support motion + call MV_AddMeshVar(InitOut%Vars%u, "General Support", [FieldTransDisp, FieldOrientation, FieldTransVel], & + DatLoc(AD_u_GSMotion), & + Mesh=u%GSMotion, & + Perturbs=[PerturbTower, Perturb, PerturbTower], & + Active=(p%GSAero.or.p%GSDrag)) + ! Add blade root motion do j = 1, p%NumBlades call MV_AddMeshVar(InitOut%Vars%u, "Blade root "//Num2LStr(j), [FieldOrientation], & @@ -6243,6 +6619,11 @@ subroutine AD_InitVars(iR, u, p, x, z, OtherState, y, m, InitOut, InputFileData, call MV_AddMeshVar(InitOut%Vars%y, "Tower", LoadFields, DatLoc(AD_y_TowerLoad), & Mesh=y%TowerLoad) + ! Add general support load + call MV_AddMeshVar(InitOut%Vars%y, "General Support", LoadFields, DatLoc(AD_y_GSLoad), & + Mesh=y%GSLoad, & + Active=p%GSDrag) + ! Loop through blades, add blade loads do j = 1, p%NumBlades Flags = VF_Line @@ -6358,6 +6739,7 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth type(FlowFieldType),target :: FF_perturb type(FlowFieldType),pointer :: FF_ptr ! need a pointer in the CalcWind_Rotor routine type(RotInflowType) :: RotInflow_perturb !< Rotor inflow, perturbed by FlowField extended inputs + type(ElemInflowType) :: GSInflow_perturb ErrStat = ErrID_None ErrMsg = '' @@ -6373,7 +6755,8 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth z => z_AD%rotors(iRotor), & OtherState => OtherState_AD%rotors(iRotor), & y_lin => m_AD%y_lin%rotors(iRotor), & - RotInflow => m_AD%Inflow(1)%RotInflow(iRotor)) + RotInflow => m_AD%Inflow(1)%RotInflow(iRotor), & + GSInflow => m_AD%Inflow(1)%GSInflow) ! Find indices for extended input variables iVarHWindSpeed = 0 @@ -6391,6 +6774,7 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth end do call AD_CalcWind_Rotor(t, u, p_AD%FlowField, p, p_AD, m_AD, RotInflow, StartNode, ErrStat, ErrMsg) + call AD_CalcWind_GS(t, u, p_AD%FlowField, p_AD%GS, p_AD, m_AD, GSInflow, StartNode, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return ! If flow field will need to be perturbed (HWindSpeed, PLexp, or PropagationDir variables) @@ -6441,6 +6825,7 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth ! Copy rotor inflow type for perturbation call AD_CopyRotInflowType(RotInflow, RotInflow_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2); if (Failed()) return + call AD_CopyElemInflowType(GSInflow, GSInflow_perturb, MESH_NEWCOPY, ErrStat2, ErrMsg2); if (Failed()) return ! Loop through input variables do i = 1, size(Vars%u) @@ -6456,9 +6841,10 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth if (associated(FF_ptr, FF_perturb)) call PerturbFlowField(Vars%u(i), p_AD%FlowField, 1, FF_ptr) StartNode = 1 call AD_CalcWind_Rotor(t, u_perturb, FF_ptr, p, p_AD, m_AD, RotInflow_perturb, StartNode, ErrStat2, ErrMsg2); if (Failed()) return + call AD_CalcWind_GS(t, u_perturb, FF_ptr, p_AD%GS, p_AD, m_AD, GSInflow_perturb, StartNode, ErrStat2, ErrMsg2); if (Failed()) return call SetInputs(t, p, p_AD, u_perturb, RotInflow_perturb, m, indx, ErrStat2, ErrMsg2); if (Failed()) return call UpdatePhi(m%BEMT_u(indx), p%BEMT, m%z_lin%BEMT%phi, p_AD%AFI, m%BEMT, m%OtherState_jac%BEMT%ValidPhi, ErrStat2, ErrMsg2); if (Failed()) return - call RotCalcOutput(t, u_perturb, RotInflow_perturb, p, p_AD, m%x_init, xd, m%z_lin, m%OtherState_jac, y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2); if (Failed()) return + call RotCalcOutput(t, u_perturb, RotInflow_perturb, GSInflow_perturb, p, p_AD, m%x_init, xd, m%z_lin, m%OtherState_jac, y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2); if (Failed()) return if (p_AD%Wake_Mod == WakeMod_FVW) then call SetInputsForFVW(p_AD, m_AD%u_perturb, 1, m_AD, ErrStat2, ErrMsg2); if(Failed()) return call FVW_CalcOutput(t, m_AD%FVW_u(1), p_AD%FVW, x_AD%FVW, xd_AD%FVW, z_AD%FVW, OtherState_AD%FVW, m_AD%FVW_y, m_AD%FVW, ErrStat2, ErrMsg2); if(Failed()) return @@ -6474,9 +6860,10 @@ SUBROUTINE AD_JacobianPInput(Vars, iRotor, t, u_AD, p_AD, x_AD, xd_AD, z_AD, Oth if (associated(FF_ptr, FF_perturb)) call PerturbFlowField(Vars%u(i), p_AD%FlowField, -1, FF_ptr) StartNode = 1 call AD_CalcWind_Rotor(t, u_perturb, FF_ptr, p, p_AD, m_AD, RotInflow_perturb, StartNode, ErrStat2, ErrMsg2); if (Failed()) return + call AD_CalcWind_GS(t, u_perturb, FF_ptr, p_AD%GS, p_AD, m_AD, GSInflow_perturb, StartNode, ErrStat2, ErrMsg2); if (Failed()) return call SetInputs(t, p, p_AD, u_perturb, RotInflow_perturb, m, indx, ErrStat2, ErrMsg2); if (Failed()) return call UpdatePhi(m%BEMT_u(indx), p%BEMT, m%z_lin%BEMT%phi, p_AD%AFI, m%BEMT, m%OtherState_jac%BEMT%ValidPhi, ErrStat2, ErrMsg2); if (Failed()) return - call RotCalcOutput(t, u_perturb, RotInflow_perturb, p, p_AD, m%x_init, xd, m%z_lin, m%OtherState_jac, y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2); if (Failed()) return + call RotCalcOutput(t, u_perturb, RotInflow_perturb, GSInflow_perturb, p, p_AD, m%x_init, xd, m%z_lin, m%OtherState_jac, y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2); if (Failed()) return if (p_AD%Wake_Mod == WakeMod_FVW) then call SetInputsForFVW(p_AD, m_AD%u_perturb, 1, m_AD, ErrStat2, ErrMsg2); if(Failed()) return call FVW_CalcOutput(t, m_AD%FVW_u(1), p_AD%FVW, x_AD%FVW, xd_AD%FVW, z_AD%FVW, OtherState_AD%FVW, m_AD%FVW_y, m_AD%FVW, ErrStat2, ErrMsg2); if(Failed()) return @@ -6621,15 +7008,16 @@ SUBROUTINE AD_JacobianPContState(Vars, iRotor, t, u, p, x, xd, z, OtherState, y, StartNode = 1 call AD_CalcWind_Rotor(t, u%rotors(iRotor), p%FlowField, p%rotors(iRotor), p, m, m%Inflow(1)%RotInflow(iRotor), StartNode, ErrStat, ErrMsg) + call AD_CalcWind_GS(t, u%rotors(1), p%FlowField, p%GS, p, m, m%Inflow(1)%GSInflow, StartNode, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return - call RotJacobianPContState(Vars, iRotor, t, u%rotors(iRotor), m%Inflow(1)%RotInflow(iRotor), p%rotors(iRotor), p, x%rotors(iRotor), xd%rotors(iRotor), z%rotors(iRotor), OtherState%rotors(iRotor), y%rotors(iRotor), m%rotors(iRotor), m, ErrStat, ErrMsg, dYdx, dXdx, dXddx, dZdx) + call RotJacobianPContState(Vars, iRotor, t, u%rotors(iRotor), m%Inflow(1)%RotInflow(iRotor), m%Inflow(1)%GSInflow, p%rotors(iRotor), p, x%rotors(iRotor), xd%rotors(iRotor), z%rotors(iRotor), OtherState%rotors(iRotor), y%rotors(iRotor), m%rotors(iRotor), m, ErrStat, ErrMsg, dYdx, dXdx, dXddx, dZdx) END SUBROUTINE AD_JacobianPContState !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions !! with respect to the continuous states (x). The partial derivatives dY/dx, dX/dx, dXd/dx, and dZ/dx are returned. -SUBROUTINE RotJacobianPContState(Vars, iRotor, t, u, RotInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, ErrStat, ErrMsg, dYdx, dXdx, dXddx, dZdx) +SUBROUTINE RotJacobianPContState(Vars, iRotor, t, u, RotInflow, GSInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, ErrStat, ErrMsg, dYdx, dXdx, dXddx, dZdx) !.................................................................................................................................. TYPE(ModVarsType), INTENT(IN ) :: Vars !< Module variables for packing arrays @@ -6637,6 +7025,7 @@ SUBROUTINE RotJacobianPContState(Vars, iRotor, t, u, RotInflow, p, p_AD, x, xd, REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(RotInputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) TYPE(RotInflowType), INTENT(IN ) :: RotInflow !< Rotor inflow + TYPE(ElemInflowType), INTENT(IN ) :: GSInflow !< General support structure inflow TYPE(RotParameterType), INTENT(IN ) :: p !< Parameters TYPE(AD_ParameterType), INTENT(IN ) :: p_AD !< Parameters TYPE(RotContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point @@ -6707,13 +7096,13 @@ SUBROUTINE RotJacobianPContState(Vars, iRotor, t, u, RotInflow, p, p_AD, x, xd, ! Calculate positive perturbation call MV_Perturb(Vars%x(i), j, 1, m%Jac%x, m%Jac%x_perturb) call AD_VarsUnpackContState(Vars, m%Jac%x_perturb, m%x_perturb) - call RotCalcOutput(t, u, RotInflow, p, p_AD, m%x_perturb, xd, z, m%OtherState_init, m%y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2) ; if (Failed()) return + call RotCalcOutput(t, u, RotInflow, GSInflow, p, p_AD, m%x_perturb, xd, z, m%OtherState_init, m%y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2) ; if (Failed()) return call AD_VarsPackOutput(Vars, m%y_lin, m%Jac%y_pos) ! Calculate negative perturbation call MV_Perturb(Vars%x(i), j, -1, m%Jac%x, m%Jac%x_perturb) call AD_VarsUnpackContState(Vars, m%Jac%x_perturb, m%x_perturb) - call RotCalcOutput(t, u, RotInflow, p, p_AD, m%x_perturb, xd, z, m%OtherState_init, m%y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2) ; if (Failed()) return + call RotCalcOutput(t, u, RotInflow, GSInflow, p, p_AD, m%x_perturb, xd, z, m%OtherState_init, m%y_lin, m, m_AD, iRotor, ErrStat2, ErrMsg2) ; if (Failed()) return call AD_VarsPackOutput(Vars, m%y_lin, m%Jac%y_neg) ! Calculate column index @@ -6854,8 +7243,9 @@ SUBROUTINE AD_JacobianPConstrState(Vars, t, u, p, x, xd, z, OtherState, y, m, Er StartNode = 1 call AD_CalcWind_Rotor(t, u%rotors(iR), p%FlowField, p%rotors(iR), p, m, m%Inflow(1)%RotInflow(iR), StartNode, ErrStat, ErrMsg) + call AD_CalcWind_GS(t, u%rotors(1), p%FlowField, p%GS, p, m, m%Inflow(1)%GSInflow, StartNode, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return - call RotJacobianPConstrState(t, u%rotors(iR), m%Inflow(1)%RotInflow(iR), p%rotors(iR), p, x%rotors(iR), xd%rotors(iR), z%rotors(iR), OtherState%rotors(iR), y%rotors(iR), m%rotors(iR), m, iR, errStat, errMsg, dYdz, dXdz, dXddz, dZdz) + call RotJacobianPConstrState(t, u%rotors(iR), m%Inflow(1)%RotInflow(iR), m%Inflow(1)%GSInflow, p%rotors(iR), p, x%rotors(iR), xd%rotors(iR), z%rotors(iR), OtherState%rotors(iR), y%rotors(iR), m%rotors(iR), m, iR, errStat, errMsg, dYdz, dXdz, dXddz, dZdz) END SUBROUTINE AD_JacobianPConstrState @@ -6863,10 +7253,11 @@ END SUBROUTINE AD_JacobianPConstrState !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to compute the Jacobians of the output (Y), continuous- (X), discrete- (Xd), and constraint-state (Z) functions !! with respect to the constraint states (z). The partial derivatives dY/dz, dX/dz, dXd/dz, and dZ/dz are returned. -SUBROUTINE RotJacobianPConstrState( t, u, RotInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRot, ErrStat, ErrMsg, dYdz, dXdz, dXddz, dZdz ) +SUBROUTINE RotJacobianPConstrState( t, u, RotInflow, GSInflow, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRot, ErrStat, ErrMsg, dYdz, dXdz, dXddz, dZdz ) REAL(DbKi), INTENT(IN ) :: t !< Time in seconds at operating point TYPE(RotInputType), INTENT(IN ) :: u !< Inputs at operating point (may change to inout if a mesh copy is required) - TYPE(RotInflowType), INTENT(IN ) :: RotInflow !< Inflow on rotor + TYPE(RotInflowType), INTENT(IN ) :: RotInflow !< Inflow on rotor + TYPE(ElemInflowType), INTENT(IN ) :: GSInflow !< Inflow on general support structure TYPE(RotParameterType), INTENT(IN ) :: p !< Parameters TYPE(AD_ParameterType), INTENT(IN ) :: p_AD !< Parameters TYPE(RotContinuousStateType), INTENT(IN ) :: x !< Continuous states at operating point @@ -6954,13 +7345,13 @@ SUBROUTINE RotJacobianPConstrState( t, u, RotInflow, p, p_AD, x, xd, z, OtherSta z_perturb%BEMT%phi(j,k) = z%BEMT%phi(j,k) + delta_p ! compute y at z_op + delta_p z - call RotCalcOutput( t, u, RotInflow, p, p_AD, x, xd, z_perturb, OtherState, y_p, m, m_AD, iRot, ErrStat2, ErrMsg2 ) ; if (Failed()) return; + call RotCalcOutput( t, u, RotInflow, GSInflow, p, p_AD, x, xd, z_perturb, OtherState, y_p, m, m_AD, iRot, ErrStat2, ErrMsg2 ) ; if (Failed()) return; ! get z_op - delta_m z z_perturb%BEMT%phi(j,k) = z%BEMT%phi(j,k) - delta_m ! compute y at z_op - delta_m z - call RotCalcOutput( t, u, RotInflow, p, p_AD, x, xd, z_perturb, OtherState, y_m, m, m_AD, iRot, ErrStat2, ErrMsg2 ) ; if (Failed()) return; + call RotCalcOutput( t, u, RotInflow, GSInflow, p, p_AD, x, xd, z_perturb, OtherState, y_m, m, m_AD, iRot, ErrStat2, ErrMsg2 ) ; if (Failed()) return; ! get central difference: call Compute_dY( p, p_AD, y_p, y_m, delta_p, delta_m, dYdz(:,i) ) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 5f919bb211..710ca6dab0 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -702,7 +702,7 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade character(ErrMsgLen) :: ErrMsg2 !< Temporary Error message character(ErrMsgLen) :: ErrMsg_NoAllBldNdOuts integer(IntKi) :: CurLine !< current entry in FileInfo_In%Lines array - real(ReKi) :: TmpRe7(7) !< temporary 8 number array for reading values in + real(ReKi) :: TmpRe10(10) !< temporary 10 number array for reading values in logical :: TwrAeroLogical !< convert TwrAero from logical (input file) to integer (new) character(1024) :: sDummy !< temporary string character(1024) :: tmpOutStr !< temporary string for writing to screen @@ -1111,18 +1111,84 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade CALL AllocAry( InputFileData%rotors(iR)%TwrCa, InputFileData%rotors(iR)%NumTwrNds, 'TwrCa', ErrStat2, ErrMsg2) if (Failed()) return do I=1,InputFileData%rotors(iR)%NumTwrNds - call ParseAry ( FileInfo_In, CurLine, 'Properties for tower node '//trim( Int2LStr( I ) )//'.', TmpRe7, 7, ErrStat2, ErrMsg2, UnEc ) + call ParseAry ( FileInfo_In, CurLine, 'Properties for tower node '//trim( Int2LStr( I ) )//'.', TmpRe10, 7, ErrStat2, ErrMsg2, UnEc ) if (Failed()) return; - InputFileData%rotors(iR)%TwrElev(I) = TmpRe7( 1) - InputFileData%rotors(iR)%TwrDiam(I) = TmpRe7( 2) - InputFileData%rotors(iR)%TwrCd(I) = TmpRe7( 3) - InputFileData%rotors(iR)%TwrTI(I) = TmpRe7( 4) - InputFileData%rotors(iR)%TwrCb(I) = TmpRe7( 5) - InputFileData%rotors(iR)%TwrCp(I) = TmpRe7( 6) - InputFileData%rotors(iR)%TwrCa(I) = TmpRe7( 7) + InputFileData%rotors(iR)%TwrElev(I) = TmpRe10( 1) + InputFileData%rotors(iR)%TwrDiam(I) = TmpRe10( 2) + InputFileData%rotors(iR)%TwrCd(I) = TmpRe10( 3) + InputFileData%rotors(iR)%TwrTI(I) = TmpRe10( 4) + InputFileData%rotors(iR)%TwrCb(I) = TmpRe10( 5) + InputFileData%rotors(iR)%TwrCp(I) = TmpRe10( 6) + InputFileData%rotors(iR)%TwrCa(I) = TmpRe10( 7) end do enddo + !====== General support structure joints ============================================================ + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + ! NumGSJoints - Number of general support joints used in the analysis (-) + call ParseVar( FileInfo_In, CurLine, "NumGSJoints", InputFileData%GS%NJoints, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + !GSJointID GSJointXi GSJointYi GSJointZi + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') 'GS Joint Table Header: '//FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + !(-) (m) (m) (m) + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') 'GS Joint Table Header: '//FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + + ! Allocate space for general support joint table + allocate( InputFileData%GS%InpJoints(InputFileData%GS%NJoints), STAT = ErrStat2) + if ( ErrStat2 /= 0 ) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = 'Error allocating space for GSInpJoints array.' + if (Failed()) return; + end if + + do I=1,InputFileData%GS%NJoints + call ParseAry ( FileInfo_In, CurLine, 'General support joint '//trim( Int2LStr( I ) )//'.', TmpRe10, 4, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return; + InputFileData%GS%InpJoints(I)%JointID = NINT(TmpRe10(1)) + InputFileData%GS%InpJoints(I)%position(1) = TmpRe10(2) + InputFileData%GS%InpJoints(I)%position(2) = TmpRe10(3) + InputFileData%GS%InpJoints(I)%position(3) = TmpRe10(4) + end do + + !====== General support structure members ============================================================ + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + ! NumGSMembers - Number of general support members used in the analysis (-) + call ParseVar( FileInfo_In, CurLine, "NumGSMembers", InputFileData%GS%NMembers, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + !GSMemberID GSMJointID1 GSMJointID2 GSMDia1 GSMDia2 GSMCd1 GSMCd2 GSMTI1 GSMTI2 GSMDiv + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') 'GS Joint Table Header: '//FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + !(-) (-) (-) (m) (m) (-) (-) (-) (-) (-) + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') 'GS Joint Table Header: '//FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + + ! Allocate space for general support joint table + allocate( InputFileData%GS%InpMembers(InputFileData%GS%NMembers), STAT = ErrStat2) + if ( ErrStat2 /= 0 ) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = 'Error allocating space for GSInpMembers array.' + if (Failed()) return; + end if + + do I=1,InputFileData%GS%NMembers + call ParseAry ( FileInfo_In, CurLine, 'General support member '//trim( Int2LStr( I ) )//'.', TmpRe10, 10, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return; + InputFileData%GS%InpMembers(I)%MemberID = NINT(TmpRe10( 1)) + InputFileData%GS%InpMembers(I)%MJointID1 = NINT(TmpRe10( 2)) + InputFileData%GS%InpMembers(I)%MJointID2 = NINT(TmpRe10( 3)) + InputFileData%GS%InpMembers(I)%MDiam1 = TmpRe10( 4) + InputFileData%GS%InpMembers(I)%MDiam2 = TmpRe10( 5) + InputFileData%GS%InpMembers(I)%MCd1 = TmpRe10( 6) + InputFileData%GS%InpMembers(I)%MCd2 = TmpRe10( 7) + InputFileData%GS%InpMembers(I)%MTI1 = TmpRe10( 8) + InputFileData%GS%InpMembers(I)%MTI2 = TmpRe10( 9) + InputFileData%GS%InpMembers(I)%MDivSize = TmpRe10(10) + end do + !====== Outputs ==================================================================================== if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo CurLine = CurLine + 1 diff --git a/modules/aerodyn/src/AeroDyn_Inflow_Types.f90 b/modules/aerodyn/src/AeroDyn_Inflow_Types.f90 index 470536defc..ec1974508e 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow_Types.f90 @@ -212,17 +212,19 @@ MODULE AeroDyn_Inflow_Types integer(IntKi), public, parameter :: ADI_u_AD_rotors_BladeRootMotion = 15 ! ADI%AD%rotors(DL%i1)%BladeRootMotion(DL%i2) integer(IntKi), public, parameter :: ADI_u_AD_rotors_BladeMotion = 16 ! ADI%AD%rotors(DL%i1)%BladeMotion(DL%i2) integer(IntKi), public, parameter :: ADI_u_AD_rotors_TFinMotion = 17 ! ADI%AD%rotors(DL%i1)%TFinMotion - integer(IntKi), public, parameter :: ADI_u_AD_rotors_UserProp = 18 ! ADI%AD%rotors(DL%i1)%UserProp - integer(IntKi), public, parameter :: ADI_y_AD_rotors_NacelleLoad = 19 ! ADI%AD%rotors(DL%i1)%NacelleLoad - integer(IntKi), public, parameter :: ADI_y_AD_rotors_HubLoad = 20 ! ADI%AD%rotors(DL%i1)%HubLoad - integer(IntKi), public, parameter :: ADI_y_AD_rotors_TowerLoad = 21 ! ADI%AD%rotors(DL%i1)%TowerLoad - integer(IntKi), public, parameter :: ADI_y_AD_rotors_BladeLoad = 22 ! ADI%AD%rotors(DL%i1)%BladeLoad(DL%i2) - integer(IntKi), public, parameter :: ADI_y_AD_rotors_TFinLoad = 23 ! ADI%AD%rotors(DL%i1)%TFinLoad - integer(IntKi), public, parameter :: ADI_y_AD_rotors_WriteOutput = 24 ! ADI%AD%rotors(DL%i1)%WriteOutput - integer(IntKi), public, parameter :: ADI_y_HHVel = 25 ! ADI%HHVel - integer(IntKi), public, parameter :: ADI_y_PLExp = 26 ! ADI%PLExp - integer(IntKi), public, parameter :: ADI_y_IW_WriteOutput = 27 ! ADI%IW_WriteOutput - integer(IntKi), public, parameter :: ADI_y_WriteOutput = 28 ! ADI%WriteOutput + integer(IntKi), public, parameter :: ADI_u_AD_rotors_GSMotion = 18 ! ADI%AD%rotors(DL%i1)%GSMotion + integer(IntKi), public, parameter :: ADI_u_AD_rotors_UserProp = 19 ! ADI%AD%rotors(DL%i1)%UserProp + integer(IntKi), public, parameter :: ADI_y_AD_rotors_NacelleLoad = 20 ! ADI%AD%rotors(DL%i1)%NacelleLoad + integer(IntKi), public, parameter :: ADI_y_AD_rotors_HubLoad = 21 ! ADI%AD%rotors(DL%i1)%HubLoad + integer(IntKi), public, parameter :: ADI_y_AD_rotors_TowerLoad = 22 ! ADI%AD%rotors(DL%i1)%TowerLoad + integer(IntKi), public, parameter :: ADI_y_AD_rotors_BladeLoad = 23 ! ADI%AD%rotors(DL%i1)%BladeLoad(DL%i2) + integer(IntKi), public, parameter :: ADI_y_AD_rotors_TFinLoad = 24 ! ADI%AD%rotors(DL%i1)%TFinLoad + integer(IntKi), public, parameter :: ADI_y_AD_rotors_GSLoad = 25 ! ADI%AD%rotors(DL%i1)%GSLoad + integer(IntKi), public, parameter :: ADI_y_AD_rotors_WriteOutput = 26 ! ADI%AD%rotors(DL%i1)%WriteOutput + integer(IntKi), public, parameter :: ADI_y_HHVel = 27 ! ADI%HHVel + integer(IntKi), public, parameter :: ADI_y_PLExp = 28 ! ADI%PLExp + integer(IntKi), public, parameter :: ADI_y_IW_WriteOutput = 29 ! ADI%IW_WriteOutput + integer(IntKi), public, parameter :: ADI_y_WriteOutput = 30 ! ADI%WriteOutput contains @@ -1980,6 +1982,8 @@ function ADI_InputMeshPointer(u, DL) result(Mesh) Mesh => u%AD%rotors(DL%i1)%BladeMotion(DL%i2) case (ADI_u_AD_rotors_TFinMotion) Mesh => u%AD%rotors(DL%i1)%TFinMotion + case (ADI_u_AD_rotors_GSMotion) + Mesh => u%AD%rotors(DL%i1)%GSMotion end select end function @@ -1999,6 +2003,8 @@ function ADI_OutputMeshPointer(y, DL) result(Mesh) Mesh => y%AD%rotors(DL%i1)%BladeLoad(DL%i2) case (ADI_y_AD_rotors_TFinLoad) Mesh => y%AD%rotors(DL%i1)%TFinLoad + case (ADI_y_AD_rotors_GSLoad) + Mesh => y%AD%rotors(DL%i1)%GSLoad end select end function @@ -2191,6 +2197,8 @@ subroutine ADI_VarPackInput(V, u, ValAry) call MV_PackMesh(V, u%AD%rotors(DL%i1)%BladeMotion(DL%i2), ValAry) ! Mesh case (ADI_u_AD_rotors_TFinMotion) call MV_PackMesh(V, u%AD%rotors(DL%i1)%TFinMotion, ValAry) ! Mesh + case (ADI_u_AD_rotors_GSMotion) + call MV_PackMesh(V, u%AD%rotors(DL%i1)%GSMotion, ValAry) ! Mesh case (ADI_u_AD_rotors_UserProp) VarVals = u%AD%rotors(DL%i1)%UserProp(V%iLB:V%iUB,V%j) ! Rank 2 Array case default @@ -2227,6 +2235,8 @@ subroutine ADI_VarUnpackInput(V, ValAry, u) call MV_UnpackMesh(V, ValAry, u%AD%rotors(DL%i1)%BladeMotion(DL%i2)) ! Mesh case (ADI_u_AD_rotors_TFinMotion) call MV_UnpackMesh(V, ValAry, u%AD%rotors(DL%i1)%TFinMotion) ! Mesh + case (ADI_u_AD_rotors_GSMotion) + call MV_UnpackMesh(V, ValAry, u%AD%rotors(DL%i1)%GSMotion) ! Mesh case (ADI_u_AD_rotors_UserProp) u%AD%rotors(DL%i1)%UserProp(V%iLB:V%iUB, V%j) = VarVals ! Rank 2 Array end select @@ -2249,6 +2259,8 @@ function ADI_InputFieldName(DL) result(Name) Name = "u%AD%rotors("//trim(Num2LStr(DL%i1))//")%BladeMotion("//trim(Num2LStr(DL%i2))//")" case (ADI_u_AD_rotors_TFinMotion) Name = "u%AD%rotors("//trim(Num2LStr(DL%i1))//")%TFinMotion" + case (ADI_u_AD_rotors_GSMotion) + Name = "u%AD%rotors("//trim(Num2LStr(DL%i1))//")%GSMotion" case (ADI_u_AD_rotors_UserProp) Name = "u%AD%rotors("//trim(Num2LStr(DL%i1))//")%UserProp" case default @@ -2282,6 +2294,8 @@ subroutine ADI_VarPackOutput(V, y, ValAry) call MV_PackMesh(V, y%AD%rotors(DL%i1)%BladeLoad(DL%i2), ValAry) ! Mesh case (ADI_y_AD_rotors_TFinLoad) call MV_PackMesh(V, y%AD%rotors(DL%i1)%TFinLoad, ValAry) ! Mesh + case (ADI_y_AD_rotors_GSLoad) + call MV_PackMesh(V, y%AD%rotors(DL%i1)%GSLoad, ValAry) ! Mesh case (ADI_y_AD_rotors_WriteOutput) VarVals = y%AD%rotors(DL%i1)%WriteOutput(V%iLB:V%iUB) ! Rank 1 Array case (ADI_y_HHVel) @@ -2324,6 +2338,8 @@ subroutine ADI_VarUnpackOutput(V, ValAry, y) call MV_UnpackMesh(V, ValAry, y%AD%rotors(DL%i1)%BladeLoad(DL%i2)) ! Mesh case (ADI_y_AD_rotors_TFinLoad) call MV_UnpackMesh(V, ValAry, y%AD%rotors(DL%i1)%TFinLoad) ! Mesh + case (ADI_y_AD_rotors_GSLoad) + call MV_UnpackMesh(V, ValAry, y%AD%rotors(DL%i1)%GSLoad) ! Mesh case (ADI_y_AD_rotors_WriteOutput) y%AD%rotors(DL%i1)%WriteOutput(V%iLB:V%iUB) = VarVals ! Rank 1 Array case (ADI_y_HHVel) @@ -2352,6 +2368,8 @@ function ADI_OutputFieldName(DL) result(Name) Name = "y%AD%rotors("//trim(Num2LStr(DL%i1))//")%BladeLoad("//trim(Num2LStr(DL%i2))//")" case (ADI_y_AD_rotors_TFinLoad) Name = "y%AD%rotors("//trim(Num2LStr(DL%i1))//")%TFinLoad" + case (ADI_y_AD_rotors_GSLoad) + Name = "y%AD%rotors("//trim(Num2LStr(DL%i1))//")%GSLoad" case (ADI_y_AD_rotors_WriteOutput) Name = "y%AD%rotors("//trim(Num2LStr(DL%i1))//")%WriteOutput" case (ADI_y_HHVel) diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 1c1f30babf..93a35342fb 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -92,7 +92,27 @@ typedef ^ AD_VTK_BLSurfaceType SiKi AirfoilCoords typedef ^ AD_VTK_RotSurfaceType AD_VTK_BLSurfaceType BladeShape {:} - - "AirfoilCoords for each blade" - typedef ^ ^ SiKi TowerRad {:} - - "radius of each ED tower node" m - +# General support data types +typedef ^ GSJointType IntKi JointID - - - "User-specified joint ID for the general support structure" - +typedef ^ GSJointType ReKi Position {3} - - "Undisplaced position of the joint" m +typedef ^ GSInpMemberType IntKi MemberID - - - "User-specified member ID for the general support structure" - +typedef ^ GSInpMemberType IntKi MJointID1 - - - "Starting joint ID of the member" - +typedef ^ GSInpMemberType IntKi MJointID2 - - - "Ending joint ID of the member" - +typedef ^ GSInpMemberType ReKi MDiam1 - - - "Starting diameter of the member" m +typedef ^ GSInpMemberType ReKi MDiam2 - - - "Ending diameter of the member" m +typedef ^ GSInpMemberType ReKi MCd1 - - - "Starting drag coefficient of the member" - +typedef ^ GSInpMemberType ReKi MCd2 - - - "Ending drag coefficient of the member" - +typedef ^ GSInpMemberType ReKi MTI1 - - - "Starting turbulence intensity of the member for the Eames tower shadow model" - +typedef ^ GSInpMemberType ReKi MTI2 - - - "Ending turbulence intensity of the member for the Eames tower shadow model" - +typedef ^ GSInpMemberType ReKi MDivSize - - - "Maximum member discretized element length" m +typedef ^ GSMemberType IntKi MemberID - - - "User-supplied integer ID for this member" - +typedef ^ GSMemberType IntKi NElements - - - "Number of elements in this member" - +typedef ^ GSMemberType IntKi NodeIndx {:} - - "Index of each of the member's nodes in the global node list" - +typedef ^ GSMemberType ReKi RefLength - - - "The reference total length for this member" m +typedef ^ GSMemberType ReKi dl - - - "The reference element length of this member" m +typedef ^ GSMemberType ReKi R {:} - - "Outer member radius at each node" m +typedef ^ GSMemberType ReKi Cd {:} - - "Drag coefficient at each node" - +typedef ^ GSMemberType ReKi TI {:} - - "Turbulence intensity at each node for the Eames tower shadow model" - # ..... Initialization data ....................................................................................................... # Define inputs that the initialization routine may need here: @@ -189,6 +209,11 @@ typedef ^ RotInputFile LOGICAL TFinAero - .FALSE. - "Calculate t typedef ^ RotInputFile CHARACTER(1024) TFinFile - - - "Input file for tail fin aerodynamics [used only when TFinAero=True]" - typedef ^ RotInputFile TFinInputFileType TFin - - - "Input file data for tail fin" - +typedef ^ GSInputFile IntKi NJoints - - - "Number of user-specified joints" - +typedef ^ GSInputFile GSJointType InpJoints {:} - - "Array of user-specified joints" - +typedef ^ GSInputFile IntKi NMembers - - - "Number of user-specified members" - +typedef ^ GSInputFile GSInpMemberType InpMembers {:} - - "Array of user-specified members" - + typedef ^ AD_InputFile Logical Echo - - - "Echo input file to echo file" - typedef ^ AD_InputFile DbKi DTAero - - - "Time interval for aerodynamic calculations {or \"default\"}" s typedef ^ AD_InputFile IntKi Wake_Mod - - - "Type of wake/induction model {0=none, 1=BEMT, 2=DBEMT, 3=FVW}" - @@ -253,7 +278,7 @@ typedef ^ AD_InputFile IntKi BldNd_BladesOut - - - "The blades to output (AD typedef ^ AD_InputFile ReKi UAStartRad - - - Starting radius for dynamic stall (fraction of rotor radius) typedef ^ AD_InputFile ReKi UAEndRad - - - Ending radius for dynamic stall (fraction of rotor radius) typedef ^ AD_InputFile RotInputFile rotors {:} - - "Rotor (blades and tower) input file data" - - +typedef ^ AD_InputFile GSInputFile GS - - - "General support input file data" - @@ -290,7 +315,7 @@ typedef ^ OtherStateType ReKi WakeLocationPoints {:}{:} - - "wake points velocit typedef ^ ElemInflowType ReKi InflowVel {:}{:} - - "U,V,W at nodes on element (note if we change the requirement that NumNodes is the same for each blade, this will need to change)" m/s typedef ^ ElemInflowType ReKi InflowAcc {:}{:} - - "Wind acceleration at nodes on element (blade or tower) (note if we change the requirement that NumNodes is the same for each blade, this will need to change)" m/s typedef ^ RotInflowType ElemInflowType Blade {:} - - "Blade wind inputs" - -typedef ^ RotInflowType ElemInflowType Tower - - - "Blade wind inputs" - +typedef ^ RotInflowType ElemInflowType Tower - - - "Tower wind inputs" - typedef ^ RotInflowType ReKi InflowOnHub {3}{1} - - "U,V,W at hub" m/s typedef ^ RotInflowType ReKi InflowOnNacelle {3}{1} - - "U,V,W at nacelle" m/s typedef ^ RotInflowType ReKi InflowOnTailFin {3}{1} - - "U,V,W at tailfin" m/s @@ -298,6 +323,7 @@ typedef ^ RotInflowType ReKi AvgDiskVel {3} - 0.0 "disk-averaged U,V,W" m/s typedef ^ AD_InflowType ReKi InflowWakeVel {:}{:} - - "U,V,W at wake points" m/s typedef ^ AD_InflowType RotInflowType RotInflow {:} - - "Inflow on rotor" - +typedef ^ AD_InflowType ElemInflowType GSInflow - - - "Inflow on general support structure" - # ..... Parameters ................................................................................................................ @@ -385,7 +411,20 @@ typedef ^ RotParameterType IntKi BldNd_NumNodesOut - - - "The blades to outpu # Tail fin parameters (per rotor) typedef ^ RotParameterType LOGICAL TFinAero - .FALSE. - "Calculate tail fin aerodynamics model (flag)" flag typedef ^ RotParameterType TFinParameterType TFin - - - "Parameters for tail fin of current rotor" - - +# General support parameters (per rotor) +typedef ^ RotParameterType LOGICAL GSAero - .FALSE. - "Calculate general support aerodynamic influences (flag)" flag +typedef ^ RotParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag +# General support parameters (shared) +typedef ^ GSParameterType LOGICAL GSAero - .FALSE. - "Calculate general support aerodynamic influences (flag)" flag +typedef ^ GSParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag +typedef ^ GSParameterType IntKi NJoints - - - "Total number of user-specified joints for the general support structure" - +typedef ^ GSParameterType IntKi NNodes - - - "Total number of general support structure nodes (joints+interior nodes)" - +typedef ^ GSParameterType IntKi NMembers - - - "Total number of general support structure members" - +typedef ^ GSParameterType GSMemberType Members {:} - - "General support structure members" - +typedef ^ GSParameterType GSJointType Joints {:} - - "General support structure joints" - +typedef ^ GSParameterType ReKi Density - - - "Fluid density" kg/m^3 +typedef ^ GSParameterType IntKi MHK - - - "MHK turbine type switch" - +typedef ^ GSParameterType ReKi WtrDpth - - - "Water depth" m # Parameters for all rotors: typedef ^ ParameterType RotParameterType rotors {:} - - "Parameter types for each rotor" - # Time step for integration of continuous states (if a fixed-step integrator is used) and update of discrete states: @@ -405,6 +444,7 @@ typedef ^ ^ ReKi SA_PsiBwd - - - "Sector Average typedef ^ ^ ReKi SA_PsiFwd - - - "Sector Average - Forward Azimuth (>0)" deg typedef ^ ^ IntKi SA_nPerSec - - - "Sector Average - Number of points per sector (>1)" - typedef ^ ParameterType SeaSt_WaveFieldType *WaveField - - - "Pointer to SeaState wave field data type" - +typedef ^ ParameterType GSParameterType GS - - - "General support structure parameters" - # ..... Inputs .................................................................................................................... # Define inputs that are contained on a mesh here: @@ -414,6 +454,7 @@ typedef ^ RotInputType MeshType HubMotion - - - "motion on the hub" - typedef ^ RotInputType MeshType BladeRootMotion {:} - - "motion on each blade root" - typedef ^ RotInputType MeshType BladeMotion {:} - - "motion on each blade" - typedef ^ RotInputType MeshType TFinMotion - - - "motion of tail fin (at tail fin ref point)" - +typedef ^ RotInputType MeshType GSMotion - - - "motion of the general support structure" - # Define inputs that are not on a mesh here: typedef ^ RotInputType ReKi UserProp {:}{:} - - "Optional user property for interpolating airfoils (per element per blade)" - @@ -428,6 +469,7 @@ typedef ^ RotOutputType MeshType HubLoad - - - "loads on the hub" - typedef ^ RotOutputType MeshType TowerLoad - - - "loads on the tower" - typedef ^ RotOutputType MeshType BladeLoad {:} - - "loads on each blade" - typedef ^ RotOutputType MeshType TFinLoad - - - "loads on tail fin (at tail fin ref point)" - +typedef ^ RotOutputType MeshType GSLoad - - - "loads on the general support structure" - # Define outputs that are not on a mesh here: typedef ^ RotOutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 01447c6f27..489fb67d71 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -106,6 +106,38 @@ MODULE AeroDyn_Types REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: TowerRad !< radius of each ED tower node [m] END TYPE AD_VTK_RotSurfaceType ! ======================= +! ========= GSJointType ======= + TYPE, PUBLIC :: GSJointType + INTEGER(IntKi) :: JointID = 0_IntKi !< User-specified joint ID for the general support structure [-] + REAL(ReKi) , DIMENSION(1:3) :: Position = 0.0_ReKi !< Undisplaced position of the joint [m] + END TYPE GSJointType +! ======================= +! ========= GSInpMemberType ======= + TYPE, PUBLIC :: GSInpMemberType + INTEGER(IntKi) :: MemberID = 0_IntKi !< User-specified member ID for the general support structure [-] + INTEGER(IntKi) :: MJointID1 = 0_IntKi !< Starting joint ID of the member [-] + INTEGER(IntKi) :: MJointID2 = 0_IntKi !< Ending joint ID of the member [-] + REAL(ReKi) :: MDiam1 = 0.0_ReKi !< Starting diameter of the member [m] + REAL(ReKi) :: MDiam2 = 0.0_ReKi !< Ending diameter of the member [m] + REAL(ReKi) :: MCd1 = 0.0_ReKi !< Starting drag coefficient of the member [-] + REAL(ReKi) :: MCd2 = 0.0_ReKi !< Ending drag coefficient of the member [-] + REAL(ReKi) :: MTI1 = 0.0_ReKi !< Starting turbulence intensity of the member for the Eames tower shadow model [-] + REAL(ReKi) :: MTI2 = 0.0_ReKi !< Ending turbulence intensity of the member for the Eames tower shadow model [-] + REAL(ReKi) :: MDivSize = 0.0_ReKi !< Maximum member discretized element length [m] + END TYPE GSInpMemberType +! ======================= +! ========= GSMemberType ======= + TYPE, PUBLIC :: GSMemberType + INTEGER(IntKi) :: MemberID = 0_IntKi !< User-supplied integer ID for this member [-] + INTEGER(IntKi) :: NElements = 0_IntKi !< Number of elements in this member [-] + INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: NodeIndx !< Index of each of the member's nodes in the global node list [-] + REAL(ReKi) :: RefLength = 0.0_ReKi !< The reference total length for this member [m] + REAL(ReKi) :: dl = 0.0_ReKi !< The reference element length of this member [m] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: R !< Outer member radius at each node [m] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Cd !< Drag coefficient at each node [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TI !< Turbulence intensity at each node for the Eames tower shadow model [-] + END TYPE GSMemberType +! ======================= ! ========= RotInitInputType ======= TYPE, PUBLIC :: RotInitInputType INTEGER(IntKi) :: NumBlades = 0_IntKi !< Number of blades on the turbine [-] @@ -210,6 +242,14 @@ MODULE AeroDyn_Types TYPE(TFinInputFileType) :: TFin !< Input file data for tail fin [-] END TYPE RotInputFile ! ======================= +! ========= GSInputFile ======= + TYPE, PUBLIC :: GSInputFile + INTEGER(IntKi) :: NJoints = 0_IntKi !< Number of user-specified joints [-] + TYPE(GSJointType) , DIMENSION(:), ALLOCATABLE :: InpJoints !< Array of user-specified joints [-] + INTEGER(IntKi) :: NMembers = 0_IntKi !< Number of user-specified members [-] + TYPE(GSInpMemberType) , DIMENSION(:), ALLOCATABLE :: InpMembers !< Array of user-specified members [-] + END TYPE GSInputFile +! ======================= ! ========= AD_InputFile ======= TYPE, PUBLIC :: AD_InputFile LOGICAL :: Echo = .false. !< Echo input file to echo file [-] @@ -273,6 +313,7 @@ MODULE AeroDyn_Types REAL(ReKi) :: UAStartRad = 0.0_ReKi !< Starting [radius] REAL(ReKi) :: UAEndRad = 0.0_ReKi !< Ending [radius] TYPE(RotInputFile) , DIMENSION(:), ALLOCATABLE :: rotors !< Rotor (blades and tower) input file data [-] + TYPE(GSInputFile) :: GS !< General support input file data [-] END TYPE AD_InputFile ! ======================= ! ========= RotContinuousStateType ======= @@ -331,7 +372,7 @@ MODULE AeroDyn_Types ! ========= RotInflowType ======= TYPE, PUBLIC :: RotInflowType TYPE(ElemInflowType) , DIMENSION(:), ALLOCATABLE :: Blade !< Blade wind inputs [-] - TYPE(ElemInflowType) :: Tower !< Blade wind inputs [-] + TYPE(ElemInflowType) :: Tower !< Tower wind inputs [-] REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnHub = 0.0_ReKi !< U,V,W at hub [m/s] REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnNacelle = 0.0_ReKi !< U,V,W at nacelle [m/s] REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnTailFin = 0.0_ReKi !< U,V,W at tailfin [m/s] @@ -342,6 +383,7 @@ MODULE AeroDyn_Types TYPE, PUBLIC :: AD_InflowType REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: InflowWakeVel !< U,V,W at wake points [m/s] TYPE(RotInflowType) , DIMENSION(:), ALLOCATABLE :: RotInflow !< Inflow on rotor [-] + TYPE(ElemInflowType) :: GSInflow !< Inflow on general support structure [-] END TYPE AD_InflowType ! ======================= ! ========= RotParameterType ======= @@ -422,8 +464,24 @@ MODULE AeroDyn_Types INTEGER(IntKi) :: BldNd_NumNodesOut = 0_IntKi !< The blades to output (AD_AllBldNdOuts) [-] LOGICAL :: TFinAero = .FALSE. !< Calculate tail fin aerodynamics model (flag) [flag] TYPE(TFinParameterType) :: TFin !< Parameters for tail fin of current rotor [-] + LOGICAL :: GSAero = .FALSE. !< Calculate general support aerodynamic influences (flag) [flag] + LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] END TYPE RotParameterType ! ======================= +! ========= GSParameterType ======= + TYPE, PUBLIC :: GSParameterType + LOGICAL :: GSAero = .FALSE. !< Calculate general support aerodynamic influences (flag) [flag] + LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] + INTEGER(IntKi) :: NJoints = 0_IntKi !< Total number of user-specified joints for the general support structure [-] + INTEGER(IntKi) :: NNodes = 0_IntKi !< Total number of general support structure nodes (joints+interior nodes) [-] + INTEGER(IntKi) :: NMembers = 0_IntKi !< Total number of general support structure members [-] + TYPE(GSMemberType) , DIMENSION(:), ALLOCATABLE :: Members !< General support structure members [-] + TYPE(GSJointType) , DIMENSION(:), ALLOCATABLE :: Joints !< General support structure joints [-] + REAL(ReKi) :: Density = 0.0_ReKi !< Fluid density [kg/m^3] + INTEGER(IntKi) :: MHK = 0_IntKi !< MHK turbine type switch [-] + REAL(ReKi) :: WtrDpth = 0.0_ReKi !< Water depth [m] + END TYPE GSParameterType +! ======================= ! ========= AD_ParameterType ======= TYPE, PUBLIC :: AD_ParameterType TYPE(RotParameterType) , DIMENSION(:), ALLOCATABLE :: rotors !< Parameter types for each rotor [-] @@ -443,6 +501,7 @@ MODULE AeroDyn_Types REAL(ReKi) :: SA_PsiFwd = 0.0_ReKi !< Sector Average - Forward Azimuth (>0) [deg] INTEGER(IntKi) :: SA_nPerSec = 0_IntKi !< Sector Average - Number of points per sector (>1) [-] TYPE(SeaSt_WaveFieldType) , POINTER :: WaveField => NULL() !< Pointer to SeaState wave field data type [-] + TYPE(GSParameterType) :: GS !< General support structure parameters [-] END TYPE AD_ParameterType ! ======================= ! ========= RotInputType ======= @@ -453,6 +512,7 @@ MODULE AeroDyn_Types TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: BladeRootMotion !< motion on each blade root [-] TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: BladeMotion !< motion on each blade [-] TYPE(MeshType) :: TFinMotion !< motion of tail fin (at tail fin ref point) [-] + TYPE(MeshType) :: GSMotion !< motion of the general support structure [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: UserProp !< Optional user property for interpolating airfoils (per element per blade) [-] END TYPE RotInputType ! ======================= @@ -468,6 +528,7 @@ MODULE AeroDyn_Types TYPE(MeshType) :: TowerLoad !< loads on the tower [-] TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: BladeLoad !< loads on each blade [-] TYPE(MeshType) :: TFinLoad !< loads on tail fin (at tail fin ref point) [-] + TYPE(MeshType) :: GSLoad !< loads on the general support structure [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< Data to be written to an output file: see WriteOutputHdr for names of each variable [see WriteOutputUnt] END TYPE RotOutputType ! ======================= @@ -585,13 +646,15 @@ MODULE AeroDyn_Types integer(IntKi), public, parameter :: AD_u_BladeRootMotion = 8 ! AD%BladeRootMotion(DL%i1) integer(IntKi), public, parameter :: AD_u_BladeMotion = 9 ! AD%BladeMotion(DL%i1) integer(IntKi), public, parameter :: AD_u_TFinMotion = 10 ! AD%TFinMotion - integer(IntKi), public, parameter :: AD_u_UserProp = 11 ! AD%UserProp - integer(IntKi), public, parameter :: AD_y_NacelleLoad = 12 ! AD%NacelleLoad - integer(IntKi), public, parameter :: AD_y_HubLoad = 13 ! AD%HubLoad - integer(IntKi), public, parameter :: AD_y_TowerLoad = 14 ! AD%TowerLoad - integer(IntKi), public, parameter :: AD_y_BladeLoad = 15 ! AD%BladeLoad(DL%i1) - integer(IntKi), public, parameter :: AD_y_TFinLoad = 16 ! AD%TFinLoad - integer(IntKi), public, parameter :: AD_y_WriteOutput = 17 ! AD%WriteOutput + integer(IntKi), public, parameter :: AD_u_GSMotion = 11 ! AD%GSMotion + integer(IntKi), public, parameter :: AD_u_UserProp = 12 ! AD%UserProp + integer(IntKi), public, parameter :: AD_y_NacelleLoad = 13 ! AD%NacelleLoad + integer(IntKi), public, parameter :: AD_y_HubLoad = 14 ! AD%HubLoad + integer(IntKi), public, parameter :: AD_y_TowerLoad = 15 ! AD%TowerLoad + integer(IntKi), public, parameter :: AD_y_BladeLoad = 16 ! AD%BladeLoad(DL%i1) + integer(IntKi), public, parameter :: AD_y_TFinLoad = 17 ! AD%TFinLoad + integer(IntKi), public, parameter :: AD_y_GSLoad = 18 ! AD%GSLoad + integer(IntKi), public, parameter :: AD_y_WriteOutput = 19 ! AD%WriteOutput contains @@ -901,6 +964,232 @@ subroutine AD_UnPackVTK_RotSurfaceType(RF, OutData) call RegUnpackAlloc(RF, OutData%TowerRad); if (RegCheckErr(RF, RoutineName)) return end subroutine +subroutine AD_CopyGSJointType(SrcGSJointTypeData, DstGSJointTypeData, CtrlCode, ErrStat, ErrMsg) + type(GSJointType), intent(in) :: SrcGSJointTypeData + type(GSJointType), intent(inout) :: DstGSJointTypeData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'AD_CopyGSJointType' + ErrStat = ErrID_None + ErrMsg = '' + DstGSJointTypeData%JointID = SrcGSJointTypeData%JointID + DstGSJointTypeData%Position = SrcGSJointTypeData%Position +end subroutine + +subroutine AD_DestroyGSJointType(GSJointTypeData, ErrStat, ErrMsg) + type(GSJointType), intent(inout) :: GSJointTypeData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'AD_DestroyGSJointType' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine AD_PackGSJointType(RF, Indata) + type(RegFile), intent(inout) :: RF + type(GSJointType), intent(in) :: InData + character(*), parameter :: RoutineName = 'AD_PackGSJointType' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%JointID) + call RegPack(RF, InData%Position) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_UnPackGSJointType(RF, OutData) + type(RegFile), intent(inout) :: RF + type(GSJointType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'AD_UnPackGSJointType' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%JointID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%Position); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_CopyGSInpMemberType(SrcGSInpMemberTypeData, DstGSInpMemberTypeData, CtrlCode, ErrStat, ErrMsg) + type(GSInpMemberType), intent(in) :: SrcGSInpMemberTypeData + type(GSInpMemberType), intent(inout) :: DstGSInpMemberTypeData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'AD_CopyGSInpMemberType' + ErrStat = ErrID_None + ErrMsg = '' + DstGSInpMemberTypeData%MemberID = SrcGSInpMemberTypeData%MemberID + DstGSInpMemberTypeData%MJointID1 = SrcGSInpMemberTypeData%MJointID1 + DstGSInpMemberTypeData%MJointID2 = SrcGSInpMemberTypeData%MJointID2 + DstGSInpMemberTypeData%MDiam1 = SrcGSInpMemberTypeData%MDiam1 + DstGSInpMemberTypeData%MDiam2 = SrcGSInpMemberTypeData%MDiam2 + DstGSInpMemberTypeData%MCd1 = SrcGSInpMemberTypeData%MCd1 + DstGSInpMemberTypeData%MCd2 = SrcGSInpMemberTypeData%MCd2 + DstGSInpMemberTypeData%MTI1 = SrcGSInpMemberTypeData%MTI1 + DstGSInpMemberTypeData%MTI2 = SrcGSInpMemberTypeData%MTI2 + DstGSInpMemberTypeData%MDivSize = SrcGSInpMemberTypeData%MDivSize +end subroutine + +subroutine AD_DestroyGSInpMemberType(GSInpMemberTypeData, ErrStat, ErrMsg) + type(GSInpMemberType), intent(inout) :: GSInpMemberTypeData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'AD_DestroyGSInpMemberType' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine AD_PackGSInpMemberType(RF, Indata) + type(RegFile), intent(inout) :: RF + type(GSInpMemberType), intent(in) :: InData + character(*), parameter :: RoutineName = 'AD_PackGSInpMemberType' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%MemberID) + call RegPack(RF, InData%MJointID1) + call RegPack(RF, InData%MJointID2) + call RegPack(RF, InData%MDiam1) + call RegPack(RF, InData%MDiam2) + call RegPack(RF, InData%MCd1) + call RegPack(RF, InData%MCd2) + call RegPack(RF, InData%MTI1) + call RegPack(RF, InData%MTI2) + call RegPack(RF, InData%MDivSize) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_UnPackGSInpMemberType(RF, OutData) + type(RegFile), intent(inout) :: RF + type(GSInpMemberType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'AD_UnPackGSInpMemberType' + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%MemberID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MJointID1); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MJointID2); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MDiam1); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MDiam2); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MCd1); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MCd2); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MTI1); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MTI2); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MDivSize); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_CopyGSMemberType(SrcGSMemberTypeData, DstGSMemberTypeData, CtrlCode, ErrStat, ErrMsg) + type(GSMemberType), intent(in) :: SrcGSMemberTypeData + type(GSMemberType), intent(inout) :: DstGSMemberTypeData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(*), parameter :: RoutineName = 'AD_CopyGSMemberType' + ErrStat = ErrID_None + ErrMsg = '' + DstGSMemberTypeData%MemberID = SrcGSMemberTypeData%MemberID + DstGSMemberTypeData%NElements = SrcGSMemberTypeData%NElements + if (allocated(SrcGSMemberTypeData%NodeIndx)) then + LB(1:1) = lbound(SrcGSMemberTypeData%NodeIndx) + UB(1:1) = ubound(SrcGSMemberTypeData%NodeIndx) + if (.not. allocated(DstGSMemberTypeData%NodeIndx)) then + allocate(DstGSMemberTypeData%NodeIndx(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSMemberTypeData%NodeIndx.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstGSMemberTypeData%NodeIndx = SrcGSMemberTypeData%NodeIndx + end if + DstGSMemberTypeData%RefLength = SrcGSMemberTypeData%RefLength + DstGSMemberTypeData%dl = SrcGSMemberTypeData%dl + if (allocated(SrcGSMemberTypeData%R)) then + LB(1:1) = lbound(SrcGSMemberTypeData%R) + UB(1:1) = ubound(SrcGSMemberTypeData%R) + if (.not. allocated(DstGSMemberTypeData%R)) then + allocate(DstGSMemberTypeData%R(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSMemberTypeData%R.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstGSMemberTypeData%R = SrcGSMemberTypeData%R + end if + if (allocated(SrcGSMemberTypeData%Cd)) then + LB(1:1) = lbound(SrcGSMemberTypeData%Cd) + UB(1:1) = ubound(SrcGSMemberTypeData%Cd) + if (.not. allocated(DstGSMemberTypeData%Cd)) then + allocate(DstGSMemberTypeData%Cd(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSMemberTypeData%Cd.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstGSMemberTypeData%Cd = SrcGSMemberTypeData%Cd + end if + if (allocated(SrcGSMemberTypeData%TI)) then + LB(1:1) = lbound(SrcGSMemberTypeData%TI) + UB(1:1) = ubound(SrcGSMemberTypeData%TI) + if (.not. allocated(DstGSMemberTypeData%TI)) then + allocate(DstGSMemberTypeData%TI(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSMemberTypeData%TI.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstGSMemberTypeData%TI = SrcGSMemberTypeData%TI + end if +end subroutine + +subroutine AD_DestroyGSMemberType(GSMemberTypeData, ErrStat, ErrMsg) + type(GSMemberType), intent(inout) :: GSMemberTypeData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'AD_DestroyGSMemberType' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(GSMemberTypeData%NodeIndx)) then + deallocate(GSMemberTypeData%NodeIndx) + end if + if (allocated(GSMemberTypeData%R)) then + deallocate(GSMemberTypeData%R) + end if + if (allocated(GSMemberTypeData%Cd)) then + deallocate(GSMemberTypeData%Cd) + end if + if (allocated(GSMemberTypeData%TI)) then + deallocate(GSMemberTypeData%TI) + end if +end subroutine + +subroutine AD_PackGSMemberType(RF, Indata) + type(RegFile), intent(inout) :: RF + type(GSMemberType), intent(in) :: InData + character(*), parameter :: RoutineName = 'AD_PackGSMemberType' + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%MemberID) + call RegPack(RF, InData%NElements) + call RegPackAlloc(RF, InData%NodeIndx) + call RegPack(RF, InData%RefLength) + call RegPack(RF, InData%dl) + call RegPackAlloc(RF, InData%R) + call RegPackAlloc(RF, InData%Cd) + call RegPackAlloc(RF, InData%TI) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_UnPackGSMemberType(RF, OutData) + type(RegFile), intent(inout) :: RF + type(GSMemberType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'AD_UnPackGSMemberType' + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%MemberID); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NElements); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%NodeIndx); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%RefLength); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%dl); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%R); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%Cd); if (RegCheckErr(RF, RoutineName)) return + call RegUnpackAlloc(RF, OutData%TI); if (RegCheckErr(RF, RoutineName)) return +end subroutine + subroutine AD_CopyRotInitInputType(SrcRotInitInputTypeData, DstRotInitInputTypeData, CtrlCode, ErrStat, ErrMsg) type(RotInitInputType), intent(in) :: SrcRotInitInputTypeData type(RotInitInputType), intent(inout) :: DstRotInitInputTypeData @@ -2128,6 +2417,155 @@ subroutine AD_UnPackRotInputFile(RF, OutData) call AD_UnpackTFinInputFileType(RF, OutData%TFin) ! TFin end subroutine +subroutine AD_CopyGSInputFile(SrcGSInputFileData, DstGSInputFileData, CtrlCode, ErrStat, ErrMsg) + type(GSInputFile), intent(in) :: SrcGSInputFileData + type(GSInputFile), intent(inout) :: DstGSInputFileData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'AD_CopyGSInputFile' + ErrStat = ErrID_None + ErrMsg = '' + DstGSInputFileData%NJoints = SrcGSInputFileData%NJoints + if (allocated(SrcGSInputFileData%InpJoints)) then + LB(1:1) = lbound(SrcGSInputFileData%InpJoints) + UB(1:1) = ubound(SrcGSInputFileData%InpJoints) + if (.not. allocated(DstGSInputFileData%InpJoints)) then + allocate(DstGSInputFileData%InpJoints(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSInputFileData%InpJoints.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call AD_CopyGSJointType(SrcGSInputFileData%InpJoints(i1), DstGSInputFileData%InpJoints(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if + DstGSInputFileData%NMembers = SrcGSInputFileData%NMembers + if (allocated(SrcGSInputFileData%InpMembers)) then + LB(1:1) = lbound(SrcGSInputFileData%InpMembers) + UB(1:1) = ubound(SrcGSInputFileData%InpMembers) + if (.not. allocated(DstGSInputFileData%InpMembers)) then + allocate(DstGSInputFileData%InpMembers(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSInputFileData%InpMembers.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call AD_CopyGSInpMemberType(SrcGSInputFileData%InpMembers(i1), DstGSInputFileData%InpMembers(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if +end subroutine + +subroutine AD_DestroyGSInputFile(GSInputFileData, ErrStat, ErrMsg) + type(GSInputFile), intent(inout) :: GSInputFileData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'AD_DestroyGSInputFile' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(GSInputFileData%InpJoints)) then + LB(1:1) = lbound(GSInputFileData%InpJoints) + UB(1:1) = ubound(GSInputFileData%InpJoints) + do i1 = LB(1), UB(1) + call AD_DestroyGSJointType(GSInputFileData%InpJoints(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(GSInputFileData%InpJoints) + end if + if (allocated(GSInputFileData%InpMembers)) then + LB(1:1) = lbound(GSInputFileData%InpMembers) + UB(1:1) = ubound(GSInputFileData%InpMembers) + do i1 = LB(1), UB(1) + call AD_DestroyGSInpMemberType(GSInputFileData%InpMembers(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(GSInputFileData%InpMembers) + end if +end subroutine + +subroutine AD_PackGSInputFile(RF, Indata) + type(RegFile), intent(inout) :: RF + type(GSInputFile), intent(in) :: InData + character(*), parameter :: RoutineName = 'AD_PackGSInputFile' + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%NJoints) + call RegPack(RF, allocated(InData%InpJoints)) + if (allocated(InData%InpJoints)) then + call RegPackBounds(RF, 1, lbound(InData%InpJoints), ubound(InData%InpJoints)) + LB(1:1) = lbound(InData%InpJoints) + UB(1:1) = ubound(InData%InpJoints) + do i1 = LB(1), UB(1) + call AD_PackGSJointType(RF, InData%InpJoints(i1)) + end do + end if + call RegPack(RF, InData%NMembers) + call RegPack(RF, allocated(InData%InpMembers)) + if (allocated(InData%InpMembers)) then + call RegPackBounds(RF, 1, lbound(InData%InpMembers), ubound(InData%InpMembers)) + LB(1:1) = lbound(InData%InpMembers) + UB(1:1) = ubound(InData%InpMembers) + do i1 = LB(1), UB(1) + call AD_PackGSInpMemberType(RF, InData%InpMembers(i1)) + end do + end if + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_UnPackGSInputFile(RF, OutData) + type(RegFile), intent(inout) :: RF + type(GSInputFile), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'AD_UnPackGSInputFile' + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%NJoints); if (RegCheckErr(RF, RoutineName)) return + if (allocated(OutData%InpJoints)) deallocate(OutData%InpJoints) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%InpJoints(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%InpJoints.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call AD_UnpackGSJointType(RF, OutData%InpJoints(i1)) ! InpJoints + end do + end if + call RegUnpack(RF, OutData%NMembers); if (RegCheckErr(RF, RoutineName)) return + if (allocated(OutData%InpMembers)) deallocate(OutData%InpMembers) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%InpMembers(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%InpMembers.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call AD_UnpackGSInpMemberType(RF, OutData%InpMembers(i1)) ! InpMembers + end do + end if +end subroutine + subroutine AD_CopyInputFile(SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg) type(AD_InputFile), intent(in) :: SrcInputFileData type(AD_InputFile), intent(inout) :: DstInputFileData @@ -2263,6 +2701,9 @@ subroutine AD_CopyInputFile(SrcInputFileData, DstInputFileData, CtrlCode, ErrSta if (ErrStat >= AbortErrLev) return end do end if + call AD_CopyGSInputFile(SrcInputFileData%GS, DstInputFileData%GS, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return end subroutine subroutine AD_DestroyInputFile(InputFileData, ErrStat, ErrMsg) @@ -2299,6 +2740,8 @@ subroutine AD_DestroyInputFile(InputFileData, ErrStat, ErrMsg) end do deallocate(InputFileData%rotors) end if + call AD_DestroyGSInputFile(InputFileData%GS, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine subroutine AD_PackInputFile(RF, Indata) @@ -2377,6 +2820,7 @@ subroutine AD_PackInputFile(RF, Indata) call AD_PackRotInputFile(RF, InData%rotors(i1)) end do end if + call AD_PackGSInputFile(RF, InData%GS) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -2462,6 +2906,7 @@ subroutine AD_UnPackInputFile(RF, OutData) call AD_UnpackRotInputFile(RF, OutData%rotors(i1)) ! rotors end do end if + call AD_UnpackGSInputFile(RF, OutData%GS) ! GS end subroutine subroutine AD_CopyRotContinuousStateType(SrcRotContinuousStateTypeData, DstRotContinuousStateTypeData, CtrlCode, ErrStat, ErrMsg) @@ -3321,6 +3766,9 @@ subroutine AD_CopyInflowType(SrcInflowTypeData, DstInflowTypeData, CtrlCode, Err if (ErrStat >= AbortErrLev) return end do end if + call AD_CopyElemInflowType(SrcInflowTypeData%GSInflow, DstInflowTypeData%GSInflow, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return end subroutine subroutine AD_DestroyInflowType(InflowTypeData, ErrStat, ErrMsg) @@ -3346,6 +3794,8 @@ subroutine AD_DestroyInflowType(InflowTypeData, ErrStat, ErrMsg) end do deallocate(InflowTypeData%RotInflow) end if + call AD_DestroyElemInflowType(InflowTypeData%GSInflow, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine subroutine AD_PackInflowType(RF, Indata) @@ -3365,6 +3815,7 @@ subroutine AD_PackInflowType(RF, Indata) call AD_PackRotInflowType(RF, InData%RotInflow(i1)) end do end if + call AD_PackElemInflowType(RF, InData%GSInflow) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -3391,6 +3842,7 @@ subroutine AD_UnPackInflowType(RF, OutData) call AD_UnpackRotInflowType(RF, OutData%RotInflow(i1)) ! RotInflow end do end if + call AD_UnpackElemInflowType(RF, OutData%GSInflow) ! GSInflow end subroutine subroutine AD_CopyRotParameterType(SrcRotParameterTypeData, DstRotParameterTypeData, CtrlCode, ErrStat, ErrMsg) @@ -3815,6 +4267,8 @@ subroutine AD_CopyRotParameterType(SrcRotParameterTypeData, DstRotParameterTypeD call AD_CopyTFinParameterType(SrcRotParameterTypeData%TFin, DstRotParameterTypeData%TFin, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + DstRotParameterTypeData%GSAero = SrcRotParameterTypeData%GSAero + DstRotParameterTypeData%GSDrag = SrcRotParameterTypeData%GSDrag end subroutine subroutine AD_DestroyRotParameterType(RotParameterTypeData, ErrStat, ErrMsg) @@ -4034,6 +4488,8 @@ subroutine AD_PackRotParameterType(RF, Indata) call RegPack(RF, InData%BldNd_NumNodesOut) call RegPack(RF, InData%TFinAero) call AD_PackTFinParameterType(RF, InData%TFin) + call RegPack(RF, InData%GSAero) + call RegPack(RF, InData%GSDrag) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4146,6 +4602,175 @@ subroutine AD_UnPackRotParameterType(RF, OutData) call RegUnpack(RF, OutData%BldNd_NumNodesOut); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinAero); if (RegCheckErr(RF, RoutineName)) return call AD_UnpackTFinParameterType(RF, OutData%TFin) ! TFin + call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_CopyGSParameterType(SrcGSParameterTypeData, DstGSParameterTypeData, CtrlCode, ErrStat, ErrMsg) + type(GSParameterType), intent(in) :: SrcGSParameterTypeData + type(GSParameterType), intent(inout) :: DstGSParameterTypeData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'AD_CopyGSParameterType' + ErrStat = ErrID_None + ErrMsg = '' + DstGSParameterTypeData%GSAero = SrcGSParameterTypeData%GSAero + DstGSParameterTypeData%GSDrag = SrcGSParameterTypeData%GSDrag + DstGSParameterTypeData%NJoints = SrcGSParameterTypeData%NJoints + DstGSParameterTypeData%NNodes = SrcGSParameterTypeData%NNodes + DstGSParameterTypeData%NMembers = SrcGSParameterTypeData%NMembers + if (allocated(SrcGSParameterTypeData%Members)) then + LB(1:1) = lbound(SrcGSParameterTypeData%Members) + UB(1:1) = ubound(SrcGSParameterTypeData%Members) + if (.not. allocated(DstGSParameterTypeData%Members)) then + allocate(DstGSParameterTypeData%Members(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSParameterTypeData%Members.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call AD_CopyGSMemberType(SrcGSParameterTypeData%Members(i1), DstGSParameterTypeData%Members(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if + if (allocated(SrcGSParameterTypeData%Joints)) then + LB(1:1) = lbound(SrcGSParameterTypeData%Joints) + UB(1:1) = ubound(SrcGSParameterTypeData%Joints) + if (.not. allocated(DstGSParameterTypeData%Joints)) then + allocate(DstGSParameterTypeData%Joints(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstGSParameterTypeData%Joints.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + do i1 = LB(1), UB(1) + call AD_CopyGSJointType(SrcGSParameterTypeData%Joints(i1), DstGSParameterTypeData%Joints(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do + end if + DstGSParameterTypeData%Density = SrcGSParameterTypeData%Density + DstGSParameterTypeData%MHK = SrcGSParameterTypeData%MHK + DstGSParameterTypeData%WtrDpth = SrcGSParameterTypeData%WtrDpth +end subroutine + +subroutine AD_DestroyGSParameterType(GSParameterTypeData, ErrStat, ErrMsg) + type(GSParameterType), intent(inout) :: GSParameterTypeData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'AD_DestroyGSParameterType' + ErrStat = ErrID_None + ErrMsg = '' + if (allocated(GSParameterTypeData%Members)) then + LB(1:1) = lbound(GSParameterTypeData%Members) + UB(1:1) = ubound(GSParameterTypeData%Members) + do i1 = LB(1), UB(1) + call AD_DestroyGSMemberType(GSParameterTypeData%Members(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(GSParameterTypeData%Members) + end if + if (allocated(GSParameterTypeData%Joints)) then + LB(1:1) = lbound(GSParameterTypeData%Joints) + UB(1:1) = ubound(GSParameterTypeData%Joints) + do i1 = LB(1), UB(1) + call AD_DestroyGSJointType(GSParameterTypeData%Joints(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do + deallocate(GSParameterTypeData%Joints) + end if +end subroutine + +subroutine AD_PackGSParameterType(RF, Indata) + type(RegFile), intent(inout) :: RF + type(GSParameterType), intent(in) :: InData + character(*), parameter :: RoutineName = 'AD_PackGSParameterType' + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%GSAero) + call RegPack(RF, InData%GSDrag) + call RegPack(RF, InData%NJoints) + call RegPack(RF, InData%NNodes) + call RegPack(RF, InData%NMembers) + call RegPack(RF, allocated(InData%Members)) + if (allocated(InData%Members)) then + call RegPackBounds(RF, 1, lbound(InData%Members), ubound(InData%Members)) + LB(1:1) = lbound(InData%Members) + UB(1:1) = ubound(InData%Members) + do i1 = LB(1), UB(1) + call AD_PackGSMemberType(RF, InData%Members(i1)) + end do + end if + call RegPack(RF, allocated(InData%Joints)) + if (allocated(InData%Joints)) then + call RegPackBounds(RF, 1, lbound(InData%Joints), ubound(InData%Joints)) + LB(1:1) = lbound(InData%Joints) + UB(1:1) = ubound(InData%Joints) + do i1 = LB(1), UB(1) + call AD_PackGSJointType(RF, InData%Joints(i1)) + end do + end if + call RegPack(RF, InData%Density) + call RegPack(RF, InData%MHK) + call RegPack(RF, InData%WtrDpth) + if (RegCheckErr(RF, RoutineName)) return +end subroutine + +subroutine AD_UnPackGSParameterType(RF, OutData) + type(RegFile), intent(inout) :: RF + type(GSParameterType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'AD_UnPackGSParameterType' + integer(B4Ki) :: i1 + integer(B4Ki) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc + if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NJoints); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NNodes); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%NMembers); if (RegCheckErr(RF, RoutineName)) return + if (allocated(OutData%Members)) deallocate(OutData%Members) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%Members(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%Members.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call AD_UnpackGSMemberType(RF, OutData%Members(i1)) ! Members + end do + end if + if (allocated(OutData%Joints)) deallocate(OutData%Joints) + call RegUnpack(RF, IsAllocAssoc); if (RegCheckErr(RF, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(RF, 1, LB, UB); if (RegCheckErr(RF, RoutineName)) return + allocate(OutData%Joints(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%Joints.', RF%ErrStat, RF%ErrMsg, RoutineName) + return + end if + do i1 = LB(1), UB(1) + call AD_UnpackGSJointType(RF, OutData%Joints(i1)) ! Joints + end do + end if + call RegUnpack(RF, OutData%Density); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%MHK); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%WtrDpth); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) @@ -4210,6 +4835,9 @@ subroutine AD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%SA_PsiFwd = SrcParamData%SA_PsiFwd DstParamData%SA_nPerSec = SrcParamData%SA_nPerSec DstParamData%WaveField => SrcParamData%WaveField + call AD_CopyGSParameterType(SrcParamData%GS, DstParamData%GS, CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return end subroutine subroutine AD_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -4245,6 +4873,8 @@ subroutine AD_DestroyParam(ParamData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) nullify(ParamData%FlowField) nullify(ParamData%WaveField) + call AD_DestroyGSParameterType(ParamData%GS, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine subroutine AD_PackParam(RF, Indata) @@ -4300,6 +4930,7 @@ subroutine AD_PackParam(RF, Indata) call SeaSt_WaveField_PackSeaSt_WaveFieldType(RF, InData%WaveField) end if end if + call AD_PackGSParameterType(RF, InData%GS) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4389,6 +5020,7 @@ subroutine AD_UnPackParam(RF, OutData) else OutData%WaveField => null() end if + call AD_UnpackGSParameterType(RF, OutData%GS) ! GS end subroutine subroutine AD_CopyRotInputType(SrcRotInputTypeData, DstRotInputTypeData, CtrlCode, ErrStat, ErrMsg) @@ -4448,6 +5080,9 @@ subroutine AD_CopyRotInputType(SrcRotInputTypeData, DstRotInputTypeData, CtrlCod call MeshCopy(SrcRotInputTypeData%TFinMotion, DstRotInputTypeData%TFinMotion, CtrlCode, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + call MeshCopy(SrcRotInputTypeData%GSMotion, DstRotInputTypeData%GSMotion, CtrlCode, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return if (allocated(SrcRotInputTypeData%UserProp)) then LB(1:2) = lbound(SrcRotInputTypeData%UserProp) UB(1:2) = ubound(SrcRotInputTypeData%UserProp) @@ -4499,6 +5134,8 @@ subroutine AD_DestroyRotInputType(RotInputTypeData, ErrStat, ErrMsg) end if call MeshDestroy( RotInputTypeData%TFinMotion, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call MeshDestroy( RotInputTypeData%GSMotion, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (allocated(RotInputTypeData%UserProp)) then deallocate(RotInputTypeData%UserProp) end if @@ -4533,6 +5170,7 @@ subroutine AD_PackRotInputType(RF, Indata) end do end if call MeshPack(RF, InData%TFinMotion) + call MeshPack(RF, InData%GSMotion) call RegPackAlloc(RF, InData%UserProp) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4576,6 +5214,7 @@ subroutine AD_UnPackRotInputType(RF, OutData) end do end if call MeshUnpack(RF, OutData%TFinMotion) ! TFinMotion + call MeshUnpack(RF, OutData%GSMotion) ! GSMotion call RegUnpackAlloc(RF, OutData%UserProp); if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4716,6 +5355,9 @@ subroutine AD_CopyRotOutputType(SrcRotOutputTypeData, DstRotOutputTypeData, Ctrl call MeshCopy(SrcRotOutputTypeData%TFinLoad, DstRotOutputTypeData%TFinLoad, CtrlCode, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + call MeshCopy(SrcRotOutputTypeData%GSLoad, DstRotOutputTypeData%GSLoad, CtrlCode, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return if (allocated(SrcRotOutputTypeData%WriteOutput)) then LB(1:1) = lbound(SrcRotOutputTypeData%WriteOutput) UB(1:1) = ubound(SrcRotOutputTypeData%WriteOutput) @@ -4758,6 +5400,8 @@ subroutine AD_DestroyRotOutputType(RotOutputTypeData, ErrStat, ErrMsg) end if call MeshDestroy( RotOutputTypeData%TFinLoad, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call MeshDestroy( RotOutputTypeData%GSLoad, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (allocated(RotOutputTypeData%WriteOutput)) then deallocate(RotOutputTypeData%WriteOutput) end if @@ -4783,6 +5427,7 @@ subroutine AD_PackRotOutputType(RF, Indata) end do end if call MeshPack(RF, InData%TFinLoad) + call MeshPack(RF, InData%GSLoad) call RegPackAlloc(RF, InData%WriteOutput) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4813,6 +5458,7 @@ subroutine AD_UnPackRotOutputType(RF, OutData) end do end if call MeshUnpack(RF, OutData%TFinLoad) ! TFinLoad + call MeshUnpack(RF, OutData%GSLoad) ! GSLoad call RegUnpackAlloc(RF, OutData%WriteOutput); if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -6501,6 +7147,10 @@ SUBROUTINE AD_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) CALL MeshExtrapInterp1(u1%rotors(i01)%TFinMotion, u2%rotors(i01)%TFinMotion, tin, u_out%rotors(i01)%TFinMotion, tin_out, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) END DO + do i01 = lbound(u_out%rotors,1),ubound(u_out%rotors,1) + CALL MeshExtrapInterp1(u1%rotors(i01)%GSMotion, u2%rotors(i01)%GSMotion, tin, u_out%rotors(i01)%GSMotion, tin_out, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + END DO do i01 = lbound(u_out%rotors,1),ubound(u_out%rotors,1) IF (ALLOCATED(u_out%rotors(i01)%UserProp) .AND. ALLOCATED(u1%rotors(i01)%UserProp)) THEN u_out%rotors(i01)%UserProp = a1*u1%rotors(i01)%UserProp + a2*u2%rotors(i01)%UserProp @@ -6599,6 +7249,10 @@ SUBROUTINE AD_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrM CALL MeshExtrapInterp2(u1%rotors(i01)%TFinMotion, u2%rotors(i01)%TFinMotion, u3%rotors(i01)%TFinMotion, tin, u_out%rotors(i01)%TFinMotion, tin_out, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) END DO + do i01 = lbound(u_out%rotors,1),ubound(u_out%rotors,1) + CALL MeshExtrapInterp2(u1%rotors(i01)%GSMotion, u2%rotors(i01)%GSMotion, u3%rotors(i01)%GSMotion, tin, u_out%rotors(i01)%GSMotion, tin_out, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + END DO do i01 = lbound(u_out%rotors,1),ubound(u_out%rotors,1) IF (ALLOCATED(u_out%rotors(i01)%UserProp) .AND. ALLOCATED(u1%rotors(i01)%UserProp)) THEN u_out%rotors(i01)%UserProp = a1*u1%rotors(i01)%UserProp + a2*u2%rotors(i01)%UserProp + a3*u3%rotors(i01)%UserProp @@ -6729,6 +7383,10 @@ SUBROUTINE AD_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg CALL MeshExtrapInterp1(y1%rotors(i01)%TFinLoad, y2%rotors(i01)%TFinLoad, tin, y_out%rotors(i01)%TFinLoad, tin_out, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) END DO + do i01 = lbound(y_out%rotors,1),ubound(y_out%rotors,1) + CALL MeshExtrapInterp1(y1%rotors(i01)%GSLoad, y2%rotors(i01)%GSLoad, tin, y_out%rotors(i01)%GSLoad, tin_out, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + END DO do i01 = lbound(y_out%rotors,1),ubound(y_out%rotors,1) IF (ALLOCATED(y_out%rotors(i01)%WriteOutput) .AND. ALLOCATED(y1%rotors(i01)%WriteOutput)) THEN y_out%rotors(i01)%WriteOutput = a1*y1%rotors(i01)%WriteOutput + a2*y2%rotors(i01)%WriteOutput @@ -6817,6 +7475,10 @@ SUBROUTINE AD_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, Err CALL MeshExtrapInterp2(y1%rotors(i01)%TFinLoad, y2%rotors(i01)%TFinLoad, y3%rotors(i01)%TFinLoad, tin, y_out%rotors(i01)%TFinLoad, tin_out, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) END DO + do i01 = lbound(y_out%rotors,1),ubound(y_out%rotors,1) + CALL MeshExtrapInterp2(y1%rotors(i01)%GSLoad, y2%rotors(i01)%GSLoad, y3%rotors(i01)%GSLoad, tin, y_out%rotors(i01)%GSLoad, tin_out, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + END DO do i01 = lbound(y_out%rotors,1),ubound(y_out%rotors,1) IF (ALLOCATED(y_out%rotors(i01)%WriteOutput) .AND. ALLOCATED(y1%rotors(i01)%WriteOutput)) THEN y_out%rotors(i01)%WriteOutput = a1*y1%rotors(i01)%WriteOutput + a2*y2%rotors(i01)%WriteOutput + a3*y3%rotors(i01)%WriteOutput @@ -6965,6 +7627,12 @@ SUBROUTINE AD_InflowType_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, Err u_out%RotInflow(i01)%AvgDiskVel = a1*u1%RotInflow(i01)%AvgDiskVel + a2*u2%RotInflow(i01)%AvgDiskVel END DO END IF ! check if allocated + IF (ALLOCATED(u_out%GSInflow%InflowVel) .AND. ALLOCATED(u1%GSInflow%InflowVel)) THEN + u_out%GSInflow%InflowVel = a1*u1%GSInflow%InflowVel + a2*u2%GSInflow%InflowVel + END IF ! check if allocated + IF (ALLOCATED(u_out%GSInflow%InflowAcc) .AND. ALLOCATED(u1%GSInflow%InflowAcc)) THEN + u_out%GSInflow%InflowAcc = a1*u1%GSInflow%InflowAcc + a2*u2%GSInflow%InflowAcc + END IF ! check if allocated END SUBROUTINE SUBROUTINE AD_InflowType_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) @@ -7065,6 +7733,12 @@ SUBROUTINE AD_InflowType_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, u_out%RotInflow(i01)%AvgDiskVel = a1*u1%RotInflow(i01)%AvgDiskVel + a2*u2%RotInflow(i01)%AvgDiskVel + a3*u3%RotInflow(i01)%AvgDiskVel END DO END IF ! check if allocated + IF (ALLOCATED(u_out%GSInflow%InflowVel) .AND. ALLOCATED(u1%GSInflow%InflowVel)) THEN + u_out%GSInflow%InflowVel = a1*u1%GSInflow%InflowVel + a2*u2%GSInflow%InflowVel + a3*u3%GSInflow%InflowVel + END IF ! check if allocated + IF (ALLOCATED(u_out%GSInflow%InflowAcc) .AND. ALLOCATED(u1%GSInflow%InflowAcc)) THEN + u_out%GSInflow%InflowAcc = a1*u1%GSInflow%InflowAcc + a2*u2%GSInflow%InflowAcc + a3*u3%GSInflow%InflowAcc + END IF ! check if allocated END SUBROUTINE function AD_InputMeshPointer(u, DL) result(Mesh) @@ -7085,6 +7759,8 @@ function AD_InputMeshPointer(u, DL) result(Mesh) Mesh => u%BladeMotion(DL%i1) case (AD_u_TFinMotion) Mesh => u%TFinMotion + case (AD_u_GSMotion) + Mesh => u%GSMotion end select end function @@ -7104,6 +7780,8 @@ function AD_OutputMeshPointer(y, DL) result(Mesh) Mesh => y%BladeLoad(DL%i1) case (AD_y_TFinLoad) Mesh => y%TFinLoad + case (AD_y_GSLoad) + Mesh => y%GSLoad end select end function @@ -7240,6 +7918,8 @@ subroutine AD_VarPackInput(V, u, ValAry) call MV_PackMesh(V, u%BladeMotion(DL%i1), ValAry) ! Mesh case (AD_u_TFinMotion) call MV_PackMesh(V, u%TFinMotion, ValAry) ! Mesh + case (AD_u_GSMotion) + call MV_PackMesh(V, u%GSMotion, ValAry) ! Mesh case (AD_u_UserProp) VarVals = u%UserProp(V%iLB:V%iUB,V%j) ! Rank 2 Array case default @@ -7276,6 +7956,8 @@ subroutine AD_VarUnpackInput(V, ValAry, u) call MV_UnpackMesh(V, ValAry, u%BladeMotion(DL%i1)) ! Mesh case (AD_u_TFinMotion) call MV_UnpackMesh(V, ValAry, u%TFinMotion) ! Mesh + case (AD_u_GSMotion) + call MV_UnpackMesh(V, ValAry, u%GSMotion) ! Mesh case (AD_u_UserProp) u%UserProp(V%iLB:V%iUB, V%j) = VarVals ! Rank 2 Array end select @@ -7298,6 +7980,8 @@ function AD_InputFieldName(DL) result(Name) Name = "u%BladeMotion("//trim(Num2LStr(DL%i1))//")" case (AD_u_TFinMotion) Name = "u%TFinMotion" + case (AD_u_GSMotion) + Name = "u%GSMotion" case (AD_u_UserProp) Name = "u%UserProp" case default @@ -7331,6 +8015,8 @@ subroutine AD_VarPackOutput(V, y, ValAry) call MV_PackMesh(V, y%BladeLoad(DL%i1), ValAry) ! Mesh case (AD_y_TFinLoad) call MV_PackMesh(V, y%TFinLoad, ValAry) ! Mesh + case (AD_y_GSLoad) + call MV_PackMesh(V, y%GSLoad, ValAry) ! Mesh case (AD_y_WriteOutput) VarVals = y%WriteOutput(V%iLB:V%iUB) ! Rank 1 Array case default @@ -7365,6 +8051,8 @@ subroutine AD_VarUnpackOutput(V, ValAry, y) call MV_UnpackMesh(V, ValAry, y%BladeLoad(DL%i1)) ! Mesh case (AD_y_TFinLoad) call MV_UnpackMesh(V, ValAry, y%TFinLoad) ! Mesh + case (AD_y_GSLoad) + call MV_UnpackMesh(V, ValAry, y%GSLoad) ! Mesh case (AD_y_WriteOutput) y%WriteOutput(V%iLB:V%iUB) = VarVals ! Rank 1 Array end select @@ -7385,6 +8073,8 @@ function AD_OutputFieldName(DL) result(Name) Name = "y%BladeLoad("//trim(Num2LStr(DL%i1))//")" case (AD_y_TFinLoad) Name = "y%TFinLoad" + case (AD_y_GSLoad) + Name = "y%GSLoad" case (AD_y_WriteOutput) Name = "y%WriteOutput" case default diff --git a/modules/openfast-library/src/FAST_Mapping.f90 b/modules/openfast-library/src/FAST_Mapping.f90 index a150e6f066..95b69e09b4 100644 --- a/modules/openfast-library/src/FAST_Mapping.f90 +++ b/modules/openfast-library/src/FAST_Mapping.f90 @@ -781,6 +781,15 @@ subroutine InitMappings_AD(Mappings, SrcMod, DstMod, Turbine, ErrStat, ErrMsg) call MapCustom(Mappings, Custom_SrvD_to_AD, SrcMod, DstMod) + case (Module_SD) + associate (AD_p_Rotor => Turbine%AD%p%Rotors(DstMod%Ins)) + call MapMotionMesh(Turbine, Mappings, & + SrcMod=SrcMod, SrcDL=DatLoc(SD_y_Y3Mesh), & ! SD%y(SrcMod%Ins)%Y3Mesh + DstMod=DstMod, DstDL=DatLoc(AD_u_GSMotion), & ! AD%u%rotors(DstMod%Ins)%GSMotion + ErrStat=ErrStat2, ErrMsg=ErrMsg2, & + Active=(AD_p_Rotor%GSAero.or.AD_p_Rotor%GSDrag)) + if (Failed()) return + end associate end select contains @@ -1955,6 +1964,18 @@ subroutine InitMappings_SD(Mappings, SrcMod, DstMod, Turbine, ErrStat, ErrMsg) select case (SrcMod%ID) + case (Module_AD) + associate (AD_p_Rotor => Turbine%AD%p%Rotors(SrcMod%Ins)) + call MapLoadMesh(Turbine, Mappings, SrcMod=SrcMod, DstMod=DstMod, & + SrcDL=DatLoc(AD_y_GSLoad), & ! AD%y%rotors(SrcMod%Ins)%GSLoad + SrcDispDL=DatLoc(AD_u_GSMotion),& ! AD%u%rotors(SrcMod%Ins)%GSMotion + DstDL=DatLoc(SD_u_LMesh), & ! SD%u(DstMod%Ins)%LMesh + DstDispDL=DatLoc(SD_y_y3Mesh),& ! SD%y(DstMod%Ins)%y3Mesh + ErrStat=ErrStat2, ErrMsg=ErrMsg2, & + Active=AD_p_Rotor%GSDrag) + if (Failed()) return + end associate + case (Module_ED) call MapMotionMesh(Turbine, Mappings, SrcMod=SrcMod, DstMod=DstMod, & From 1c42a55f9f4e8d5ad3bd2a0283af41d4f3070906 Mon Sep 17 00:00:00 2001 From: Lu Wang Date: Fri, 17 Apr 2026 14:26:32 -0600 Subject: [PATCH 2/4] Add a summary file for the AD general support structure and input validation --- modules/aerodyn/src/AeroDyn.f90 | 88 ++++++++++++++++++++++-- modules/aerodyn/src/AeroDyn_IO.f90 | 70 +++++++++++++++++++ modules/aerodyn/src/AeroDyn_Registry.txt | 8 ++- modules/aerodyn/src/AeroDyn_Types.f90 | 20 +++++- 4 files changed, 176 insertions(+), 10 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 38a2a3de9e..e0b8b955b2 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -446,12 +446,16 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call Init_GSParam(InputFileData%GS, p%GS, InputFileData%AirDens, InitInp%MHK, InitInp%WtrDpth, errStat2, errMsg2 ) if (Failed()) return; if (nRotors >= 1_IntKi) then - p%rotors(1)%GSAero = p%GS%GSAero + p%rotors(1)%GSAero = p%GS%GSAero ! True if GSInfl .or. GSShdw + p%rotors(1)%GSInfl = p%GS%GSInfl + p%rotors(1)%GSShdw = p%GS%GSShdw p%rotors(1)%GSDrag = p%GS%GSDrag ! Only rotor 1 handles GS drag force end if do iR = 2, nRotors - p%rotors(iR)%GSAero = p%GS%GSAero - p%rotors(iR)%GSDrag = .false. ! Only rotor 1 handles GS drag force + p%rotors(iR)%GSAero = p%GS%GSAero ! True if GSInfl .or. GSShdw + p%rotors(iR)%GSInfl = p%GS%GSInfl + p%rotors(iR)%GSShdw = p%GS%GSShdw + p%rotors(iR)%GSDrag = .false. ! Only rotor 1 handles GS drag force enddo !............................................................................................ @@ -629,8 +633,10 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call AD_PrintSum( InputFileData, p%rotors(iR), p, u, y, NumBlades(iR), InputFileData%rotors(iR)%BladeProps(:), ErrStat2, ErrMsg2 ) if (Failed()) return; enddo + if ( p%GS%GSAero .or. p%GS%GSDrag ) then + call AD_PrintSum_GS( p%GS, p, u%rotors(1), y%rotors(1), ErrStat, ErrMsg ); if (Failed()) return + end if end if - !............................................................................................ ! If you want to choose your own rate instead of using what the glue code suggests, tell the glue code the rate at which ! this module must be called here: @@ -4879,6 +4885,72 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, calcCrvAngle, ErrSt end do end if + !.................. + ! check for generalized support structure + !.................. + ! Joints + if (InputFileData%GS%NJoints<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'NumGSJoints cannot be negative.', ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%NJoints==1_IntKi) then + call SetErrStat( ErrID_Fatal, 'Generalized support structure requires at least two joints (NumGSJoints>=2).', ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + do j = 1,InputFileData%GS%NJoints + if (InputFileData%GS%InpJoints(j)%JointID<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'GSJointID cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ) + if(Failed()) return + end if + do k = 1,InputFileData%GS%NJoints + if (j==k) cycle + if (InputFileData%GS%InpJoints(j)%JointID == InputFileData%GS%InpJoints(k)%JointID) then + call SetErrStat( ErrID_Fatal, 'GSJointID must be unique for each joint; check row '//trim(num2lstr(j))//' and row '//trim(num2lstr(k)), ErrStat, ErrMsg, RoutineName ) + if(Failed()) return + end if + end do + end do + ! Members + if (InputFileData%GS%NMembers<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'NumGSMembers cannot be negative.', ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + do j = 1,InputFileData%GS%NMembers + if (InputFileData%GS%InpMembers(j)%MemberID<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'GSMemberID cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + do k = 1,InputFileData%GS%NMembers + if (j==k) cycle + if (InputFileData%GS%InpMembers(j)%MemberID == InputFileData%GS%InpMembers(k)%MemberID) then + call SetErrStat( ErrID_Fatal, 'GSMemberID must be unique for each member; check row '//trim(num2lstr(j))//' and row '//trim(num2lstr(k)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + end do + if (InputFileData%GS%InpMembers(j)%MJointID1<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'GSMJointID1 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MJointID2<0_IntKi) then + call SetErrStat( ErrID_Fatal, 'GSMJointID2 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MJointID1 == InputFileData%GS%InpMembers(j)%MJointID2) then + call SetErrStat( ErrID_Fatal, 'GSMJointID1 and GSMJointID2 must be distinct for each member; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MDiam1<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMDia1 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MDiam2<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMDia2 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MCd1<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMCd1 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MCd2<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMCd2 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MTI1<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMTI1 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + if (InputFileData%GS%InpMembers(j)%MTI2<0.0_ReKi) then + call SetErrStat( ErrID_Fatal, 'GSMTI2 cannot be negative; check row '//trim(num2lstr(j)), ErrStat, ErrMsg, RoutineName ); if(Failed()) return + end if + end do + contains SUBROUTINE Fatal(ErrMsg_in) @@ -5309,6 +5381,8 @@ SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMs if (InputFileData%NMembers==0_IntKi) then p%GSAero = .false. + p%GSInfl = .false. + p%GSShdw = .false. p%GSDrag = .false. p%Density = 0.0_ReKi p%MHK = MHK @@ -5320,8 +5394,10 @@ SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMs end if ! Default GSAero and GSDrag to true for now; can be based on user input later - p%GSAero = .true. - p%GSDrag = .true. + p%GSInfl = .true. + p%GSShdw = .true. + p%GSAero = p%GSInfl .or. p%GSShdw + p%GSDrag = .true. p%Density = Density p%NMembers = InputFileData%NMembers p%NJoints = InputFileData%NJoints diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 710ca6dab0..d7f598f658 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -2170,6 +2170,76 @@ END SUBROUTINE AD_PrintSum !---------------------------------------------------------------------------------------------------------------------------------- +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE AD_PrintSum_GS( p, p_AD, u, y, ErrStat, ErrMsg ) +! This routine generates the summary file, which contains a summary of input file options. + use YAML, only: yaml_write_var + ! passed variables + TYPE(GSParameterType), INTENT(IN) :: p ! Parameters + TYPE(AD_ParameterType), INTENT(IN) :: p_AD ! Parameters + TYPE(RotInputType), INTENT(IN) :: u ! inputs + TYPE(RotOutputType), INTENT(IN) :: y ! outputs + + INTEGER(IntKi), INTENT(OUT) :: ErrStat + CHARACTER(*), INTENT(OUT) :: ErrMsg + + ! Local variables. + + INTEGER(IntKi) :: I, J ! Generic loop counter + INTEGER(IntKi) :: JointID, NodeIndx + INTEGER(IntKi) :: UnSu ! I/O unit number for the summary output file + + if (p%NMembers<=0_IntKi) return + + ! Open the summary file and give it a heading. + + !$OMP critical(fileopen_critical) + CALL GetNewUnit( UnSu, ErrStat, ErrMsg ) + CALL OpenFOutFile ( UnSu, TRIM( p_AD%RootName )//'.GS.sum', ErrStat, ErrMsg ) + !$OMP end critical(fileopen_critical) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! Heading: + WRITE (UnSu,'(/,A)') 'This summary information was generated by '//TRIM( GetNVD(AD_Ver) )// & + ' on '//CurDate()//' at '//CurTime()//'.' + + WRITE (UnSu,'(/,/,A)') '====== General support structure ==================================================================' + + WRITE (UnSu,'(/,A,L1)') 'Compute influence: ',p%GSInfl + WRITE (UnSu,'(A,L1)') 'Compute shadow effect: ',p%GSShdw + WRITE (UnSu,'(A,L1)') 'Compute drag force: ',p%GSDrag + + WRITE (UnSu,'(/,A)') 'Number of joints: '//trim(num2lstr(p%NJoints)) + WRITE (UnSu,'(A)') 'Number of members: '//trim(num2lstr(p%NMembers)) + WRITE (UnSu,'(A)') 'Number of nodes: '//trim(num2lstr(u%GSMotion%Nnodes))//' (joints + member interior nodes)' + + WRITE (UnSu,'(/,A)') 'In the table below, a member interior node will have joint ID -1.' + + ! MemberID, JointID, NodeIndx, NodeX, NodeY, NodeZ, R, Cd, TI + WRITE (UnSu,'(/,9(1x,A14))') 'MemberID', 'JointID', 'NodeIndx', 'Node_xi', 'Node_yi', 'Node_zi', 'Node_R', 'Node_Cd', 'Node_TI' + WRITE (UnSu,'(9(1x,A14))') ' (-)', ' (-)', ' (-)', ' (m)', ' (m)', ' (m)', ' (m)', ' (-)', ' (-)' + DO I=1,p%NMembers + associate(mem=>p%Members(I)) + DO J=1,p%Members(I)%NElements+1 + NodeIndx = mem%NodeIndx(J) + IF (NodeIndx<=p%NJoints) THEN + JointID = p%Joints(NodeIndx)%JointID + ELSE + JointID = -1 + END IF + WRITE(UnSu,'(3(I15),6(F15.6))') & + mem%MemberID, JointID, NodeIndx, & + u%GSMotion%position(1,NodeIndx), u%GSMotion%position(2,NodeIndx), u%GSMotion%position(3,NodeIndx), & + mem%R(J),mem%Cd(J),mem%TI(J) + END DO + end associate + END DO + CLOSE(UnSu) +RETURN +END SUBROUTINE AD_PrintSum_GS +!---------------------------------------------------------------------------------------------------------------------------------- + + !********************************************************************************************************************************** ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" ! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 93a35342fb..8e28891940 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -412,10 +412,14 @@ typedef ^ RotParameterType IntKi BldNd_NumNodesOut - - - "The blades to outpu typedef ^ RotParameterType LOGICAL TFinAero - .FALSE. - "Calculate tail fin aerodynamics model (flag)" flag typedef ^ RotParameterType TFinParameterType TFin - - - "Parameters for tail fin of current rotor" - # General support parameters (per rotor) -typedef ^ RotParameterType LOGICAL GSAero - .FALSE. - "Calculate general support aerodynamic influences (flag)" flag +typedef ^ RotParameterType LOGICAL GSAero - .FALSE. - "Calculate general support influence or shadow (flag)" flag +typedef ^ RotParameterType LOGICAL GSInfl - .FALSE. - "Calculate general support aerodynamic influence (flag)" flag +typedef ^ RotParameterType LOGICAL GSShdw - .FALSE. - "Calculate general support shadow/wake deficit (flag)" flag typedef ^ RotParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag # General support parameters (shared) -typedef ^ GSParameterType LOGICAL GSAero - .FALSE. - "Calculate general support aerodynamic influences (flag)" flag +typedef ^ GSParameterType LOGICAL GSAero - .FALSE. - "Calculate general support influence or shadow (flag)" flag +typedef ^ GSParameterType LOGICAL GSInfl - .FALSE. - "Calculate general support aerodynamic influence (flag)" flag +typedef ^ GSParameterType LOGICAL GSShdw - .FALSE. - "Calculate general support shadow/wake deficit (flag)" flag typedef ^ GSParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag typedef ^ GSParameterType IntKi NJoints - - - "Total number of user-specified joints for the general support structure" - typedef ^ GSParameterType IntKi NNodes - - - "Total number of general support structure nodes (joints+interior nodes)" - diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 489fb67d71..0098f25a4a 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -464,13 +464,17 @@ MODULE AeroDyn_Types INTEGER(IntKi) :: BldNd_NumNodesOut = 0_IntKi !< The blades to output (AD_AllBldNdOuts) [-] LOGICAL :: TFinAero = .FALSE. !< Calculate tail fin aerodynamics model (flag) [flag] TYPE(TFinParameterType) :: TFin !< Parameters for tail fin of current rotor [-] - LOGICAL :: GSAero = .FALSE. !< Calculate general support aerodynamic influences (flag) [flag] + LOGICAL :: GSAero = .FALSE. !< Calculate general support influence or shadow (flag) [flag] + LOGICAL :: GSInfl = .FALSE. !< Calculate general support aerodynamic influence (flag) [flag] + LOGICAL :: GSShdw = .FALSE. !< Calculate general support shadow/wake deficit (flag) [flag] LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] END TYPE RotParameterType ! ======================= ! ========= GSParameterType ======= TYPE, PUBLIC :: GSParameterType - LOGICAL :: GSAero = .FALSE. !< Calculate general support aerodynamic influences (flag) [flag] + LOGICAL :: GSAero = .FALSE. !< Calculate general support influence or shadow (flag) [flag] + LOGICAL :: GSInfl = .FALSE. !< Calculate general support aerodynamic influence (flag) [flag] + LOGICAL :: GSShdw = .FALSE. !< Calculate general support shadow/wake deficit (flag) [flag] LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] INTEGER(IntKi) :: NJoints = 0_IntKi !< Total number of user-specified joints for the general support structure [-] INTEGER(IntKi) :: NNodes = 0_IntKi !< Total number of general support structure nodes (joints+interior nodes) [-] @@ -4268,6 +4272,8 @@ subroutine AD_CopyRotParameterType(SrcRotParameterTypeData, DstRotParameterTypeD call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return DstRotParameterTypeData%GSAero = SrcRotParameterTypeData%GSAero + DstRotParameterTypeData%GSInfl = SrcRotParameterTypeData%GSInfl + DstRotParameterTypeData%GSShdw = SrcRotParameterTypeData%GSShdw DstRotParameterTypeData%GSDrag = SrcRotParameterTypeData%GSDrag end subroutine @@ -4489,6 +4495,8 @@ subroutine AD_PackRotParameterType(RF, Indata) call RegPack(RF, InData%TFinAero) call AD_PackTFinParameterType(RF, InData%TFin) call RegPack(RF, InData%GSAero) + call RegPack(RF, InData%GSInfl) + call RegPack(RF, InData%GSShdw) call RegPack(RF, InData%GSDrag) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4603,6 +4611,8 @@ subroutine AD_UnPackRotParameterType(RF, OutData) call RegUnpack(RF, OutData%TFinAero); if (RegCheckErr(RF, RoutineName)) return call AD_UnpackTFinParameterType(RF, OutData%TFin) ! TFin call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSInfl); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSShdw); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4620,6 +4630,8 @@ subroutine AD_CopyGSParameterType(SrcGSParameterTypeData, DstGSParameterTypeData ErrStat = ErrID_None ErrMsg = '' DstGSParameterTypeData%GSAero = SrcGSParameterTypeData%GSAero + DstGSParameterTypeData%GSInfl = SrcGSParameterTypeData%GSInfl + DstGSParameterTypeData%GSShdw = SrcGSParameterTypeData%GSShdw DstGSParameterTypeData%GSDrag = SrcGSParameterTypeData%GSDrag DstGSParameterTypeData%NJoints = SrcGSParameterTypeData%NJoints DstGSParameterTypeData%NNodes = SrcGSParameterTypeData%NNodes @@ -4700,6 +4712,8 @@ subroutine AD_PackGSParameterType(RF, Indata) integer(B4Ki) :: LB(1), UB(1) if (RF%ErrStat >= AbortErrLev) return call RegPack(RF, InData%GSAero) + call RegPack(RF, InData%GSInfl) + call RegPack(RF, InData%GSShdw) call RegPack(RF, InData%GSDrag) call RegPack(RF, InData%NJoints) call RegPack(RF, InData%NNodes) @@ -4738,6 +4752,8 @@ subroutine AD_UnPackGSParameterType(RF, OutData) logical :: IsAllocAssoc if (RF%ErrStat /= ErrID_None) return call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSInfl); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSShdw); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NJoints); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NNodes); if (RegCheckErr(RF, RoutineName)) return From aec25f0fb818936e810411650a3d7844d522f3a0 Mon Sep 17 00:00:00 2001 From: Lu Wang Date: Fri, 17 Apr 2026 14:42:05 -0600 Subject: [PATCH 3/4] Correct AD general support member radius --- modules/aerodyn/src/AeroDyn.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index e0b8b955b2..651b19903c 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -5484,7 +5484,7 @@ SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMs call AllocAry( p%members(iMem)%TI, numDiv+1_IntKi, 'Turbulence intensity of each member nodes', ErrStat2, ErrMsg2 ); if (Failed()) return do iNode = 1,numDiv+1_IntKi s = real(iNode-1_IntKi,ReKi) / real(numDiv,ReKi) - p%members(iMem)%R(iNode) = InputFileData%InpMembers(iMem)%MDiam1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MDiam2 * s + p%members(iMem)%R(iNode) = (InputFileData%InpMembers(iMem)%MDiam1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MDiam2 * s) * 0.5_ReKi p%members(iMem)%Cd(iNode) = InputFileData%InpMembers(iMem)%MCd1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MCd2 * s p%members(iMem)%TI(iNode) = InputFileData%InpMembers(iMem)%MTI1 * (1.0_ReKi-s) + InputFileData%InpMembers(iMem)%MTI2 * s enddo From 62a5cc424ce92fce4156b1d4611da6ab96c1115b Mon Sep 17 00:00:00 2001 From: Lu Wang Date: Fri, 17 Apr 2026 18:03:42 -0600 Subject: [PATCH 4/4] Update internal flags and switches for the general support models to match the existing tower model setup --- modules/aerodyn/src/AeroDyn.f90 | 96 +++++++++---------- modules/aerodyn/src/AeroDyn_IO.f90 | 37 ++++++- modules/aerodyn/src/AeroDyn_Registry.txt | 33 ++++--- modules/aerodyn/src/AeroDyn_Types.f90 | 60 +++++++----- modules/openfast-library/src/FAST_Mapping.f90 | 4 +- 5 files changed, 140 insertions(+), 90 deletions(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 651b19903c..4695bf0a0b 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -446,16 +446,16 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call Init_GSParam(InputFileData%GS, p%GS, InputFileData%AirDens, InitInp%MHK, InitInp%WtrDpth, errStat2, errMsg2 ) if (Failed()) return; if (nRotors >= 1_IntKi) then - p%rotors(1)%GSAero = p%GS%GSAero ! True if GSInfl .or. GSShdw - p%rotors(1)%GSInfl = p%GS%GSInfl - p%rotors(1)%GSShdw = p%GS%GSShdw - p%rotors(1)%GSDrag = p%GS%GSDrag ! Only rotor 1 handles GS drag force + p%rotors( 1)%hasGSMod = p%GS%hasGSMod + p%rotors( 1)%GSPotent = p%GS%GSPotent + p%rotors( 1)%GSShadow = p%GS%GSShadow + p%rotors( 1)%GSAero = p%GS%GSAero ! Only rotor 1 handles GS drag force end if do iR = 2, nRotors - p%rotors(iR)%GSAero = p%GS%GSAero ! True if GSInfl .or. GSShdw - p%rotors(iR)%GSInfl = p%GS%GSInfl - p%rotors(iR)%GSShdw = p%GS%GSShdw - p%rotors(iR)%GSDrag = .false. ! Only rotor 1 handles GS drag force + p%rotors(iR)%hasGSMod = p%GS%hasGSMod + p%rotors(iR)%GSPotent = p%GS%GSPotent + p%rotors(iR)%GSShadow = p%GS%GSShadow + p%rotors(iR)%GSAero = GSAero_none ! Only rotor 1 handles GS drag force enddo !............................................................................................ @@ -633,7 +633,7 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut call AD_PrintSum( InputFileData, p%rotors(iR), p, u, y, NumBlades(iR), InputFileData%rotors(iR)%BladeProps(:), ErrStat2, ErrMsg2 ) if (Failed()) return; enddo - if ( p%GS%GSAero .or. p%GS%GSDrag ) then + if ( p%GS%hasGSMod ) then call AD_PrintSum_GS( p%GS, p, u%rotors(1), y%rotors(1), ErrStat, ErrMsg ); if (Failed()) return end if end if @@ -1086,7 +1086,7 @@ subroutine Init_y(y, u, p, errStat, errMsg) errStat = ErrID_None errMsg = "" - if (p%GSDrag) then + if (p%GSAero/=GSAero_none) then call MeshCopy ( SrcMesh = u%GSMotion & , DestMesh = y%GSLoad & , CtrlCode = MESH_SIBLING & @@ -1240,7 +1240,7 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er !................ ! general support structure !................ - if (p%GSAero .or. p%GSDrag) then + if (p%hasGSMod) then call MeshCreate ( BlankMesh = u%GSMotion & ,IOS = COMPONENT_INPUT & @@ -2276,31 +2276,31 @@ subroutine AD_CalcWind_GS(t, u, FlowField, p, p_AD, m, GSInflow, StartNode, ErrS ErrStat = ErrID_None ErrMsg = "" - if (p%GSAero.or.p%GSDrag) then - ! If rotor is MHK, add water depth to z coordinate - if (p%MHK /= MHK_None) then - PosOffset = [0.0_ReKi, 0.0_ReKi, p%WtrDpth] - else - PosOffset = 0.0_ReKi - end if - if (p%MHK /= MHK_None .and. p_AD%CompSeaSt) then ! MHK turbines with waves - call WaveField_GetWaveVelAcc_AD(p_AD%WaveField, m%WaveField_m, & - StartNode, t, & - real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & - GSInflow%InflowVel, & - NoAcc, ErrStat2, ErrMsg2, & - BoxExceedAllow=.true.) - if(Failed()) return - else - call IfW_FlowField_GetVelAcc(FlowField, StartNode, t, & - real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & - GSInflow%InflowVel, & - NoAcc, ErrStat2, ErrMsg2, & - BoxExceedAllow=.true., PosOffset=PosOffset) - if(Failed()) return - end if - StartNode = StartNode + p%NNodes + if (.not.p%hasGSMod) return + + ! If rotor is MHK, add water depth to z coordinate + if (p%MHK /= MHK_None) then + PosOffset = [0.0_ReKi, 0.0_ReKi, p%WtrDpth] + else + PosOffset = 0.0_ReKi + end if + if (p%MHK /= MHK_None .and. p_AD%CompSeaSt) then ! MHK turbines with waves + call WaveField_GetWaveVelAcc_AD(p_AD%WaveField, m%WaveField_m, & + StartNode, t, & + real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & + GSInflow%InflowVel, & + NoAcc, ErrStat2, ErrMsg2, & + BoxExceedAllow=.true.) + if(Failed()) return + else + call IfW_FlowField_GetVelAcc(FlowField, StartNode, t, & + real(u%GSMotion%Position + u%GSMotion%TranslationDisp, ReKi), & + GSInflow%InflowVel, & + NoAcc, ErrStat2, ErrMsg2, & + BoxExceedAllow=.true., PosOffset=PosOffset) + if(Failed()) return end if + StartNode = StartNode + p%NNodes contains logical function Failed() @@ -2465,7 +2465,7 @@ subroutine RotCalcOutput( t, u, RotInflow, GSInflow, p, p_AD, x, xd, z, OtherSta call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif - if (p%GSDrag) then + if (p%GSAero/=GSAero_none) then call ADGS_CalcOutput(p_AD%GS, u, GSInflow, m, y, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif @@ -5380,10 +5380,10 @@ SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMs ErrMsg = "" if (InputFileData%NMembers==0_IntKi) then - p%GSAero = .false. - p%GSInfl = .false. - p%GSShdw = .false. - p%GSDrag = .false. + p%GSPotent = GSPotent_none + p%GSShadow = GSShadow_none + p%GSAero = GSAero_none + p%hasGSMod = .false. p%Density = 0.0_ReKi p%MHK = MHK p%WtrDpth = WtrDpth @@ -5393,11 +5393,11 @@ SUBROUTINE Init_GSParam( InputFileData, p, Density, MHK, WtrDpth, ErrStat, ErrMs return end if - ! Default GSAero and GSDrag to true for now; can be based on user input later - p%GSInfl = .true. - p%GSShdw = .true. - p%GSAero = p%GSInfl .or. p%GSShdw - p%GSDrag = .true. + ! Default values for now; can be based on user input later + p%GSPotent = GSPotent_baseline + p%GSShadow = GSShadow_Powles + p%GSAero = GSAero_noVIV + p%hasGSMod = (p%GSPotent/=GSPotent_none) .or. (p%GSShadow/=GSShadow_none) .or. (p%GSAero/=GSAero_none) p%Density = Density p%NMembers = InputFileData%NMembers p%NJoints = InputFileData%NJoints @@ -5872,7 +5872,7 @@ SUBROUTINE ADGS_CalcOutput(p, u, GSInflow, m, y, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" - IF (.not.p%GSDrag) RETURN + IF (p%GSAero==GSAero_none) RETURN y%GSLoad%Force = 0.0_ReKi y%GSLoad%moment = 0.0_ReKi @@ -6625,7 +6625,7 @@ subroutine AD_InitVars(iR, u, p, x, z, OtherState, y, m, InitOut, InputFileData, DatLoc(AD_u_GSMotion), & Mesh=u%GSMotion, & Perturbs=[PerturbTower, Perturb, PerturbTower], & - Active=(p%GSAero.or.p%GSDrag)) + Active=p%hasGSMod) ! Add blade root motion do j = 1, p%NumBlades @@ -6698,7 +6698,7 @@ subroutine AD_InitVars(iR, u, p, x, z, OtherState, y, m, InitOut, InputFileData, ! Add general support load call MV_AddMeshVar(InitOut%Vars%y, "General Support", LoadFields, DatLoc(AD_y_GSLoad), & Mesh=y%GSLoad, & - Active=p%GSDrag) + Active=(p%GSAero/=GSAero_none)) ! Loop through blades, add blade loads do j = 1, p%NumBlades diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index d7f598f658..0ed68dba64 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -2188,6 +2188,7 @@ SUBROUTINE AD_PrintSum_GS( p, p_AD, u, y, ErrStat, ErrMsg ) INTEGER(IntKi) :: I, J ! Generic loop counter INTEGER(IntKi) :: JointID, NodeIndx INTEGER(IntKi) :: UnSu ! I/O unit number for the summary output file + CHARACTER(100) :: Msg ! temporary string for writing appropriate text to summary file if (p%NMembers<=0_IntKi) return @@ -2205,9 +2206,39 @@ SUBROUTINE AD_PrintSum_GS( p, p_AD, u, y, ErrStat, ErrMsg ) WRITE (UnSu,'(/,/,A)') '====== General support structure ==================================================================' - WRITE (UnSu,'(/,A,L1)') 'Compute influence: ',p%GSInfl - WRITE (UnSu,'(A,L1)') 'Compute shadow effect: ',p%GSShdw - WRITE (UnSu,'(A,L1)') 'Compute drag force: ',p%GSDrag + select case (p%GSPotent) + case (GSPotent_none) + Msg = 'none' + case (GSPotent_baseline) + Msg = 'baseline model' + case (GSPotent_bak) + Msg = "Bak correction" + case default + Msg = 'unknown' + end select + WRITE (UnSu,'(/,A)') 'Potential-flow influence model: '//trim(num2lstr(p%GSPotent))//' ('//trim(Msg)//')' + + select case (p%GSShadow) + case (GSShadow_none) + Msg = 'none' + case (GSShadow_Powles) + Msg = 'Powles model' + case (GSShadow_Eames) + Msg = "Eames model" + case default + Msg = 'unknown' + end select + WRITE (UnSu,'(A)') 'Downstream shadow/wake model: '//trim(num2lstr(p%GSShadow))//' ('//trim(Msg)//')' + + select case (p%GSAero) + case (GSAero_none) + Msg = 'none' + case (GSAero_NoVIV) + Msg = 'drag only' + case default + Msg = 'unknown' + end select + WRITE (UnSu,'(A)') 'Flow-induced load model: '//trim(num2lstr(p%GSAero))//' ('//trim(Msg)//')' WRITE (UnSu,'(/,A)') 'Number of joints: '//trim(num2lstr(p%NJoints)) WRITE (UnSu,'(A)') 'Number of members: '//trim(num2lstr(p%NMembers)) diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 8e28891940..7b700d399b 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -34,9 +34,20 @@ param ^ - IntKi TwrShadow_none - 0 - "no tower s param ^ - IntKi TwrShadow_Powles - 1 - "Powles tower shadow model" - param ^ - IntKi TwrShadow_Eames - 2 - "Eames tower shadow model" - -param ^ - IntKi TwrAero_none - 0 - "no tower aero" - -param ^ - IntKi TwrAero_noVIV - 1 - "Tower aero model without VIV" - -param ^ - IntKi TwrAero_VIV - 2 - "Tower aero model with VIV" - +param ^ - IntKi TwrAero_none - 0 - "no tower aero" - +param ^ - IntKi TwrAero_noVIV - 1 - "Tower aero model without VIV" - +param ^ - IntKi TwrAero_VIV - 2 - "Tower aero model with VIV" - + +param ^ - IntKi GSPotent_none - 0 - "no general support potential flow" - +param ^ - IntKi GSPotent_baseline - 1 - "baseline general support potential flow" - +param ^ - IntKi GSPotent_Bak - 2 - "general support potential flow with Bak correction" - + +param ^ - IntKi GSShadow_none - 0 - "no general support shadow" - +param ^ - IntKi GSShadow_Powles - 1 - "Powles general support shadow model" - +param ^ - IntKi GSShadow_Eames - 2 - "Eames general support shadow model" - + +param ^ - IntKi GSAero_none - 0 - "no general support aero" - +param ^ - IntKi GSAero_noVIV - 1 - "General support aero model without VIV" - param ^ - IntKi SA_Wgt_Uniform - 1 - "Sector average weighting - Uniform" - #param ^ - IntKi SA_Wgt_Impulse - 1 - "Sector average weighting - Impulse" - @@ -412,15 +423,15 @@ typedef ^ RotParameterType IntKi BldNd_NumNodesOut - - - "The blades to outpu typedef ^ RotParameterType LOGICAL TFinAero - .FALSE. - "Calculate tail fin aerodynamics model (flag)" flag typedef ^ RotParameterType TFinParameterType TFin - - - "Parameters for tail fin of current rotor" - # General support parameters (per rotor) -typedef ^ RotParameterType LOGICAL GSAero - .FALSE. - "Calculate general support influence or shadow (flag)" flag -typedef ^ RotParameterType LOGICAL GSInfl - .FALSE. - "Calculate general support aerodynamic influence (flag)" flag -typedef ^ RotParameterType LOGICAL GSShdw - .FALSE. - "Calculate general support shadow/wake deficit (flag)" flag -typedef ^ RotParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag +typedef ^ RotParameterType LOGICAL hasGSMod - .FALSE. - "Has general support structure model (flag)" flag +typedef ^ RotParameterType IntKi GSPotent - - - "Type of general support influence based on potential flow around the member {0=none, 1=baseline potential flow, 2=potential flow with Bak correction}" - +typedef ^ RotParameterType IntKi GSShadow - - - "Type of general support downstream shadow effect {0=none, 1=Powles model, 2=Eames model}" - +typedef ^ RotParameterType IntKi GSAero - - - "Type of flow-induced loads on the general support {0=none, 1=Drag}" - # General support parameters (shared) -typedef ^ GSParameterType LOGICAL GSAero - .FALSE. - "Calculate general support influence or shadow (flag)" flag -typedef ^ GSParameterType LOGICAL GSInfl - .FALSE. - "Calculate general support aerodynamic influence (flag)" flag -typedef ^ GSParameterType LOGICAL GSShdw - .FALSE. - "Calculate general support shadow/wake deficit (flag)" flag -typedef ^ GSParameterType LOGICAL GSDrag - .FALSE. - "Calculate general support drag force (flag)" flag +typedef ^ GSParameterType LOGICAL hasGSMod - .FALSE. - "Has general support structure model (flag)" flag +typedef ^ GSParameterType IntKi GSPotent - - - "Type of general support influence based on potential flow around the member {0=none, 1=baseline potential flow, 2=potential flow with Bak correction}" - +typedef ^ GSParameterType IntKi GSShadow - - - "Type of general support downstream shadow effect {0=none, 1=Powles model, 2=Eames model}" - +typedef ^ GSParameterType IntKi GSAero - - - "Type of flow-induced loads on the general support {0=none, 1=Drag}" - typedef ^ GSParameterType IntKi NJoints - - - "Total number of user-specified joints for the general support structure" - typedef ^ GSParameterType IntKi NNodes - - - "Total number of general support structure nodes (joints+interior nodes)" - typedef ^ GSParameterType IntKi NMembers - - - "Total number of general support structure members" - diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 0098f25a4a..f38dc92554 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -52,6 +52,14 @@ MODULE AeroDyn_Types INTEGER(IntKi), PUBLIC, PARAMETER :: TwrAero_none = 0 ! no tower aero [-] INTEGER(IntKi), PUBLIC, PARAMETER :: TwrAero_noVIV = 1 ! Tower aero model without VIV [-] INTEGER(IntKi), PUBLIC, PARAMETER :: TwrAero_VIV = 2 ! Tower aero model with VIV [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSPotent_none = 0 ! no general support potential flow [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSPotent_baseline = 1 ! baseline general support potential flow [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSPotent_Bak = 2 ! general support potential flow with Bak correction [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSShadow_none = 0 ! no general support shadow [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSShadow_Powles = 1 ! Powles general support shadow model [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSShadow_Eames = 2 ! Eames general support shadow model [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSAero_none = 0 ! no general support aero [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: GSAero_noVIV = 1 ! General support aero model without VIV [-] INTEGER(IntKi), PUBLIC, PARAMETER :: SA_Wgt_Uniform = 1 ! Sector average weighting - Uniform [-] INTEGER(IntKi), PUBLIC, PARAMETER :: TFinAero_none = 0 ! no tail fin aero [-] INTEGER(IntKi), PUBLIC, PARAMETER :: TFinAero_polar = 1 ! polar-based tail fin aerodynamics [-] @@ -464,18 +472,18 @@ MODULE AeroDyn_Types INTEGER(IntKi) :: BldNd_NumNodesOut = 0_IntKi !< The blades to output (AD_AllBldNdOuts) [-] LOGICAL :: TFinAero = .FALSE. !< Calculate tail fin aerodynamics model (flag) [flag] TYPE(TFinParameterType) :: TFin !< Parameters for tail fin of current rotor [-] - LOGICAL :: GSAero = .FALSE. !< Calculate general support influence or shadow (flag) [flag] - LOGICAL :: GSInfl = .FALSE. !< Calculate general support aerodynamic influence (flag) [flag] - LOGICAL :: GSShdw = .FALSE. !< Calculate general support shadow/wake deficit (flag) [flag] - LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] + LOGICAL :: hasGSMod = .FALSE. !< Has general support structure model (flag) [flag] + INTEGER(IntKi) :: GSPotent = 0_IntKi !< Type of general support influence based on potential flow around the member {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} [-] + INTEGER(IntKi) :: GSShadow = 0_IntKi !< Type of general support downstream shadow effect {0=none, 1=Powles model, 2=Eames model} [-] + INTEGER(IntKi) :: GSAero = 0_IntKi !< Type of flow-induced loads on the general support {0=none, 1=Drag} [-] END TYPE RotParameterType ! ======================= ! ========= GSParameterType ======= TYPE, PUBLIC :: GSParameterType - LOGICAL :: GSAero = .FALSE. !< Calculate general support influence or shadow (flag) [flag] - LOGICAL :: GSInfl = .FALSE. !< Calculate general support aerodynamic influence (flag) [flag] - LOGICAL :: GSShdw = .FALSE. !< Calculate general support shadow/wake deficit (flag) [flag] - LOGICAL :: GSDrag = .FALSE. !< Calculate general support drag force (flag) [flag] + LOGICAL :: hasGSMod = .FALSE. !< Has general support structure model (flag) [flag] + INTEGER(IntKi) :: GSPotent = 0_IntKi !< Type of general support influence based on potential flow around the member {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} [-] + INTEGER(IntKi) :: GSShadow = 0_IntKi !< Type of general support downstream shadow effect {0=none, 1=Powles model, 2=Eames model} [-] + INTEGER(IntKi) :: GSAero = 0_IntKi !< Type of flow-induced loads on the general support {0=none, 1=Drag} [-] INTEGER(IntKi) :: NJoints = 0_IntKi !< Total number of user-specified joints for the general support structure [-] INTEGER(IntKi) :: NNodes = 0_IntKi !< Total number of general support structure nodes (joints+interior nodes) [-] INTEGER(IntKi) :: NMembers = 0_IntKi !< Total number of general support structure members [-] @@ -4271,10 +4279,10 @@ subroutine AD_CopyRotParameterType(SrcRotParameterTypeData, DstRotParameterTypeD call AD_CopyTFinParameterType(SrcRotParameterTypeData%TFin, DstRotParameterTypeData%TFin, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + DstRotParameterTypeData%hasGSMod = SrcRotParameterTypeData%hasGSMod + DstRotParameterTypeData%GSPotent = SrcRotParameterTypeData%GSPotent + DstRotParameterTypeData%GSShadow = SrcRotParameterTypeData%GSShadow DstRotParameterTypeData%GSAero = SrcRotParameterTypeData%GSAero - DstRotParameterTypeData%GSInfl = SrcRotParameterTypeData%GSInfl - DstRotParameterTypeData%GSShdw = SrcRotParameterTypeData%GSShdw - DstRotParameterTypeData%GSDrag = SrcRotParameterTypeData%GSDrag end subroutine subroutine AD_DestroyRotParameterType(RotParameterTypeData, ErrStat, ErrMsg) @@ -4494,10 +4502,10 @@ subroutine AD_PackRotParameterType(RF, Indata) call RegPack(RF, InData%BldNd_NumNodesOut) call RegPack(RF, InData%TFinAero) call AD_PackTFinParameterType(RF, InData%TFin) + call RegPack(RF, InData%hasGSMod) + call RegPack(RF, InData%GSPotent) + call RegPack(RF, InData%GSShadow) call RegPack(RF, InData%GSAero) - call RegPack(RF, InData%GSInfl) - call RegPack(RF, InData%GSShdw) - call RegPack(RF, InData%GSDrag) if (RegCheckErr(RF, RoutineName)) return end subroutine @@ -4610,10 +4618,10 @@ subroutine AD_UnPackRotParameterType(RF, OutData) call RegUnpack(RF, OutData%BldNd_NumNodesOut); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%TFinAero); if (RegCheckErr(RF, RoutineName)) return call AD_UnpackTFinParameterType(RF, OutData%TFin) ! TFin + call RegUnpack(RF, OutData%hasGSMod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSPotent); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSShadow); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSInfl); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSShdw); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return end subroutine subroutine AD_CopyGSParameterType(SrcGSParameterTypeData, DstGSParameterTypeData, CtrlCode, ErrStat, ErrMsg) @@ -4629,10 +4637,10 @@ subroutine AD_CopyGSParameterType(SrcGSParameterTypeData, DstGSParameterTypeData character(*), parameter :: RoutineName = 'AD_CopyGSParameterType' ErrStat = ErrID_None ErrMsg = '' + DstGSParameterTypeData%hasGSMod = SrcGSParameterTypeData%hasGSMod + DstGSParameterTypeData%GSPotent = SrcGSParameterTypeData%GSPotent + DstGSParameterTypeData%GSShadow = SrcGSParameterTypeData%GSShadow DstGSParameterTypeData%GSAero = SrcGSParameterTypeData%GSAero - DstGSParameterTypeData%GSInfl = SrcGSParameterTypeData%GSInfl - DstGSParameterTypeData%GSShdw = SrcGSParameterTypeData%GSShdw - DstGSParameterTypeData%GSDrag = SrcGSParameterTypeData%GSDrag DstGSParameterTypeData%NJoints = SrcGSParameterTypeData%NJoints DstGSParameterTypeData%NNodes = SrcGSParameterTypeData%NNodes DstGSParameterTypeData%NMembers = SrcGSParameterTypeData%NMembers @@ -4711,10 +4719,10 @@ subroutine AD_PackGSParameterType(RF, Indata) integer(B4Ki) :: i1 integer(B4Ki) :: LB(1), UB(1) if (RF%ErrStat >= AbortErrLev) return + call RegPack(RF, InData%hasGSMod) + call RegPack(RF, InData%GSPotent) + call RegPack(RF, InData%GSShadow) call RegPack(RF, InData%GSAero) - call RegPack(RF, InData%GSInfl) - call RegPack(RF, InData%GSShdw) - call RegPack(RF, InData%GSDrag) call RegPack(RF, InData%NJoints) call RegPack(RF, InData%NNodes) call RegPack(RF, InData%NMembers) @@ -4751,10 +4759,10 @@ subroutine AD_UnPackGSParameterType(RF, OutData) integer(IntKi) :: stat logical :: IsAllocAssoc if (RF%ErrStat /= ErrID_None) return + call RegUnpack(RF, OutData%hasGSMod); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSPotent); if (RegCheckErr(RF, RoutineName)) return + call RegUnpack(RF, OutData%GSShadow); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%GSAero); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSInfl); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSShdw); if (RegCheckErr(RF, RoutineName)) return - call RegUnpack(RF, OutData%GSDrag); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NJoints); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NNodes); if (RegCheckErr(RF, RoutineName)) return call RegUnpack(RF, OutData%NMembers); if (RegCheckErr(RF, RoutineName)) return diff --git a/modules/openfast-library/src/FAST_Mapping.f90 b/modules/openfast-library/src/FAST_Mapping.f90 index 95b69e09b4..5ce660ead2 100644 --- a/modules/openfast-library/src/FAST_Mapping.f90 +++ b/modules/openfast-library/src/FAST_Mapping.f90 @@ -787,7 +787,7 @@ subroutine InitMappings_AD(Mappings, SrcMod, DstMod, Turbine, ErrStat, ErrMsg) SrcMod=SrcMod, SrcDL=DatLoc(SD_y_Y3Mesh), & ! SD%y(SrcMod%Ins)%Y3Mesh DstMod=DstMod, DstDL=DatLoc(AD_u_GSMotion), & ! AD%u%rotors(DstMod%Ins)%GSMotion ErrStat=ErrStat2, ErrMsg=ErrMsg2, & - Active=(AD_p_Rotor%GSAero.or.AD_p_Rotor%GSDrag)) + Active=(AD_p_Rotor%hasGSMod)) if (Failed()) return end associate end select @@ -1972,7 +1972,7 @@ subroutine InitMappings_SD(Mappings, SrcMod, DstMod, Turbine, ErrStat, ErrMsg) DstDL=DatLoc(SD_u_LMesh), & ! SD%u(DstMod%Ins)%LMesh DstDispDL=DatLoc(SD_y_y3Mesh),& ! SD%y(DstMod%Ins)%y3Mesh ErrStat=ErrStat2, ErrMsg=ErrMsg2, & - Active=AD_p_Rotor%GSDrag) + Active=AD_p_Rotor%GSAero/=GSAero_none) if (Failed()) return end associate