Professional Documents
Culture Documents
***********************************************************************************
***********************************************
MODULE AeroSubs
USE NWTC_Library
USE AeroDyn14_Types
IMPLICIT NONE
CONTAINS
! ************************************************
! AeroDyn Subroutines for YawDyn, ADAMS,
! SymDyn and FAST.
! ************************************************
! UNIVERSITY OF UTAH, MECHANICAL ENGINEERING DEPARTMENT
! Local Variables:
INTEGER :: ElIndex
INTEGER :: IELM
INTEGER :: IndPrint
INTEGER :: K
INTEGER :: UnIn
INTEGER :: ErrStatLcl
LOGICAL :: PremEOF_indicator
CHARACTER(1024) :: LINE
CHARACTER(1024) :: FilePath ! The path name of the
AeroDyn input file (so files listed in it can be defined relative to the main input
file location)
CHARACTER(ErrMsgLen) :: ErrMessLcl
character(*), parameter :: RoutineName = 'AD14_GetInput'
!bjj: error handling here needs to be fixed! (we overwrite any non-AbortErrLev
errors)
ErrStat = ErrID_None
ErrMess = ''
! Function definition
!-------------------------------------------------------------------------------
------------------
! Open the AeroDyn input file
!-------------------------------------------------------------------------------
------------------
CALL OpenFInpFile(UnIn, TRIM(InitInp%ADFileName), ErrStatLcl, ErrMessLcl)
CALL SetErrStat(ErrStatLcl, ErrMessLcl,ErrStat, ErrMess,RoutineName)
IF (ErrStat >= AbortErrLev) THEN
CLOSE(UnIn)
RETURN
END IF
!-------------------------------------------------------------------------------
------------------
! If the echo file is open, write the header...
!-------------------------------------------------------------------------------
------------------
IF ( p%Echo ) THEN
WRITE( p%UnEc, '(// A /)' ) 'AeroDyn input data from file "'//TRIM( InitInp
%ADFileName )//'":'
END IF
!-------------------------------------------------------------------------------
------------------
! Read the AeroDyn input file
!-------------------------------------------------------------------------------
------------------
p%SIunit = .TRUE.
CALL Conv2UC(LINE(1:7))
CALL Conv2UC(LINE(1:6))
CALL Conv2UC(LINE(1:7))
CASE ('DYNIN')
P%DynInfl = .TRUE.
m%DynInit = .TRUE.
CASE DEFAULT
CALL ProgWarn( ' Error: Expecting "EQUIL" or "DYNIN" inflow model
option.')
ErrStat = ErrID_Fatal
CLOSE(UnIn)
RETURN
END SELECT
CALL ProgWarn( ' All wake calculations are turned off! This option is
recommended only '// &
'in high winds or for debugging.' )
CASE ('WAKE')
P%Wake = .TRUE.
P%Swirl = .FALSE.
CASE ('SWIRL')
P%Wake = .TRUE.
P%Swirl = .TRUE.
CASE DEFAULT
CALL ProgWarn( ' Error: Expecting "NONE", "WAKE", or "SWIRL" wake model
option.')
ErrStat = ErrID_Fatal
CLOSE(UnIn)
RETURN
END SELECT
p%Rotor%HH = InitInp%HubHt
!bjj: this is a hack job to allow both the new tower influence and the old tower
wake models to be used
! CALL ReadStr( UnIn, InitInp%ADFileName, LINE, VarName='NewTowerModel?',
VarDescr='Check for tower influence model', ErrStat=ErrStat )
CALL ReadVar( UnIn, InitInp%ADFileName, LINE, VarName='NewTowerModel?',
VarDescr='Check for tower influence model', ErrStat=ErrStat, ErrMsg=ErrMess )
IF (ErrStat >= AbortErrLev) THEN
CLOSE(UnIn)
RETURN
END IF
! Check if this is the "special string" to indicate the new tower influence
model
CALL Conv2UC( Line )
IF ( INDEX(Line, "NEWTOWER" ) > 0 ) THEN
!----------------------------------------------------------------------------
------------------
! New tower influence model, as implemented by PJM
!----------------------------------------------------------------------------
------------------
P%TwrProps%PJM_Version = .TRUE.
ELSE
!----------------------------------------------------------------------------
------------------
! Old tower influence model, read TwrShad from Line for now
!----------------------------------------------------------------------------
------------------
P%TwrProps%PJM_Version = .FALSE.
END IF
!----------------
! Read in the tower shadow reference point (distance from yaw axis to hub)
CALL ReadVar( UnIn, InitInp%ADFileName, P%TwrProps%T_Shad_Refpt,
VarName='T_Shad_Refpt', VarDescr='Tower shadow reference point', ErrStat=ErrStat,
ErrMsg=ErrMess)
IF (ErrStat >= AbortErrLev) THEN
CLOSE(UnIn)
RETURN
END IF
END IF
IF ( P%Wind%Rho == 0.0 .AND. P%DynInfl ) THEN ! Turn off the GDW if RHO = 0.
It will crash
CALL ProgWarn( 'Air density is zero. Dynamic Inflow will be turned off to
avoid program crash.' )
P%DynInfl = .FALSE.
ENDIF
!............................................................................
..................
! Allocate space for the airfoil data file name(s), then read them
!............................................................................
..................
IF (.NOT. ALLOCATED(P%AirFoil%FoilNm)) THEN
ALLOCATE ( P%AirFoil%FoilNm( P%AirFoil%NumFoil ) , STAT=ErrStat )
IF ( ErrStat /= ErrID_None ) THEN
CALL ProgWarn(' Error allocating space for the FoilNm array.')
close(unin)
RETURN
END IF
END IF
CALL ReadAryLines( UnIn, InitInp%ADFileName, P%AirFoil%FoilNm, P%AirFoil
%NumFoil, AryName='FoilNm', AryDescr='Airfoil file names', ErrStat=ErrStat,
ErrMsg=ErrMess )
IF (ErrStat >= AbortErrLev) THEN
CLOSE(UnIn)
RETURN
END IF
DO K=1,P%AirFoil%NumFoil
IF ( PathIsRelative( P%AirFoil%FoilNm(K) ) ) P%AirFoil%FoilNm(K) =
TRIM(FilePath)//TRIM( P%AirFoil%FoilNm(K) )
END DO
!............................................................................
..................
! Allocate space for blade element data and read the arrays
! Read blade element data, check some inputs, convert twist to radians
!............................................................................
..................
CALL AllocArrays (InitInp, P, x, xd, z, m, y, 'Element')
DO IElm = 1, p%Element%NElm
IF (ErrStat == 0) THEN
READ(Line,*,IOSTAT=ErrStat) P%Element%RElm(IElm), P%Element%Twist(IElm), P
%Blade%DR(IElm), P%Blade%C(IElm), P%AirFoil%NFoil(IElm)
END IF
IF ( ErrStat == 0 ) THEN
!'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''
! Check if AeroDyn will print out the element and/or wind data
!'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''
CALL Conv2UC(LINE)
m%ElOut%ElPrList(IElm) = 0 ! INITIALIZE
IndPrint = INDEX(LINE,"PRINT")
IF (IndPrint > 0) THEN
IF (LINE(IndPrint-2:IndPrint+4) /= "NOPRINT") THEN
m%ElOut%NumElOut = m%ElOut%NumElOut + 1
m%ElOut%ElPrList(IElm) = m%ElOut%NumElOut
END IF
ENDIF
m%ElOut%WndElPrList(IElm) = 0 ! INITIALIZE
IndPrint = INDEX(LINE,"WIND")
IF (IndPrint > 0) THEN
IF (LINE(IndPrint-2:IndPrint-1) /= "NO") THEN
m%ElOut%NumWndElOut = m%ElOut%NumWndElOut + 1
m%ElOut%WndElPrList(IElm) = m%ElOut%NumWndElOut
END IF
ENDIF
!'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''
! Echo data to the file NWTC_Library echo file, if requested
!'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''
P%Element%Twist(IElm) = P%Element%Twist(IElm)*D2R
ENDDO ! IELM
!............................................................................
..................
! Read multiple airfoil table option
!............................................................................
..................
PremEOF_indicator = .FALSE.
READ(UnIn,*,IOSTAT=ErrStatLcl) Line !read MultiTab -- it may not
exist
IF (ErrStatLcl > 0 ) THEN
CALL WrScr1 ( ' Invalid character input for file "'//TRIM( InitInp
%ADFileName )//'".' )
CALL ProgWarn ( ' The error occurred while trying to read "MultiTab".' )
ErrStat=ErrID_Fatal
close(unin)
RETURN
ELSE IF (ErrStatLcl == 0) THEN
IF ( p%Echo ) THEN
WRITE (p%UnEc, "( 15X, A, T30, ' - ', A, /, 2X, A )" ) &
'MultiTab', 'Multiple airfoil table option',
'"'//TRIM( Line )//'"'
END IF
ELSE
p%MultiTab = .FALSE.
p%Reynolds = .FALSE.
PremEOF_indicator = .TRUE.
! CALL PremEOF ( TRIM( Fil ), Variable, TrapThisError )
END IF
!-------------------------------------------------------------------------------
------------------
! Close AeroDyn input file
!-------------------------------------------------------------------------------
------------------
CLOSE(UnIn)
!-------------------------------------------------------------------------------
------------------
! Read airfoil data and check for MultiTab values using LINE, which was read
above
!-------------------------------------------------------------------------------
------------------
CALL READFL(InitInp, P, x, xd, z, m, y, ErrStatLcl, ErrMessLcl)
CALL SetErrStat(ErrStatLcl, ErrMessLcl, ErrStat, ErrMess,'AD_GetInput')
IF ( ErrStat >= AbortErrLev ) THEN
close(unin)
RETURN
END IF
DO K = 1, p%AirFoil%NumFoil
IF ( p%AirFoil%NTables(K) > 1 ) THEN
IF ( ( m%AirFoil%MulTabLoc < p%AirFoil%MulTabMet(K,1) ) .OR. &
( m%AirFoil%MulTabLoc > p%AirFoil%MulTabMet(K,p%AirFoil
%NTables(K) ) ))THEN
CALL ProgWarn( 'Error interpolating between airfoil tables.
'// &
' Initial interpolation value = '//TRIM(Num2LStr(m
%AirFoil%MulTabLoc))// &
' is outside table range of '//TRIM(Num2LStr(p
%AirFoil%MulTabMet(K,1)))// &
' to '//TRIM(Num2LStr(p%AirFoil%MulTabMet(K,p
%AirFoil%NTables(K))))// &
' in airfoil file #'//TRIM(Int2LStr(K))//'.' )
ErrStat = ErrID_Fatal
RETURN
END IF
END IF ! NTables(K) > 1
ENDDO ! K
CASE ( 'RENUM' )
p%MultiTab = .TRUE.
p%Reynolds = .TRUE.
CASE ( 'SINGLE' )
p%MultiTab = .FALSE.
p%Reynolds = .FALSE.
CASE DEFAULT
CALL WrScr( ' Error: control model option must be "USER", "RENUM" or
"SINGLE".' )
END SELECT
ELSE
p%MultiTab = .FALSE.
p%Reynolds = .FALSE.
END IF
ENDIF
!-------------------------------------------------------------------------------
------------------
! Read tower drag input file, if necessary
!-------------------------------------------------------------------------------
------------------
IF (p%TwrProps%TwrPotent .OR. p%TwrProps%TwrShadow .OR. p%TwrProps%CalcTwrAero)
THEN ! Read in the tower drag file
CALL READTwr(UnIn, InitInp, P, x, xd, z, m, y, ErrStat, ErrMess )
IF (ErrStat /= ErrID_None) RETURN
END IF
!-------------------------------------------------------------------------------
------------------
! Initialize variables for printing
!-------------------------------------------------------------------------------
------------------
IF ( m%ElOut%NumElOut > 0 .OR. m%ElOut%NumWndElOut > 0 ) THEN
p%ElemPrn = .TRUE.
CALL AllocArrays (InitInp, P, x, xd, z, m, y, 'ElPrint')
!-------------------------------------------------------------------------------
------------------
! Initialize Beddoes dynamic stall data
!-------------------------------------------------------------------------------
------------------
IF ( p%DStall ) CALL BEDDAT( P, x, xd, z, m, y, ErrStat, ErrMess )
RETURN
contains
SUBROUTINE CleanUp()
CLOSE(UnIn)
! Local Variables:
INTEGER :: IElm
INTEGER :: IFoil
INTEGER :: UnOut
INTEGER :: I,K
INTEGER(IntKi) :: ErrStatLcl
CHARACTER( 2) :: Dst_Unit
CHARACTER(150) :: Frmt
CHARACTER( 4) :: Mass_Unit
CHARACTER( 35) :: MESAGE
CHARACTER( 3) :: Vel_Unit
ErrStat = ErrID_None
ErrMess = ""
! Function definition
CALL GetNewUnit( UnOut, ErrStat, ErrMess )
CALL OpenFOutFile( UnOut, FileName, ErrStatLcl, ErrMessLcl)
CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,'ADOut' )
IF ( ErrStat >= AbortErrLev ) THEN
CLOSE(UnOut)
RETURN
END IF
IF (p%SIUNIT) THEN
Dst_Unit = 'm'
Mass_Unit = 'kg'
Vel_Unit = 'mps'
ELSE
Dst_Unit = 'ft'
Mass_Unit = 'slug'
Vel_Unit = 'fps'
ENDIF
! Ec_Ch11Frmt is a parameter defined for echo output in the NWTC Subroutine Library
MESAGE = 'Units for input and output'
IF ( p%SIUNIT ) THEN
WRITE(UnOut,Ec_Ch11Frmt) 'SI','SysUnits',MESAGE
ELSE
WRITE(UnOut,Ec_Ch11Frmt) 'ENGLISH','SysUnits',MESAGE
ENDIF
IF ( p%TwrProps%PJM_Version ) THEN
WRITE(UnOut,Ec_LgFrmt) p%TwrProps%TwrPotent,'TwrPotent','Calculate tower
potential flow [T or F]'
WRITE(UnOut,Ec_LgFrmt) p%TwrProps%TwrShadow,'TwrShadow','Calculate tower shadow
[T or F]'
IF ( p%TwrProps%TwrPotent .OR. p%TwrProps%TwrShadow ) THEN
WRITE(UnOut,Ec_StrFrmt) 'TwrFile','Tower drag file name',TRIM(P%TwrProps
%TwrFile)
ELSE
WRITE(UnOut,Ec_Ch11Frmt) '[none]','TwrFile','No tower drag properties file'
ENDIF
ELSE
WRITE(UnOut,Ec_ReFrmt) p%TwrProps%TwrShad,'TwrShad','Tower shadow centerline
velocity deficit'
WRITE(UnOut,Ec_ReFrmt) p%TwrProps%ShadHWid,'ShadHWid','Tower shadow half width,
'//TRIM(Dst_Unit)
WRITE(UnOut,Ec_ReFrmt) p%TwrProps%T_Shad_Refpt,'T_Shad_Refpt','Tower shadow
reference point, '//TRIM(Dst_Unit)
END IF
DO IFoil = 1, p%AirFoil%NUMFOIL
WRITE(UnOut,'(A)') '"'//TRIM(p%AirFoil%FOILNM(IFoil))//'"'
END DO ! IFoil
!-------------------------------------------------------------------------------
------------------
! write out element information
!-------------------------------------------------------------------------------
------------------
Frmt = '(3X,A10,8("'//Delim//'",A10))'
WRITE(UnOut,'( )')
! column names
! column data
Frmt = '(3X, I10, 4("'//Delim//'",F10.5),"'//Delim//'",I10,"'//Delim//'",A10,
2("'//Delim//'",F10.5) )'
DO IElm = 1, p%Element%NELM
IF (m%ElOut%ElPrList(IElm) /= 0) THEN
MESAGE = 'Yes'
ELSE
MESAGE = 'No'
ENDIF
IF ( p%MultiTab ) THEN
WRITE(UnOut,'(A)') 'MULTI Multiple airfoil tables used'
ELSE
WRITE(UnOut,'( )')
ENDIF
IF ( p%DSTALL ) THEN
Frmt = '(3X,A, 21(:F8.4,3X) )'
DO K = 1, P%AirFoil%NTables(1)
WRITE(UnOut,'(/A/)') ' BEDDOES DYNAMIC STALL PARAMETERS:'
WRITE(UnOut, Frmt) 'CN SLOPE ', ( m%Beddoes%CNA(I,K), I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut, Frmt) 'STALL CN (UPPER) ', ( m%Beddoes%CNS(I,K), I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut, Frmt) 'STALL CN (LOWER) ', ( m%Beddoes%CNSL(I,K), I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut, Frmt) 'ZERO LIFT AOA ', ( m%Beddoes%AOL(I,K)*R2D, I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut, Frmt) 'MIN DRAG AOA ', ( m%Beddoes%AOD(I,K)*R2D, I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut, Frmt) 'MIN DRAG COEFF ', ( m%Beddoes%CDO(I,K), I = 1, P
%AirFoil%NUMFOIL )
WRITE(UnOut,'(/)')
ENDDO !K
CLOSE (UnOut )
RETURN
END SUBROUTINE ADOut
! ****************************************************
SUBROUTINE READFL(InitInp, P, x, xd, z, m, y, ErrStat, ErrMess )
! Reads a data file containing airfoil angle of attack,
! CL and CD, and dynamic stall parameters
! ****************************************************
!
===================================================================================
=================
USE AeroGenSubs, ONLY: AllocArrays
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_InitInputType), INTENT(INOUT) :: InitInp
TYPE(AD14_ParameterType), INTENT(INOUT) :: p ! Parameters
TYPE(AD14_ContinuousStateType), INTENT(INOUT) :: x ! Initial
continuous states
TYPE(AD14_DiscreteStateType), INTENT(INOUT) :: xd ! Initial discrete
states
TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Initial guess of
the constraint states
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Initial system
outputs (outputs are not calculated;
INTEGER(IntKi), INTENT( OUT) :: ErrStat
CHARACTER(*), INTENT( OUT) :: ErrMess
! Local Variables:
INTEGER :: IPHI
INTEGER :: I
INTEGER :: K
INTEGER :: Sttus
INTEGER :: NFOILID
INTEGER :: NumLines
INTEGER :: NUNIT
INTEGER :: IOS
LOGICAL :: ALPosPI
LOGICAL :: ALNegPI
ErrStat = ErrID_None
ErrMess = ""
! The first loop checks existence and file length to set NumCL
DO NFOILID = 1, p%AirFoil%NUMFOIL
NumLines = 0
IOS = 0
DO WHILE (IOS == 0)
READ ( NUNIT, '()', IOSTAT=IOS )
NumLines = NumLines + 1
END DO
CLOSE (NUNIT)
END DO ! NFOILID
Sttus = 0
IF (.NOT. ALLOCATED(CLPosPI)) THEN
ALLOCATE ( CLPosPI(P%AirFoil%NTables(NFOILID)) , STAT=Sttus )
IF ( Sttus /= 0 ) THEN
CALL SetErrStat( ErrID_Fatal, ' Error allocating memory for CLPosPI
array.', ErrStat, ErrMess, 'READFL' )
close(NUNIT)
RETURN
END IF
END IF
p%AirFoil%NLIFT(NFOILID) = 0
ALPosPI = .FALSE.
ALNegPI = .FALSE.
DO I = 1, p%AirFoil%NumCL
IF ( p%PMOMENT ) THEN
ELSE
m%AirFoil%CM(NFOILID,I,:) = 0.
ENDIF
DO IPHI = 1, p%AirFoil%NTables(NFOILID)
IF ( ABS( m%AirFoil%AL( NFOILID, I ) ) > 185.) THEN
CALL SetErrStat( ErrID_Fatal, 'Probable error in airfoil data table
number '//TRIM(Int2LStr(NFOILID))// &
' Angle of attack exceeds 185 degrees.', ErrStat,
ErrMess, 'READFL')
CLOSE(NUNIT)
RETURN
ENDIF
ENDDO ! IPHI
! Store the values at 180 deg. and -180 deg. for check
IF ( m%AirFoil%AL (NFOILID, I ) == 180. ) THEN
ALPosPI = .TRUE.
Do IPHI = 1, p%AirFoil%NTables(NFOILID)
CLPosPI(IPHI) = m%AirFoil%CL(NFOILID,I,IPHI)
CDPosPI(IPHI) = m%AirFoil%CD(NFOILID,I,IPHI)
CMPosPI(IPHI) = m%AirFoil%CM(NFOILID,I,IPHI)
END Do ! IPHI
ENDDO ! I
END DO !NUMFOIL
RETURN
RETURN
END SUBROUTINE READFL
! ****************************************************
SUBROUTINE READTwr(UnIn, InitInp, P, x, xd, z, m, y, ErrStat, ErrMess )
! This subroutine reads the tower properties input file, allocating TwrProps
variables to do so.
! The tower data file contains radius and Re vs CD data as well as the tower wake
constant.
! ****************************************************
!
===================================================================================
=================
IMPLICIT NONE
! Passed Variables:
INTEGER, INTENT(IN) :: UnIn
TYPE(AD14_InitInputType), INTENT(INOUT) :: InitInp
TYPE(AD14_ParameterType), INTENT(INOUT) :: p ! Parameters
TYPE(AD14_ContinuousStateType), INTENT(INOUT) :: x ! Initial
continuous states
TYPE(AD14_DiscreteStateType), INTENT(INOUT) :: xd ! Initial discrete
states
TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Initial guess of
the constraint states
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Initial system
outputs (outputs are not calculated;
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Local Variables:
!-------------------------------------------------------------------------------
------------------
! Open the file for reading
!-------------------------------------------------------------------------------
------------------
FilName = p%TwrProps%TwrFile
CALL OpenFInpFile (UnIn, TRIM(FilName), ErrStat, ErrMess )
IF ( ErrStat /= ErrID_None ) RETURN
!-------------------------------------------------------------------------------
------------------
! Read the heading, section 1
!-------------------------------------------------------------------------------
------------------
! Read in constant for tower wake model = 0 full potential flow = 0.1 model
of Bak et al.
CALL ReadVar( UnIn, FilName, p%TwrProps%Tower_Wake_Constant,
'Tower_Wake_Constant', 'Constant for tower wake model', ErrStat, ErrMess )
IF ( ErrStat /= ErrID_None ) RETURN
!-------------------------------------------------------------------------------
------------------
! Allocate TwrProps arrays with NTwrHt, NTwrRe, and NTwrCD dimensions; these
arrays are
! read in the next 2 sections of this file.
!-------------------------------------------------------------------------------
------------------
!-------------------------------------------------------------------------------
------------------
! Read section 2, DISTRIBUTED TOWER PROPERTIES;
! section contains 2 heading lines in addition to NTwrHt rows of data with 3
columns
!-------------------------------------------------------------------------------
------------------
! Read in 2 header/comment lines
CALL ReadCom( UnIn, FilName, 'Distributed Tower Properties header 1', ErrStat,
ErrMess )
IF ( ErrStat /= ErrID_None ) RETURN
CALL ReadCom( UnIn, FilName, 'Distributed Tower Properties header 2', ErrStat,
ErrMess )
IF ( ErrStat /= ErrID_None ) RETURN
IF ( ErrStat == 0 ) THEN
IF ( p%Echo ) THEN
WRITE (p%UnEc,'(2X,ES11.4e2, 2X,ES11.4e2, 2X,I11)') p%TwrProps
%TwrHtFr(I), p%TwrProps%TwrWid(I), p%TwrProps%NTwrCDCol(I)
END IF
ELSE IF ( ErrStat < 0 ) THEN
CALL ProgWarn( ' Premature end of file while reading line
'//TRIM(Int2Lstr(I))// &
' of the distributed tower properties in file
"'//TRIM(FilName)//'."' )
RETURN
ELSE
CALL ProgWarn( ' Error reading line '//TRIM(Int2Lstr(I))// &
' of the distributed tower properties in file
"'//TRIM(FilName)//'."' )
RETURN
END IF
!............................................................................
..................
! Check to see if values look reasonable
!............................................................................
..................
END DO ! I
!-------------------------------------------------------------------------------
------------------
! Read section 3, Re vs CD PROPERTIES;
! this section has 2 header lines plus NTwrRe rows of data with NTwrCD+1 columns
!-------------------------------------------------------------------------------
------------------
CALL ReadCom( UnIn, FilName, 'Re vs CD Properties header 2', ErrStat, ErrMess )
IF ( ErrStat /= ErrID_None ) RETURN
Fmt = '('//TRIM(Int2Lstr(p%TwrProps%NTwrCD+1))//'(2X,ES11.4e2))'
DO I = 1, p%TwrProps%NTwrRe
IF ( ErrStat == 0 ) THEN
IF ( p%Echo ) THEN
WRITE (p%UnEc,Fmt) p%TwrProps%TwrRe(I), (p%TwrProps%TwrCD(I,J), J = 1,
p%TwrProps%NTwrCD)
END IF
ELSE IF ( ErrStat < 0 ) THEN
CALL ProgWarn( ' Premature end of file while reading line
'//TRIM(Int2Lstr(I))// &
' of the tower Re vs CD properties in file
"'//TRIM(FilName)//'."' )
RETURN
ELSE
CALL ProgWarn( ' Error reading line '//TRIM(Int2Lstr(I))// &
' of the tower Re vs CD properties in file
"'//TRIM(FilName)//'."' )
RETURN
END IF
END DO ! I
!-------------------------------------------------------------------------------
------------------
! close the file and return
!-------------------------------------------------------------------------------
------------------
CLOSE( UnIn )
RETURN
REAL(ReKi),INTENT(OUT) :: DFN
REAL(ReKi),INTENT(OUT) :: DFT
REAL(ReKi),INTENT(OUT) :: PMA
REAL(ReKi),INTENT(IN) :: PSI
REAL(ReKi),INTENT(IN) :: RLOCAL
REAL(ReKi),INTENT(IN) :: VNB
REAL(ReKi),INTENT(IN) :: VNROTOR2
REAL(ReKi),INTENT(IN) :: VNW
REAL(ReKi),INTENT(INOUT) :: VT
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
LOGICAL, INTENT(IN) :: Initial
! Local Variables:
REAL(ReKi) :: CDA
REAL(ReKi) :: CLA
REAL(ReKi) :: CMA
REAL(ReKi) :: CPHI
REAL(ReKi) :: PHI
REAL(ReKi) :: QA
REAL(ReKi) :: ReNum
REAL(ReKi) :: SPHI
REAL(ReKi) :: Vinduced
REAL(ReKi) :: VN
ErrStat = ErrID_None
ErrMess = ""
! Turn wake off when using dynamic inflow and tip speed goes low. Wake will
remain off.
IF ( P%DYNINFL ) THEN
! USE dynamic inflow model to find A
CALL VINDINF( P, m, ErrStatLcl, ErrMessLcl, &
J, IBlade, RLOCAL, VNW, VNB, VT, PSI ) !possibly changes VT,
A, and AP
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' )
IF (ErrStat >= AbortErrLev) RETURN
ELSE
! USE momentum balance to find A
CALL VIND( P, m, ErrStatLcl, ErrMessLcl, &
J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT ) !changes VT, A,
and AP
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' )
IF (ErrStat >= AbortErrLev) RETURN
! Apply skewed-wake correction, if applicable
IF( m%SKEW ) CALL VNMOD( P, m, ErrStatLcl, ErrMessLcl,&
J, IBlade, RLOCAL, PSI ) !changes A
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' )
IF (ErrStat >= AbortErrLev) RETURN
ENDIF
ELSE
! Ignore the wake calculation entirely
m%Element%A (J,IBLADE) = 0.0
m%Element%AP(J,IBLADE) = 0.0
ENDIF
ENDIF
m%Element%W2(J,IBlade) = VN * VN + VT * VT
IF ( P%DSTALL ) THEN
! USE Beddoes dynamic stall model
IF (Initial) THEN ! USE static data on first pass
CALL BEDINIT ( P, m, ErrStatLcl, ErrMessLcl, &
J, IBlade, m%Element%ALPHA(J,IBlade))
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'ELEMFRC' )
IF (ErrStat >= AbortErrLev) RETURN
IF ( P%PMOMENT ) THEN
PMA = CMA * QA * P%Blade%C(J)
ELSE
PMA = 0.
CMA = 0.
ENDIF
ENDIF
RETURN
END SUBROUTINE ELEMFRC
!======================================================
SUBROUTINE VIND( P, m, ErrStat, ErrMess, &
J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT )
! SUBROUTINE VIND( J, IBlade, RLOCAL, VNROTOR2, VNW, VNB, VT )
! calculates the axial induction factor for each
! annular segment and time step.
! ***************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN ) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization
variables
INTEGER, INTENT(IN ) :: J
INTEGER, INTENT(IN ) :: IBlade
INTEGER(IntKi), INTENT( OUT) :: ErrStat
CHARACTER(*), INTENT( OUT) :: ErrMess
! Local Variables:
REAL(ReKi) :: A2
REAL(ReKi) :: A2P
REAL(ReKi) :: AI
REAL(ReKi) :: ALPHA
REAL(ReKi) :: ASTEP
REAL(ReKi) :: ATOLER2
REAL(ReKi) :: ATOLERBY10
REAL(ReKi) :: CDA
REAL(ReKi) :: CLA
REAL(ReKi) :: CMA
REAL(ReKi) :: DAI
REAL(ReKi) :: DAI1
REAL(ReKi) :: DELAI
REAL(ReKi) :: PHI
REAL(ReKi) :: SOLFACT
REAL(ReKi) :: VNA
REAL(ReKi) :: VT2_Inv
REAL(ReKi) :: VTA
INTEGER :: ICOUNT
INTEGER :: MAXICOUNT
INTEGER :: Sttus
INTEGER(IntKi) :: ErrStatLcl
character(ErrMsgLen) :: ErrMessLcl
ErrStat = ErrID_None
ErrMess = ""
!-mlb Let's USE the old value of the A from before it was corrected for skew.
AI = m%Element%OLD_A_NS( J, IBLADE )
DAI1 = 0.05
A2P = m%Element%OLD_AP_NS( J, IBLADE )
ASTEP = 0.5
ICOUNT = 0
A2 = AI
DAI = A2 - AI
ICOUNT = ICOUNT + 1
A2 = AI
DAI = A2 - AI
EXIT
ENDIF
AI = AI + DELAI
DAI1 = DELAI
END DO
RETURN
END SUBROUTINE VIND
! ***************************************************
SUBROUTINE VINDERR( P, m, ErrStat, ErrMess, &
VNW, VX, VID, J, IBLADE )
! SUBROUTINE VINDERR( VNW, VX, VID, J, IBLADE )
! used to write warning messages to the screen
! when VN or VT is high.
! ***************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
REAL(ReKi),INTENT(IN) :: VNW
REAL(ReKi),INTENT(IN) :: VX
ErrStat = ErrID_None
ErrMess = ""
! Don't write messages if we've already done it 5 times
IF ( m%AFLAGVinderr ) RETURN
m%NERRORS = m%NERRORS + 1
RETURN
END SUBROUTINE VINDERR
! ******************************************************
SUBROUTINE AXIND (P, m, ErrStat, ErrMess, &
VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, &
A2P, J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL )
! SUBROUTINE AXIND ( VNW, VNB, VNA, VTA, VT, VT2_Inv, VNROTOR2, A2, &
! A2P, J, SOLFACT, ALPHA, PHI, CLA, CDA, CMA, RLOCAL )
! calculates a new axial induction factor from
! given values of velocities and geometry. This routine
! is called by vind as part of the iteration process
! ******************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
REAL(ReKi),INTENT(INOUT) :: A2
REAL(ReKi),INTENT(INOUT) :: A2P
REAL(ReKi),INTENT(OUT) :: ALPHA
REAL(ReKi),INTENT(OUT) :: CDA
REAL(ReKi),INTENT(OUT) :: CLA
REAL(ReKi),INTENT(OUT) :: CMA
REAL(ReKi),INTENT(OUT) :: PHI
REAL(ReKi),INTENT(IN) :: RLOCAL
REAL(ReKi),INTENT(IN) :: SOLFACT
REAL(ReKi),INTENT(OUT) :: VNA
REAL(ReKi),INTENT(IN) :: VNB
REAL(ReKi),INTENT(IN) :: VNROTOR2
REAL(ReKi),INTENT(IN) :: VNW
REAL(ReKi),INTENT(IN) :: VT
REAL(ReKi),INTENT(IN) :: VT2_Inv
REAL(ReKi),INTENT(OUT) :: VTA
INTEGER ,INTENT(IN) :: J
! Local Variables:
REAL(ReKi) :: CH
REAL(ReKi) :: CPhi
! COS( PHI )
REAL(ReKi) :: SPHI
REAL(ReKi) :: SWRLARG
REAL(ReKi) :: W2
ErrStat = ErrID_None
ErrMess = ""
! Get the tip loss values for the element (if they change)
IF (p%InducedVel%TLOSS) CALL GetTipLoss ( P, m, ErrStat, ErrMess, &
J, SPHI, m%TIPLOSS, RLOCAL)
! Get the hub loss values for the element (if they change)
IF (p%InducedVel%HLOSS) CALL GetPrandtlLoss ( P%Element%HLCNST(J), SPHI, m%HUBLOSS)
IF ( p%SWIRL ) THEN
IF ( p%InducedVel%EquilDT ) THEN ! USE PROP-PC style tangential induction
equation with the addition of the drag term.
! Because of the singularity that occurs when phi approaches zero,
! let's test for small phi and set a' equal to a small, negative number.
IF ( ( ABS( SPhi ) > 0.01 ) .AND. ( ABS( CPhi ) > 0.01 ) ) THEN
A2P = SOLFACT*( CLA*SPhi - CDA*CPhi )*( 1.0 + A2P )*VNROTOR2/( 4.0*m
%LOSS*SPhi*CPhi )
ELSEIF ( ABS( SPhi ) > 0.01 ) THEN ! Tangential velocity near zero, phi
near 90 degrees.
A2P = SOLFACT*( CLA*SPhi - CDA*SIGN( 0.01_ReKi, CPhi ) )*( 1.0 + A2P )
*VNROTOR2/( 4.0*m%LOSS*SPhi*SIGN( 0.01_ReKi, CPhi ) )
ELSE ! Normal velocity near zero, phi near 0 degrees.
A2P = SOLFACT*( CLA*SIGN( 0.01_ReKi, SPhi ) - CDA*CPhi )*( 1.0 + A2P )
*VNROTOR2/( 4.0*m%LOSS*SIGN( 0.01_ReKi, SPhi )*CPhi )
ENDIF
ELSE
SWRLARG = 1.0 + 4.0*m%LOSS*A2*VNW*VNA*VT2_Inv
IF ( SWRLARG < 0.0 ) THEN
A2P = 0.0
ELSE
A2P = 0.5*( -1.0 + SQRT( SWRLARG ) )
ENDIF
ENDIF
ELSE
A2P = 0.0
ENDIF
RETURN
END SUBROUTINE AXIND
! ***************************************************
FUNCTION GetReynolds( WindSpd, ChordLen, KinVisc )
! computes the Reynolds number for the element, divided by 1.0E6
! ***************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi),INTENT(IN) :: WindSpd
REAL(ReKi),INTENT(IN) :: ChordLen
REAL(ReKi),INTENT(IN) :: KinVisc
! function definition
REAL(ReKi) :: GetReynolds
RETURN
END FUNCTION GetReynolds
! ***************************************************
SUBROUTINE GetTipLoss( P, m, ErrStat, ErrMess, &
J, SPHI, TIPLOSS, RLOCAL )
! SUBROUTINE GetTipLoss( J, SPHI, TIPLOSS, RLOCAL )
! computes the tip loss constant for element J
! TIPLOSS is returned to AXIND
! Uses the Prandtl tip loss model with a correction
! from Georgia Tech (2002 ASME Wind Energy Symposium)
! ***************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi), INTENT(IN) :: SPHI
REAL(ReKi), INTENT(IN) :: RLOCAL
REAL(ReKi), INTENT(OUT) :: TIPLOSS
INTEGER , INTENT(IN) :: J
! Local Variables:
ErrStat = ErrID_None
ErrMess = ""
RETURN
END SUBROUTINE GetTipLoss
! ***************************************************
REAL(ReKi),INTENT(IN) :: LCnst
REAL(ReKi),INTENT(OUT) :: PrLOSS
REAL(ReKi),INTENT(IN) :: SPHI
! Local Variables:
REAL(ReKi) :: F
RETURN
END SUBROUTINE GetPrandtlLoss
!
===================================================================================
=================
SUBROUTINE GetTwrInfluence ( P, m, ErrStat, ErrMess, &
VX, VY, InputPosition)
!SUBROUTINE GetTwrInfluence (VX, VY, InputPosition)
! Computes tower shadow or dam influence on the blade
! Note that this routine assumes there are NO tower deflections.
!
! Use the Riso tower dam model of Bak, Madsen and Johansen
! This model is based on potential flow and is applicable in front of and behind
the tower,
! although in the wake we use the method of Powles
! PJM, NREL
!
! bjj, jmj: this function should return the influence parameters, which will be
based on some mean
! wind direction (or possibly the direction at the tower) for a given height,
instead of using the
! local velocity/direction so that all points on a horizontal slice of air can use
the same
! deficit at each given time. Will need the tower position, too.
!
===================================================================================
=================
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
! Local Variables:
ErrStat = ErrID_None
ErrMess = ""
!-------------------------------------------------------------------------------
------------------
! This subroutine is only valid for TwrPotent and TwrShadow features
!-------------------------------------------------------------------------------
------------------
IF (.NOT. p%TwrProps%TwrPotent .AND. .NOT. p%TwrProps%TwrShadow) RETURN
!-------------------------------------------------------------------------------
------------------
! Initialize some variables
!-------------------------------------------------------------------------------
------------------
ZGrnd = InputPosition(3) - p%Rotor%HH ! distance between position
and hub !BJJ: this should really be the tower height (position), not HH
V_total = SQRT( VX**2 + VY**2 ) ! total wind speed
!-------------------------------------------------------------------------------
------------------
! Tower influence calculations aren't necessary for zero velocity
!-------------------------------------------------------------------------------
------------------
IF ( V_total <= 0.0 ) RETURN
!-------------------------------------------------------------------------------
------------------
! For the current element location, get the appropriate tower properties and
calculate the
! element distance from from the tower.
! BJJ: If we're above the tower top, is the radius zero?
!-------------------------------------------------------------------------------
------------------
IF (ZGrnd < 0.0) THEN !bjj added this condition.... check that it's
correct
!bjj: what does this exactly mean? "temporarily disabled?"
IF( .NOT. m%AFLAGTwrInflu) THEN
CALL ProgWarn( ' Tower model temporarily disabled due to possible tower
strike.'// &
' This message will not be repeated though the condition
may persist.' )
!write a blank line (so FAST doesn't write over it)
CALL WrScr( ' ' )
m%AFLAGTwrInflu = .TRUE.
ENDIF
RETURN
END IF
ENDIF
!-------------------------------------------------------------------------------
------------------
! Store the wind direction for later
!-------------------------------------------------------------------------------
------------------
!-------------------------------------------------------------------------------
------------------
! Calculate the influence due to potential flow around tower based on velocity
at element
!-------------------------------------------------------------------------------
------------------
IF ( P%TwrProps%TwrPotent ) THEN
! When above the tower, smooth the transition to the free-stream
IF ( ZGrnd > 0 ) THEN
Yg = SQRT( InputPosition(2)**2 + ZGrnd**2 )
ELSE
Yg = InputPosition(2)
ENDIF
!-------------------------------------------------------------------------------
------------------
! Calculate the influence of tower shadow if user specifies and we are downwind
of the tower
!-------------------------------------------------------------------------------
------------------
IF ( P%TwrProps%TwrShadow ) THEN
IF ( angle <= PiBy2 ) THEN ! We are downwind of the tower in shadow territory
END IF
END IF !TwrShadow
!-------------------------------------------------------------------------------
------------------
! Apply the tower influence to the input wind speeds
!-------------------------------------------------------------------------------
------------------
VX_wind = WindXInf*V_total
VY_wind = WindYInf*V_total
RETURN
!
===================================================================================
=================
SUBROUTINE GetTwrSectProp ( P, m, ErrStat, ErrMess, &
InputPosition, VelHor, TwrElRad, TwrElCD )
!SUBROUTINE GetTwrSectProp (InputPosition, VelHor, TwrElRad, TwrElCD)
! Returns the tower radius and CD for the vertical location
! of the element currently being evaluated for tower influence.
!
===================================================================================
=================
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi), INTENT(IN) :: InputPosition(3) ! Location where tower
properties are desired
REAL(ReKi), INTENT(IN) :: VelHor ! The horizontal wind speed,
used to get Reynolds number, if necessary
REAL(ReKi), INTENT(OUT) :: TwrElRad ! Radius of the tower element
REAL(ReKi), INTENT(OUT) :: TwrElCD ! Drag coefficient of the tower
element
! Local Variables:
REAL(ReKi) :: P1 ! Interpolation weighting factor
REAL(ReKi) :: P2 ! Interpolation weighting factor
REAL(ReKi) :: TwrElCD1 ! Dummy variable for 2-D interpolation
REAL(ReKi) :: TwrElCD2 ! Dummy variable for 2-D interpolation
REAL(ReKi) :: TwrElHt ! Non-dimensional height of the tower
element
REAL(ReKi) :: TwrElRe ! Reynold's # of the tower element
ErrStat = ErrID_None
ErrMess = ""
!-------------------------------------------------------------------------------
------------------
! Get the tower radius, TwrElRad, by interpolating into the TwrWid(:) array
!-------------------------------------------------------------------------------
------------------
!-------------------------------------------------------------------------------
------------------
! Get the section CD, TwrElCD, by interpolating into the TwrCD(:,:) array
!-------------------------------------------------------------------------------
------------------
N2P1 = N2 + 1
P2 = MIN( MAX( (TwrElHt - p%TwrProps%TwrHtFr(N2)) / (p%TwrProps
%TwrHtFr(N2P1) - p%TwrProps%TwrHtFr(N2)), REAL(0.0, ReKi) ), REAL(1.0, ReKi) )
END IF
RETURN
END SUBROUTINE GetTwrSectProp
!
===================================================================================
=================
FUNCTION AD_WindVelocityWithDisturbance( Time, u, p, x, xd, z, m, y, ErrStat,
ErrMsg, &
InputPosition, InputVelocity )
! InputPosition, TShadC1, TShadC2,
PJM_Version )
!FUNCTION AD_WindVelocityWithDisturbance( InputPosition, TShadC1, TShadC2,
PJM_Version, LeStat )
! This function computes the (dimensional) wind velocity components at the
location InputPosition
! in the inertial frame of reference, including any tower shadow defecit.
! ** Formerly SUBROUTINE VEL and later SUBROUTINE VWrel2G( VNRotor2, At_Hub ) **
!----------------------------------------------------------------------------------
------------------
IMPLICIT NONE
! Passed Variables:
REAL(ReKi),INTENT(IN) :: InputPosition(3) !
REAL(ReKi),INTENT(IN) :: InputVelocity(3) ! undisturbed
velocity
! REAL(ReKi),INTENT(IN) :: TShadC1
! REAL(ReKi),INTENT(IN) :: TShadC2
! LOGICAL,INTENT(IN) :: PJM_Version
! function definition
REAL(ReKi) :: AD_WindVelocityWithDisturbance(3)
! Local variables
! INTEGER :: Sttus
! INTEGER :: TmpErrStat
! CHARACTER(ErrMsgLen) :: TmpErrMsg
ErrStat = ErrID_None
ErrMsg = ""
AD_WindVelocityWithDisturbance(:) = InputVelocity
IF ( p%TwrProps%PJM_Version ) THEN
! Bypass tower shadow for zero horizontal wind, check U-component first
to save time.
IF ( angle <= PiBy2 ) THEN ! Skip cases where we are upwind of the
tower -- bjj: DOES THIS ACTUALLY WORK? WHAT ABOUT
radius = SQRT( InputPosition(1)**2 + InputPosition(2)**2 )
! bjj: shouldn't this be relative to the hub position?
AD_WindVelocityWithDisturbance(1:2) =
AD_WindVelocityWithDisturbance(1:2) * ( 1. - shadow )
END IF
RETURN
!
===================================================================================
=================
SUBROUTINE DiskVel ( Time, P, m, AvgInfVel, ErrStat, ErrMess )
! SUBROUTINE DiskVel
! calculates the mean velocities relative to the rotor disk
! calls routine to get wind velocity at a specified location
!
! Updated on 08/12/97 xyz-direction changed
! Combined VELD and GETSKEW 04/24/01
! Updated 12/1/09 to use new inflow module; WindInf_ADhack_diskVel MUST be
replaced!
! ********************************************
IMPLICIT NONE
! Passed Variables:
REAL(DbKi), INTENT(IN) :: Time
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization
variables
REAL(ReKi), INTENT(IN) :: AvgInfVel(3) !some sort of
averaged wind speed (currently depends on wind file type)
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
REAL(ReKi) :: Vinplane
REAL(ReKi) :: VXY
ErrStat = ErrID_None
ErrMess = ""
ENDIF
RETURN
END SUBROUTINE DiskVel
!=======================================================================
SUBROUTINE TwrAeroLoads ( p, Node, NodeDCMGbl, NodeVelGbl, NodeWindVelGbl,
NodeFrcGbl )
! This routine calcualtes the aeroynamic loads of all tower nodes above the
mean sea level.
! It doesn't worry about whether or not a node is below water. The aero
loads will be far less than the hydro loads.
IMPLICIT NONE
! Arguments:
! Local variables.
IndLo = 1
!MLB: Why have two different calls? Can't the second accommodate the first? Is
the first method more efficient than the second method if there is only one Cd
column?
!MLB: This logic was stolen from AeroSubs.f90\GetTwrSectProp().
NodeFrcLcl(1) = 0.5*TwrNodeCd*p%Wind%Rho*p%TwrProps
%TwrNodeWidth(Node)*RelNmlWndSpd*NodeVelRelLcl(1)
NodeFrcLcl(2) = 0.5*TwrNodeCd*p%Wind%Rho*p%TwrProps
%TwrNodeWidth(Node)*RelNmlWndSpd*NodeVelRelLcl(2)
NodeFrcLcl(3) = 0.0
RETURN
! ****************************************
SUBROUTINE VNMOD( P, m, ErrStat, ErrMess, &
J, IBlade, RLOCAL, PSI )
! SUBROUTINE VNMOD( J, IBlade, RLOCAL, PSI )
! applies the skewed wake correction
! to the axial induction factor A.
! ****************************************
!USE Blade
!USE Element
!USE Wind
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(IN) :: PSI
REAL(ReKi),INTENT(IN) :: RLOCAL
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
! Local Variables:
REAL(ReKi) :: BB
REAL(ReKi) :: SANG
ErrStat = ErrID_None
ErrMess = ""
RETURN
END SUBROUTINE VNMOD
! **********************************************************
SUBROUTINE BEDINIT( P, m, ErrStat, ErrMess, &
J, IBlade, ALPHA )
! SUBROUTINE BEDINIT( J, IBlade, ALPHA )
! calculates initial values of Beddoes 'f' arrays
! **********************************************************
!USE Airfoil
!USE Beddoes
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(INOUT) :: ALPHA
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
! Local Variables:
REAL(ReKi) :: AOL1
REAL(ReKi) :: CNA1
REAL(ReKi) :: FSPA
REAL(ReKi) :: FSPB
REAL(ReKi) :: FSPCA
REAL(ReKi) :: FSPCB
REAL(ReKi) :: P0
REAL(ReKi) :: P1
REAL(ReKi) :: P2
REAL(ReKi) :: SRFP
REAL(ReKi) :: TEMP
INTEGER :: I
INTEGER :: I1
INTEGER :: I1P1
INTEGER :: I2
INTEGER :: I2P1
INTEGER :: N
INTEGER :: NP1
ErrStat = ErrID_None
ErrMess = ""
m%Beddoes%ANE(J,IBLADE) = ALPHA
m%Beddoes%AFE(J,IBLADE) = ALPHA
I = P%AirFoil%NFOIL(J)
IF (N == 0 ) THEN
CNA1 = m%Beddoes%CNA(I,1)
AOL1 = m%Beddoes%AOL(I,1)
ELSE IF( N == P%AirFoil%NTables(I) ) THEN
CNA1 = m%Beddoes%CNA(I,N)
AOL1 = m%Beddoes%AOL(I,N)
ELSE
NP1 = N+1
P0 = (m%AirFoil%MulTabLoc-P%AirFoil%MulTabMet(I,N))/(P%AirFoil
%MulTabMet(I,NP1)-P%AirFoil%MulTabMet(I,N))
CNA1 = m%Beddoes%CNA(I,N) + P0 * ( m%Beddoes%CNA(I,NP1) - m%Beddoes%CNA(I,N)
)
AOL1 = m%Beddoes%AOL(I,N) + P0 * ( m%Beddoes%AOL(I,NP1) - m%Beddoes%AOL(I,N)
)
END IF
ELSE
CNA1 = m%Beddoes%CNA(I,1)
AOL1 = m%Beddoes%AOL(I,1)
ENDIF
IF ( I1 == 0 ) THEN
I1 = 1
I1P1 = 2
P1 = 0.0
ELSEIF ( I1 == P%AirFoil%NLIFT(I) ) THEN
I1P1 = I1
I1 = I1 - 1
P1 = 1.0
ELSE
I1P1 = I1 + 1
!bjj: check for division by zero?
P1 = ( m%AirFoil%AL(I,I1) - ALPHA ) / ( m%AirFoil%AL(I,I1) - m%AirFoil
%AL(I,I1P1) )
ENDIF
IF ( I2 == 0 ) THEN
I2P1 = 2
I2 = 1
P2 = 0.0
ELSE IF( I2 == P%AirFoil%NTables(I) ) THEN
I2P1 = I2
I2 = I2 - 1
P2 = 1.0
ELSE
I2P1 = I2 + 1
P2 = (m%AirFoil%MulTabLoc-P%AirFoil%MulTabMet(I,I2))/(P%AirFoil
%MulTabMet(I,I2P1)-P%AirFoil%MulTabMet(I,I2))
ENDIF
ELSE
ENDIF
m%Beddoes%FSP(J,IBLADE) = 1.0
m%Beddoes%FSPC(J,IBLADE) = 1.0
ELSE
TEMP = 2.*SQRT(ABS(m%Beddoes%FSP(J,IBLADE)/(m%Beddoes%AFE(J,IBLADE)-AOL1)))-1.
m%Beddoes%FSP(J,IBLADE) = TEMP * TEMP * SIGN ( 1.0_ReKi, TEMP )
IF ( m%Beddoes%FSP(J,IBLADE) > 1.0 ) m%Beddoes%FSP(J,IBLADE) = 1.0
IF ( m%Beddoes%FSP(J,IBLADE) < -1.0 ) m%Beddoes%FSP(J,IBLADE) = -1.0
ENDIF
RETURN
END SUBROUTINE BEDINIT
! *****************************************************
SUBROUTINE BedUpdate( m )
! Update old Beddoes parameters at new time step
! *****************************************************
!USE Beddoes
IMPLICIT NONE
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
m%Beddoes%ANE1 = m%Beddoes%ANE
m%Beddoes%ADOT1 = m%Beddoes%ADOT
m%Beddoes%OLDXN = m%Beddoes%XN
m%Beddoes%OLDYN = m%Beddoes%YN
m%Beddoes%CNPOT1 = m%Beddoes%CNPOT
m%Beddoes%OLDDPP = m%Beddoes%DPP
m%Beddoes%FSP1 = m%Beddoes%FSP
m%Beddoes%FSPC1 = m%Beddoes%FSPC
m%Beddoes%OLDTAU = m%Beddoes%TAU
m%Beddoes%OLDDF = m%Beddoes%DF
m%Beddoes%OLDDFC = m%Beddoes%DFC
m%Beddoes%OLDDN = m%Beddoes%DN
m%Beddoes%OLDCNV = m%Beddoes%CNV
m%Beddoes%CVN1 = m%Beddoes%CVN
m%Beddoes%CNP1 = m%Beddoes%CNP
m%Beddoes%CNPD1 = m%Beddoes%CNPD
m%Beddoes%OLDSEP = m%Beddoes%BEDSEP
m%Beddoes%QX1 = m%Beddoes%QX
m%Beddoes%OLDDQ = m%Beddoes%DQ
m%Beddoes%AFE1 = m%Beddoes%AFE
m%Beddoes%DQP1 = m%Beddoes%DQP
m%Beddoes%DFAFE1 = m%Beddoes%DFAFE
RETURN
END SUBROUTINE BedUpdate
! *****************************************************
SUBROUTINE BEDDAT ( P, x, xd, z, m, y, ErrStat, ErrMess )
! USED TO INPUT PARAMETERS FOR THE
! Beddoes DYNAMIC STALL MODEL
! *****************************************************
!USE Airfoil
!USE Beddoes
!USE Switch
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(INOUT) :: p ! Parameters
TYPE(AD14_ContinuousStateType), INTENT(INOUT) :: x ! Initial
continuous states
TYPE(AD14_DiscreteStateType), INTENT(INOUT) :: xd ! Initial discrete
states
TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Initial guess of
the constraint states
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Initial system
outputs (outputs are not calculated;
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Local Variables:
REAL(ReKi) :: ETA
REAL(ReKi) :: CA
REAL(ReKi) :: SA
INTEGER :: I
INTEGER :: J
INTEGER :: K
ErrStat = ErrID_None
ErrMess = ""
P%Beddoes%TVL = 11.0
P%Beddoes%TP = 1.7
P%Beddoes%TV = 6.0
P%Beddoes%TF = 3.0
ETA = .99 !bjj: this doesn't seem to be used for anything....
IF ( P%SIUNIT ) THEN
! SI UNITS--m/sec
P%Beddoes%AS = 335.
ELSE
! ENGLISH UNITS--ft/sec
P%Beddoes%AS = 1100.
ENDIF
DO J =1,P%AirFoil%NUMFOIL
DO K =1,P%AirFoil%NTables(J)
DO I = 1, P%AirFoil%NLIFT(J)
CA = COS( m%AirFoil%AL(J,I) )
SA = SIN( m%AirFoil%AL(J,I) )
m%Beddoes%CN = m%AirFoil%CL(J,I,K) * CA + ( m%AirFoil%CD(J,I,K) - m
%Beddoes%CDO(J,K) ) * SA
m%Beddoes%CC = m%AirFoil%CL(J,I,K) * SA - ( m%AirFoil%CD(J,I,K) - m
%Beddoes%CDO(J,K) ) * CA
END DO !I
END DO !K
END DO !J
m%Beddoes%VOR = .FALSE.
m%Beddoes%SHIFT = .FALSE.
m%Beddoes%BEDSEP = .FALSE.
m%Beddoes%ANE1 = 0.
m%Beddoes%OLDCNV = 0.
m%Beddoes%CVN1 = 0.
m%Beddoes%CNPOT1 = 0.
m%Beddoes%CNP1 = 0.
m%Beddoes%CNPD1 = 0.
m%Beddoes%OLDDF = 0.
m%Beddoes%OLDDFC = 0.
m%Beddoes%OLDDPP = 0.
m%Beddoes%FSP1 = 0.
m%Beddoes%FSPC1 = 0.
m%Beddoes%TAU = 0.
m%Beddoes%OLDTAU = 0.
m%Beddoes%OLDXN = 0.
m%Beddoes%OLDYN = 0.
RETURN
END SUBROUTINE BEDDAT
! ******************************************************
SUBROUTINE BeddoesModel( P, m, ErrStat, ErrMess, &
W2, J, IBlade, ALPHA, CLA, CDA ,CMA )
! uses the Beddoes dynamic stall model
! the routine is entered with an angle of attack
! and returns CL, CD, and CM.
! This routine is used regardless of whether the element
! is actually in dynamic stall state.
!
! VARIABLES:
! W2 = Relative velocity squared over blade element
! J = Index which identifies the blade element
! ALPHA = Angle of attack in radians
! CLA = Lift coeff. which is calculated by the routine
! CDA = Drag coeff. which is calculated by the routine
! CMA = Moment coeff. which is calculated by the routine
! ******************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(IN) :: ALPHA
REAL(ReKi),INTENT(OUT) :: CDA
REAL(ReKi),INTENT(OUT) :: CLA
REAL(ReKi),INTENT(OUT) :: CMA
REAL(ReKi),INTENT(IN) :: W2
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
! Local Variables:
REAL(ReKi) :: AE
REAL(ReKi) :: AOD1
REAL(ReKi) :: AOL1
REAL(ReKi) :: CA
REAL(ReKi) :: CDO1
REAL(ReKi) :: CNA1
REAL(ReKi) :: CNS1
REAL(ReKi) :: CNSL1
REAL(ReKi) :: P1
REAL(ReKi) :: SA
REAL(ReKi) :: VREL
INTEGER :: I
INTEGER :: N
INTEGER :: NP1
ErrStat = ErrID_None
ErrMess = ""
! Check to see if element has multiple airfoil tables, then interpolate values
! of constants based on the current location.
I = P%AirFoil%NFOIL(J)
IF ( N == 0 ) THEN
CNA1 = m%Beddoes%CNA( I,1)
AOL1 = m%Beddoes%AOL( I,1)
CNS1 = m%Beddoes%CNS( I,1)
CNSL1 = m%Beddoes%CNSL(I,1)
AOD1 = m%Beddoes%AOD( I,1)
CDO1 = m%Beddoes%CDO( I,1)
ELSE IF ( N == P%AirFoil%NTables(I) ) THEN
CNA1 = m%Beddoes%CNA( I,N)
AOL1 = m%Beddoes%AOL( I,N)
CNS1 = m%Beddoes%CNS( I,N)
CNSL1 = m%Beddoes%CNSL(I,N)
AOD1 = m%Beddoes%AOD( I,N)
CDO1 = m%Beddoes%CDO( I,N)
ELSE
NP1 = N+1
!bjj: check for division by zero?
P1 = (m%AirFoil%MulTabLoc-P%AirFoil%MulTabMet(I,N))/(P%AirFoil
%MulTabMet(I,NP1)-P%AirFoil%MulTabMet(I,N))
ELSE
CNA1 = m%Beddoes%CNA(I,1)
AOL1 = m%Beddoes%AOL(I,1)
CNS1 = m%Beddoes%CNS(I,1)
CNSL1 = m%Beddoes%CNSL(I,1)
AOD1 = m%Beddoes%AOD(I,1)
CDO1 = m%Beddoes%CDO(I,1)
ENDIF
m%Beddoes%AN = ALPHA
VREL = SQRT( W2 )
CA = COS( m%Beddoes%AN )
SA = SIN( m%Beddoes%AN )
CLA = m%Beddoes%CN * CA + m%Beddoes%CC * SA
CDA = m%Beddoes%CN * SA - m%Beddoes%CC * CA + CDO1
CMA = m%AirFoil%PMC
RETURN
END SUBROUTINE BeddoesModel
! ******************************************************
SUBROUTINE ATTACH( P, m, ErrStat, ErrMess, &
VREL, J, IBlade, CNA1, AOL1, AE )
! PART OF THE Beddoes DYNAMIC STALL MODEL.
! ******************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization
variables
INTEGER(IntKi), INTENT( OUT) :: ErrStat
CHARACTER(*), INTENT( OUT) :: ErrMess
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
! Local Variables:
REAL(ReKi) :: B2
REAL(ReKi) :: BS
REAL(ReKi) :: CNI
REAL(ReKi) :: CNQ
REAL(ReKi) :: CO
REAL(ReKi) :: DA
REAL(ReKi) :: PRP
REAL(ReKi) :: X0
REAL(ReKi) :: XKA
REAL(ReKi) :: XM
ErrStat = ErrID_None
ErrMess = ""
XM = VREL / p%Beddoes%AS
B2 = 1.0 - XM * XM
m%Beddoes%DS = 2. * m%DT * VREL/p%Blade%C(J)
BS = B2 * m%Beddoes%DS
XKA = .75/( ( 1. - XM ) + PI * B2 * XM * XM * 0.413 )
X0 = m%DT * p%Beddoes%AS / p%Blade%C(J) / XKA
CO = XKA * p%Blade%C(J) / p%Beddoes%AS / XM
DA = m%Beddoes%ANE(J,IBLADE) - m%Beddoes%ANE1(J,IBLADE)
m%Beddoes%ADOT(J,IBLADE) = DA / m%DT
m%Beddoes%XN(J,IBLADE) = m%Beddoes%OLDXN(J,IBLADE)*EXP(-.14*BS) + .
3*DA*EXP(-.07*BS)
m%Beddoes%YN(J,IBLADE) = m%Beddoes%OLDYN(J,IBLADE)*EXP(-.53*BS) + .
7*DA*EXP(-.265*BS)
RETURN
END SUBROUTINE ATTACH
! ******************************************************
SUBROUTINE SEPAR( P, m, ErrStat, ErrMess, &
NFT, J, IBlade, IFOIL, CNA1, AOL1, CNS1, CNSL1 )
! SUBROUTINE SEPAR( NFT, J, IBlade, IFOIL, CNA1, AOL1, CNS1, CNSL1 )
! PART OF THE Beddoes DYNAMIC STALL MODEL
! ******************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
REAL(ReKi),INTENT(IN) :: AOL1
REAL(ReKi),INTENT(IN) :: CNA1
REAL(ReKi),INTENT(IN) :: CNS1
REAL(ReKi),INTENT(IN) :: CNSL1
! Local Variables:
REAL(ReKi) :: AFEP
REAL(ReKi) :: AFF
REAL(ReKi) :: CMPA
REAL(ReKi) :: CMPB
REAL(ReKi) :: FSPA
REAL(ReKi) :: FSPB
REAL(ReKi) :: FSPCA
REAL(ReKi) :: FSPCB
REAL(ReKi) :: P1
REAL(ReKi) :: P2
REAL(ReKi) :: SRFP
REAL(ReKi) :: SRFPC
REAL(ReKi) :: TEMP
REAL(ReKi) :: TFE
INTEGER :: I1
INTEGER :: I1P1
INTEGER :: I2
INTEGER :: I2P1
ErrStat = ErrID_None
ErrMess = ""
TFE = p%Beddoes%TF
m%Beddoes%DPP(J,IBLADE) = m%Beddoes%OLDDPP(J,IBLADE) * EXP(-m%Beddoes%DS/P
%Beddoes%TP) &
+ ( m%Beddoes%CNPOT(J,IBLADE) - m%Beddoes%CNPOT1(J,IBLADE) ) *
EXP(-.5*m%Beddoes%DS/P%Beddoes%TP)
m%Beddoes%CNP(J,IBLADE) = m%Beddoes%CNPOT(J,IBLADE) - m%Beddoes%DPP(J,IBLADE)
m%Beddoes%CNPD(J,IBLADE) = m%Beddoes%CNP(J,IBLADE) - m%Beddoes%CNP1(J,IBLADE)
IF (I1 == 0) THEN
I1 = 1
ELSE IF ( I1 == NFT ) THEN
I1 = I1 - 1
END IF
I1P1 = I1 + 1
IF ( I2 == 0 ) THEN
I2 = 1
I2P1 = 2
P2 = 0.0
ELSE IF ( I2 == p%AirFoil%NTables(IFOIL) ) THEN
I2P1 = I2
I2 = I2 - 1
P2 = 1.0
ELSE
I2P1 = I2 + 1
P2=(m%AirFoil%MulTabLoc-p%AirFoil%MulTabMet(IFOIL,I2))/(p%AirFoil
%MulTabMet(IFOIL,I2P1)-p%AirFoil%MulTabMet(IFOIL,I2))
END IF
ELSE
ENDIF
ENDIF
AFEP=m%Beddoes%AFE(J,IBLADE) - m%Beddoes%DFAFE(J,IBLADE)
IF (I1 == 0) THEN
I1 = 1
I1P1 = 2
P1 = 0.0
ELSEIF ( I1 == NFT ) THEN
I1P1 = I1
I1 = I1 - 1
P1 = 1.0
ELSE
I1P1 = I1 + 1
P1 = (m%AirFoil%AL(IFOIL,I1) - AFEP)/(m%AirFoil%AL(IFOIL,I1) - m%AirFoil
%AL(IFOIL,I1P1))
END IF
ELSE
ENDIF
RETURN
END SUBROUTINE SEPAR
! ******************************************************
SUBROUTINE VORTEX( P, m, ErrStat, ErrMess, &
J, IBlade, AE )
! PART OF THE Beddoes DYNAMIC STALL MODEL
! ******************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(IN) :: AE
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
! Local Variables:
REAL(ReKi) :: CMV
REAL(ReKi) :: TSH
REAL(ReKi) :: TVE
ErrStat = ErrID_None
ErrMess = ""
TVE = P%Beddoes%TV
m%Beddoes%CVN(J,IBLADE) = m%Beddoes%CNCP * ( 1. - m%Beddoes%FK )
IF (m%Beddoes%VOR) THEN
m%Beddoes%CNV(J,IBLADE) = m%Beddoes%OLDCNV(J,IBLADE) * EXP(-m%Beddoes%DS/TVE) &
+ (m%Beddoes%CVN(J,IBLADE) - m%Beddoes%CVN1(J,IBLADE)) * EXP(-.5*m
%Beddoes%DS/TVE)
ELSE
m%Beddoes%CNV(J,IBLADE) = m%Beddoes%OLDCNV(J,IBLADE) * EXP(-m%Beddoes%DS/
(TVE*.5))
ENDIF
ELSE
RETURN
END SUBROUTINE VORTEX
! ******************************************************
SUBROUTINE CLCD( P, m, ErrStat, ErrMess, &
ALPHA, CLA, CDA, CMA, I )
! SUBROUTINE CLCD( ALPHA, CLA, CDA, CMA, I, ErrStat )
! returns values of lift and drag coeffs.
! This subroutine interpolates airfoil coefficients
! from a table of airfoil data. The table must consist
! of ALPHA, CL and CD over the entire range of angles
! that will be encountered.
!
! VARIABLES:
! CLA = Returned value of lift coefficient
! CDA = Returned value of drag coeff
! CMA = Returned value of pitching moment coeff
! ALPHA = Angle of attack (radians)
! AL = Array containing the angle of attack
! CL = Array containing the lift coeffs. at AL(I)
! CD = Array containing the drag coeffs. at AL(I)
! CM = Array containing the moment coeffs. at AL(I)
! I = Airfoil ID for this element, equal to NFoil(J), where J is the
index identifying the blade element
! MulTabLoc= Multiple airfoil table location for this element
! MulTabMet= Array containing the multiple airfoil table metric
! ******************************************************
!USE Airfoil
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(INOUT) :: ALPHA
REAL(ReKi),INTENT(OUT) :: CDA
REAL(ReKi),INTENT(OUT) :: CLA
REAL(ReKi),INTENT(OUT) :: CMA
! Local Variables:
REAL(ReKi) :: CDA1
REAL(ReKi) :: CDA2
REAL(ReKi) :: CLA1
REAL(ReKi) :: CLA2
REAL(ReKi) :: CMA1
REAL(ReKi) :: CMA2
REAL(ReKi) :: P1
REAL(ReKi) :: P2
INTEGER :: N1
INTEGER :: N1P1
INTEGER :: N2
INTEGER :: N2P1
INTEGER :: NTAB
ErrStat = ErrID_None
ErrMess = ""
NTAB = P%AirFoil%NLIFT(I)
ErrStat = ErrID_Fatal
RETURN
ENDIF
IF (N1 == 0) THEN
N1 = 1
N1P1 = 2
P1 = 0.0
ELSEIF(N1 == NTAB) THEN
N1P1 = N1
N1 = N1 - 1
P1 = 1.0
ELSE
N1P1 = N1 + 1
P1 = ( ALPHA - m%AirFoil%AL(I, N1) )/( m%AirFoil%AL(I, N1P1) - m%AirFoil%AL(I,
N1) )
END IF
IF (N2 == 0) THEN
N2 = 1
N2P1 = 2
P2 = 0.0
ELSE IF ( N2 == P%AirFoil%NTables(I) ) THEN
N2P1 = N2
N2 = N2 - 1
P2 = 1.0
ELSE
N2P1 = N2 + 1
P2 = (m%AirFoil%MulTabLoc - P%AirFoil%MulTabMet(I,N2))/(P%AirFoil
%MulTabMet(I,N2P1)-P%AirFoil%MulTabMet(I,N2))
END IF
ELSE
ENDIF
RETURN
END SUBROUTINE CLCD
! **************************************************
FUNCTION SAT( X, VAL, SLOPE )
! AOA saturation function 02/15/98
! **************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi) :: SAT
REAL(ReKi),INTENT(IN) :: SLOPE
REAL(ReKi),INTENT(IN) :: VAL
REAL(ReKi),INTENT(IN) :: X
RETURN
END FUNCTION SAT
!
! Modified for FFWIND. Subroutine VG2ROTOR was added.
! A. Suzuki, 11/05/99.
! **************************************
IMPLICIT NONE
! Passed Variables:
REAL(DbKi), INTENT(IN) :: Time
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
INTEGER :: ErrStatLcL ! Error status
returned by called routines.
CHARACTER(ErrMsgLen) :: ErrMessLcl ! Error message
returned by called routines.
ErrStat = ErrID_None
ErrMess = ""
IF ( P%DYNINFL ) THEN
! Calculate the dynamic inflow paremeters for the new time step
IF( TIME > 1.0D0 ) THEN
CALL INFDIST(P, m, ErrStatLcl, ErrMessLcl)
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'Inflow' )
IF (ErrStat >= AbortErrLev) RETURN
END IF
ENDIF ! DYNINFL
RETURN
END SUBROUTINE Inflow
! **************************************
INTEGER, INTENT(IN) :: J
INTEGER, INTENT(IN) :: IBlade
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Local Variables:
REAL(ReKi) :: fElem
! psiBar is Suzuki's, WindPsi is Shawler's
!REAL(ReKi) :: psiBar
REAL(ReKi) :: Rzero
REAL(ReKi) :: WindPsi
INTEGER :: mode
ErrStat = ErrID_None
ErrMess = ""
IF ( P%SWIRL ) THEN
fElem = SQRT( DFN * DFN + DFT * DFT )
ELSE
fElem = DFN
ENDIF
fElem = fElem / P%Blade%R
! Save values rotor loads for USE in Newtime (to accumulate rotor loads)
DO mode = 1, P%DynInflow%MAXINFLO
m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl,
ErrMessLcl )
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'GetRM' )
IF (ErrStat >= AbortErrLev) RETURN
END DO ! mode
!+++++++++++++++++++++++++++++++++++++++++++++++++++++
!Suzuki's method
!DO mode = MaxInflo+1, maxInfl
! m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) *
COS( REAL(MRvector(mode)) * psiBar )
! m%DynInflow%RMS_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode ) *
SIN( REAL(MRvector(mode)) * psiBar )
!END DO ! mode
! Shawler's method
DO mode = p%DynInflow%MaxInflo+1, maxInfl
m%DynInflow%RMC_SAVE(IBLADE, J, mode) = fElem * XPHI( Rzero, mode, ErrStatLcl,
ErrMessLcl ) * COS( REAL(MRvector(mode)) * WindPsi )
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'GetRM' )
IF (ErrStat >= AbortErrLev) RETURN
END DO ! mode
!++++++++++++++++++++++++++++++++++++++++++++++++++++++
RETURN
END SUBROUTINE GetRM
! **************************************
!USE Blade
!USE DynInflow
!USE Element
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
INTEGER :: iblad
INTEGER :: ielem
INTEGER :: mode
ErrStat = ErrID_None
ErrMess = ""
m%DynInflow%PhiLqC = 0.
m%DynInflow%PhiLqS = 0.
DO mode = 1, maxInfl
DO iblad = 1, P%NumBl
DO ielem = 1, P%Element%NELM
m%DynInflow%PhiLqC(mode) = m%DynInflow%PhiLqC(mode) + m%DynInflow
%RMC_SAVE(iblad, ielem, mode)
IF (mode >= p%DynInflow%MaxInflo+1) &
m%DynInflow%PhiLqS(mode) = m%DynInflow%PhiLqS(mode) + m%DynInflow
%RMS_SAVE(iblad, ielem, mode)
END DO !ielem
END DO !iblad
END DO !mode
RETURN
END SUBROUTINE GetPhiLq
! *************************************************************
SUBROUTINE infinit( P, m, ErrStat, ErrMess )
! Initializes the variables in the dynamic inflow equation.
! Called only once to initialize the GDW parameters.
! *************************************************************
IMPLICIT NONE
! Local Variables:
INTEGER :: i
INTEGER :: iElem
INTEGER :: irow
INTEGER :: jBlade
INTEGER :: jcol
INTEGER :: k
INTEGER :: mode
ErrStat = ErrID_None
ErrMess = ""
! calculate and store the M-R matrices, which are used in Subroutine LMATRIX.
DO irow = 1, maxInfl
DO jcol = 1, maxInfl
m%DynInflow%MminR (irow,jcol) = MIN( MRvector(jcol) , MRvector(irow) )
m%DynInflow%MplusR (irow,jcol) = MRvector(jcol) + MRvector(irow)
m%DynInflow%MminusR(irow,jcol) = ABS( MRvector(jcol) - MRvector(irow) )
END DO !jcol
END DO !irow
! Calculate the tip speed of the rotor. This isn't constant in ADAMS.
! Thus, it will be updated at every time step in ADAMS.
m%DynInflow%TipSpeed = MAX(P%Blade%r * m%Rotor%revs, 1.0e-6_ReKi)
! A's are normalized by the normal wind speed, while Lambda's are
! mormalized by the tip speed. Make the conversion.
! xLambda_M = xLambda_M * (-VrotorX/TipSpeed)
m%DynInflow%xLambda_M = m%DynInflow%xLambda_M * v3
! Calculate the disk skew angle function using the effective disk angle
! of attack.
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Shawler - USE the single wake skew angle, squared variable means its always
positive
! and because blade azimuth position is measured using windpsi the wake skew
! is defined in the right direction relative to the oncoming wind,
! ie directly downwind.
!Suzuki:
!xKaiC = TAN( .5 * ATAN( -v2 / totalInf ) )
!xKaiS = TAN( .5 * ATAN( v1 / totalInf ) )
!xkai = TAN( .5 * SIGN( ATAN( SQRT( vplane2 ) / totalInf ), v2 ) )
!Shawler:
m%DynInflow%xkai = TAN( .5 * ATAN( SQRT( Vplane2 ) / m%DynInflow%totalInf ) )
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! To calculate the initial values of xAlpha & xBeta, get [L] matrices
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Suzuki:
!CALL LMATRIX ( m,p,xKaiC, 1 )
!CALL LMATRIX ( m,p,xKaiS, 2 )
! Shawler:
CALL LMATRIX ( m,p, 1, ErrStat, ErrMess )
IF (ErrStat /= ErrID_None) THEN
ErrMess='infinit:'//TRIM(ErrMess)
RETURN
END IF
CALL LMATRIX ( m,p, 2, ErrStat, ErrMess )
IF (ErrStat /= ErrID_None) THEN
ErrMess='infinit:'//TRIM(ErrMess)
RETURN
END IF
m%DynInflow%xBeta (i) = 0.
DO k = P%DynInflow%MaxInflo+1, maxInfl
m%DynInflow%xBeta (i) = m%DynInflow%xBeta (i) + m%DynInflow%xLsin(i,k) *
tauSin(k)
END DO !k
m%DynInflow%xBeta (i) = .5 * m%DynInflow%xBeta (i) / m%DynInflow%Vparam
END DO !i
RETURN
END SUBROUTINE infinit
! **********************************************************************
SUBROUTINE infupdt( P, m, ErrStat, ErrMess )
! INFUPDT updates the OLD variables of inflow distribution parameters.
! The program must call this subroutine before calling
! the subroutine INFDIST.
! **********************************************************************
!USE DynInflow
IMPLICIT NONE
ErrStat = ErrID_None
ErrMess = ""
!+++++++++++++++++++++++++++
!Suzuki:
!oldKaiC = xKaiC
!oldKaiS = xKaiS
!Shawler:
m%DynInflow%oldKai = m%DynInflow%xKai
!+++++++++++++++++++++++++++
m%DynInflow%old_LmdM = m%DynInflow%xLambda_M
DO i = 1, maxInfl
m%DynInflow%old_Alph(i) = m%DynInflow%xAlpha (i)
m%DynInflow%dAlph_dt(i,4) = m%DynInflow%dAlph_dt(i,3)
m%DynInflow%dAlph_dt(i,3) = m%DynInflow%dAlph_dt(i,2)
m%DynInflow%dAlph_dt(i,2) = m%DynInflow%dAlph_dt(i,1)
END DO !i
DO i = P%DynInflow%MaxInflo+1, maxInfl
m%DynInflow%old_Beta(i) = m%DynInflow%xBeta (i)
m%DynInflow%dBeta_dt(i,4) = m%DynInflow%dBeta_dt(i,3)
m%DynInflow%dBeta_dt(i,3) = m%DynInflow%dBeta_dt(i,2)
m%DynInflow%dBeta_dt(i,2) = m%DynInflow%dBeta_dt(i,1)
END DO !i
RETURN
END SUBROUTINE infupdt
! **********************************************************************
SUBROUTINE DynDebug (Time, P, x, xd, z, m, y, ErrStat, ErrMess, RHScos, RHSsin)
! Write out debugging information
! **********************************************************************
IMPLICIT NONE
REAL(DbKi), INTENT(IN) :: Time
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_ContinuousStateType), INTENT(INOUT) :: x ! Initial
continuous states
TYPE(AD14_DiscreteStateType), INTENT(INOUT) :: xd ! Initial discrete
states
TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Initial guess of
the constraint states
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Initial system
outputs (outputs are not calculated;
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
! Local Variables:
INTEGER :: i
INTEGER :: NumOut
INTEGER, PARAMETER :: UnDyn = 80
CHARACTER(50) :: Frmt
ErrStat = ErrID_None
ErrMess = ""
NumOut = maxInfl+(maxInfl-P%DynInflow%MaxInflo) + 1
IF (m%OnePassDynDbg) THEN
m%OnePassDynDbg = .FALSE.
ENDIF
ENDIF
RETURN
END SUBROUTINE DynDebug
! **********************************************************************
SUBROUTINE infdist( P, m, ErrStat, ErrMess )
! INFDIST calculates the inflow (induced flow) distribution
! parameters using Generalized Dynamic Wake Theory.
! **********************************************************************
IMPLICIT NONE
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Local Variables:
INTEGER :: i
INTEGER :: k
INTEGER :: mode
ErrStat = ErrID_None
ErrMess = ""
m%DynInflow%TipSpeed = MAX(P%Blade%r * m%Rotor%revs, 1.0e-6_ReKi) !bjj: why is
this here AND in InfInit()?
! Non-dimensional time
m%DynInflow%DTO = m%DT * m%Rotor%REVS
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Suzuki:
! Update [L_cos] and [L_sin] matrices only if 'xkai' has changed.
! Then invert [L_cos] & [L_sin] matrices.
!IF ( xKaiC /= oldKaiC ) THEN
! CALL LMATRIX ( xKaiC, 1 )
! CALL MATINV ( xLcos, xLsin, maxInfl, MaxInflo, 1 )
!ENDIF
DO i = 1, P%DynInflow%MaxInflo
m%DynInflow%dAlph_dt(i,1) = p%DynInflow%xMinv(i) * RHScos(i)
END DO !i
DO i = P%DynInflow%MaxInflo+1, maxInfl
m%DynInflow%dAlph_dt(i,1) = p%DynInflow%xMinv(i) * RHScos(i)
m%DynInflow%dBeta_dt(i,1) = p%DynInflow%xMinv(i) * RHSsin(i)
END DO !i
! Added additional output for GDW debugging - comment out for distribution
!CALL DynDebug (Time, P, x, xd, z, m, y, ErrStat, ErrMess, RHScos, RHSsin)
RETURN
END SUBROUTINE infdist
! *************************************************************
SUBROUTINE vindinf( P, m, ErrStat, ErrMess, &
iradius, iblade, rlocal, vnw, VNB, VT, psi )
! vindinf calculates the axial induction factor for each
! element position using the calculated inflow parameters.
! Called by ElemFrc for each element at a new time step.
! *************************************************************
IMPLICIT NONE
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed Variables:
REAL(ReKi),INTENT(IN) :: psi
REAL(ReKi),INTENT(IN) :: rlocal
REAL(ReKi),INTENT(IN) :: VNB
REAL(ReKi),INTENT(IN) :: vnw
REAL(ReKi),INTENT(INOUT) :: VT
! Local Variables:
REAL(ReKi) :: A2P
!Suzuki uses psiBar, Shawler - WindPsi
!REAL(ReKi) :: psibar
REAL(ReKi) :: Rzero
REAL(ReKi) :: SWRLARG
REAL(ReKi) :: Windpsi
INTEGER :: mode
m%Element%A(iRadius,iBlade) = 0.
DO mode = 1, p%DynInflow%MaxInflo
m%Element%A(iRadius,iBlade) = m%Element%A(iRadius,iBlade) &
+ xphi(Rzero,mode,ErrStatLcl, ErrMessLcl) * m%DynInflow
%xAlpha(mode)
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'vindinf' )
IF (ErrStat >= AbortErrLev) RETURN
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!Suzuki:
!DO mode = MaxInflo+1, maxInfl
! A(iRadius,iBlade) = A(iRadius,iBlade) + xphi(Rzero,mode) * &
!! & + phis(Rzero, MRvector(mode), NJvector(mode) ) *
! ( xAlpha(mode) * COS( REAL(MRvector(MODE)) * psibar ) &
! + xBeta (mode) * SIN( REAL(MRvector(MODE)) * psibar ) )
!END DO !mode
! Shawler:
DO mode = p%DynInflow%MaxInflo+1, maxInfl
m%Element%A(iRadius,iBlade) = m%Element%A(iRadius,iBlade) +
xphi(Rzero,mode,ErrStatLcl, ErrMessLcl) * &
( m%DynInflow%xAlpha(mode) * COS( REAL(MRvector(MODE)) * Windpsi ) &
+ m%DynInflow%xBeta (mode) * SIN( REAL(MRvector(MODE)) * Windpsi ) )
CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'vindinf' )
IF (ErrStat >= AbortErrLev) RETURN
END DO !mode
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ENDIF
RETURN
END SUBROUTINE vindinf
! ***********************************************************************
SUBROUTINE ABPRECOR( F, OLDF, DFDT, DT, N, N0 )
! Integrates Function F by Adams-Bashford Predictor and Adams-Moulton
! Corrector using four previous values of dF/dt.
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
INTEGER ,INTENT(IN) :: N
INTEGER ,INTENT(IN) :: N0
REAL(ReKi),INTENT(IN) :: DT
REAL(ReKi),INTENT(IN) :: DFDT ( N0:N, 4 )
REAL(ReKi),INTENT(OUT) :: F ( N0:N )
REAL(ReKi),INTENT(IN) :: OLDF ( N0:N )
! Local Variables:
REAL(ReKi) :: DFDT0
INTEGER :: I
DO I = N0, N
! Adams-Bashford Predictor
F(I) = OLDF(I) + ( 55. * DFDT(I,1) - 59. * DFDT(I,2) &
+ 37. * DFDT(I,3) - 9. * DFDT(I,4) ) * DT / 24.
! Adams-Moulton Corrector
F(I) = OLDF(I) + ( 9. * DFDT0 + 19. * DFDT(I,1) &
- 5. * DFDT(I,2) + DFDT(I,3) ) * DT / 24.
END DO !I
RETURN
END SUBROUTINE ABPRECOR
! ***********************************************************************
SUBROUTINE LMATRIX ( m, p, matrixMode,ErrStat, ErrMess)
! LMATRIX calculates the [L_***] matrix using Gamma matrix and xkai=X.
! matrixMode = 1 : Calculate [L_cos] matrix
! matrixMode = 2 : Calculate [L_sin] matrix
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m ! Misc/optimization
variables
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
INTEGER ,INTENT(IN) :: matrixMode
REAL(ReKi) :: X
! Local Variables:
REAL(ReKi) :: XM
INTEGER :: IROW
INTEGER :: JCOL
ErrStat = ErrID_None
ErrMess = ""
X = m%DynInflow%xKai
CASE DEFAULT
CALL ProgAbort( 'Value of matrixMode = '//TRIM(Int2LStr(matrixMode))//' must be
1 or 2.')
END SELECT
RETURN
END SUBROUTINE LMATRIX
! ***********************************************************************
SUBROUTINE MATINV( A0, A1, N, N0, invMode,ErrStat,ErrMsg )
! Inverts the [L_cos] and [L_sin] matrices.
! Subroutine GAUSSJ (modified) from "Numerical Recipe" is needed.
! invMode = 1 : Invert [L_cos] matrix
! invMode = 2 : Invert [L_sin] matrix
!**********************************************************************
IMPLICIT NONE
! Passed Variables:
INTEGER ,INTENT(IN) :: invMode
INTEGER ,INTENT(IN) :: N
INTEGER ,INTENT(IN) :: N0
REAL(ReKi),INTENT(INOUT) :: A0 ( N , N )
REAL(ReKi),INTENT(INOUT) :: A1 ( N0+1:N , N0+1:N )
! Local Variables:
REAL(ReKi) :: DUMMY( N-N0, N-N0 )
INTEGER :: I
INTEGER :: J
ErrStat = ErrID_None
ErrMsg = ""
CASE (1)
CALL GAUSSJ(A0,N,ErrStat,ErrMsg)
IF (ErrStat /= ErrID_None) THEN
ErrMsg = 'MATINV:'//TRIM(ErrMsg)
RETURN
END IF
CASE DEFAULT
CALL ProgAbort( 'Value of invMode = '//TRIM(Int2LStr(invMode))//' must be 1 or
2.')
IF (ErrStat >= AbortErrLev) RETURN
END SELECT
RETURN
END SUBROUTINE MATINV
! ***********************************************************************
SUBROUTINE gaussj(a,n, ErrStat, ErrMsg)
! Invert a matrix by Gauss-Jordan Method. The original source code
! from "Numerical Recipe" was slightly modified.
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
INTEGER , INTENT(IN) :: n
REAL(ReKi), INTENT(INOUT) :: a(n,n)
! Local Variables:
REAL(ReKi) :: big
REAL(ReKi) :: dum
REAL(ReKi) :: pivinv
INTEGER :: i
INTEGER :: icol
INTEGER :: indxc(NMAX)
INTEGER :: indxr(NMAX)
INTEGER :: ipiv(NMAX)
INTEGER :: irow
INTEGER :: j
INTEGER :: k
INTEGER :: l
INTEGER :: ll
ErrStat=ErrID_None
ErrMsg=""
DO j=1,n
ipiv(j)=0
END DO !j
DO i=1,n
big=0.
DO j=1,n
IF (ipiv(j) /= 1) THEN
DO k=1,n
IF (ipiv(k) == 0) THEN
IF (ABS(a(j,k)) >= big) THEN
big=ABS(a(j,k))
irow=j
icol=k
ENDIF
DO k=1,n
dum=a(k,indxr(l))
a(k,indxr(l))=a(k,indxc(l))
a(k,indxc(l))=dum
END DO !k
ENDIF
END DO !l
RETURN
END SUBROUTINE gaussj
! ***********************************************************************
FUNCTION FGAMMA( R, J, M, N )
! Calculate the GAMMA matrix. It is NOT the statistical function.
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi) :: FGAMMA
INTEGER ,INTENT(IN) :: J
INTEGER ,INTENT(IN) :: M
INTEGER ,INTENT(IN) :: N
INTEGER ,INTENT(IN) :: R
IF ( MOD(R+M,2) == 0 ) THEN
FGAMMA = (-1)**((N+J-2*R)*.5) * 2. &
* SQRT( REAL( (2*N+1) * (2*J+1) ) ) &
/ SQRT( HFUNC(M,N) * HFUNC(R,J) ) &
/ REAL( (J+N) * (J+N+2) * ((J-N)*(J-N)-1) )
ELSE IF ( ABS(J-N) == 1 ) THEN !bjj: why don't we use the pi() variable? or
PibyTwo
FGAMMA = 3.14159265 * SIGN(1., REAL(R-M) ) * .5 &
/ SQRT( HFUNC(M,N) * HFUNC(R,J) ) &
/ SQRT( REAL( (2*N+1) * (2*J+1) ) )
ELSE
FGAMMA = 0.
ENDIF
RETURN
END FUNCTION FGAMMA
! ***********************************************************************
FUNCTION HFUNC( M, N )
! Calculates the value of function H(m,n).
! Warning: This subroutine is not optimized for large m or n.
! Although H(m,n) is a well behaving function, it may
! cause math overflow, if m or n is large.
!bjj: we only call with with the MRvector and NJvector (parameter) values. This
could
! possibly increase performance if implemented differently....
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi) :: HFUNC
INTEGER ,INTENT(IN) :: M
INTEGER ,INTENT(IN) :: N
! Local Variables:
INTEGER :: NMM ! n minus M
INTEGER :: NPM ! N plus M
IF ( N <= M ) THEN
CALL ProgAbort( 'Value of N = '//TRIM(Int2LStr(N))//' must be geater than M =
'//TRIM(Int2LStr(M))//'.' )
ENDIF
NPM = N + M
NMM = N - M
RETURN
END FUNCTION HFUNC
! ***********************************************************************
INTEGER FUNCTION IDUBFACT( I )
! Calculates the double factorial of an integer I
! IDUBFACT( I ) = I!! = I*(I-2)*(I-4)*...*4*2 for I = even
! or = I*(I-2)*(I-4)*...*3*1 for I = odd
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
INTEGER ,INTENT(IN) :: I
! Local Variables:
INTEGER :: K
IF ( I >= 1 ) THEN
IDUBFACT = 1
DO K = I, 1, -2
IDUBFACT = IDUBFACT * K
END DO !K
! ***********************************************************************
FUNCTION xphi( Rzero, mode,ErrStat, ErrMsg )
! Set up the PHI coefficients. They are the results from Mathematica.
! phi(1) = sqrt( 3.) ! m=0, n=1
! phi(2) = 2*sqrt(7) (1.5 - 3.75 Rzero**2 ) / 3.! m=0, n=3
! phi(3) = sqrt( 15./ 2.) *Rzero ! m=1, n=2
! phi(4) = 4*(15/4 * Rzero - 105/16 *Rzero**3 )/sqrt(5)! m=1, n=4
! phi(5) = sqrt( 105./ 2.) / 2. *Rzero**2 ! m=2, n=3
! phi(6) = sqrt( 35.) *3. / 4. *Rzero**3 ! m=3, n=4
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi),INTENT(IN) :: Rzero
REAL(ReKi) :: xphi
RETURN
END FUNCTION xphi
!***********************************************************************
! akihiro 06/25/00
! This subroutine is not currently used, may be used in the future.
!
FUNCTION phis( Rzero, r, j )
! Calculates the PHI coefficients. This function is not used unless
! the # of inflow states is increased greater than 10 (Mode 7 and higher)
! ***********************************************************************
IMPLICIT NONE
! Passed Variables:
REAL(ReKi) :: phis
REAL(ReKi),INTENT(IN) :: Rzero
INTEGER ,INTENT(IN) :: j
INTEGER ,INTENT(IN) :: r
! Local Variables:
INTEGER :: q
phis = 0.
DO q = r, j-1, 2
phis = phis &
+ Rzero ** q * (-1.) **((q-r)/2) * REAL( idubfact(j+q) ) &
/ REAL( idubfact(q-r) * idubfact(q+r) * idubfact(j-q-1) )
END DO !q
RETURN
END FUNCTION phis
!***********************************************************
SUBROUTINE WindAzimuthZero (psi,VrotorY,VrotorZ,WindPsi)
! Subroutine added by JRS to define the zero azimuth datum in
! a wind based co-ordinate system, for USE in the dynamic inflow
! routines.
! Calculates the rotational measurement in radians
! of the resultant of two vectors, VrotorZ and VrotorY.
! VrotorZ is positive vertically upwards and negative vertically
! downwards, VrotorY is positive to the left and negative
! to the right, both when looking towards the rotor from upwind.
! Zero degrees azimuth is defined when veritically down
! and rises with a clockwise rotation.
IMPLICIT NONE
! Passed Variables:
REAL(ReKi),INTENT(IN) :: psi,VrotorY,VrotorZ
REAL(ReKi),INTENT(OUT) :: WindPsi
RETURN
END SUBROUTINE WindAzimuthZero
! ********************************************************************
!
===================================================================================
=================
SUBROUTINE CheckRComp( P, x, xd, z, m, y, ErrStat, ErrMess, &
ADFile, HubRadius, TipRadius )
! This routine checks to see if RElm(:) and DR(:) are compatible within a
millimeter;
!----------------------------------------------------------------------------------
------------------
IMPLICIT NONE
TYPE(AD14_ParameterType), INTENT(IN) :: p ! Parameters
TYPE(AD14_ContinuousStateType), INTENT(INOUT) :: x ! Initial
continuous states
TYPE(AD14_DiscreteStateType), INTENT(INOUT) :: xd ! Initial discrete
states
TYPE(AD14_ConstraintStateType), INTENT(INOUT) :: z ! Initial guess of
the constraint states
TYPE(AD14_MiscVarType), INTENT(INOUT) :: m !
Misc/optimization variables
TYPE(AD14_OutputType), INTENT(INOUT) :: y ! Initial system
outputs (outputs are not calculated;
INTEGER, INTENT(OUT) :: ErrStat
CHARACTER(*), INTENT(OUT) :: ErrMess
! Passed variables
! Local variables.
ErrStat = ErrID_None
ErrMess = ""
! Write error message since the input DR(:) are not close to the
calculated DRNodesNew(:)
ErrMess = ' Input values for DR(:) are not compatible with input RElm(:).'
CALL WrScr1(TRIM(ErrMess))
CALL WrScr( ' To make them compatible, please modify DR in the AeroDyn input
file, '// TRIM( ADFile ) //', as follows:' )
CALL WrScr1(' DR (Old) --> DR (New) ')
DO I = 1,P%Element%NElm
WRITE( DRChange, "(' ', F13.4, ' --> ', F13.4, ' ')" ) P%Blade%DR(I),
DRNodesNew(I)
CALL WrScr( DRChange )
ENDDO !I
RETURN
ENDIF
RETURN
END SUBROUTINE CheckRComp