diff --git a/modules/aerodyn/src/AirfoilInfo.f90 b/modules/aerodyn/src/AirfoilInfo.f90 index b00886b7d..bd4409c62 100644 --- a/modules/aerodyn/src/AirfoilInfo.f90 +++ b/modules/aerodyn/src/AirfoilInfo.f90 @@ -1745,12 +1745,7 @@ subroutine AFI_ComputeAirfoilCoefs1D( AOA, p, AFI_interp, errStat, errMsg, Table ! Spline interpolation of lower table based on requested AOA - - IntAFCoefs(1:s1) = CubicSplineInterpM( Alpha & - , p%Table(iTab)%Alpha & - , p%Table(iTab)%Coefs & - , p%Table(iTab)%SplineCoefs & - , ErrStat, ErrMsg ) + CALL CubicSplineInterpM( Alpha, p%Table(iTab)%Alpha, p%Table(iTab)%Coefs, p%Table(iTab)%SplineCoefs, IntAFCoefs(1:s1) ) end if AFI_interp%Cl = IntAFCoefs(p%ColCl) diff --git a/modules/hydrodyn/src/HydroDyn.txt b/modules/hydrodyn/src/HydroDyn.txt index 44d3a4826..4e8d8ae19 100644 --- a/modules/hydrodyn/src/HydroDyn.txt +++ b/modules/hydrodyn/src/HydroDyn.txt @@ -71,7 +71,7 @@ typedef HydroDyn/HydroDyn InitInputType CHARACTER(1 typedef ^ ^ LOGICAL UseInputFile - .TRUE. - "Supplied by Driver: .TRUE. if using a input file, .FALSE. if all inputs are being passed in by the caller" - typedef ^ ^ FileInfoType PassedFileData - - - "If we don't use the input file, pass everything through this" - typedef ^ ^ CHARACTER(1024) OutRootName - - - "Supplied by Driver: The name of the root file (without extension) including the full path" - -typedef ^ ^ Logical Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - +typedef ^ ^ Logical Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - typedef ^ ^ ReKi Gravity - - - "Supplied by Driver: Gravitational acceleration" "(m/s^2)" typedef ^ ^ DbKi TMax - - - "Supplied by Driver: The total simulation time" "(sec)" typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" - diff --git a/modules/hydrodyn/src/Morison.f90 b/modules/hydrodyn/src/Morison.f90 index e410f903f..fb7003e21 100644 --- a/modules/hydrodyn/src/Morison.f90 +++ b/modules/hydrodyn/src/Morison.f90 @@ -4988,8 +4988,7 @@ SUBROUTINE GetSectionHstLds_Rec( origin, pos0, k_hat, x_hat, y_hat, Sa, Sb, dSad s2 = 0.0_DbKi; end if - dFdl(1:3) = dFdl(1:3) + & - -n(:,i) * ( z1*(s2-s1) + 0.5_DbKi*(z2-z1)/s*(s2*s2-s1*s1) ) + dFdl(1:3) = dFdl(1:3) -n(:,i) * ( z1*(s2-s1) + 0.5_DbKi*(z2-z1)/s*(s2*s2-s1*s1) ) C(1) = (z2-z1)*(x2-x1)/3.0_DbKi/(s*s)*(s2**3-s1**3) + 0.5_DbKi*((z2-z1)*(x1-x0)/s+(x2-x1)*z1/s)*(s2*s2-s1*s1) + z1*(x1-x0)*(s2-s1) C(2) = (z2-z1)*(y2-y1)/3.0_DbKi/(s*s)*(s2**3-s1**3) + 0.5_DbKi*((z2-z1)*(y1-y0)/s+(y2-y1)*z1/s)*(s2*s2-s1*s1) + z1*(y1-y0)*(s2-s1) C(3) = (z2-z1)*(z2-z1)/3.0_DbKi/(s*s)*(s2**3-s1**3) + 0.5_DbKi*((z2-z1)*(z1-z0)/s+(z2-z1)*z1/s)*(s2*s2-s1*s1) + z1*(z1-z0)*(s2-s1) diff --git a/modules/moordyn/src/MoorDyn_Driver.f90 b/modules/moordyn/src/MoorDyn_Driver.f90 index 3ed23fc7c..772b46a7a 100644 --- a/modules/moordyn/src/MoorDyn_Driver.f90 +++ b/modules/moordyn/src/MoorDyn_Driver.f90 @@ -78,15 +78,14 @@ PROGRAM MoorDyn_Driver ! SeaState types TYPE(SeaSt_InitInputType) :: InitInData_SeaSt ! Input data for initialization TYPE(SeaSt_InitOutputType) :: InitOutData_SeaSt ! Output data from initialization - type(SeaSt_ContinuousStateType) :: x_SeaSt ! Continuous states - type(SeaSt_DiscreteStateType) :: xd_SeaSt ! Discrete states - type(SeaSt_ConstraintStateType) :: z_SeaSt ! Constraint states - type(SeaSt_OtherStateType) :: OtherState_SeaSt ! Other states - type(SeaSt_MiscVarType) :: m_SeaSt ! Misc/optimization variables - type(SeaSt_ParameterType) :: p_SeaSt ! Parameters - type(SeaSt_InputType) :: u_SeaSt(1) ! System inputs - type(SeaSt_OutputType) :: y_SeaSt ! System outputs - LOGICAL :: SeaState_Initialized = .FALSE. + type(SeaSt_ContinuousStateType) :: x_SeaSt ! Continuous states + type(SeaSt_DiscreteStateType) :: xd_SeaSt ! Discrete states + type(SeaSt_ConstraintStateType) :: z_SeaSt ! Constraint states + type(SeaSt_OtherStateType) :: OtherState_SeaSt ! Other states + type(SeaSt_MiscVarType) :: m_SeaSt ! Misc/optimization variables + type(SeaSt_ParameterType) :: p_SeaSt ! Parameters + type(SeaSt_InputType) :: u_SeaSt(1) ! System inputs + type(SeaSt_OutputType) :: y_SeaSt ! System outputs ! Motion file parsing type(FileInfoType) :: FileInfo_PrescribeMtn !< The derived type for holding the prescribed forces input file for parsing -- we may pass this in the future @@ -138,6 +137,7 @@ PROGRAM MoorDyn_Driver ErrStat = ErrID_None UnEcho=-1 ! set to -1 as echo is no longer used by MD UnIn =-1 + ! TODO: Sort out error handling (two sets of flags currently used) @@ -210,8 +210,6 @@ PROGRAM MoorDyn_Driver ! allocate Input and Output arrays; used for interpolation and extrapolation Allocate(MD_uTimes(MD_interp_order + 1)) - - ! @bonnie : This is in the FAST developers glue code example, but it's probably not needed here. Allocate(MD_u(MD_interp_order + 1)) @@ -237,8 +235,8 @@ PROGRAM MoorDyn_Driver InitInData_SeaSt%TMax = MD_InitInp%TMax InitInData_SeaSt%Linearize = MD_InitInp%Linearize - CALL SeaSt_Init( InitInData_SeaSt, u_SeaSt(1), p_SeaSt, x_SeaSt, xd_SeaSt, z_SeaSt, OtherState_SeaSt, y_SeaSt, m_SeaSt, dtC, InitOutData_SeaSt, ErrStat2, ErrMsg2 ); call AbortIfFailed() - SeaState_Initialized = .TRUE. + CALL SeaSt_Init( InitInData_SeaSt, u_SeaSt(1), p_SeaSt, x_SeaSt, xd_SeaSt, z_SeaSt, OtherState_SeaSt, y_SeaSt, m_SeaSt, dtC, InitOutData_SeaSt, ErrStat2, ErrMsg2 ) + call AbortIfFailed() IF ( dtC /= drvrInitInp%dtC) THEN ErrMsg2 = 'The SeaState Module attempted to change the coupling timestep, but this is not allowed. The SeaState Module must use the Driver coupling timestep.' @@ -252,13 +250,10 @@ PROGRAM MoorDyn_Driver END IF ! call the initialization routine - CALL MD_Init( MD_InitInp, MD_u(1), MD_p, MD_x , MD_xd, MD_xc, MD_xo, MD_y, MD_m, dtC, MD_InitOut, ErrStat2, ErrMsg2 ); call AbortIfFailed() + CALL MD_Init( MD_InitInp, MD_u(1), MD_p, MD_x , MD_xd, MD_xc, MD_xo, MD_y, MD_m, dtC, MD_InitOut, ErrStat2, ErrMsg2 ) + call AbortIfFailed() - CALL MD_DestroyInitInput ( MD_InitInp , ErrStat2, ErrMsg2 ); call AbortIfFailed() - CALL MD_DestroyInitOutput ( MD_InitOut , ErrStat2, ErrMsg2 ); call AbortIfFailed() - - CALL DispNVD( MD_InitOut%Ver ) - + CALL DispNVD( MD_InitOut%Ver ) ! determine number of input channels expected from driver input file time series (DOFs including active tensioning channels) if (allocated(MD_u(1)%DeltaL)) then @@ -693,50 +688,47 @@ PROGRAM MoorDyn_Driver CALL RunTimes( ProgStrtTime, ProgStrtCPU, SimStrtTime, SimStrtCPU, t ) ! Destroy all objects - IF (SeaState_Initialized) THEN - CALL SeaSt_End( u_SeaSt(1), p_SeaSt, x_SeaSt, xd_SeaSt, z_SeaSt, OtherState_SeaSt, y_SeaSt, m_SeaSt, ErrStat2, ErrMsg2); call AbortIfFailed() - ENDIF - CALL MD_End( MD_u(1), MD_p, MD_x, MD_xd, MD_xc , MD_xo, MD_y, MD_m, ErrStat2, ErrMsg2 ); call AbortIfFailed() - - do j = 2,MD_interp_order+1 - call MD_DestroyInput( MD_u(j), ErrStat2, ErrMsg2) - end do - - if ( ErrStat /= ErrID_None ) THEN ! Display all errors - CALL WrScr1( "Errors: " ) - CALL WrScr( trim(GetErrStr(ErrStat))//': '//trim(ErrMsg) ) - endif - - !close (un) - call CleanUp() + call EndAndCleanUp() CALL NormStop() CONTAINS - + !------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE AbortIfFailed() - - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver') - - if (ErrStat >= AbortErrLev) then - if (SeaState_Initialized) then - call SeaSt_End( u_SeaSt(1), p_SeaSt, x_SeaSt, xd_SeaSt, z_SeaSt, OtherState_SeaSt, y_SeaSt, m_SeaSt, ErrStat2, ErrMsg2) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) - end if - - CALL SeaSt_DestroyInitOutput( InitOutData_SeaSt, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) - CALL SeaSt_DestroyInitInput( InitInData_SeaSt, ErrStat2, ErrMsg2 ) - call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) - - call CleanUp() - Call ProgAbort(trim(ErrMsg)) - elseif ( ErrStat2 /= ErrID_None ) THEN - CALL WrScr1( trim(GetErrStr(ErrStat2))//': '//trim(ErrMsg2)//NewLine) - end if + + if (ErrStat >= AbortErrLev .OR. ErrStat2 >= AbortErrLev) then + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver') + + call EndAndCleanUp() + Call ProgAbort(trim(ErrMsg)) + elseif ( ErrStat2 /= ErrID_None ) THEN ! print messages as we get them (but don't call SetErrStat or they will be printed 2x) + CALL WrScr1( trim(GetErrStr(ErrStat2))//': '//trim(ErrMsg2)//NewLine) + end if + END SUBROUTINE AbortIfFailed + !------------------------------------------------------------------------------------------------------------------------------- + SUBROUTINE EndAndCleanUp() + CALL SeaSt_DestroyInitOutput( InitOutData_SeaSt, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + CALL SeaSt_DestroyInitInput( InitInData_SeaSt, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + + CALL MD_DestroyInitOutput( MD_InitOut, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + CALL MD_DestroyInitInput( MD_InitInp, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + + call SeaSt_End( u_SeaSt(1), p_SeaSt, x_SeaSt, xd_SeaSt, z_SeaSt, OtherState_SeaSt, y_SeaSt, m_SeaSt, ErrStat2, ErrMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + + CALL MD_End( MD_u(1), MD_p, MD_x, MD_xd, MD_xc , MD_xo, MD_y, MD_m, ErrStat2, ErrMsg2 ) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + + do j = 2,MD_interp_order+1 + call MD_DestroyInput( MD_u(j), ErrStat2, ErrMsg2) + call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'MoorDyn_Driver' ) + end do - SUBROUTINE CleanUp() if(UnEcho >0) CLOSE( UnEcho ) if(UnIn >0) CLOSE( UnIn ) @@ -749,7 +741,15 @@ SUBROUTINE CleanUp() IF (ALLOCATED(rd_in2 )) DEALLOCATE(rd_in2 ) IF (ALLOCATED(rdd_in )) DEALLOCATE(rdd_in ) IF (ALLOCATED(rdd_in2 )) DEALLOCATE(rdd_in2 ) - END SUBROUTINE CleanUp + IF (ALLOCATED(TmpRe )) DEALLOCATE(TmpRe ) + + + + if ( ErrStat /= ErrID_None ) THEN ! Display all errors + CALL WrScr1( "Errors: " ) + CALL WrScr( trim(GetErrStr(ErrStat))//': '//trim(ErrMsg) ) + endif + END SUBROUTINE EndAndCleanUp !------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE ReadDriverInputFile( inputFile, InitInp) diff --git a/modules/moordyn/src/MoorDyn_Misc.f90 b/modules/moordyn/src/MoorDyn_Misc.f90 index 4466718db..a1db2de91 100644 --- a/modules/moordyn/src/MoorDyn_Misc.f90 +++ b/modules/moordyn/src/MoorDyn_Misc.f90 @@ -1071,7 +1071,6 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) REAL(SiKi) :: WaveDOmega ! frequency step REAL(SiKi), ALLOCATABLE :: SinWaveDir(:) ! SIN( WaveDirArr(I) ) -- Each wave frequency has a unique wave direction. REAL(SiKi), ALLOCATABLE :: CosWaveDir(:) ! COS( WaveDirArr(I) ) -- Each wave frequency has a unique wave direction. - LOGICAL :: WaveMultiDir = .FALSE. ! Indicates the waves are multidirectional -- set by WaveField pointer if enabled REAL(SiKi), ALLOCATABLE :: TmpFFTWaveElev(:) ! Data for the FFT calculation TYPE(FFT_DataType) :: FFT_Data ! the instance of the FFT module we're using @@ -1083,7 +1082,6 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) COMPLEX(SiKi), PARAMETER :: ImagNmbr = (0.0,1.0) ! The imaginary number, SQRT(-1.0) COMPLEX(SiKi) :: ImagOmega ! = ImagNmbr*Omega (rad/s) REAL(DbKi), ALLOCATABLE :: WaveNmbr(:) ! wave number for frequency array - REAL(SiKi), ALLOCATABLE :: WaveDirArr(:) ! Wave direction array. Each frequency has a unique direction of WaveNDir > 1 (degrees). 0's for WaveKin = 1 or if disabled in SeaState. REAL(SiKi), ALLOCATABLE :: WaveElevC0(:,:) ! Discrete Fourier transform of the instantaneous elevation of incident waves at the ref point (meters) COMPLEX(SiKi), ALLOCATABLE :: WaveElevC( :) ! Discrete Fourier transform of the instantaneous elevation of incident waves at the ref point (meters) COMPLEX(SiKi), ALLOCATABLE :: WaveAccCHx(:) ! Discrete Fourier transform of the instantaneous horizontal acceleration in x-direction of incident waves before applying stretching at the zi-coordinates for points (m/s^2) @@ -1412,7 +1410,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) END IF ! Warning check to make sure SeaState and MoorDyn have the same wave dir. For now, no wave spreading. This can be updated - IF (p%WaveField%WaveDir /= WaveDir) THEN + IF (p%WaveField%WaveDir /= WaveDir) THEN !bjj: the local WaveDir doesn't appear to be used when WaveKin = 2 and p%WaveField%WaveDirArr is true, so I don't think this error message is completely valid. IF (p%writeLog > 0) THEN WRITE(p%UnLog, '(A)' ) " WARNING SeaState WaveDir does not match MoorDyn WaveDir. Using MoorDyn values for interpolating SeaState data to MoorDyn grid." ENDIF @@ -1422,7 +1420,7 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ! Info check for if MoorDyn dtWave is non-zero. Users may set this accidentially, or could be left over in an input file IF (p%dtWave > 0) THEN IF (p%writeLog > 0) THEN - WRITE(p%UnLog, '(A)' ) " MoorDyn dtWave is ignored when using WaveKinMod = 2 becasue wave frequency information is supplied by SeaState" + WRITE(p%UnLog, '(A)' ) " MoorDyn dtWave is ignored when using WaveKinMod = 2 because wave frequency information is supplied by SeaState" ENDIF END IF @@ -1445,15 +1443,8 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) NStepWave = p%WaveField%NStepWave ! Pull some other things out of the WaveField pointer - WaveMultiDir = p%WaveField%WaveMultiDir p%ntWave = NStepWave ! set ntWave to NStepWave - ! Set wave spreading array if enabled in SeaState, otherwise set to zero - If (WaveMultiDir) THEN - ! Note: allocations not needed here because they are already allocated in SeaState - WaveDirArr = p%WaveField%WaveDirArr - ENDIF - ELSEIF (p%WaveKin == 1) THEN ! must be a filepath therefore read wave elevations from timeseries ! NOTE: there is a decent ammount of code duplication (intentional for now) with what is in SeaState that eventually @@ -1659,9 +1650,9 @@ SUBROUTINE setupWaterKin(WaterKinString, p, Tmax, ErrStat, ErrMsg) ALLOCATE ( SinWaveDir(0:NStepWave2), STAT=ErrStat2); ErrMsg2 = 'Cannot allocate SinWaveDir.'; IF (Failed0()) RETURN ! Set the CosWaveDir and SinWaveDir values. - IF (WaveMultiDir) THEN ! This is only possible with WaveKinMod = 2 - CosWaveDir=COS(D2R*WaveDirArr) - SinWaveDir=SIN(D2R*WaveDirArr) + IF (p%WaveKin == 2 .and. p%WaveField%WaveMultiDir) THEN ! This is only possible with WaveKinMod = 2 + CosWaveDir=COS(D2R*p%WaveField%WaveDirArr) + SinWaveDir=SIN(D2R*p%WaveField%WaveDirArr) ELSE CosWaveDir=COS(D2R*WaveDir) SinWaveDir=SIN(D2R*WaveDir) diff --git a/modules/nwtc-library/src/ModMesh.f90 b/modules/nwtc-library/src/ModMesh.f90 index 5a34676be..f92548522 100644 --- a/modules/nwtc-library/src/ModMesh.f90 +++ b/modules/nwtc-library/src/ModMesh.f90 @@ -2928,7 +2928,7 @@ SUBROUTINE PackMotionMesh(M, Ary, indx_first, FieldMask, TrimOP) if (PackForTrimSolution) then do i=1,M%NNodes - call DCM_logMap(M%Orientation(:,:,i), logmap, ErrStat2, ErrMsg2) !NOTE: we cannot use GetSmllRotAngs because we CANNOT assume that all DCMs in the code are small. + logmap = EulerExtract(M%Orientation(:,:,i)) !NOTE: we cannot use GetSmllRotAngs because we CANNOT assume that all DCMs in the code are small. do k=1,3 Ary(indx_first) = logmap(k) indx_first = indx_first + 1 diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 204db312b..67bbe4213 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -3038,7 +3038,7 @@ END SUBROUTINE ParseChVar !! !! WARNING: This routine assumes the "words" containing the variable name and value are <= 20 characters. !! Use ParseVarWDefault (nwtc_io::parsevarwdefault) instead of directly calling a specific routine in the generic interface. - SUBROUTINE ParseChVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseChVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEcIn ) ! Arguments declarations. @@ -3046,7 +3046,7 @@ SUBROUTINE ParseChVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status. INTEGER(IntKi), INTENT(INOUT) :: LineNum !< The number of the line to parse. - INTEGER, INTENT(IN), OPTIONAL :: UnEc !< I/O unit for echo file. If present and > 0, write to UnEc. + INTEGER, INTENT(IN), OPTIONAL :: UnEcIn ! I/O unit for echo file. If present and > 0, write to UnEc. CHARACTER(*), INTENT(OUT) :: Var !< The variable to receive the input value. CHARACTER(*), INTENT(IN) :: VarDefault !< The default value for the variable. @@ -3058,6 +3058,7 @@ SUBROUTINE ParseChVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ! Local declarations. + INTEGER :: UnEc ! I/O unit for echo file. INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3066,6 +3067,12 @@ SUBROUTINE ParseChVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat=ErrID_None ErrMsg = "" + + if (PRESENT(UnEcIn)) then + UnEc = UnEcIn + else + UnEc = 0 + end if ! First parse this as a string CALL ParseVar ( FileInfo, LineNum, ExpVarName, defaultStr, ErrStatLcl, ErrMsg2, UnEc ) @@ -3218,7 +3225,7 @@ SUBROUTINE ParseR8Var ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE END SUBROUTINE ParseR8Var !======================================================================= !> \copydoc nwtc_io::parsechvarwdefault - SUBROUTINE ParseR8VarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseR8VarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEcIn ) ! Arguments declarations. @@ -3226,7 +3233,7 @@ SUBROUTINE ParseR8VarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, INTEGER(IntKi), INTENT(OUT) :: ErrStat ! The error status. INTEGER(IntKi), INTENT(INOUT) :: LineNum ! The number of the line to parse. - INTEGER, INTENT(IN), OPTIONAL :: UnEc ! I/O unit for echo file. If present and > 0, write to UnEc. + INTEGER, INTENT(IN), OPTIONAL :: UnEcIn ! I/O unit for echo file. If present and > 0, write to UnEc. REAL(R8Ki), INTENT(OUT) :: Var ! The double-precision REAL variable to receive the input value. REAL(R8Ki), INTENT(IN) :: VarDefault ! The double-precision REAL used as the default. @@ -3238,6 +3245,7 @@ SUBROUTINE ParseR8VarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ! Local declarations. + INTEGER :: UnEc ! I/O unit for echo file. INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3247,6 +3255,12 @@ SUBROUTINE ParseR8VarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat=ErrID_None ErrMsg = "" + if (PRESENT(UnEcIn)) then + UnEc = UnEcIn + else + UnEc = 0 + end if + ! First parse this as a string CALL ParseVar ( FileInfo, LineNum, ExpVarName, defaultStr, ErrStatLcl, ErrMsg2, UnEc ) CALL SetErrStat(ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -3515,7 +3529,7 @@ SUBROUTINE ParseInVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE END SUBROUTINE ParseInVar !======================================================================= !> \copydoc nwtc_io::parsechvarwdefault - SUBROUTINE ParseInVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseInVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEcIn ) ! This subroutine parses the specified line of text for two words. One should be a ! the name of a integer variable and the other an integer value. @@ -3530,7 +3544,7 @@ SUBROUTINE ParseInVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, INTEGER(IntKi), INTENT(OUT) :: ErrStat ! The error status. INTEGER(IntKi), INTENT(INOUT) :: LineNum ! The number of the line to parse. - INTEGER, INTENT(IN), OPTIONAL :: UnEc ! I/O unit for echo file. If present and > 0, write to UnEc. + INTEGER, INTENT(IN), OPTIONAL :: UnEcIn ! I/O unit for echo file. If present and > 0, write to UnEc. INTEGER(IntKi), INTENT(OUT) :: Var ! The INTEGER variable to receive the input value. INTEGER(IntKi), INTENT(IN) :: VarDefault ! The INTEGER used as the default. @@ -3542,6 +3556,7 @@ SUBROUTINE ParseInVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ! Local declarations. + INTEGER :: UnEc ! I/O unit for echo file. INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3550,6 +3565,12 @@ SUBROUTINE ParseInVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat=ErrID_None ErrMsg = "" + + if (PRESENT(UnEcIn)) then + UnEc = UnEcIn + else + UnEc = 0 + end if ! First parse this as a string CALL ParseVar ( FileInfo, LineNum, ExpVarName, defaultStr, ErrStatLcl, ErrMsg2, UnEc ) @@ -3702,7 +3723,7 @@ SUBROUTINE ParseLoVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE END SUBROUTINE ParseLoVar !======================================================================= !> \copydoc nwtc_io::parsechvarwdefault - SUBROUTINE ParseLoVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseLoVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEcIn ) ! Arguments declarations. @@ -3710,7 +3731,7 @@ SUBROUTINE ParseLoVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, INTEGER(IntKi), INTENT(OUT) :: ErrStat ! The error status. INTEGER(IntKi), INTENT(INOUT) :: LineNum ! The number of the line to parse. - INTEGER, INTENT(IN), OPTIONAL :: UnEc ! I/O unit for echo file. If present and > 0, write to UnEc. + INTEGER, INTENT(IN), OPTIONAL :: UnEcIn ! I/O unit for echo file. If present and > 0, write to UnEc. LOGICAL, INTENT(OUT) :: Var ! The LOGICAL variable to receive the input value. LOGICAL, INTENT(IN) :: VarDefault ! The LOGICAL used as the default. @@ -3722,6 +3743,7 @@ SUBROUTINE ParseLoVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ! Local declarations. + INTEGER :: UnEc ! I/O unit for echo file. INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3731,6 +3753,12 @@ SUBROUTINE ParseLoVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat=ErrID_None ErrMsg = "" + if (PRESENT(UnEcIn)) then + UnEc = UnEcIn + else + UnEc = 0 + end if + ! First parse this as a string CALL ParseVar ( FileInfo, LineNum, ExpVarName, defaultStr, ErrStatLcl, ErrMsg2, UnEc ) CALL SetErrStat(ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -3881,7 +3909,7 @@ SUBROUTINE ParseSiVar ( FileInfo, LineNum, ExpVarName, Var, ErrStat, ErrMsg, UnE END SUBROUTINE ParseSiVar !======================================================================= !> \copydoc nwtc_io::parsechvarwdefault - SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEc ) + SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat, ErrMsg, UnEcIn ) ! Arguments declarations. @@ -3889,7 +3917,7 @@ SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, INTEGER(IntKi), INTENT(OUT) :: ErrStat ! The error status. INTEGER(IntKi), INTENT(INOUT) :: LineNum ! The number of the line to parse. - INTEGER, INTENT(IN), OPTIONAL :: UnEc ! I/O unit for echo file. If present and > 0, write to UnEc. + INTEGER, INTENT(IN), OPTIONAL :: UnEcIn ! I/O unit for echo file. If present and > 0, write to UnEc. REAL(SiKi), INTENT(OUT) :: Var ! The single-precision REAL variable to receive the input value. REAL(SiKi), INTENT(IN) :: VarDefault ! The single-precision REAL used as the default. @@ -3901,6 +3929,7 @@ SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ! Local declarations. + INTEGER :: UnEc ! I/O unit for echo file. INTEGER(IntKi) :: ErrStatLcl ! Error status local to this routine. CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -3909,6 +3938,12 @@ SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, ErrStat=ErrID_None ErrMsg = "" + + if (PRESENT(UnEcIn)) then + UnEc = UnEcIn + else + UnEc = 0 + end if ! First parse this as a string CALL ParseVar ( FileInfo, LineNum, ExpVarName, defaultStr, ErrStatLcl, ErrMsg2, UnEc ) diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 928321aff..5cafdc949 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -301,18 +301,24 @@ SUBROUTINE AddOrSub2Pi_R4 ( OldAngle, NewAngle ) ! Local declarations: REAL(SiKi) :: DelAngle ! The difference between OldAngle and NewAngle, rad. - + integer :: n, i ! Add or subtract 2*Pi in order to convert NewAngle two within Pi of OldAngle: + DelAngle = OldAngle - NewAngle + n = int(DelAngle / TwoPi_R4) + NewAngle = NewAngle + n * TwoPi_R4 DelAngle = OldAngle - NewAngle + - DO WHILE ( ABS( DelAngle ) > Pi_R4 ) + i = 0 + DO WHILE ( ABS( DelAngle ) > Pi_R4 .and. .not. EqualRealNos(OldAngle, NewAngle) .and. i < 10) NewAngle = NewAngle + SIGN( TwoPi_R4, DelAngle ) DelAngle = OldAngle - NewAngle + i = i + 1 END DO @@ -331,6 +337,7 @@ SUBROUTINE AddOrSub2Pi_R8 ( OldAngle, NewAngle ) ! Local declarations: REAL(R8Ki) :: DelAngle ! The difference between OldAngle and NewAngle, rad. + integer :: n, i @@ -339,17 +346,23 @@ SUBROUTINE AddOrSub2Pi_R8 ( OldAngle, NewAngle ) DelAngle = OldAngle - NewAngle - DO WHILE ( ABS( DelAngle ) > Pi_R8 ) + n = int(DelAngle / TwoPi_R8) + NewAngle = NewAngle + n * TwoPi_R8 + DelAngle = OldAngle - NewAngle + + i = 0 + DO WHILE ( ABS( DelAngle ) > Pi_R8 .and. .not. EqualRealNos(OldAngle, NewAngle) .and. i < 10) NewAngle = NewAngle + SIGN( TwoPi_R8, DelAngle ) DelAngle = OldAngle - NewAngle + i = i + 1 END DO RETURN END SUBROUTINE AddOrSub2Pi_R8 !======================================================================= - FUNCTION BlendCosine( x, LowerBound, UpperBound ) RESULT(S) + PURE FUNCTION BlendCosine( x, LowerBound, UpperBound ) RESULT(S) REAL(ReKi), INTENT(IN) :: x ! REAL(ReKi), INTENT(IN) :: LowerBound !< if x <= LowerBound, S=0 @@ -1006,12 +1019,7 @@ END FUNCTION CubicSplineInterp ! ( X, AryLen, XAry, YAry, Coef, ErrStat, ErrMsg !! One must call cubicsplineinit first to compute the coefficients of the cubics. !! This routine does not require that the XAry be regularly spaced. !! This version of the routine works with multiple curves that share the same X values. - FUNCTION CubicSplineInterpM ( X, XAry, YAry, Coef, ErrStat, ErrMsg ) RESULT( Res ) - - ! Function declaration. - - REAL(ReKi), ALLOCATABLE :: Res(:) ! The result of this function - + SUBROUTINE CubicSplineInterpM ( X, XAry, YAry, Coef, Res ) ! Argument declarations: @@ -1019,46 +1027,31 @@ FUNCTION CubicSplineInterpM ( X, XAry, YAry, Coef, ErrStat, ErrMsg ) RESULT( Res REAL(ReKi), INTENT(IN) :: X !< The value we are trying to interpolate for REAL(ReKi), INTENT(IN) :: XAry (:) !< Input array of regularly spaced x values REAL(ReKi), INTENT(IN) :: YAry (:,:) !< Input array of y values with multiple curves - - INTEGER(IntKi), INTENT(OUT) :: ErrStat !< Error status - - CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message + REAL(ReKi), INTENT(OUT) :: Res(:) !< The result of this function ! Local declarations. REAL(ReKi) :: XOff ! The distance from X to XAry(ILo). + REAL(ReKi) :: XOff2 ! The distance from X to XAry(ILo). + REAL(ReKi) :: XOff3 ! The distance from X to XAry(ILo). - INTEGER(IntKi) :: ErrStatLcL ! Local error status. INTEGER :: ILo ! The index into the array for which X is just above or equal to XAry(ILo). - INTEGER :: NumCrvs ! Number of curves to be interpolated. INTEGER :: NumPts ! Number of points in each curve. - CHARACTER(*), PARAMETER :: RoutineName = 'RegCubicSplineInterpM' ! How big are the arrays? NumPts = SIZE( XAry ) - NumCrvs = SIZE( YAry, 2 ) - - ALLOCATE ( Res( NumCrvs ) , STAT=ErrStatLcl ) - IF ( ErrStatLcl /= 0 ) THEN - ErrStat = ErrID_Fatal - ErrMsg = RoutineName//':Error allocating memory for the function result array.' - RETURN - ELSE - ErrStat = ErrID_None - ErrMsg = "" - ENDIF ! See if X is within the range of XAry. Return the end point if it is not. IF ( X <= XAry(1) ) THEN - Res(:) = YAry(1,:) + Res = YAry(1,:) RETURN ELSEIF ( X >= XAry(NumPts) ) THEN - Res(:) = YAry(NumPts,:) + Res = YAry(NumPts,:) RETURN ENDIF ! ( X <= XAry(1) ) @@ -1068,12 +1061,14 @@ FUNCTION CubicSplineInterpM ( X, XAry, YAry, Coef, ErrStat, ErrMsg ) RESULT( Res CALL LocateBin( X, XAry, ILo, NumPts ) XOff = X - XAry(ILo) + XOff2 = XOff * XOff + XOff3 = XOff2 * XOff - Res(:) = Coef(ILo,:,0) + XOff*( Coef(ILo,:,1) + XOff*( Coef(ILo,:,2) + XOff*Coef(ILo,:,3) ) ) + Res = Coef(ILo,:,0) + Coef(ILo,:,1)*XOff + Coef(ILo,:,2) * XOff2 + Coef(ILo,:,3)*XOff3 RETURN - END FUNCTION CubicSplineInterpM ! ( X, XAry, YAry, Coef, ErrStat, ErrMsg ) + END SUBROUTINE CubicSplineInterpM !======================================================================= !> This function returns the matrix exponential, \f$\Lambda = \exp(\lambda)\f$, of an input skew-symmetric matrix, \f$\lambda\f$. !! @@ -1265,18 +1260,18 @@ END FUNCTION DCM_expR !! Use DCM_logMap (nwtc_num::dcm_logmap) instead of directly calling a specific routine in the generic interface. SUBROUTINE DCM_logMapD(DCM, logMap, ErrStat, ErrMsg, thetaOut) - REAL(DbKi), INTENT(IN) :: DCM(3,3) !< the direction cosine matrix, \f$\Lambda\f$ - REAL(DbKi), INTENT( OUT) :: logMap(3) !< vector containing \f$\lambda_1\f$, \f$\lambda_2\f$, and \f$\lambda_3\f$, the unique components of skew-symmetric matrix \f$\lambda\f$ - REAL(DbKi),OPTIONAL,INTENT( OUT) :: thetaOut !< the angle of rotation, \f$\theta\f$; output only for debugging + REAL(R8Ki), INTENT(IN) :: DCM(3,3) !< the direction cosine matrix, \f$\Lambda\f$ + REAL(R8Ki), INTENT( OUT) :: logMap(3) !< vector containing \f$\lambda_1\f$, \f$\lambda_2\f$, and \f$\lambda_3\f$, the unique components of skew-symmetric matrix \f$\lambda\f$ + REAL(R8Ki),OPTIONAL,INTENT( OUT) :: thetaOut !< the angle of rotation, \f$\theta\f$; output only for debugging INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - REAL(DbKi) :: theta - REAL(DbKi) :: cosTheta - REAL(DbKi) :: TwoSinTheta - REAL(DbKi) :: v(3) - REAL(DbKi) :: divisor + REAL(R8Ki) :: theta + REAL(R8Ki) :: cosTheta + REAL(R8Ki) :: TwoSinTheta + REAL(R8Ki) :: v(3) + REAL(R8Ki) :: divisor INTEGER(IntKi) :: indx_max ! initialization @@ -1284,8 +1279,8 @@ SUBROUTINE DCM_logMapD(DCM, logMap, ErrStat, ErrMsg, thetaOut) ErrMsg = "" - cosTheta = 0.5_DbKi*( trace(DCM) - 1.0_DbKi ) - cosTheta = min( max(cosTheta,-1.0_DbKi), 1.0_DbKi ) !make sure it's in a valid range (to avoid cases where this is slightly outside the +/-1 range) + cosTheta = 0.5_DbKi*( trace(DCM) - 1.0_R8Ki ) + cosTheta = min( max(cosTheta,-1.0_R8Ki), 1.0_R8Ki ) !make sure it's in a valid range (to avoid cases where this is slightly outside the +/-1 range) theta = ACOS( cosTheta ) ! Eq. 25 ( 0<=theta<=pi ) IF ( PRESENT( thetaOut ) ) THEN @@ -1341,13 +1336,13 @@ SUBROUTINE DCM_logMapD(DCM, logMap, ErrStat, ErrMsg, thetaOut) v(3) = -DCM(2,1) + DCM(1,2) !-skewSym(2,1) = 2*sin(theta)/theta * lambda(3) = (small positive value with theta near pi) * lambda(3) indx_max = maxloc( abs(v), 1 ) ! find component with largest magnitude - if ( .not. EqualRealNos( sign(1.0_DbKi,v(indx_max)), sign(1.0_DbKi,logMap(indx_max)) )) logMap = -logMap + if ( .not. EqualRealNos( sign(1.0_R8Ki,v(indx_max)), sign(1.0_R8Ki,logMap(indx_max)) )) logMap = -logMap ELSE - TwoSinTheta = 2.0_DbKi*sin(theta) + TwoSinTheta = 2.0_R8Ki*sin(theta) - IF ( EqualRealNos(0.0_DbKi, theta) .or. EqualRealNos( 0.0_DbKi, TwoSinTheta ) ) THEN + IF ( EqualRealNos(0.0_R8Ki, theta) .or. EqualRealNos( 0.0_DbKi, TwoSinTheta ) ) THEN !skewSym = DCM - TRANSPOSE(DCM) ! @@ -1490,13 +1485,13 @@ END SUBROUTINE DCM_logMapR !! Use DCM_SetLogMapForInterp (nwtc_num::dcm_setlogmapforinterp) instead of directly calling a specific routine in the generic interface. SUBROUTINE DCM_SetLogMapForInterpD( tensor ) - REAL(DbKi), INTENT(INOUT) :: tensor(:,:) !< a 3xn matrix, whose columns represent individual skew-symmetric matrices. On exit, + REAL(R8Ki), INTENT(INOUT) :: tensor(:,:) !< a 3xn matrix, whose columns represent individual skew-symmetric matrices. On exit, !! each column will be within \f$2\pi\f$ of the previous column, allowing for interpolation !! of the quantities. - REAL(DbKi) :: diff1, diff2 ! magnitude-squared of difference between two adjacent values - REAL(DbKi) :: temp(3), temp1(3) ! difference between two tensors - REAL(DbKi) :: period(3) ! the period to add to the rotational parameters + REAL(R8Ki) :: diff1, diff2 ! magnitude-squared of difference between two adjacent values + REAL(R8Ki) :: temp(3), temp1(3) ! difference between two tensors + REAL(R8Ki) :: period(3) ! the period to add to the rotational parameters INTEGER(IntKi) :: nc ! size of the tensors matrix INTEGER(IntKi) :: ic ! loop counters for each array dimension @@ -1765,7 +1760,7 @@ END FUNCTION EulerConstructR4 FUNCTION EulerConstructR8(theta) result(M) ! this function creates a rotation matrix, M, from a 3-2-1 intrinsic rotation -!! sequence of the 3 Tait-Bryan angles (1-2-3 extrinsic rotation), theta_x, theta_y, and theta_z, in radians. + ! sequence of the 3 Tait-Bryan angles (1-2-3 extrinsic rotation), theta_x, theta_y, and theta_z, in radians. ! M represents a change of basis (from global to local coordinates; ! not a physical rotation of the body). it is the inverse of EulerExtract (nwtc_num::eulerextract). ! @@ -4159,17 +4154,18 @@ subroutine kernelSmoothing(x, f, kernelType, radius, fNew) REAL(ReKi) :: k REAL(ReKi) :: k_sum REAL(ReKi) :: w + REAL(ReKi) :: RadiusFix INTEGER(IntKi) :: Exp1 INTEGER(IntKi) :: Exp2 REAL(ReKi) :: u(size(x)) INTEGER :: i, j INTEGER :: n - ! check that radius > 0 ! check that size(x) = size(f)=size(fNew) ! check that kernelType is a valid number n = size(x) + RadiusFix = max(abs(radius),epsilon(radius)) ! ensure radius is a positive number ! make sure that the value of u is in [-1 and 1] for these kernels: @@ -4197,7 +4193,7 @@ subroutine kernelSmoothing(x, f, kernelType, radius, fNew) fNew = 0.0_ReKi ! whole array operation do j=1,n ! for each value in f: - u = (x - x(j)) / radius ! whole array operation + u = (x - x(j)) / RadiusFix ! whole array operation do i=1,n u(i) = min( 1.0_ReKi, max( -1.0_ReKi, u(i) ) ) end do @@ -4220,7 +4216,7 @@ subroutine kernelSmoothing(x, f, kernelType, radius, fNew) fNew = 0.0_ReKi ! whole array operation do j=1,n ! for each value in f: - u = (x - x(j)) / radius ! whole array operation + u = (x - x(j)) / RadiusFix ! whole array operation k_sum = 0.0_ReKi do i=1,n @@ -5411,7 +5407,7 @@ END SUBROUTINE RombergInt !======================================================================= !> This routine displays a message that gives that status of the simulation and the predicted end time of day. !! It is intended to be used with SimStatus (nwtc_num::simstatus) and SimStatus_FirstTime (nwtc_num::simstatus_firsttime). - SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, UsrTime_out, DescStrIn ) + SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, UsrTime_out, DescStrIn, useCases ) IMPLICIT NONE @@ -5423,6 +5419,7 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, Us REAL(ReKi), INTENT(IN) :: UsrTime2 !< User CPU time for simulation (without initialization) REAL(DbKi), INTENT(IN) :: ZTime !< The final simulation time (not necessarially TMax) INTEGER(IntKi), INTENT(IN), OPTIONAL:: UnSum !< optional unit number of file. If present and > 0, + LOGICAL, INTENT(IN), OPTIONAL:: useCases !< optional number of cases. If present and > 0, ZTime represents number of cases, not time (for steady-state outputs) REAL(ReKi), INTENT(OUT),OPTIONAL:: UsrTime_out !< User CPU time for entire run - optional value returned to calling routine CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus @@ -5441,7 +5438,8 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, Us CHARACTER( 8) :: TimePer CHARACTER(MaxWrScrLen) :: BlankLine - CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + LOGICAL :: UseCaseStr !< use cases if (present(DescStrIn)) then @@ -5450,6 +5448,13 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, Us DescStr = "" end if + if (present(useCases)) then + UseCaseStr = useCases + else + UseCaseStr = .false. + end if + + ! Get the end times to compare with start times. CALL DATE_AND_TIME ( VALUES=EndTimes ) @@ -5494,9 +5499,14 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, Us CALL WrScr ( ' Total CPU Time: '//TRIM( Num2LStr( Factor*UsrTime ) )//TRIM( TimePer ) ) ! CALL WrScr ( ' ') ! CALL WrScr ( ' Simulation Real Time: '//TRIM( Num2LStr( Factor*ClckTimeSim ) )//TRIM( TimePer ) ) - CALL WrScr ( ' Simulation CPU Time: '//TRIM( Num2LStr( Factor*UsrTimeSim ) )//TRIM( TimePer ) ) - CALL WrScr ( ' Simulated Time: '//TRIM( Num2LStr( Factor*REAL( ZTime ) ) )//TRIM( TimePer ) ) - CALL WrScr ( ' Time Ratio (Sim/CPU): '//TRIM( Num2LStr( TRatio ) ) ) + CALL WrScr ( ' Simulation CPU Time: '//TRIM( Num2LStr( Factor*UsrTimeSim ) )//TRIM( TimePer ) ) + if (UseCaseStr) then + CALL WrScr ( ' Simulated Cases: '//TRIM( Num2LStr( REAL( ZTime ) ) ) ) + CALL WrScr ( ' Time Ratio (CPU/case): '//TRIM( Num2LStr( Factor/TRatio ) )//TRIM(TimePer)//' per case' ) + else + CALL WrScr ( ' Simulated Time: '//TRIM( Num2LStr( Factor*REAL( ZTime ) ) )//TRIM( TimePer ) ) + CALL WrScr ( ' Time Ratio (Sim/CPU): '//TRIM( Num2LStr( TRatio ) ) ) + end if IF (PRESENT(UnSum)) THEN IF (UnSum>0) THEN @@ -5504,8 +5514,13 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UnSum, Us WRITE( UnSum, '(A)') ' Total Real Time: '//TRIM( Num2LStr( Factor*ClckTime ) )//TRIM( TimePer ) WRITE( UnSum, '(A)') ' Total CPU Time: '//TRIM( Num2LStr( Factor*UsrTime ) )//TRIM( TimePer ) WRITE( UnSum, '(A)') ' Simulation CPU Time: '//TRIM( Num2LStr( Factor*UsrTimeSim ) )//TRIM( TimePer ) - WRITE( UnSum, '(A)') ' Simulated Time: '//TRIM( Num2LStr( Factor*REAL( ZTime ) ) )//TRIM( TimePer ) - WRITE( UnSum, '(A)') ' Time Ratio (Sim/CPU): '//TRIM( Num2LStr( TRatio ) ) + if (UseCaseStr) then + WRITE( UnSum, '(A)') ' Simulated Cases: '//TRIM( Num2LStr( REAL( ZTime ) ) ) + WRITE( UnSum, '(A)') ' Time Ratio (CPU/case): '//TRIM( Num2LStr( Factor/TRatio ) )//TRIM(TimePer)//' per case' + else + WRITE( UnSum, '(A)') ' Simulated Time: '//TRIM( Num2LStr( Factor*REAL( ZTime ) ) )//TRIM( TimePer ) + WRITE( UnSum, '(A)') ' Time Ratio (Sim/CPU): '//TRIM( Num2LStr( TRatio ) ) + end if END IF END IF @@ -5624,7 +5639,7 @@ END SUBROUTINE SetConstants !======================================================================= !> This routine displays a message that gives that status of the simulation. !! It is intended to be used with RunTimes (nwtc_num::runtimes) and SimStatus (nwtc_num::simstatus). - SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTimeSim, ZTime, TMax, DescStrIn ) + SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTimeSim, ZTime, TMax, DescStrIn, useCases) IMPLICIT NONE @@ -5637,12 +5652,12 @@ SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTime REAL(ReKi), INTENT( OUT) :: UsrTimeSim !< User CPU time for simulation (without initialization) CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus - - ! Local variables. + LOGICAL, INTENT(IN), OPTIONAL :: useCases !< optional number of cases. If present and > 0, ZTime represents number of cases, not time (for steady-state outputs) + ! Local variables REAL(ReKi) :: CurrClockTime ! Current time in seconds past midnight. - CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus - + CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + LOGICAL :: UseCaseStr !< use cases if (present(DescStrIn)) then DescStr = DescStrIn @@ -5650,6 +5665,11 @@ SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTime DescStr = "" end if + if (present(useCases)) then + UseCaseStr = useCases + else + UseCaseStr = .false. + end if ! How many seconds past midnight? @@ -5659,7 +5679,7 @@ SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTime CurrClockTime = TimeValues2Seconds( SimStrtTime ) - + if (.NOT. UseCaseStr) & CALL WrScr ( trim(DescStr)//' Time: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )//' seconds.') diff --git a/modules/nwtc-library/src/VTK.f90 b/modules/nwtc-library/src/VTK.f90 index e4ffc614d..fc48a1ef7 100644 --- a/modules/nwtc-library/src/VTK.f90 +++ b/modules/nwtc-library/src/VTK.f90 @@ -162,8 +162,8 @@ SUBROUTINE ReadVTK_SP_info( FileName, descr, dims, origin, gridSpacing, vecLabel END IF !$OMP critical(fileopenNWTCio_critical) - CALL GetNewUnit( Un, ErrStat2, ErrMsg2 ) - CALL OpenFInpFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) + CALL GetNewUnit( Un, ErrStat, ErrMsg ) + CALL OpenFInpFile ( Un, TRIM(FileName), ErrStat2, ErrMsg2 ) !$OMP end critical(fileopenNWTCio_critical) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return diff --git a/modules/openfast-library/src/FAST_SS_Subs.f90 b/modules/openfast-library/src/FAST_SS_Subs.f90 index 82b7c8584..7df4677ff 100644 --- a/modules/openfast-library/src/FAST_SS_Subs.f90 +++ b/modules/openfast-library/src/FAST_SS_Subs.f90 @@ -104,6 +104,10 @@ SUBROUTINE FAST_InitializeSteadyState_T( Turbine, ErrStat, ErrMsg ) Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, CompAeroMaps, ErrStat, ErrMsg ) call InitFlowField() + + CALL SimStatus_FirstTime( Turbine%m_FAST%TiLstPrn, Turbine%m_FAST%PrevClockTime, Turbine%m_FAST%SimStrtTime, Turbine%m_FAST%UsrTime2, & + t_initial, Turbine%p_FAST%TMax, Turbine%p_FAST%TDesc, useCases=Turbine%p_FAST%CompAeroMaps) + contains !> AD15 now directly accesses FlowField data from IfW. Since we don't use IfW, we need to manually set the FlowField data diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index f45a789a4..40d9da134 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -9554,7 +9554,7 @@ SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, SED, BD, SrvD, AD, ADsk, end if IF (p_FAST%WrSttsTime .and. PrintRunTimes) THEN - CALL RunTimes( m_FAST%StrtTime, m_FAST%UsrTime1, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global, UnSum=y_FAST%UnSum, DescStrIn=p_FAST%TDesc ) + CALL RunTimes( m_FAST%StrtTime, m_FAST%UsrTime1, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global, UnSum=y_FAST%UnSum, DescStrIn=p_FAST%TDesc, useCases=p_FAST%CompAeroMaps ) END IF IF (y_FAST%UnSum > 0) THEN CLOSE(y_FAST%UnSum) diff --git a/modules/seastate/src/SeaState_Output.f90 b/modules/seastate/src/SeaState_Output.f90 index b5b900e4f..7dacda0be 100644 --- a/modules/seastate/src/SeaState_Output.f90 +++ b/modules/seastate/src/SeaState_Output.f90 @@ -966,7 +966,7 @@ SUBROUTINE SeaStOut_CloseOutput ( p, ErrStat, ErrMsg ) ! Write the summary file header - IF ( p%UnOutFile > -1 ) THEN + IF ( p%UnOutFile > 0 ) THEN ! WRITE (p%UnOutFile,'(/,A/)', IOSTAT=ErrStat) 'This output file was closed on '//CurDate()//' at '//CurTime()//'.' !-------------------------------------------------------------------------------------------------