From 2b72582dedc591ca8ddb3e250befc2cb585c5be3 Mon Sep 17 00:00:00 2001 From: Bonnie Jonkman Date: Mon, 25 Oct 2021 14:47:50 -0600 Subject: [PATCH 001/130] Update IfW docs --- docs/source/user/inflowwind/driver.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/source/user/inflowwind/driver.rst b/docs/source/user/inflowwind/driver.rst index b0ef7a0170..13a8490c92 100644 --- a/docs/source/user/inflowwind/driver.rst +++ b/docs/source/user/inflowwind/driver.rst @@ -27,6 +27,7 @@ Command-line syntax for InflowWind driver: /vv -- very verbose output /hawc -- convert wind file specified in InflowWind to HAWC format /bladed -- convert wind file specified in InflowWind to Bladed format + /uniform -- convert wind file specified in InflowWind to Uniform-wind format /vtk -- convert wind file specified in InflowWind to VTK format /help -- print this help menu and exit @@ -89,6 +90,15 @@ vtk file for each time in the full-field data structure, and the entire Y-Z grid is printed in each file. This format can be used to visualize the wind field using a viewer such as ParaView. +Uniform Wind +~~~~~~~~~~~~ + +This format generates a text file in the uniform wind format. Converting to this format will +generally lose information in the file because it specifies the wind speed and direction +at only one point and approximates the shear as a power-law exponent. + + + Converting uniform wind to full-field wind format ------------------------------------------------- @@ -113,3 +123,18 @@ full-field wind files, equal to the time it takes to travel the distance of half the grid width. When using the resulting full-field files, care must be taken that the aeroelastic code does not treat it as periodic. + +Converting from a full-field wind format to uniform wind format +--------------------------------------------------------------- + +When converting from a full-field wind format to a uniform wind file, the following assumptions are used: + +- The gust speed, horizontal shear, and vertical linear shear are all 0. +- The Uniform Wind reference height is on a full-field grid point. +- The upflow is calculated using the mean upflow value at the reference point. +- The mean wind direction and upflow are removed from the reference grid point before writing the velocities to the Uniform Wind file. +- The wind direction in the file is the sum of the mean wind direction and the instantaneous direction calculated between instantaneous U and V wind components. +- The power law exponent is either + + 1. The power-law exponent specified in InflowWind (if a power law wind profile is used to add to the turbulence with native-Bladed or HAWC2 files), or + 2. Calculated by using the mean wind speeds at two points: the reference (hub) height and the uppermost height on the grid. \ No newline at end of file From ffea9e7b56a08b91ecd93dededc2312360d45647 Mon Sep 17 00:00:00 2001 From: Bonnie Jonkman Date: Mon, 25 Oct 2021 15:37:29 -0600 Subject: [PATCH 002/130] IfW: move misc vars (needed for future updates) --- modules/inflowwind/src/InflowWind.txt | 29 +- modules/inflowwind/src/InflowWind_Types.f90 | 3512 +++++++++---------- 2 files changed, 1771 insertions(+), 1770 deletions(-) diff --git a/modules/inflowwind/src/InflowWind.txt b/modules/inflowwind/src/InflowWind.txt index d00380ea4d..aa425d1202 100644 --- a/modules/inflowwind/src/InflowWind.txt +++ b/modules/inflowwind/src/InflowWind.txt @@ -106,7 +106,7 @@ typedef ^ ^ IntKi NumWindPoin typedef ^ ^ IntKi TurbineID - 0 - "Wind turbine ID number in the fixed (DEFAULT) file name when FixedWindFileRootName = .TRUE. (used by FAST.Farm)" - typedef ^ ^ LOGICAL FixedWindFileRootName - .FALSE. - "Do the wind data files have a fixed (DEFAULT) file name? (used by FAST.Farm)" - typedef ^ ^ LOGICAL UseInputFile - .TRUE. - "Should we read everthing from an input file, or do we get it some other way" - -typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" +typedef ^ ^ CHARACTER(1024) RootName - - - "RootName for writing output files" typedef ^ ^ FileInfoType PassedFileData - - - "If we don't use the input file, pass everything through this" - typedef ^ ^ LOGICAL WindType2UseInputFile - .TRUE. - "Flag for toggling file based IO in wind type 2." - typedef ^ ^ FileInfoType WindType2Data - - - "Optional slot for wind type 2 data if file IO is not used." - @@ -126,19 +126,6 @@ typedef ^ InitOutputType LOGICAL RotFra typedef ^ InitOutputType LOGICAL IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - -# ..... Misc/Optimization variables................................................................................................. -# Define any data that are used only for efficiency purposes (these variables are not associated with time): -# e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. -typedef ^ MiscVarType IntKi TimeIndex - 0 - "An Index into the TData array" - -typedef ^ ^ IfW_UniformWind_MiscVarType UniformWind - - - "MiscVars from UniformWind" - -typedef ^ ^ IfW_TSFFWind_MiscVarType TSFFWind - - - "MiscVars from TSFFWind" - -typedef ^ ^ IfW_HAWCWind_MiscVarType HAWCWind - - - "MiscVars from HAWCWind" - -typedef ^ ^ IfW_BladedFFWind_MiscVarType BladedFFWind - - - "MiscVars from BladedFFWind" - -typedef ^ ^ IfW_UserWind_MiscVarType UserWind - - - "MiscVars from UserWind" - -typedef ^ ^ IfW_4Dext_MiscVarType FDext - - - "MiscVars from FDext" - -typedef ^ ^ ReKi AllOuts : - - "An array holding the value of all of the calculated (not only selected) output channels" "see OutListParameters.xlsx spreadsheet" -typedef ^ ^ ReKi WindViUVW :: - - "List of UVW velocities for wind velocity measurements, 3xNWindVel. corresponds to ParamData%WindViXYZ" meters/second - # ..... Parameters ................................................................................................................ # Define parameters here: @@ -191,3 +178,17 @@ typedef ^ ContinuousStateType ReKi DummyContSt typedef ^ DiscreteStateType ReKi DummyDiscState - - - "Remove this variable if you have discrete states" - typedef ^ ConstraintStateType ReKi DummyConstrState - - - "Remove this variable if you have constraint states" - typedef ^ OtherStateType ReKi DummyOtherState - - - "Remove this variable if you have other states" - + + +# ..... Misc/Optimization variables................................................................................................. +# Define any data that are used only for efficiency purposes (these variables are not associated with time): +# e.g. indices for searching in an array, large arrays that are local variables in any routine called multiple times, etc. +typedef ^ MiscVarType IntKi TimeIndex - 0 - "An Index into the TData array" - +typedef ^ ^ IfW_UniformWind_MiscVarType UniformWind - - - "MiscVars from UniformWind" - +typedef ^ ^ IfW_TSFFWind_MiscVarType TSFFWind - - - "MiscVars from TSFFWind" - +typedef ^ ^ IfW_HAWCWind_MiscVarType HAWCWind - - - "MiscVars from HAWCWind" - +typedef ^ ^ IfW_BladedFFWind_MiscVarType BladedFFWind - - - "MiscVars from BladedFFWind" - +typedef ^ ^ IfW_UserWind_MiscVarType UserWind - - - "MiscVars from UserWind" - +typedef ^ ^ IfW_4Dext_MiscVarType FDext - - - "MiscVars from FDext" - +typedef ^ ^ ReKi AllOuts : - - "An array holding the value of all of the calculated (not only selected) output channels" "see OutListParameters.xlsx spreadsheet" +typedef ^ ^ ReKi WindViUVW :: - - "List of UVW velocities for wind velocity measurements, 3xNWindVel. corresponds to ParamData%WindViXYZ" meters/second \ No newline at end of file diff --git a/modules/inflowwind/src/InflowWind_Types.f90 b/modules/inflowwind/src/InflowWind_Types.f90 index 8575aab02f..edad566271 100644 --- a/modules/inflowwind/src/InflowWind_Types.f90 +++ b/modules/inflowwind/src/InflowWind_Types.f90 @@ -143,19 +143,6 @@ MODULE InflowWind_Types LOGICAL , DIMENSION(:), ALLOCATABLE :: IsLoad_u !< Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix) [-] END TYPE InflowWind_InitOutputType ! ======================= -! ========= InflowWind_MiscVarType ======= - TYPE, PUBLIC :: InflowWind_MiscVarType - INTEGER(IntKi) :: TimeIndex = 0 !< An Index into the TData array [-] - TYPE(IfW_UniformWind_MiscVarType) :: UniformWind !< MiscVars from UniformWind [-] - TYPE(IfW_TSFFWind_MiscVarType) :: TSFFWind !< MiscVars from TSFFWind [-] - TYPE(IfW_HAWCWind_MiscVarType) :: HAWCWind !< MiscVars from HAWCWind [-] - TYPE(IfW_BladedFFWind_MiscVarType) :: BladedFFWind !< MiscVars from BladedFFWind [-] - TYPE(IfW_UserWind_MiscVarType) :: UserWind !< MiscVars from UserWind [-] - TYPE(IfW_4Dext_MiscVarType) :: FDext !< MiscVars from FDext [-] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: AllOuts !< An array holding the value of all of the calculated (not only selected) output channels [see OutListParameters.xlsx spreadsheet] - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: WindViUVW !< List of UVW velocities for wind velocity measurements, 3xNWindVel. corresponds to ParamData%WindViXYZ [meters/second] - END TYPE InflowWind_MiscVarType -! ======================= ! ========= InflowWind_ParameterType ======= TYPE, PUBLIC :: InflowWind_ParameterType CHARACTER(1024) :: RootFileName !< Root of the InflowWind input filename [-] @@ -218,6 +205,19 @@ MODULE InflowWind_Types REAL(ReKi) :: DummyOtherState !< Remove this variable if you have other states [-] END TYPE InflowWind_OtherStateType ! ======================= +! ========= InflowWind_MiscVarType ======= + TYPE, PUBLIC :: InflowWind_MiscVarType + INTEGER(IntKi) :: TimeIndex = 0 !< An Index into the TData array [-] + TYPE(IfW_UniformWind_MiscVarType) :: UniformWind !< MiscVars from UniformWind [-] + TYPE(IfW_TSFFWind_MiscVarType) :: TSFFWind !< MiscVars from TSFFWind [-] + TYPE(IfW_HAWCWind_MiscVarType) :: HAWCWind !< MiscVars from HAWCWind [-] + TYPE(IfW_BladedFFWind_MiscVarType) :: BladedFFWind !< MiscVars from BladedFFWind [-] + TYPE(IfW_UserWind_MiscVarType) :: UserWind !< MiscVars from UserWind [-] + TYPE(IfW_4Dext_MiscVarType) :: FDext !< MiscVars from FDext [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: AllOuts !< An array holding the value of all of the calculated (not only selected) output channels [see OutListParameters.xlsx spreadsheet] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: WindViUVW !< List of UVW velocities for wind velocity measurements, 3xNWindVel. corresponds to ParamData%WindViXYZ [meters/second] + END TYPE InflowWind_MiscVarType +! ======================= CONTAINS SUBROUTINE InflowWind_CopyWindFileMetaData( SrcWindFileMetaDataData, DstWindFileMetaDataData, CtrlCode, ErrStat, ErrMsg ) TYPE(WindFileMetaData), INTENT(IN) :: SrcWindFileMetaDataData @@ -2360,9 +2360,9 @@ SUBROUTINE InflowWind_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, Err END IF END SUBROUTINE InflowWind_UnPackInitOutput - SUBROUTINE InflowWind_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_MiscVarType), INTENT(IN) :: SrcMiscData - TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: DstMiscData + SUBROUTINE InflowWind_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_ParameterType), INTENT(IN) :: SrcParamData + TYPE(InflowWind_ParameterType), INTENT(INOUT) :: DstParamData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -2372,85 +2372,142 @@ SUBROUTINE InflowWind_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, Err INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyMisc' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyParam' ! ErrStat = ErrID_None ErrMsg = "" - DstMiscData%TimeIndex = SrcMiscData%TimeIndex - CALL IfW_UniformWind_CopyMisc( SrcMiscData%UniformWind, DstMiscData%UniformWind, CtrlCode, ErrStat2, ErrMsg2 ) + DstParamData%RootFileName = SrcParamData%RootFileName + DstParamData%CTTS_Flag = SrcParamData%CTTS_Flag + DstParamData%RotateWindBox = SrcParamData%RotateWindBox + DstParamData%DT = SrcParamData%DT + DstParamData%PropagationDir = SrcParamData%PropagationDir + DstParamData%VFlowAngle = SrcParamData%VFlowAngle + DstParamData%RotToWind = SrcParamData%RotToWind + DstParamData%RotFromWind = SrcParamData%RotFromWind +IF (ALLOCATED(SrcParamData%WindViXYZprime)) THEN + i1_l = LBOUND(SrcParamData%WindViXYZprime,1) + i1_u = UBOUND(SrcParamData%WindViXYZprime,1) + i2_l = LBOUND(SrcParamData%WindViXYZprime,2) + i2_u = UBOUND(SrcParamData%WindViXYZprime,2) + IF (.NOT. ALLOCATED(DstParamData%WindViXYZprime)) THEN + ALLOCATE(DstParamData%WindViXYZprime(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%WindViXYZprime.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%WindViXYZprime = SrcParamData%WindViXYZprime +ENDIF + DstParamData%WindType = SrcParamData%WindType + DstParamData%ReferenceHeight = SrcParamData%ReferenceHeight + DstParamData%RefPosition = SrcParamData%RefPosition + DstParamData%NWindVel = SrcParamData%NWindVel +IF (ALLOCATED(SrcParamData%WindViXYZ)) THEN + i1_l = LBOUND(SrcParamData%WindViXYZ,1) + i1_u = UBOUND(SrcParamData%WindViXYZ,1) + i2_l = LBOUND(SrcParamData%WindViXYZ,2) + i2_u = UBOUND(SrcParamData%WindViXYZ,2) + IF (.NOT. ALLOCATED(DstParamData%WindViXYZ)) THEN + ALLOCATE(DstParamData%WindViXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%WindViXYZ.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%WindViXYZ = SrcParamData%WindViXYZ +ENDIF + CALL IfW_UniformWind_CopyParam( SrcParamData%UniformWind, DstParamData%UniformWind, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_TSFFWind_CopyMisc( SrcMiscData%TSFFWind, DstMiscData%TSFFWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL IfW_TSFFWind_CopyParam( SrcParamData%TSFFWind, DstParamData%TSFFWind, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_HAWCWind_CopyMisc( SrcMiscData%HAWCWind, DstMiscData%HAWCWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL IfW_BladedFFWind_CopyParam( SrcParamData%BladedFFWind, DstParamData%BladedFFWind, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_BladedFFWind_CopyMisc( SrcMiscData%BladedFFWind, DstMiscData%BladedFFWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL IfW_HAWCWind_CopyParam( SrcParamData%HAWCWind, DstParamData%HAWCWind, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_UserWind_CopyMisc( SrcMiscData%UserWind, DstMiscData%UserWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL IfW_UserWind_CopyParam( SrcParamData%UserWind, DstParamData%UserWind, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_4Dext_CopyMisc( SrcMiscData%FDext, DstMiscData%FDext, CtrlCode, ErrStat2, ErrMsg2 ) + CALL IfW_4Dext_CopyParam( SrcParamData%FDext, DstParamData%FDext, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN -IF (ALLOCATED(SrcMiscData%AllOuts)) THEN - i1_l = LBOUND(SrcMiscData%AllOuts,1) - i1_u = UBOUND(SrcMiscData%AllOuts,1) - IF (.NOT. ALLOCATED(DstMiscData%AllOuts)) THEN - ALLOCATE(DstMiscData%AllOuts(i1_l:i1_u),STAT=ErrStat2) + DstParamData%NumOuts = SrcParamData%NumOuts +IF (ALLOCATED(SrcParamData%OutParam)) THEN + i1_l = LBOUND(SrcParamData%OutParam,1) + i1_u = UBOUND(SrcParamData%OutParam,1) + IF (.NOT. ALLOCATED(DstParamData%OutParam)) THEN + ALLOCATE(DstParamData%OutParam(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%AllOuts.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParam.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstMiscData%AllOuts = SrcMiscData%AllOuts + DO i1 = LBOUND(SrcParamData%OutParam,1), UBOUND(SrcParamData%OutParam,1) + CALL NWTC_Library_Copyoutparmtype( SrcParamData%OutParam(i1), DstParamData%OutParam(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO ENDIF -IF (ALLOCATED(SrcMiscData%WindViUVW)) THEN - i1_l = LBOUND(SrcMiscData%WindViUVW,1) - i1_u = UBOUND(SrcMiscData%WindViUVW,1) - i2_l = LBOUND(SrcMiscData%WindViUVW,2) - i2_u = UBOUND(SrcMiscData%WindViUVW,2) - IF (.NOT. ALLOCATED(DstMiscData%WindViUVW)) THEN - ALLOCATE(DstMiscData%WindViUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) +IF (ALLOCATED(SrcParamData%OutParamLinIndx)) THEN + i1_l = LBOUND(SrcParamData%OutParamLinIndx,1) + i1_u = UBOUND(SrcParamData%OutParamLinIndx,1) + i2_l = LBOUND(SrcParamData%OutParamLinIndx,2) + i2_u = UBOUND(SrcParamData%OutParamLinIndx,2) + IF (.NOT. ALLOCATED(DstParamData%OutParamLinIndx)) THEN + ALLOCATE(DstParamData%OutParamLinIndx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%WindViUVW.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParamLinIndx.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstMiscData%WindViUVW = SrcMiscData%WindViUVW + DstParamData%OutParamLinIndx = SrcParamData%OutParamLinIndx ENDIF - END SUBROUTINE InflowWind_CopyMisc + CALL Lidar_CopyParam( SrcParamData%lidar, DstParamData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + END SUBROUTINE InflowWind_CopyParam - SUBROUTINE InflowWind_DestroyMisc( MiscData, ErrStat, ErrMsg ) - TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: MiscData + SUBROUTINE InflowWind_DestroyParam( ParamData, ErrStat, ErrMsg ) + TYPE(InflowWind_ParameterType), INTENT(INOUT) :: ParamData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyMisc' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyParam' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - CALL IfW_UniformWind_DestroyMisc( MiscData%UniformWind, ErrStat, ErrMsg ) - CALL IfW_TSFFWind_DestroyMisc( MiscData%TSFFWind, ErrStat, ErrMsg ) - CALL IfW_HAWCWind_DestroyMisc( MiscData%HAWCWind, ErrStat, ErrMsg ) - CALL IfW_BladedFFWind_DestroyMisc( MiscData%BladedFFWind, ErrStat, ErrMsg ) - CALL IfW_UserWind_DestroyMisc( MiscData%UserWind, ErrStat, ErrMsg ) - CALL IfW_4Dext_DestroyMisc( MiscData%FDext, ErrStat, ErrMsg ) -IF (ALLOCATED(MiscData%AllOuts)) THEN - DEALLOCATE(MiscData%AllOuts) +IF (ALLOCATED(ParamData%WindViXYZprime)) THEN + DEALLOCATE(ParamData%WindViXYZprime) ENDIF -IF (ALLOCATED(MiscData%WindViUVW)) THEN - DEALLOCATE(MiscData%WindViUVW) +IF (ALLOCATED(ParamData%WindViXYZ)) THEN + DEALLOCATE(ParamData%WindViXYZ) ENDIF - END SUBROUTINE InflowWind_DestroyMisc + CALL IfW_UniformWind_DestroyParam( ParamData%UniformWind, ErrStat, ErrMsg ) + CALL IfW_TSFFWind_DestroyParam( ParamData%TSFFWind, ErrStat, ErrMsg ) + CALL IfW_BladedFFWind_DestroyParam( ParamData%BladedFFWind, ErrStat, ErrMsg ) + CALL IfW_HAWCWind_DestroyParam( ParamData%HAWCWind, ErrStat, ErrMsg ) + CALL IfW_UserWind_DestroyParam( ParamData%UserWind, ErrStat, ErrMsg ) + CALL IfW_4Dext_DestroyParam( ParamData%FDext, ErrStat, ErrMsg ) +IF (ALLOCATED(ParamData%OutParam)) THEN +DO i1 = LBOUND(ParamData%OutParam,1), UBOUND(ParamData%OutParam,1) + CALL NWTC_Library_Destroyoutparmtype( ParamData%OutParam(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(ParamData%OutParam) +ENDIF +IF (ALLOCATED(ParamData%OutParamLinIndx)) THEN + DEALLOCATE(ParamData%OutParamLinIndx) +ENDIF + CALL Lidar_DestroyParam( ParamData%lidar, ErrStat, ErrMsg ) + END SUBROUTINE InflowWind_DestroyParam - SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_MiscVarType), INTENT(IN) :: InData + TYPE(InflowWind_ParameterType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -2465,7 +2522,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackMisc' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackParam' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2481,10 +2538,31 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! TimeIndex + Int_BufSz = Int_BufSz + 1*LEN(InData%RootFileName) ! RootFileName + Int_BufSz = Int_BufSz + 1 ! CTTS_Flag + Int_BufSz = Int_BufSz + 1 ! RotateWindBox + Db_BufSz = Db_BufSz + 1 ! DT + Re_BufSz = Re_BufSz + 1 ! PropagationDir + Re_BufSz = Re_BufSz + 1 ! VFlowAngle + Re_BufSz = Re_BufSz + SIZE(InData%RotToWind) ! RotToWind + Re_BufSz = Re_BufSz + SIZE(InData%RotFromWind) ! RotFromWind + Int_BufSz = Int_BufSz + 1 ! WindViXYZprime allocated yes/no + IF ( ALLOCATED(InData%WindViXYZprime) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! WindViXYZprime upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WindViXYZprime) ! WindViXYZprime + END IF + Int_BufSz = Int_BufSz + 1 ! WindType + Re_BufSz = Re_BufSz + 1 ! ReferenceHeight + Re_BufSz = Re_BufSz + SIZE(InData%RefPosition) ! RefPosition + Int_BufSz = Int_BufSz + 1 ! NWindVel + Int_BufSz = Int_BufSz + 1 ! WindViXYZ allocated yes/no + IF ( ALLOCATED(InData%WindViXYZ) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! WindViXYZ upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WindViXYZ) ! WindViXYZ + END IF ! Allocate buffers for subtypes, if any (we'll get sizes from these) Int_BufSz = Int_BufSz + 3 ! UniformWind: size of buffers for each call to pack subtype - CALL IfW_UniformWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, .TRUE. ) ! UniformWind + CALL IfW_UniformWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, .TRUE. ) ! UniformWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2501,7 +2579,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err DEALLOCATE(Int_Buf) END IF Int_BufSz = Int_BufSz + 3 ! TSFFWind: size of buffers for each call to pack subtype - CALL IfW_TSFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! TSFFWind + CALL IfW_TSFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! TSFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2517,42 +2595,42 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Int_BufSz = Int_BufSz + 3 ! HAWCWind: size of buffers for each call to pack subtype - CALL IfW_HAWCWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, .TRUE. ) ! HAWCWind + Int_BufSz = Int_BufSz + 3 ! BladedFFWind: size of buffers for each call to pack subtype + CALL IfW_BladedFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! BladedFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! HAWCWind + IF(ALLOCATED(Re_Buf)) THEN ! BladedFFWind Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! HAWCWind + IF(ALLOCATED(Db_Buf)) THEN ! BladedFFWind Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! HAWCWind + IF(ALLOCATED(Int_Buf)) THEN ! BladedFFWind Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Int_BufSz = Int_BufSz + 3 ! BladedFFWind: size of buffers for each call to pack subtype - CALL IfW_BladedFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! BladedFFWind + Int_BufSz = Int_BufSz + 3 ! HAWCWind: size of buffers for each call to pack subtype + CALL IfW_HAWCWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, .TRUE. ) ! HAWCWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! BladedFFWind + IF(ALLOCATED(Re_Buf)) THEN ! HAWCWind Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! BladedFFWind + IF(ALLOCATED(Db_Buf)) THEN ! HAWCWind Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! BladedFFWind + IF(ALLOCATED(Int_Buf)) THEN ! HAWCWind Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF Int_BufSz = Int_BufSz + 3 ! UserWind: size of buffers for each call to pack subtype - CALL IfW_UserWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, .TRUE. ) ! UserWind + CALL IfW_UserWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, .TRUE. ) ! UserWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2569,7 +2647,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err DEALLOCATE(Int_Buf) END IF Int_BufSz = Int_BufSz + 3 ! FDext: size of buffers for each call to pack subtype - CALL IfW_4Dext_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, .TRUE. ) ! FDext + CALL IfW_4Dext_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, .TRUE. ) ! FDext CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2585,16 +2663,52 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Int_BufSz = Int_BufSz + 1 ! AllOuts allocated yes/no - IF ( ALLOCATED(InData%AllOuts) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! AllOuts upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%AllOuts) ! AllOuts - END IF - Int_BufSz = Int_BufSz + 1 ! WindViUVW allocated yes/no - IF ( ALLOCATED(InData%WindViUVW) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! WindViUVW upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%WindViUVW) ! WindViUVW + Int_BufSz = Int_BufSz + 1 ! NumOuts + Int_BufSz = Int_BufSz + 1 ! OutParam allocated yes/no + IF ( ALLOCATED(InData%OutParam) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! OutParam upper/lower bounds for each dimension + DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) + Int_BufSz = Int_BufSz + 3 ! OutParam: size of buffers for each call to pack subtype + CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, .TRUE. ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! OutParam + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! OutParam + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! OutParam + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO END IF + Int_BufSz = Int_BufSz + 1 ! OutParamLinIndx allocated yes/no + IF ( ALLOCATED(InData%OutParamLinIndx) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! OutParamLinIndx upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%OutParamLinIndx) ! OutParamLinIndx + END IF + Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype + CALL Lidar_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! lidar + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! lidar + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! lidar + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2622,9 +2736,83 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Db_Xferred = 1 Int_Xferred = 1 - IntKiBuf(Int_Xferred) = InData%TimeIndex + DO I = 1, LEN(InData%RootFileName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootFileName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + IntKiBuf(Int_Xferred) = TRANSFER(InData%CTTS_Flag, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - CALL IfW_UniformWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, OnlySize ) ! UniformWind + IntKiBuf(Int_Xferred) = TRANSFER(InData%RotateWindBox, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DT + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%PropagationDir + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%VFlowAngle + Re_Xferred = Re_Xferred + 1 + DO i2 = LBOUND(InData%RotToWind,2), UBOUND(InData%RotToWind,2) + DO i1 = LBOUND(InData%RotToWind,1), UBOUND(InData%RotToWind,1) + ReKiBuf(Re_Xferred) = InData%RotToWind(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + DO i2 = LBOUND(InData%RotFromWind,2), UBOUND(InData%RotFromWind,2) + DO i1 = LBOUND(InData%RotFromWind,1), UBOUND(InData%RotFromWind,1) + ReKiBuf(Re_Xferred) = InData%RotFromWind(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + IF ( .NOT. ALLOCATED(InData%WindViXYZprime) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZprime,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZprime,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZprime,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZprime,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%WindViXYZprime,2), UBOUND(InData%WindViXYZprime,2) + DO i1 = LBOUND(InData%WindViXYZprime,1), UBOUND(InData%WindViXYZprime,1) + ReKiBuf(Re_Xferred) = InData%WindViXYZprime(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IntKiBuf(Int_Xferred) = InData%WindType + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%ReferenceHeight + Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%RefPosition,1), UBOUND(InData%RefPosition,1) + ReKiBuf(Re_Xferred) = InData%RefPosition(i1) + Re_Xferred = Re_Xferred + 1 + END DO + IntKiBuf(Int_Xferred) = InData%NWindVel + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%WindViXYZ) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZ,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZ,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZ,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZ,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%WindViXYZ,2), UBOUND(InData%WindViXYZ,2) + DO i1 = LBOUND(InData%WindViXYZ,1), UBOUND(InData%WindViXYZ,1) + ReKiBuf(Re_Xferred) = InData%WindViXYZ(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + CALL IfW_UniformWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, OnlySize ) ! UniformWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2652,7 +2840,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_TSFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, OnlySize ) ! TSFFWind + CALL IfW_TSFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, OnlySize ) ! TSFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2680,7 +2868,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_HAWCWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, OnlySize ) ! HAWCWind + CALL IfW_BladedFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, OnlySize ) ! BladedFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2708,7 +2896,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_BladedFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, OnlySize ) ! BladedFFWind + CALL IfW_HAWCWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, OnlySize ) ! HAWCWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2736,7 +2924,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_UserWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, OnlySize ) ! UserWind + CALL IfW_UserWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, OnlySize ) ! UserWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2764,7 +2952,7 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_4Dext_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, OnlySize ) ! FDext + CALL IfW_4Dext_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, OnlySize ) ! FDext CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2792,48 +2980,104 @@ SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - IF ( .NOT. ALLOCATED(InData%AllOuts) ) THEN + IntKiBuf(Int_Xferred) = InData%NumOuts + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%OutParam) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%AllOuts,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AllOuts,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParam,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParam,1) Int_Xferred = Int_Xferred + 2 - DO i1 = LBOUND(InData%AllOuts,1), UBOUND(InData%AllOuts,1) - ReKiBuf(Re_Xferred) = InData%AllOuts(i1) - Re_Xferred = Re_Xferred + 1 - END DO + DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) + CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, OnlySize ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO END IF - IF ( .NOT. ALLOCATED(InData%WindViUVW) ) THEN + IF ( .NOT. ALLOCATED(InData%OutParamLinIndx) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViUVW,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViUVW,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParamLinIndx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParamLinIndx,1) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViUVW,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViUVW,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParamLinIndx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParamLinIndx,2) Int_Xferred = Int_Xferred + 2 - DO i2 = LBOUND(InData%WindViUVW,2), UBOUND(InData%WindViUVW,2) - DO i1 = LBOUND(InData%WindViUVW,1), UBOUND(InData%WindViUVW,1) - ReKiBuf(Re_Xferred) = InData%WindViUVW(i1,i2) - Re_Xferred = Re_Xferred + 1 + DO i2 = LBOUND(InData%OutParamLinIndx,2), UBOUND(InData%OutParamLinIndx,2) + DO i1 = LBOUND(InData%OutParamLinIndx,1), UBOUND(InData%OutParamLinIndx,1) + IntKiBuf(Int_Xferred) = InData%OutParamLinIndx(i1,i2) + Int_Xferred = Int_Xferred + 1 END DO END DO END IF - END SUBROUTINE InflowWind_PackMisc + CALL Lidar_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END SUBROUTINE InflowWind_PackParam + + SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: OutData + TYPE(InflowWind_ParameterType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -2846,7 +3090,7 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackMisc' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackParam' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2857,55 +3101,105 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%TimeIndex = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL IfW_UniformWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%UniformWind, ErrStat2, ErrMsg2 ) ! UniformWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) + DO I = 1, LEN(OutData%RootFileName) + OutData%RootFileName(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN + END DO ! I + OutData%CTTS_Flag = TRANSFER(IntKiBuf(Int_Xferred), OutData%CTTS_Flag) + Int_Xferred = Int_Xferred + 1 + OutData%RotateWindBox = TRANSFER(IntKiBuf(Int_Xferred), OutData%RotateWindBox) + Int_Xferred = Int_Xferred + 1 + OutData%DT = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%PropagationDir = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%VFlowAngle = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%RotToWind,1) + i1_u = UBOUND(OutData%RotToWind,1) + i2_l = LBOUND(OutData%RotToWind,2) + i2_u = UBOUND(OutData%RotToWind,2) + DO i2 = LBOUND(OutData%RotToWind,2), UBOUND(OutData%RotToWind,2) + DO i1 = LBOUND(OutData%RotToWind,1), UBOUND(OutData%RotToWind,1) + OutData%RotToWind(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + i1_l = LBOUND(OutData%RotFromWind,1) + i1_u = UBOUND(OutData%RotFromWind,1) + i2_l = LBOUND(OutData%RotFromWind,2) + i2_u = UBOUND(OutData%RotFromWind,2) + DO i2 = LBOUND(OutData%RotFromWind,2), UBOUND(OutData%RotFromWind,2) + DO i1 = LBOUND(OutData%RotFromWind,1), UBOUND(OutData%RotFromWind,1) + OutData%RotFromWind(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViXYZprime not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WindViXYZprime)) DEALLOCATE(OutData%WindViXYZprime) + ALLOCATE(OutData%WindViXYZprime(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViXYZprime.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%WindViXYZprime,2), UBOUND(OutData%WindViXYZprime,2) + DO i1 = LBOUND(OutData%WindViXYZprime,1), UBOUND(OutData%WindViXYZprime,1) + OutData%WindViXYZprime(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + OutData%WindType = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%ReferenceHeight = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%RefPosition,1) + i1_u = UBOUND(OutData%RefPosition,1) + DO i1 = LBOUND(OutData%RefPosition,1), UBOUND(OutData%RefPosition,1) + OutData%RefPosition(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + OutData%NWindVel = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViXYZ not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WindViXYZ)) DEALLOCATE(OutData%WindViXYZ) + ALLOCATE(OutData%WindViXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViXYZ.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%WindViXYZ,2), UBOUND(OutData%WindViXYZ,2) + DO i1 = LBOUND(OutData%WindViXYZ,1), UBOUND(OutData%WindViXYZ,1) + OutData%WindViXYZ(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN END IF Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) Re_Xferred = Re_Xferred + Buf_size @@ -2932,7 +3226,7 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_TSFFWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%TSFFWind, ErrStat2, ErrMsg2 ) ! TSFFWind + CALL IfW_UniformWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%UniformWind, ErrStat2, ErrMsg2 ) ! UniformWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2972,7 +3266,7 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_HAWCWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%HAWCWind, ErrStat2, ErrMsg2 ) ! HAWCWind + CALL IfW_TSFFWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%TSFFWind, ErrStat2, ErrMsg2 ) ! TSFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -3012,7 +3306,7 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_BladedFFWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%BladedFFWind, ErrStat2, ErrMsg2 ) ! BladedFFWind + CALL IfW_BladedFFWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%BladedFFWind, ErrStat2, ErrMsg2 ) ! BladedFFWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -3052,7 +3346,7 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_UserWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%UserWind, ErrStat2, ErrMsg2 ) ! UserWind + CALL IfW_HAWCWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%HAWCWind, ErrStat2, ErrMsg2 ) ! HAWCWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -3092,32 +3386,112 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_4Dext_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%FDext, ErrStat2, ErrMsg2 ) ! FDext + CALL IfW_UserWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%UserWind, ErrStat2, ErrMsg2 ) ! UserWind CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! AllOuts not allocated + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_4Dext_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%FDext, ErrStat2, ErrMsg2 ) ! FDext + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%NumOuts = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParam not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 i1_l = IntKiBuf( Int_Xferred ) i1_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%AllOuts)) DEALLOCATE(OutData%AllOuts) - ALLOCATE(OutData%AllOuts(i1_l:i1_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%OutParam)) DEALLOCATE(OutData%OutParam) + ALLOCATE(OutData%OutParam(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%AllOuts.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParam.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%AllOuts,1), UBOUND(OutData%AllOuts,1) - OutData%AllOuts(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO + DO i1 = LBOUND(OutData%OutParam,1), UBOUND(OutData%OutParam,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackoutparmtype( Re_Buf, Db_Buf, Int_Buf, OutData%OutParam(i1), ErrStat2, ErrMsg2 ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViUVW not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParamLinIndx not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -3127,24 +3501,64 @@ SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, i2_l = IntKiBuf( Int_Xferred ) i2_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WindViUVW)) DEALLOCATE(OutData%WindViUVW) - ALLOCATE(OutData%WindViUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%OutParamLinIndx)) DEALLOCATE(OutData%OutParamLinIndx) + ALLOCATE(OutData%OutParamLinIndx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViUVW.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParamLinIndx.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i2 = LBOUND(OutData%WindViUVW,2), UBOUND(OutData%WindViUVW,2) - DO i1 = LBOUND(OutData%WindViUVW,1), UBOUND(OutData%WindViUVW,1) - OutData%WindViUVW(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i2 = LBOUND(OutData%OutParamLinIndx,2), UBOUND(OutData%OutParamLinIndx,2) + DO i1 = LBOUND(OutData%OutParamLinIndx,1), UBOUND(OutData%OutParamLinIndx,1) + OutData%OutParamLinIndx(i1,i2) = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 END DO END DO END IF - END SUBROUTINE InflowWind_UnPackMisc + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL Lidar_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_ParameterType), INTENT(IN) :: SrcParamData - TYPE(InflowWind_ParameterType), INTENT(INOUT) :: DstParamData + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END SUBROUTINE InflowWind_UnPackParam + + SUBROUTINE InflowWind_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_InputType), INTENT(IN) :: SrcInputData + TYPE(InflowWind_InputType), INTENT(INOUT) :: DstInputData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -3154,142 +3568,49 @@ SUBROUTINE InflowWind_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyParam' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyInput' ! ErrStat = ErrID_None ErrMsg = "" - DstParamData%RootFileName = SrcParamData%RootFileName - DstParamData%CTTS_Flag = SrcParamData%CTTS_Flag - DstParamData%RotateWindBox = SrcParamData%RotateWindBox - DstParamData%DT = SrcParamData%DT - DstParamData%PropagationDir = SrcParamData%PropagationDir - DstParamData%VFlowAngle = SrcParamData%VFlowAngle - DstParamData%RotToWind = SrcParamData%RotToWind - DstParamData%RotFromWind = SrcParamData%RotFromWind -IF (ALLOCATED(SrcParamData%WindViXYZprime)) THEN - i1_l = LBOUND(SrcParamData%WindViXYZprime,1) - i1_u = UBOUND(SrcParamData%WindViXYZprime,1) - i2_l = LBOUND(SrcParamData%WindViXYZprime,2) - i2_u = UBOUND(SrcParamData%WindViXYZprime,2) - IF (.NOT. ALLOCATED(DstParamData%WindViXYZprime)) THEN - ALLOCATE(DstParamData%WindViXYZprime(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%WindViXYZprime.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%WindViXYZprime = SrcParamData%WindViXYZprime -ENDIF - DstParamData%WindType = SrcParamData%WindType - DstParamData%ReferenceHeight = SrcParamData%ReferenceHeight - DstParamData%RefPosition = SrcParamData%RefPosition - DstParamData%NWindVel = SrcParamData%NWindVel -IF (ALLOCATED(SrcParamData%WindViXYZ)) THEN - i1_l = LBOUND(SrcParamData%WindViXYZ,1) - i1_u = UBOUND(SrcParamData%WindViXYZ,1) - i2_l = LBOUND(SrcParamData%WindViXYZ,2) - i2_u = UBOUND(SrcParamData%WindViXYZ,2) - IF (.NOT. ALLOCATED(DstParamData%WindViXYZ)) THEN - ALLOCATE(DstParamData%WindViXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%WindViXYZ.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%WindViXYZ = SrcParamData%WindViXYZ -ENDIF - CALL IfW_UniformWind_CopyParam( SrcParamData%UniformWind, DstParamData%UniformWind, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_TSFFWind_CopyParam( SrcParamData%TSFFWind, DstParamData%TSFFWind, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_BladedFFWind_CopyParam( SrcParamData%BladedFFWind, DstParamData%BladedFFWind, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_HAWCWind_CopyParam( SrcParamData%HAWCWind, DstParamData%HAWCWind, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_UserWind_CopyParam( SrcParamData%UserWind, DstParamData%UserWind, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - CALL IfW_4Dext_CopyParam( SrcParamData%FDext, DstParamData%FDext, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - DstParamData%NumOuts = SrcParamData%NumOuts -IF (ALLOCATED(SrcParamData%OutParam)) THEN - i1_l = LBOUND(SrcParamData%OutParam,1) - i1_u = UBOUND(SrcParamData%OutParam,1) - IF (.NOT. ALLOCATED(DstParamData%OutParam)) THEN - ALLOCATE(DstParamData%OutParam(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParam.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DO i1 = LBOUND(SrcParamData%OutParam,1), UBOUND(SrcParamData%OutParam,1) - CALL NWTC_Library_Copyoutparmtype( SrcParamData%OutParam(i1), DstParamData%OutParam(i1), CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - ENDDO -ENDIF -IF (ALLOCATED(SrcParamData%OutParamLinIndx)) THEN - i1_l = LBOUND(SrcParamData%OutParamLinIndx,1) - i1_u = UBOUND(SrcParamData%OutParamLinIndx,1) - i2_l = LBOUND(SrcParamData%OutParamLinIndx,2) - i2_u = UBOUND(SrcParamData%OutParamLinIndx,2) - IF (.NOT. ALLOCATED(DstParamData%OutParamLinIndx)) THEN - ALLOCATE(DstParamData%OutParamLinIndx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) +IF (ALLOCATED(SrcInputData%PositionXYZ)) THEN + i1_l = LBOUND(SrcInputData%PositionXYZ,1) + i1_u = UBOUND(SrcInputData%PositionXYZ,1) + i2_l = LBOUND(SrcInputData%PositionXYZ,2) + i2_u = UBOUND(SrcInputData%PositionXYZ,2) + IF (.NOT. ALLOCATED(DstInputData%PositionXYZ)) THEN + ALLOCATE(DstInputData%PositionXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParamLinIndx.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%PositionXYZ.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstParamData%OutParamLinIndx = SrcParamData%OutParamLinIndx + DstInputData%PositionXYZ = SrcInputData%PositionXYZ ENDIF - CALL Lidar_CopyParam( SrcParamData%lidar, DstParamData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) + CALL Lidar_CopyInput( SrcInputData%lidar, DstInputData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - END SUBROUTINE InflowWind_CopyParam + END SUBROUTINE InflowWind_CopyInput - SUBROUTINE InflowWind_DestroyParam( ParamData, ErrStat, ErrMsg ) - TYPE(InflowWind_ParameterType), INTENT(INOUT) :: ParamData + SUBROUTINE InflowWind_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(InflowWind_InputType), INTENT(INOUT) :: InputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyParam' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyInput' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(ParamData%WindViXYZprime)) THEN - DEALLOCATE(ParamData%WindViXYZprime) -ENDIF -IF (ALLOCATED(ParamData%WindViXYZ)) THEN - DEALLOCATE(ParamData%WindViXYZ) -ENDIF - CALL IfW_UniformWind_DestroyParam( ParamData%UniformWind, ErrStat, ErrMsg ) - CALL IfW_TSFFWind_DestroyParam( ParamData%TSFFWind, ErrStat, ErrMsg ) - CALL IfW_BladedFFWind_DestroyParam( ParamData%BladedFFWind, ErrStat, ErrMsg ) - CALL IfW_HAWCWind_DestroyParam( ParamData%HAWCWind, ErrStat, ErrMsg ) - CALL IfW_UserWind_DestroyParam( ParamData%UserWind, ErrStat, ErrMsg ) - CALL IfW_4Dext_DestroyParam( ParamData%FDext, ErrStat, ErrMsg ) -IF (ALLOCATED(ParamData%OutParam)) THEN -DO i1 = LBOUND(ParamData%OutParam,1), UBOUND(ParamData%OutParam,1) - CALL NWTC_Library_Destroyoutparmtype( ParamData%OutParam(i1), ErrStat, ErrMsg ) -ENDDO - DEALLOCATE(ParamData%OutParam) -ENDIF -IF (ALLOCATED(ParamData%OutParamLinIndx)) THEN - DEALLOCATE(ParamData%OutParamLinIndx) +IF (ALLOCATED(InputData%PositionXYZ)) THEN + DEALLOCATE(InputData%PositionXYZ) ENDIF - CALL Lidar_DestroyParam( ParamData%lidar, ErrStat, ErrMsg ) - END SUBROUTINE InflowWind_DestroyParam + CALL Lidar_DestroyInput( InputData%lidar, ErrStat, ErrMsg ) + END SUBROUTINE InflowWind_DestroyInput - SUBROUTINE InflowWind_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_ParameterType), INTENT(IN) :: InData + TYPE(InflowWind_InputType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -3304,7 +3625,7 @@ SUBROUTINE InflowWind_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackParam' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackInput' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -3320,309 +3641,77 @@ SUBROUTINE InflowWind_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1*LEN(InData%RootFileName) ! RootFileName - Int_BufSz = Int_BufSz + 1 ! CTTS_Flag - Int_BufSz = Int_BufSz + 1 ! RotateWindBox - Db_BufSz = Db_BufSz + 1 ! DT - Re_BufSz = Re_BufSz + 1 ! PropagationDir - Re_BufSz = Re_BufSz + 1 ! VFlowAngle - Re_BufSz = Re_BufSz + SIZE(InData%RotToWind) ! RotToWind - Re_BufSz = Re_BufSz + SIZE(InData%RotFromWind) ! RotFromWind - Int_BufSz = Int_BufSz + 1 ! WindViXYZprime allocated yes/no - IF ( ALLOCATED(InData%WindViXYZprime) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! WindViXYZprime upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%WindViXYZprime) ! WindViXYZprime - END IF - Int_BufSz = Int_BufSz + 1 ! WindType - Re_BufSz = Re_BufSz + 1 ! ReferenceHeight - Re_BufSz = Re_BufSz + SIZE(InData%RefPosition) ! RefPosition - Int_BufSz = Int_BufSz + 1 ! NWindVel - Int_BufSz = Int_BufSz + 1 ! WindViXYZ allocated yes/no - IF ( ALLOCATED(InData%WindViXYZ) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! WindViXYZ upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%WindViXYZ) ! WindViXYZ + Int_BufSz = Int_BufSz + 1 ! PositionXYZ allocated yes/no + IF ( ALLOCATED(InData%PositionXYZ) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! PositionXYZ upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%PositionXYZ) ! PositionXYZ END IF ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! UniformWind: size of buffers for each call to pack subtype - CALL IfW_UniformWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, .TRUE. ) ! UniformWind + Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype + CALL Lidar_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! UniformWind + IF(ALLOCATED(Re_Buf)) THEN ! lidar Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! UniformWind + IF(ALLOCATED(Db_Buf)) THEN ! lidar Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! UniformWind + IF(ALLOCATED(Int_Buf)) THEN ! lidar Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Int_BufSz = Int_BufSz + 3 ! TSFFWind: size of buffers for each call to pack subtype - CALL IfW_TSFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! TSFFWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) - IF(ALLOCATED(Re_Buf)) THEN ! TSFFWind - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! TSFFWind - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! TSFFWind - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - Int_BufSz = Int_BufSz + 3 ! BladedFFWind: size of buffers for each call to pack subtype - CALL IfW_BladedFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! BladedFFWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! BladedFFWind - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! BladedFFWind - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! BladedFFWind - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - Int_BufSz = Int_BufSz + 3 ! HAWCWind: size of buffers for each call to pack subtype - CALL IfW_HAWCWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, .TRUE. ) ! HAWCWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! HAWCWind - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! HAWCWind - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! HAWCWind - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - Int_BufSz = Int_BufSz + 3 ! UserWind: size of buffers for each call to pack subtype - CALL IfW_UserWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, .TRUE. ) ! UserWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! UserWind - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! UserWind - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! UserWind - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - Int_BufSz = Int_BufSz + 3 ! FDext: size of buffers for each call to pack subtype - CALL IfW_4Dext_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, .TRUE. ) ! FDext - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! FDext - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! FDext - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! FDext - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - Int_BufSz = Int_BufSz + 1 ! NumOuts - Int_BufSz = Int_BufSz + 1 ! OutParam allocated yes/no - IF ( ALLOCATED(InData%OutParam) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! OutParam upper/lower bounds for each dimension - DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) - Int_BufSz = Int_BufSz + 3 ! OutParam: size of buffers for each call to pack subtype - CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, .TRUE. ) ! OutParam - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! OutParam - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! OutParam - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! OutParam - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - END DO - END IF - Int_BufSz = Int_BufSz + 1 ! OutParamLinIndx allocated yes/no - IF ( ALLOCATED(InData%OutParamLinIndx) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! OutParamLinIndx upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%OutParamLinIndx) ! OutParamLinIndx - END IF - Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype - CALL Lidar_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! lidar - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! lidar - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! lidar - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF - IF ( Re_BufSz .GT. 0 ) THEN - ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Db_BufSz .GT. 0 ) THEN - ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Int_BufSz .GT. 0 ) THEN - ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) - - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - - DO I = 1, LEN(InData%RootFileName) - IntKiBuf(Int_Xferred) = ICHAR(InData%RootFileName(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I - IntKiBuf(Int_Xferred) = TRANSFER(InData%CTTS_Flag, IntKiBuf(1)) - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%RotateWindBox, IntKiBuf(1)) - Int_Xferred = Int_Xferred + 1 - DbKiBuf(Db_Xferred) = InData%DT - Db_Xferred = Db_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%PropagationDir - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%VFlowAngle - Re_Xferred = Re_Xferred + 1 - DO i2 = LBOUND(InData%RotToWind,2), UBOUND(InData%RotToWind,2) - DO i1 = LBOUND(InData%RotToWind,1), UBOUND(InData%RotToWind,1) - ReKiBuf(Re_Xferred) = InData%RotToWind(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - DO i2 = LBOUND(InData%RotFromWind,2), UBOUND(InData%RotFromWind,2) - DO i1 = LBOUND(InData%RotFromWind,1), UBOUND(InData%RotFromWind,1) - ReKiBuf(Re_Xferred) = InData%RotFromWind(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - IF ( .NOT. ALLOCATED(InData%WindViXYZprime) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZprime,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZprime,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZprime,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZprime,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%WindViXYZprime,2), UBOUND(InData%WindViXYZprime,2) - DO i1 = LBOUND(InData%WindViXYZprime,1), UBOUND(InData%WindViXYZprime,1) - ReKiBuf(Re_Xferred) = InData%WindViXYZprime(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - IntKiBuf(Int_Xferred) = InData%WindType - Int_Xferred = Int_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%ReferenceHeight - Re_Xferred = Re_Xferred + 1 - DO i1 = LBOUND(InData%RefPosition,1), UBOUND(InData%RefPosition,1) - ReKiBuf(Re_Xferred) = InData%RefPosition(i1) - Re_Xferred = Re_Xferred + 1 - END DO - IntKiBuf(Int_Xferred) = InData%NWindVel - Int_Xferred = Int_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%WindViXYZ) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZ,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZ,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViXYZ,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViXYZ,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%WindViXYZ,2), UBOUND(InData%WindViXYZ,2) - DO i1 = LBOUND(InData%WindViXYZ,1), UBOUND(InData%WindViXYZ,1) - ReKiBuf(Re_Xferred) = InData%WindViXYZ(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - CALL IfW_UniformWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, OnlySize ) ! UniformWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - CALL IfW_TSFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, OnlySize ) ! TSFFWind + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%PositionXYZ) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%PositionXYZ,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PositionXYZ,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%PositionXYZ,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PositionXYZ,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%PositionXYZ,2), UBOUND(InData%PositionXYZ,2) + DO i1 = LBOUND(InData%PositionXYZ,1), UBOUND(InData%PositionXYZ,1) + ReKiBuf(Re_Xferred) = InData%PositionXYZ(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + CALL Lidar_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -3650,216 +3739,13 @@ SUBROUTINE InflowWind_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - CALL IfW_BladedFFWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, OnlySize ) ! BladedFFWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN + END SUBROUTINE InflowWind_PackInput - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - CALL IfW_HAWCWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, OnlySize ) ! HAWCWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - CALL IfW_UserWind_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, OnlySize ) ! UserWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - CALL IfW_4Dext_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, OnlySize ) ! FDext - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IntKiBuf(Int_Xferred) = InData%NumOuts - Int_Xferred = Int_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%OutParam) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParam,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParam,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) - CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, OnlySize ) ! OutParam - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - END DO - END IF - IF ( .NOT. ALLOCATED(InData%OutParamLinIndx) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParamLinIndx,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParamLinIndx,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParamLinIndx,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParamLinIndx,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%OutParamLinIndx,2), UBOUND(InData%OutParamLinIndx,2) - DO i1 = LBOUND(InData%OutParamLinIndx,1), UBOUND(InData%OutParamLinIndx,1) - IntKiBuf(Int_Xferred) = InData%OutParamLinIndx(i1,i2) - Int_Xferred = Int_Xferred + 1 - END DO - END DO - END IF - CALL Lidar_PackParam( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - END SUBROUTINE InflowWind_PackParam - - SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE InflowWind_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_ParameterType), INTENT(INOUT) :: OutData + TYPE(InflowWind_InputType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -3872,7 +3758,7 @@ SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackParam' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackInput' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -3883,41 +3769,7 @@ SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - DO I = 1, LEN(OutData%RootFileName) - OutData%RootFileName(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I - OutData%CTTS_Flag = TRANSFER(IntKiBuf(Int_Xferred), OutData%CTTS_Flag) - Int_Xferred = Int_Xferred + 1 - OutData%RotateWindBox = TRANSFER(IntKiBuf(Int_Xferred), OutData%RotateWindBox) - Int_Xferred = Int_Xferred + 1 - OutData%DT = DbKiBuf(Db_Xferred) - Db_Xferred = Db_Xferred + 1 - OutData%PropagationDir = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%VFlowAngle = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - i1_l = LBOUND(OutData%RotToWind,1) - i1_u = UBOUND(OutData%RotToWind,1) - i2_l = LBOUND(OutData%RotToWind,2) - i2_u = UBOUND(OutData%RotToWind,2) - DO i2 = LBOUND(OutData%RotToWind,2), UBOUND(OutData%RotToWind,2) - DO i1 = LBOUND(OutData%RotToWind,1), UBOUND(OutData%RotToWind,1) - OutData%RotToWind(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - i1_l = LBOUND(OutData%RotFromWind,1) - i1_u = UBOUND(OutData%RotFromWind,1) - i2_l = LBOUND(OutData%RotFromWind,2) - i2_u = UBOUND(OutData%RotFromWind,2) - DO i2 = LBOUND(OutData%RotFromWind,2), UBOUND(OutData%RotFromWind,2) - DO i1 = LBOUND(OutData%RotFromWind,1), UBOUND(OutData%RotFromWind,1) - OutData%RotFromWind(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViXYZprime not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! PositionXYZ not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -3927,50 +3779,15 @@ SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, i2_l = IntKiBuf( Int_Xferred ) i2_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WindViXYZprime)) DEALLOCATE(OutData%WindViXYZprime) - ALLOCATE(OutData%WindViXYZprime(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%PositionXYZ)) DEALLOCATE(OutData%PositionXYZ) + ALLOCATE(OutData%PositionXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViXYZprime.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%PositionXYZ.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i2 = LBOUND(OutData%WindViXYZprime,2), UBOUND(OutData%WindViXYZprime,2) - DO i1 = LBOUND(OutData%WindViXYZprime,1), UBOUND(OutData%WindViXYZprime,1) - OutData%WindViXYZprime(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - OutData%WindType = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%ReferenceHeight = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - i1_l = LBOUND(OutData%RefPosition,1) - i1_u = UBOUND(OutData%RefPosition,1) - DO i1 = LBOUND(OutData%RefPosition,1), UBOUND(OutData%RefPosition,1) - OutData%RefPosition(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - OutData%NWindVel = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViXYZ not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WindViXYZ)) DEALLOCATE(OutData%WindViXYZ) - ALLOCATE(OutData%WindViXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViXYZ.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i2 = LBOUND(OutData%WindViXYZ,2), UBOUND(OutData%WindViXYZ,2) - DO i1 = LBOUND(OutData%WindViXYZ,1), UBOUND(OutData%WindViXYZ,1) - OutData%WindViXYZ(i1,i2) = ReKiBuf(Re_Xferred) + DO i2 = LBOUND(OutData%PositionXYZ,2), UBOUND(OutData%PositionXYZ,2) + DO i1 = LBOUND(OutData%PositionXYZ,1), UBOUND(OutData%PositionXYZ,1) + OutData%PositionXYZ(i1,i2) = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 END DO END DO @@ -4008,229 +3825,316 @@ SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL IfW_UniformWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%UniformWind, ErrStat2, ErrMsg2 ) ! UniformWind + CALL Lidar_UnpackInput( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL IfW_TSFFWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%TSFFWind, ErrStat2, ErrMsg2 ) ! TSFFWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN + END SUBROUTINE InflowWind_UnPackInput - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL IfW_BladedFFWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%BladedFFWind, ErrStat2, ErrMsg2 ) ! BladedFFWind + SUBROUTINE InflowWind_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_OutputType), INTENT(IN) :: SrcOutputData + TYPE(InflowWind_OutputType), INTENT(INOUT) :: DstOutputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyOutput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcOutputData%VelocityUVW)) THEN + i1_l = LBOUND(SrcOutputData%VelocityUVW,1) + i1_u = UBOUND(SrcOutputData%VelocityUVW,1) + i2_l = LBOUND(SrcOutputData%VelocityUVW,2) + i2_u = UBOUND(SrcOutputData%VelocityUVW,2) + IF (.NOT. ALLOCATED(DstOutputData%VelocityUVW)) THEN + ALLOCATE(DstOutputData%VelocityUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VelocityUVW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%VelocityUVW = SrcOutputData%VelocityUVW +ENDIF +IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN + i1_l = LBOUND(SrcOutputData%WriteOutput,1) + i1_u = UBOUND(SrcOutputData%WriteOutput,1) + IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN + ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%WriteOutput = SrcOutputData%WriteOutput +ENDIF + DstOutputData%DiskVel = SrcOutputData%DiskVel + CALL Lidar_CopyOutput( SrcOutputData%lidar, DstOutputData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + END SUBROUTINE InflowWind_CopyOutput + + SUBROUTINE InflowWind_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(InflowWind_OutputType), INTENT(INOUT) :: OutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(OutputData%VelocityUVW)) THEN + DEALLOCATE(OutputData%VelocityUVW) +ENDIF +IF (ALLOCATED(OutputData%WriteOutput)) THEN + DEALLOCATE(OutputData%WriteOutput) +ENDIF + CALL Lidar_DestroyOutput( OutputData%lidar, ErrStat, ErrMsg ) + END SUBROUTINE InflowWind_DestroyOutput + + SUBROUTINE InflowWind_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(InflowWind_OutputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! VelocityUVW allocated yes/no + IF ( ALLOCATED(InData%VelocityUVW) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! VelocityUVW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%VelocityUVW) ! VelocityUVW + END IF + Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no + IF ( ALLOCATED(InData%WriteOutput) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput + END IF + Re_BufSz = Re_BufSz + SIZE(InData%DiskVel) ! DiskVel + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype + CALL Lidar_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size + IF(ALLOCATED(Re_Buf)) THEN ! lidar + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size + IF(ALLOCATED(Db_Buf)) THEN ! lidar + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size + IF(ALLOCATED(Int_Buf)) THEN ! lidar + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) END IF - CALL IfW_HAWCWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%HAWCWind, ErrStat2, ErrMsg2 ) ! HAWCWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL IfW_UserWind_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%UserWind, ErrStat2, ErrMsg2 ) ! UserWind - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL IfW_4Dext_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%FDext, ErrStat2, ErrMsg2 ) ! FDext + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%VelocityUVW) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%VelocityUVW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VelocityUVW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%VelocityUVW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VelocityUVW,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%VelocityUVW,2), UBOUND(InData%VelocityUVW,2) + DO i1 = LBOUND(InData%VelocityUVW,1), UBOUND(InData%VelocityUVW,1) + ReKiBuf(Re_Xferred) = InData%VelocityUVW(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) + ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + DO i1 = LBOUND(InData%DiskVel,1), UBOUND(InData%DiskVel,1) + ReKiBuf(Re_Xferred) = InData%DiskVel(i1) + Re_Xferred = Re_Xferred + 1 + END DO + CALL Lidar_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - OutData%NumOuts = IntKiBuf(Int_Xferred) + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END SUBROUTINE InflowWind_PackOutput + + SUBROUTINE InflowWind_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(InflowWind_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VelocityUVW not allocated Int_Xferred = Int_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParam not allocated + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%VelocityUVW)) DEALLOCATE(OutData%VelocityUVW) + ALLOCATE(OutData%VelocityUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VelocityUVW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%VelocityUVW,2), UBOUND(OutData%VelocityUVW,2) + DO i1 = LBOUND(OutData%VelocityUVW,1), UBOUND(OutData%VelocityUVW,1) + OutData%VelocityUVW(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 i1_l = IntKiBuf( Int_Xferred ) i1_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%OutParam)) DEALLOCATE(OutData%OutParam) - ALLOCATE(OutData%OutParam(i1_l:i1_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) + ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParam.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%OutParam,1), UBOUND(OutData%OutParam,1) + DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) + OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + i1_l = LBOUND(OutData%DiskVel,1) + i1_u = UBOUND(OutData%DiskVel,1) + DO i1 = LBOUND(OutData%DiskVel,1), UBOUND(OutData%DiskVel,1) + OutData%DiskVel(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO Buf_size=IntKiBuf( Int_Xferred ) Int_Xferred = Int_Xferred + 1 IF(Buf_size > 0) THEN @@ -4264,135 +4168,48 @@ SUBROUTINE InflowWind_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL NWTC_Library_Unpackoutparmtype( Re_Buf, Db_Buf, Int_Buf, OutData%OutParam(i1), ErrStat2, ErrMsg2 ) ! OutParam + CALL Lidar_UnpackOutput( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParamLinIndx not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%OutParamLinIndx)) DEALLOCATE(OutData%OutParamLinIndx) - ALLOCATE(OutData%OutParamLinIndx(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParamLinIndx.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i2 = LBOUND(OutData%OutParamLinIndx,2), UBOUND(OutData%OutParamLinIndx,2) - DO i1 = LBOUND(OutData%OutParamLinIndx,1), UBOUND(OutData%OutParamLinIndx,1) - OutData%OutParamLinIndx(i1,i2) = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - END DO - END DO - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL Lidar_UnpackParam( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - END SUBROUTINE InflowWind_UnPackParam + END SUBROUTINE InflowWind_UnPackOutput - SUBROUTINE InflowWind_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_InputType), INTENT(IN) :: SrcInputData - TYPE(InflowWind_InputType), INTENT(INOUT) :: DstInputData + SUBROUTINE InflowWind_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: DstContStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyInput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyContState' ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(SrcInputData%PositionXYZ)) THEN - i1_l = LBOUND(SrcInputData%PositionXYZ,1) - i1_u = UBOUND(SrcInputData%PositionXYZ,1) - i2_l = LBOUND(SrcInputData%PositionXYZ,2) - i2_u = UBOUND(SrcInputData%PositionXYZ,2) - IF (.NOT. ALLOCATED(DstInputData%PositionXYZ)) THEN - ALLOCATE(DstInputData%PositionXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%PositionXYZ.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstInputData%PositionXYZ = SrcInputData%PositionXYZ -ENDIF - CALL Lidar_CopyInput( SrcInputData%lidar, DstInputData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - END SUBROUTINE InflowWind_CopyInput + DstContStateData%DummyContState = SrcContStateData%DummyContState + END SUBROUTINE InflowWind_CopyContState - SUBROUTINE InflowWind_DestroyInput( InputData, ErrStat, ErrMsg ) - TYPE(InflowWind_InputType), INTENT(INOUT) :: InputData + SUBROUTINE InflowWind_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: ContStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyInput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyContState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(InputData%PositionXYZ)) THEN - DEALLOCATE(InputData%PositionXYZ) -ENDIF - CALL Lidar_DestroyInput( InputData%lidar, ErrStat, ErrMsg ) - END SUBROUTINE InflowWind_DestroyInput + END SUBROUTINE InflowWind_DestroyContState - SUBROUTINE InflowWind_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_InputType), INTENT(IN) :: InData + TYPE(InflowWind_ContinuousStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -4407,7 +4224,7 @@ SUBROUTINE InflowWind_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackInput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackContState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -4423,29 +4240,7 @@ SUBROUTINE InflowWind_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! PositionXYZ allocated yes/no - IF ( ALLOCATED(InData%PositionXYZ) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! PositionXYZ upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%PositionXYZ) ! PositionXYZ - END IF - ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype - CALL Lidar_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! lidar - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! lidar - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! lidar - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF + Re_BufSz = Re_BufSz + 1 ! DummyContState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4473,61 +4268,15 @@ SUBROUTINE InflowWind_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Db_Xferred = 1 Int_Xferred = 1 - IF ( .NOT. ALLOCATED(InData%PositionXYZ) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%PositionXYZ,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PositionXYZ,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%PositionXYZ,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%PositionXYZ,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%PositionXYZ,2), UBOUND(InData%PositionXYZ,2) - DO i1 = LBOUND(InData%PositionXYZ,1), UBOUND(InData%PositionXYZ,1) - ReKiBuf(Re_Xferred) = InData%PositionXYZ(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - CALL Lidar_PackInput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - END SUBROUTINE InflowWind_PackInput + ReKiBuf(Re_Xferred) = InData%DummyContState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE InflowWind_PackContState - SUBROUTINE InflowWind_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE InflowWind_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_InputType), INTENT(INOUT) :: OutData + TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -4536,11 +4285,9 @@ SUBROUTINE InflowWind_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, INTEGER(IntKi) :: Db_Xferred INTEGER(IntKi) :: Int_Xferred INTEGER(IntKi) :: i - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackInput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackContState' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -4551,142 +4298,43 @@ SUBROUTINE InflowWind_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! PositionXYZ not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%PositionXYZ)) DEALLOCATE(OutData%PositionXYZ) - ALLOCATE(OutData%PositionXYZ(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%PositionXYZ.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i2 = LBOUND(OutData%PositionXYZ,2), UBOUND(OutData%PositionXYZ,2) - DO i1 = LBOUND(OutData%PositionXYZ,1), UBOUND(OutData%PositionXYZ,1) - OutData%PositionXYZ(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL Lidar_UnpackInput( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - END SUBROUTINE InflowWind_UnPackInput + OutData%DummyContState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE InflowWind_UnPackContState - SUBROUTINE InflowWind_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_OutputType), INTENT(IN) :: SrcOutputData - TYPE(InflowWind_OutputType), INTENT(INOUT) :: DstOutputData - INTEGER(IntKi), INTENT(IN ) :: CtrlCode + SUBROUTINE InflowWind_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyDiscState' ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(SrcOutputData%VelocityUVW)) THEN - i1_l = LBOUND(SrcOutputData%VelocityUVW,1) - i1_u = UBOUND(SrcOutputData%VelocityUVW,1) - i2_l = LBOUND(SrcOutputData%VelocityUVW,2) - i2_u = UBOUND(SrcOutputData%VelocityUVW,2) - IF (.NOT. ALLOCATED(DstOutputData%VelocityUVW)) THEN - ALLOCATE(DstOutputData%VelocityUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VelocityUVW.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstOutputData%VelocityUVW = SrcOutputData%VelocityUVW -ENDIF -IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN - i1_l = LBOUND(SrcOutputData%WriteOutput,1) - i1_u = UBOUND(SrcOutputData%WriteOutput,1) - IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN - ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstOutputData%WriteOutput = SrcOutputData%WriteOutput -ENDIF - DstOutputData%DiskVel = SrcOutputData%DiskVel - CALL Lidar_CopyOutput( SrcOutputData%lidar, DstOutputData%lidar, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - END SUBROUTINE InflowWind_CopyOutput + DstDiscStateData%DummyDiscState = SrcDiscStateData%DummyDiscState + END SUBROUTINE InflowWind_CopyDiscState - SUBROUTINE InflowWind_DestroyOutput( OutputData, ErrStat, ErrMsg ) - TYPE(InflowWind_OutputType), INTENT(INOUT) :: OutputData + SUBROUTINE InflowWind_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: DiscStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyDiscState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(OutputData%VelocityUVW)) THEN - DEALLOCATE(OutputData%VelocityUVW) -ENDIF -IF (ALLOCATED(OutputData%WriteOutput)) THEN - DEALLOCATE(OutputData%WriteOutput) -ENDIF - CALL Lidar_DestroyOutput( OutputData%lidar, ErrStat, ErrMsg ) - END SUBROUTINE InflowWind_DestroyOutput + END SUBROUTINE InflowWind_DestroyDiscState - SUBROUTINE InflowWind_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_OutputType), INTENT(IN) :: InData + TYPE(InflowWind_DiscreteStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -4701,7 +4349,7 @@ SUBROUTINE InflowWind_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackDiscState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -4717,35 +4365,7 @@ SUBROUTINE InflowWind_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! VelocityUVW allocated yes/no - IF ( ALLOCATED(InData%VelocityUVW) ) THEN - Int_BufSz = Int_BufSz + 2*2 ! VelocityUVW upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%VelocityUVW) ! VelocityUVW - END IF - Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no - IF ( ALLOCATED(InData%WriteOutput) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput - END IF - Re_BufSz = Re_BufSz + SIZE(InData%DiskVel) ! DiskVel - ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! lidar: size of buffers for each call to pack subtype - CALL Lidar_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, .TRUE. ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN ! lidar - Re_BufSz = Re_BufSz + SIZE( Re_Buf ) - DEALLOCATE(Re_Buf) - END IF - IF(ALLOCATED(Db_Buf)) THEN ! lidar - Db_BufSz = Db_BufSz + SIZE( Db_Buf ) - DEALLOCATE(Db_Buf) - END IF - IF(ALLOCATED(Int_Buf)) THEN ! lidar - Int_BufSz = Int_BufSz + SIZE( Int_Buf ) - DEALLOCATE(Int_Buf) - END IF + Re_BufSz = Re_BufSz + 1 ! DummyDiscState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -4773,80 +4393,15 @@ SUBROUTINE InflowWind_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Db_Xferred = 1 Int_Xferred = 1 - IF ( .NOT. ALLOCATED(InData%VelocityUVW) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%VelocityUVW,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VelocityUVW,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%VelocityUVW,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VelocityUVW,2) - Int_Xferred = Int_Xferred + 2 - - DO i2 = LBOUND(InData%VelocityUVW,2), UBOUND(InData%VelocityUVW,2) - DO i1 = LBOUND(InData%VelocityUVW,1), UBOUND(InData%VelocityUVW,1) - ReKiBuf(Re_Xferred) = InData%VelocityUVW(i1,i2) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) - ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - DO i1 = LBOUND(InData%DiskVel,1), UBOUND(InData%DiskVel,1) - ReKiBuf(Re_Xferred) = InData%DiskVel(i1) - Re_Xferred = Re_Xferred + 1 - END DO - CALL Lidar_PackOutput( Re_Buf, Db_Buf, Int_Buf, InData%lidar, ErrStat2, ErrMsg2, OnlySize ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf - Re_Xferred = Re_Xferred + SIZE(Re_Buf) - DEALLOCATE(Re_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Db_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf - Db_Xferred = Db_Xferred + SIZE(Db_Buf) - DEALLOCATE(Db_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - IF(ALLOCATED(Int_Buf)) THEN - IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 - IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf - Int_Xferred = Int_Xferred + SIZE(Int_Buf) - DEALLOCATE(Int_Buf) - ELSE - IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 - ENDIF - END SUBROUTINE InflowWind_PackOutput + ReKiBuf(Re_Xferred) = InData%DummyDiscState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE InflowWind_PackDiscState - SUBROUTINE InflowWind_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE InflowWind_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_OutputType), INTENT(INOUT) :: OutData + TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -4855,11 +4410,9 @@ SUBROUTINE InflowWind_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat INTEGER(IntKi) :: Db_Xferred INTEGER(IntKi) :: Int_Xferred INTEGER(IntKi) :: i - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackDiscState' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -4870,98 +4423,13 @@ SUBROUTINE InflowWind_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VelocityUVW not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%VelocityUVW)) DEALLOCATE(OutData%VelocityUVW) - ALLOCATE(OutData%VelocityUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VelocityUVW.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i2 = LBOUND(OutData%VelocityUVW,2), UBOUND(OutData%VelocityUVW,2) - DO i1 = LBOUND(OutData%VelocityUVW,1), UBOUND(OutData%VelocityUVW,1) - OutData%VelocityUVW(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) - ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) - OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - i1_l = LBOUND(OutData%DiskVel,1) - i1_u = UBOUND(OutData%DiskVel,1) - DO i1 = LBOUND(OutData%DiskVel,1), UBOUND(OutData%DiskVel,1) - OutData%DiskVel(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) - Re_Xferred = Re_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) - Db_Xferred = Db_Xferred + Buf_size - END IF - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) - Int_Xferred = Int_Xferred + Buf_size - END IF - CALL Lidar_UnpackOutput( Re_Buf, Db_Buf, Int_Buf, OutData%lidar, ErrStat2, ErrMsg2 ) ! lidar - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat >= AbortErrLev) RETURN - - IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) - IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) - IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - END SUBROUTINE InflowWind_UnPackOutput + OutData%DummyDiscState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE InflowWind_UnPackDiscState - SUBROUTINE InflowWind_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_ContinuousStateType), INTENT(IN) :: SrcContStateData - TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: DstContStateData + SUBROUTINE InflowWind_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_ConstraintStateType), INTENT(IN) :: SrcConstrStateData + TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -4969,29 +4437,29 @@ SUBROUTINE InflowWind_CopyContState( SrcContStateData, DstContStateData, CtrlCod INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyConstrState' ! ErrStat = ErrID_None ErrMsg = "" - DstContStateData%DummyContState = SrcContStateData%DummyContState - END SUBROUTINE InflowWind_CopyContState + DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState + END SUBROUTINE InflowWind_CopyConstrState - SUBROUTINE InflowWind_DestroyContState( ContStateData, ErrStat, ErrMsg ) - TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: ContStateData + SUBROUTINE InflowWind_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) + TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: ConstrStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyConstrState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE InflowWind_DestroyContState + END SUBROUTINE InflowWind_DestroyConstrState - SUBROUTINE InflowWind_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_ContinuousStateType), INTENT(IN) :: InData + TYPE(InflowWind_ConstraintStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -5006,7 +4474,7 @@ SUBROUTINE InflowWind_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackConstrState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -5022,7 +4490,7 @@ SUBROUTINE InflowWind_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyContState + Re_BufSz = Re_BufSz + 1 ! DummyConstrState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -5050,15 +4518,15 @@ SUBROUTINE InflowWind_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyContState + ReKiBuf(Re_Xferred) = InData%DummyConstrState Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_PackContState + END SUBROUTINE InflowWind_PackConstrState - SUBROUTINE InflowWind_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE InflowWind_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_ContinuousStateType), INTENT(INOUT) :: OutData + TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -5069,7 +4537,7 @@ SUBROUTINE InflowWind_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS INTEGER(IntKi) :: i INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackConstrState' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -5080,13 +4548,13 @@ SUBROUTINE InflowWind_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyContState = ReKiBuf(Re_Xferred) + OutData%DummyConstrState = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_UnPackContState + END SUBROUTINE InflowWind_UnPackConstrState - SUBROUTINE InflowWind_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_DiscreteStateType), INTENT(IN) :: SrcDiscStateData - TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + SUBROUTINE InflowWind_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_OtherStateType), INTENT(IN) :: SrcOtherStateData + TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: DstOtherStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -5094,29 +4562,29 @@ SUBROUTINE InflowWind_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCod INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyOtherState' ! ErrStat = ErrID_None ErrMsg = "" - DstDiscStateData%DummyDiscState = SrcDiscStateData%DummyDiscState - END SUBROUTINE InflowWind_CopyDiscState + DstOtherStateData%DummyOtherState = SrcOtherStateData%DummyOtherState + END SUBROUTINE InflowWind_CopyOtherState - SUBROUTINE InflowWind_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) - TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: DiscStateData + SUBROUTINE InflowWind_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) + TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: OtherStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyOtherState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE InflowWind_DestroyDiscState + END SUBROUTINE InflowWind_DestroyOtherState - SUBROUTINE InflowWind_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_DiscreteStateType), INTENT(IN) :: InData + TYPE(InflowWind_OtherStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -5131,7 +4599,7 @@ SUBROUTINE InflowWind_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackOtherState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -5147,7 +4615,7 @@ SUBROUTINE InflowWind_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyDiscState + Re_BufSz = Re_BufSz + 1 ! DummyOtherState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -5175,15 +4643,15 @@ SUBROUTINE InflowWind_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyDiscState + ReKiBuf(Re_Xferred) = InData%DummyOtherState Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_PackDiscState + END SUBROUTINE InflowWind_PackOtherState - SUBROUTINE InflowWind_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE InflowWind_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_DiscreteStateType), INTENT(INOUT) :: OutData + TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -5194,7 +4662,7 @@ SUBROUTINE InflowWind_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS INTEGER(IntKi) :: i INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackOtherState' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -5205,43 +4673,101 @@ SUBROUTINE InflowWind_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyDiscState = ReKiBuf(Re_Xferred) + OutData%DummyOtherState = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_UnPackDiscState + END SUBROUTINE InflowWind_UnPackOtherState - SUBROUTINE InflowWind_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_ConstraintStateType), INTENT(IN) :: SrcConstrStateData - TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + SUBROUTINE InflowWind_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) + TYPE(InflowWind_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: DstMiscData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyMisc' ! ErrStat = ErrID_None ErrMsg = "" - DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState - END SUBROUTINE InflowWind_CopyConstrState + DstMiscData%TimeIndex = SrcMiscData%TimeIndex + CALL IfW_UniformWind_CopyMisc( SrcMiscData%UniformWind, DstMiscData%UniformWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL IfW_TSFFWind_CopyMisc( SrcMiscData%TSFFWind, DstMiscData%TSFFWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL IfW_HAWCWind_CopyMisc( SrcMiscData%HAWCWind, DstMiscData%HAWCWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL IfW_BladedFFWind_CopyMisc( SrcMiscData%BladedFFWind, DstMiscData%BladedFFWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL IfW_UserWind_CopyMisc( SrcMiscData%UserWind, DstMiscData%UserWind, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL IfW_4Dext_CopyMisc( SrcMiscData%FDext, DstMiscData%FDext, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcMiscData%AllOuts)) THEN + i1_l = LBOUND(SrcMiscData%AllOuts,1) + i1_u = UBOUND(SrcMiscData%AllOuts,1) + IF (.NOT. ALLOCATED(DstMiscData%AllOuts)) THEN + ALLOCATE(DstMiscData%AllOuts(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%AllOuts.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%AllOuts = SrcMiscData%AllOuts +ENDIF +IF (ALLOCATED(SrcMiscData%WindViUVW)) THEN + i1_l = LBOUND(SrcMiscData%WindViUVW,1) + i1_u = UBOUND(SrcMiscData%WindViUVW,1) + i2_l = LBOUND(SrcMiscData%WindViUVW,2) + i2_u = UBOUND(SrcMiscData%WindViUVW,2) + IF (.NOT. ALLOCATED(DstMiscData%WindViUVW)) THEN + ALLOCATE(DstMiscData%WindViUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstMiscData%WindViUVW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstMiscData%WindViUVW = SrcMiscData%WindViUVW +ENDIF + END SUBROUTINE InflowWind_CopyMisc - SUBROUTINE InflowWind_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) - TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + SUBROUTINE InflowWind_DestroyMisc( MiscData, ErrStat, ErrMsg ) + TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: MiscData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyMisc' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE InflowWind_DestroyConstrState + CALL IfW_UniformWind_DestroyMisc( MiscData%UniformWind, ErrStat, ErrMsg ) + CALL IfW_TSFFWind_DestroyMisc( MiscData%TSFFWind, ErrStat, ErrMsg ) + CALL IfW_HAWCWind_DestroyMisc( MiscData%HAWCWind, ErrStat, ErrMsg ) + CALL IfW_BladedFFWind_DestroyMisc( MiscData%BladedFFWind, ErrStat, ErrMsg ) + CALL IfW_UserWind_DestroyMisc( MiscData%UserWind, ErrStat, ErrMsg ) + CALL IfW_4Dext_DestroyMisc( MiscData%FDext, ErrStat, ErrMsg ) +IF (ALLOCATED(MiscData%AllOuts)) THEN + DEALLOCATE(MiscData%AllOuts) +ENDIF +IF (ALLOCATED(MiscData%WindViUVW)) THEN + DEALLOCATE(MiscData%WindViUVW) +ENDIF + END SUBROUTINE InflowWind_DestroyMisc - SUBROUTINE InflowWind_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE InflowWind_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_ConstraintStateType), INTENT(IN) :: InData + TYPE(InflowWind_MiscVarType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -5256,7 +4782,7 @@ SUBROUTINE InflowWind_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSt LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackMisc' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -5272,132 +4798,120 @@ SUBROUTINE InflowWind_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSt Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyConstrState - IF ( Re_BufSz .GT. 0 ) THEN - ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Db_BufSz .GT. 0 ) THEN - ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF ( Int_BufSz .GT. 0 ) THEN - ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + Int_BufSz = Int_BufSz + 1 ! TimeIndex + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! UniformWind: size of buffers for each call to pack subtype + CALL IfW_UniformWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, .TRUE. ) ! UniformWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 + IF(ALLOCATED(Re_Buf)) THEN ! UniformWind + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! UniformWind + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! UniformWind + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! TSFFWind: size of buffers for each call to pack subtype + CALL IfW_TSFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! TSFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - ReKiBuf(Re_Xferred) = InData%DummyConstrState - Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_PackConstrState + IF(ALLOCATED(Re_Buf)) THEN ! TSFFWind + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! TSFFWind + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! TSFFWind + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! HAWCWind: size of buffers for each call to pack subtype + CALL IfW_HAWCWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, .TRUE. ) ! HAWCWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) - REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_ConstraintStateType), INTENT(INOUT) :: OutData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - ! Local variables - INTEGER(IntKi) :: Buf_size - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackConstrState' - ! buffers to store meshes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - OutData%DummyConstrState = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_UnPackConstrState - - SUBROUTINE InflowWind_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(InflowWind_OtherStateType), INTENT(IN) :: SrcOtherStateData - TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: DstOtherStateData - INTEGER(IntKi), INTENT(IN ) :: CtrlCode - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg -! Local - INTEGER(IntKi) :: i,j,k - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_CopyOtherState' -! - ErrStat = ErrID_None - ErrMsg = "" - DstOtherStateData%DummyOtherState = SrcOtherStateData%DummyOtherState - END SUBROUTINE InflowWind_CopyOtherState + IF(ALLOCATED(Re_Buf)) THEN ! HAWCWind + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! HAWCWind + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! HAWCWind + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! BladedFFWind: size of buffers for each call to pack subtype + CALL IfW_BladedFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, .TRUE. ) ! BladedFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) - TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: OtherStateData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_DestroyOtherState' - INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 -! - ErrStat = ErrID_None - ErrMsg = "" - END SUBROUTINE InflowWind_DestroyOtherState + IF(ALLOCATED(Re_Buf)) THEN ! BladedFFWind + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! BladedFFWind + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! BladedFFWind + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! UserWind: size of buffers for each call to pack subtype + CALL IfW_UserWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, .TRUE. ) ! UserWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) - REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(InflowWind_OtherStateType), INTENT(IN) :: InData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly - ! Local variables - INTEGER(IntKi) :: Re_BufSz - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_BufSz - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_BufSz - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 - LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_PackOtherState' - ! buffers to store subtypes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + IF(ALLOCATED(Re_Buf)) THEN ! UserWind + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! UserWind + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! UserWind + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! FDext: size of buffers for each call to pack subtype + CALL IfW_4Dext_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, .TRUE. ) ! FDext + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - OnlySize = .FALSE. - IF ( PRESENT(SizeOnly) ) THEN - OnlySize = SizeOnly - ENDIF - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_BufSz = 0 - Db_BufSz = 0 - Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyOtherState + IF(ALLOCATED(Re_Buf)) THEN ! FDext + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! FDext + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! FDext + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! AllOuts allocated yes/no + IF ( ALLOCATED(InData%AllOuts) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! AllOuts upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%AllOuts) ! AllOuts + END IF + Int_BufSz = Int_BufSz + 1 ! WindViUVW allocated yes/no + IF ( ALLOCATED(InData%WindViUVW) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! WindViUVW upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WindViUVW) ! WindViUVW + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -5425,39 +4939,525 @@ SUBROUTINE InflowWind_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrSta Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyOtherState - Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_PackOtherState + IntKiBuf(Int_Xferred) = InData%TimeIndex + Int_Xferred = Int_Xferred + 1 + CALL IfW_UniformWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UniformWind, ErrStat2, ErrMsg2, OnlySize ) ! UniformWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE InflowWind_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) - REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(InflowWind_OtherStateType), INTENT(INOUT) :: OutData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - ! Local variables - INTEGER(IntKi) :: Buf_size - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackOtherState' - ! buffers to store meshes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - OutData%DummyOtherState = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END SUBROUTINE InflowWind_UnPackOtherState + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL IfW_TSFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%TSFFWind, ErrStat2, ErrMsg2, OnlySize ) ! TSFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL IfW_HAWCWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%HAWCWind, ErrStat2, ErrMsg2, OnlySize ) ! HAWCWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL IfW_BladedFFWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%BladedFFWind, ErrStat2, ErrMsg2, OnlySize ) ! BladedFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL IfW_UserWind_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%UserWind, ErrStat2, ErrMsg2, OnlySize ) ! UserWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL IfW_4Dext_PackMisc( Re_Buf, Db_Buf, Int_Buf, InData%FDext, ErrStat2, ErrMsg2, OnlySize ) ! FDext + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF ( .NOT. ALLOCATED(InData%AllOuts) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%AllOuts,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%AllOuts,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%AllOuts,1), UBOUND(InData%AllOuts,1) + ReKiBuf(Re_Xferred) = InData%AllOuts(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%WindViUVW) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViUVW,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViUVW,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WindViUVW,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WindViUVW,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%WindViUVW,2), UBOUND(InData%WindViUVW,2) + DO i1 = LBOUND(InData%WindViUVW,1), UBOUND(InData%WindViUVW,1) + ReKiBuf(Re_Xferred) = InData%WindViUVW(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE InflowWind_PackMisc + + SUBROUTINE InflowWind_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(InflowWind_MiscVarType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'InflowWind_UnPackMisc' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%TimeIndex = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_UniformWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%UniformWind, ErrStat2, ErrMsg2 ) ! UniformWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_TSFFWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%TSFFWind, ErrStat2, ErrMsg2 ) ! TSFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_HAWCWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%HAWCWind, ErrStat2, ErrMsg2 ) ! HAWCWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_BladedFFWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%BladedFFWind, ErrStat2, ErrMsg2 ) ! BladedFFWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_UserWind_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%UserWind, ErrStat2, ErrMsg2 ) ! UserWind + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL IfW_4Dext_UnpackMisc( Re_Buf, Db_Buf, Int_Buf, OutData%FDext, ErrStat2, ErrMsg2 ) ! FDext + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! AllOuts not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%AllOuts)) DEALLOCATE(OutData%AllOuts) + ALLOCATE(OutData%AllOuts(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%AllOuts.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%AllOuts,1), UBOUND(OutData%AllOuts,1) + OutData%AllOuts(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WindViUVW not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WindViUVW)) DEALLOCATE(OutData%WindViUVW) + ALLOCATE(OutData%WindViUVW(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WindViUVW.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%WindViUVW,2), UBOUND(OutData%WindViUVW,2) + DO i1 = LBOUND(OutData%WindViUVW,1), UBOUND(OutData%WindViUVW,1) + OutData%WindViUVW(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + END SUBROUTINE InflowWind_UnPackMisc SUBROUTINE InflowWind_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) From 38490ebd37a78dfada0640e72075684b47494aee Mon Sep 17 00:00:00 2001 From: Bonnie Jonkman Date: Mon, 25 Oct 2021 15:38:11 -0600 Subject: [PATCH 003/130] IfW C bindings: added SAVE attribute to avoid compiler warning --- modules/inflowwind/src/IfW_C_Binding.f90 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/inflowwind/src/IfW_C_Binding.f90 b/modules/inflowwind/src/IfW_C_Binding.f90 index 51782d0b69..4dcf33e1c4 100644 --- a/modules/inflowwind/src/IfW_C_Binding.f90 +++ b/modules/inflowwind/src/IfW_C_Binding.f90 @@ -32,16 +32,16 @@ MODULE InflowWind_C_BINDING PUBLIC :: IfW_C_End ! Accessible to all routines inside module - TYPE(InflowWind_InputType) :: InputData !< Inputs to InflowWind - TYPE(InflowWind_InitInputType) :: InitInp - TYPE(InflowWind_InitOutputType) :: InitOutData !< Initial output data -- Names, units, and version info. - TYPE(InflowWind_ParameterType) :: p !< Parameters - TYPE(InflowWind_ContinuousStateType) :: ContStates !< Initial continuous states - TYPE(InflowWind_DiscreteStateType) :: DiscStates !< Initial discrete states - TYPE(InflowWind_ConstraintStateType) :: ConstrStates !< Constraint states at Time - TYPE(InflowWind_OtherStateType) :: OtherStates !< Initial other/optimization states - TYPE(InflowWind_OutputType) :: y !< Initial output (outputs are not calculated; only the output mesh is initialized) - TYPE(InflowWind_MiscVarType) :: m !< Misc variables for optimization (not copied in glue code) + TYPE(InflowWind_InputType) , SAVE :: InputData !< Inputs to InflowWind + TYPE(InflowWind_InitInputType) , SAVE :: InitInp + TYPE(InflowWind_InitOutputType) , SAVE :: InitOutData !< Initial output data -- Names, units, and version info. + TYPE(InflowWind_ParameterType) , SAVE :: p !< Parameters + TYPE(InflowWind_ContinuousStateType) , SAVE :: ContStates !< Initial continuous states + TYPE(InflowWind_DiscreteStateType) , SAVE :: DiscStates !< Initial discrete states + TYPE(InflowWind_ConstraintStateType) , SAVE :: ConstrStates !< Constraint states at Time + TYPE(InflowWind_OtherStateType) , SAVE :: OtherStates !< Initial other/optimization states + TYPE(InflowWind_OutputType) , SAVE :: y !< Initial output (outputs are not calculated; only the output mesh is initialized) + TYPE(InflowWind_MiscVarType) , SAVE :: m !< Misc variables for optimization (not copied in glue code) ! This must exactly match the value in the Python interface. We are not using the variable 'ErrMsgLen' ! so that we avoid issues if ErrMsgLen changes in the NWTC Library. If the value of ErrMsgLen does change From 1eacabc04a3eeb0b0c52d18c4fb0d39fea718a2d Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 16 Dec 2021 14:46:46 -0700 Subject: [PATCH 004/130] ROM: reduced order model solve docs with SED and ADsk --- .../OpenFAST_Algorithms.pdf | Bin 243089 -> 246581 bytes .../OpenFAST_Algorithms.tex | 157 ++++++++++-------- 2 files changed, 86 insertions(+), 71 deletions(-) diff --git a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.pdf b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.pdf index bfc129788489e6c310ca661aded2240407844695..8c3c2ba9cd14bb951b6e5e75206a49803b8a9527 100644 GIT binary patch delta 102794 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 -+8%gavLahjuDK&FUOl@6?=x;CKTN+%2&`X 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 delta 99354 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 diff --git a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex index 1e891a7c30..4cf872aa58 100644 --- a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex +++ b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex @@ -22,7 +22,7 @@ %----------------------------------------------------------- \begin{document} \title{Solve Algorithms in OpenFAST} -\author{Bonnie Jonkman} +\author{B Jonkman, A Platt} %\begin{abstract} %This document is used to describe the algorithms implemented in FAST v8. %\end{abstract} @@ -39,21 +39,23 @@ \section{Definitions and Nomenclature} \textbf{Module} & \textbf{Abbreviation} & \textbf{Abbreviation}\\ \textbf{Name} & \textbf{in Module} & \textbf{in this Document}\\ \hline - ElastoDyn & ED & ED \\ - BeamDyn & BD & BD \\ - AeroDyn14 & AD14 & AD14 \\ - AeroDyn & AD & AD \\ - ServoDyn & SrvD & SrvD \\ - SubDyn & SD & SD \\ - ExtPtfm & ExtPtfm & ExtPtfm \\ - HydroDyn & HydroDyn & HD \\ - MAP++ & MAPp & MAP \\ - FEAMooring & FEAM & FEAM \\ - MoorDyn & MD & MD \\ - OrcaFlexInterface & Orca & Orca \\ - InflowWind & IfW & IfW \\ - IceFloe & IceFloe & IceF \\ - IceDyn & IceD & IceD \\ + ElastoDyn & ED & ED \\ + BeamDyn & BD & BD \\ + AeroDyn14 & AD14 & AD14 \\ + AeroDyn & AD & AD \\ + ServoDyn & SrvD & SrvD \\ + SubDyn & SD & SD \\ + ExtPtfm & ExtPtfm & ExtPtfm \\ + HydroDyn & HydroDyn & HD \\ + MAP++ & MAPp & MAP \\ + FEAMooring & FEAM & FEAM \\ + MoorDyn & MD & MD \\ + OrcaFlexInterface & Orca & Orca \\ + InflowWind & IfW & IfW \\ + IceFloe & IceFloe & IceF \\ + IceDyn & IceD & IceD \\ + AeroDisk & ADsk & ADsk \\ + Simplified ElastoDyn & SED & SED \\ \end{tabular} \caption{Abbreviations for modules in FAST v8} \label{tab:Abbrev} @@ -85,47 +87,51 @@ \section{Input-Output Relationships} % \start SolveOption2 \State % SolveOption2a_Inp2BD - \State $\mathit{y\_ED} \gets \Call{ED\_CalcOutput}{\mathit{p\_ED},\mathit{u\_ED},\mathit{x\_ED},\mathit{xd\_ED},\mathit{z\_ED}}$ - \State $\mathit{u\_BD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED,y\_SrvD}}$ + \State $\mathit{y\_ED} \gets \Call{ED\_CalcOutput}{\mathit{p\_ED, u\_ED, x\_ED, xd\_ED, z\_ED}}$ + \State $\mathit{y\_SED} \gets \Call{SED\_CalcOutput}{\mathit{p\_SED, u\_SED, x\_SED, xd\_SED, z\_SED}}$ + \State $\mathit{u\_BD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SrvD}}$ \State % SolveOption2b_Inp2IfW - \State $\mathit{y\_BD} \gets \Call{BD\_CalcOutput}{\mathit{p\_BD},\mathit{u\_BD},\mathit{x\_BD},\mathit{xd\_BD},\mathit{z\_BD}}$ - \State $\mathit{u\_AD}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED,y\_BD}}$ - \State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED} at \mathit{u\_AD} nodes}$ + \State $\mathit{y\_BD} \gets \Call{BD\_CalcOutput}{\mathit{p\_BD, u\_BD, x\_BD, xd\_BD, z\_BD}}$ + \State $\mathit{u\_AD}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}}$ + \State $\mathit{u\_ADsk}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}}$ + \State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED} at \mathit{u\_AD} nodes}$ \State % SolveOption2c_Inp2AD_SrvD \State $\mathit{y\_IfW} \gets \Call{IfW\_CalcOutput}{\mathit{u\_IfW} and other \mathit{IfW} data structures}$ \State $\mathit{u\_AD}($InflowWind only$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_IfW}}$ - \State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED},\mathit{y\_IfW},\mathit{y\_BD}}$ + \State $\mathit{u\_ADsk}($InflowWind only$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_IfW}}$ + \State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_IfW, y\_BD}}$ \State % main - \State $\mathit{y\_AD} \gets \Call{AD\_CalcOutput}{\mathit{p\_AD},\mathit{u\_AD},\mathit{x\_AD},\mathit{xd\_AD},\mathit{z\_AD}}$ + \State $\mathit{y\_AD} \gets \Call{AD\_CalcOutput}{\mathit{p\_AD, u\_AD, x\_AD, xd\_AD, z\_AD}}$ + \State $\mathit{y\_ADsk} \gets \Call{ADsk\_CalcOutput}{\mathit{p\_ADsk, u\_ADsk, x\_ADsk, xd\_ADsk, z\_ADsk}}$ \State $\mathit{y\_SrvD} \gets \Call{SrvD\_CalcOutput}{}( \! \begin{aligned}[t] - & \mathit{p\_SrvD},\mathit{u\_SrvD}, \\ - & \mathit{x\_SrvD},\mathit{xd\_SrvD},\mathit{z\_SrvD}) \\ + & \mathit{p\_SrvD, u\_SrvD}, \\ + & \mathit{x\_SrvD, xd\_SrvD, z\_SrvD}) \\ \end{aligned}$ - \State $\mathit{u\_ED} \gets \Call{TransferOutputsToInputs}{\mathit{y\_AD},\mathit{y\_SrvD}}$ - \State $\mathit{u\_BD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_AD,y\_SrvD}}$ + \State $\mathit{u\_ED} \gets \Call{TransferOutputsToInputs}{\mathit{y\_AD, y\_ADsk, y\_SrvD}}$ + \State $\mathit{u\_BD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_AD, y\_ADsk, y\_SrvD}}$ % \end SolveOption2 %%%% %%%% % \begin Transfer_ED_to_HD_SD_BD_Mooring \State -% \State $\mathit{u\_ED}($not platform reference point$) \gets \Call{TransferOutputsToInputs}{y\_SrvD,y\_AD}$ %\Comment{sets all but platform reference point inputs} +% \State $\mathit{u\_ED}($not platform reference point$) \gets \Call{TransferOutputsToInputs}{y\_SrvD, y\_AD, y\_ADsk}$ %\Comment{sets all but platform reference point inputs} % \State $\mathit{u\_BD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ % only if not BD_Solve_Option1 - \State $\mathit{u\_HD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_SD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_ExtPtfm} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_MAP} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_FEAM} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_MD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State $\mathit{u\_Orca} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_HD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_SD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_ExtPtfm} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_MAP} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_FEAM} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_MD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ + \State $\mathit{u\_Orca} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ \State $\mathit{u\_SrvD\%PtfmStC} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$\footnote{Only if using ServoDyn Structural control with platform TMD.} % \end Transfer_ED_to_HD_SD_BD_Mooring %%%% @@ -133,9 +139,10 @@ \section{Input-Output Relationships} \State \State \Call{SolveOption1}{\null} \State - \State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{u\_AD},\mathit{y\_ED}}$ - \State $\mathit{u\_AD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED}}$ - \State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED},\mathit{y\_AD},\mathit{y\_BD},\mathit{y\_SD}}$ + \State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{u\_AD, u\_ADsk, y\_ED, y\_SED}}$ + \State $\mathit{u\_AD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED}}$ + \State $\mathit{u\_ADsk} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED}}$ + \State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_AD, u\_ADsk, y\_BD, y\_SD}}$ \EndProcedure \end{algorithmic} @@ -158,6 +165,7 @@ \section{Input-Output Relationships} This procedure implements Solve Option 1 for the accelerations and loads in \emph{HydroDyn},\emph{SubDyn},\emph{MAP},\emph{FEAMooring},\emph{OrcaFlexInterface},\emph{MoorDyn}, \emph{BeamDyn}, \emph{ExtPtfm}, \emph{IceFloe}, \emph{IceDyn}, and \emph{ElastoDyn} (at its platform reference point mesh). The other input-output relationships for these modules are solved using Solve Option 2. +This solve option is not used when the \textit{Simplified ElastoDyn} module is in use. %\begin{algorithm}[ht] %\caption{Input-Output Solve for $HydroDyn$, $SubDyn$, $MAP$, $FEAMooring$, and the Platform Reference Point Mesh in $ElastoDyn$} @@ -166,24 +174,24 @@ \section{Input-Output Relationships} \Procedure{SolveOption1}{\null} \State - \State $\mathit{y\_MAP} \gets \Call{CalcOutput}{\mathit{p\_MAP},\mathit{u\_MAP},\mathit{x\_MAP},\mathit{xd\_MAP},\mathit{z\_MAP}}$ - \State $\mathit{y\_MD} \gets \Call{CalcOutput}{\mathit{p\_MD},\mathit{u\_MD},\mathit{x\_MD},\mathit{xd\_MD},\mathit{z\_MD}}$ - \State $\mathit{y\_FEAM} \gets \Call{CalcOutput}{\mathit{p\_FEAM},\mathit{u\_FEAM},\mathit{x\_FEAM},\mathit{xd\_FEAM},\mathit{z\_FEAM}}$ - \State $\mathit{y\_IceF} \gets \Call{CalcOutput}{\mathit{p\_IceF},\mathit{u\_IceF},\mathit{x\_IceF},\mathit{xd\_IceF},\mathit{z\_IceF}}$ - \State $\mathit{y\_IceD(:)} \gets \Call{CalcOutput}{\mathit{p\_IceD(:)},\mathit{u\_IceD(:)},\mathit{x\_IceD(:)},\mathit{xd\_IceD(:)},\mathit{z\_IceD(:)}}$ - \State $\mathit{y\_SrvD} \gets \Call{CalcOutput}{\mathit{p\_SrvD},\mathit{u\_SrvD},\mathit{x\_SrvD},\mathit{xd\_SrvD},\mathit{z\_SrvD}}$\footnote{Only if using ServoDyn Structural control with platform TMD.} + \State $\mathit{y\_MAP} \gets \Call{CalcOutput}{\mathit{p\_MAP, u\_MAP, x\_MAP, xd\_MAP, z\_MAP}}$ + \State $\mathit{y\_MD} \gets \Call{CalcOutput}{\mathit{p\_MD, u\_MD, x\_MD, xd\_MD, z\_MD}}$ + \State $\mathit{y\_FEAM} \gets \Call{CalcOutput}{\mathit{p\_FEAM, u\_FEAM, x\_FEAM, xd\_FEAM, z\_FEAM}}$ + \State $\mathit{y\_IceF} \gets \Call{CalcOutput}{\mathit{p\_IceF, u\_IceF, x\_IceF, xd\_IceF, z\_IceF}}$ + \State $\mathit{y\_IceD(:)} \gets \Call{CalcOutput}{\mathit{p\_IceD(:), u\_IceD(:), x\_IceD(:), xd\_IceD(:), z\_IceD(:)}}$ + \State $\mathit{y\_SrvD} \gets \Call{CalcOutput}{\mathit{p\_SrvD, u\_SrvD, x\_SrvD, xd\_SrvD, z\_SrvD}}$\footnote{Only if using ServoDyn Structural control with platform or tower TMD and full ElastoDyn.} \State - \State\Comment{Form $u$ vector using loads and accelerations from $\mathit{u\_HD}$, $\mathit{u\_BD}$, $\mathit{u\_SD}$, $\mathit{u\_Orca}$, $\mathit{u\_ExtPtfm}$, $\mathit{u\_SrvD}$\footnote{Only if using ServoDyn Structural control with platform TMD and SubDyn.} and platform reference input from $\mathit{u\_ED}$} + \State\Comment{Form $u$ vector using loads and accelerations from $\mathit{u\_HD}$, $\mathit{u\_BD}$, $\mathit{u\_SD}$, $\mathit{u\_Orca}$, $\mathit{u\_ExtPtfm}$, $\mathit{u\_SrvD}$\footnote{Only if using ServoDyn Structural control with platform or tower TMD and full ElastoDyn and SubDyn.} and platform reference input from $\mathit{u\_ED}$} \State - \State $u \gets \Call{u\_vec}{\mathit{u\_HD},\mathit{u\_SD},\mathit{u\_ED},\mathit{u\_BD},\mathit{u\_Orca},\mathit{u\_ExtPtfm}}$ + \State $u \gets \Call{u\_vec}{\mathit{u\_HD, u\_SD, u\_ED, u\_BD, u\_Orca, u\_ExtPtfm}}$ \State $k \gets 0$ \Loop\Comment{Solve for loads and accelerations (direct feed-through terms)} - \State $y\_ED \gets \Call{ED\_CalcOutput}{\mathit{p\_ED},\mathit{u\_ED},\mathit{x\_ED},\mathit{xd\_ED},\mathit{z\_ED}}$ - \State $y\_SD \gets \Call{SD\_CalcOutput}{\mathit{p\_SD},\mathit{u\_SD},\mathit{x\_SD},\mathit{xd\_SD},\mathit{z\_SD}}$ - \State $y\_HD \gets \Call{HD\_CalcOutput}{\mathit{p\_HD},\mathit{u\_HD},\mathit{x\_HD},\mathit{xd\_HD},\mathit{z\_HD}}$ - \State $y\_BD \gets \Call{BD\_CalcOutput}{\mathit{p\_BD},\mathit{u\_BD},\mathit{x\_BD},\mathit{xd\_BD},\mathit{z\_BD}}$ - \State $y\_Orca \gets \Call{Orca\_CalcOutput}{\mathit{p\_Orca},\mathit{u\_Orca},\mathit{x\_Orca},\mathit{xd\_Orca},\mathit{z\_Orca}}$ - \State $\mathit{y\_ExtPtfm} \gets \Call{CalcOutput}{\mathit{p\_ExtPtfm},\mathit{u\_ExtPtfm},\mathit{x\_ExtPtfm},\mathit{xd\_ExtPtfm},\mathit{z\_ExtPtfm}}$ + \State $y\_ED \gets \Call{ED\_CalcOutput}{\mathit{p\_ED, u\_ED, x\_ED, xd\_ED, z\_ED}}$ + \State $y\_SD \gets \Call{SD\_CalcOutput}{\mathit{p\_SD, u\_SD, x\_SD, xd\_SD, z\_SD}}$ + \State $y\_HD \gets \Call{HD\_CalcOutput}{\mathit{p\_HD, u\_HD, x\_HD, xd\_HD, z\_HD}}$ + \State $y\_BD \gets \Call{BD\_CalcOutput}{\mathit{p\_BD, u\_BD, x\_BD, xd\_BD, z\_BD}}$ + \State $y\_Orca \gets \Call{Orca\_CalcOutput}{\mathit{p\_Orca, u\_Orca, x\_Orca, xd\_Orca, z\_Orca}}$ + \State $\mathit{y\_ExtPtfm} \gets \Call{CalcOutput}{\mathit{p\_ExtPtfm, u\_ExtPtfm, x\_ExtPtfm, xd\_ExtPtfm, z\_ExtPtfm}}$ \If{ $k \geq k\_max$} \State exit loop @@ -196,8 +204,8 @@ \section{Input-Output Relationships} \State$\mathit{u\_MD\_tmp} \gets \Call{TransferMeshMotions}{y\_ED}$ \State$\mathit{u\_IceF\_tmp} \gets \Call{TransferMeshMotions}{y\_SD}$ \State$\mathit{u\_IceD\_tmp(:)} \gets \Call{TransferMeshMotions}{y\_SD}$ - \State$\mathit{u\_HD\_tmp} \gets \Call{TransferMeshMotions}{y\_ED,y\_SD}$ - \State$\mathit{u\_SrvD\_tmp} \gets \Call{TransferMeshMotions}{y\_ED,y\_SD}$\footnote{Only if using ServoDyn Structural control with platform TMD.} + \State$\mathit{u\_HD\_tmp} \gets \Call{TransferMeshMotions}{y\_ED, y\_SD}$ + \State$\mathit{u\_SrvD\_tmp} \gets \Call{TransferMeshMotions}{y\_ED, y\_SD}$\footnote{\label{FN1}Only if using ServoDyn Structural control with platform or tower TMD and full ElastoDyn.} \State$\mathit{u\_SD\_tmp} \gets \! \begin{aligned}[t] & \Call{TransferMeshMotions}{\mathit{y\_ED}} \\ @@ -209,13 +217,14 @@ \section{Input-Output Relationships} & \mathit{y\_IceD(:)}, \mathit{u\_IceD\_tmp(:)}, \\ \end{aligned} \end{aligned}$ + \addtocounter{footnote}{-1} % back up counter for footnotemakr below \State$\mathit{u\_ED\_tmp} \gets \Call{TransferMeshLoads}{}( \! \begin{aligned}[t] & \mathit{y\_ED}, \\ - & \mathit{y\_HD}, \mathit{u\_HD\_tmp}, \\ - & \mathit{y\_SD}, \mathit{u\_SD\_tmp}, \\ - & \mathit{y\_MAP}, \mathit{u\_MAP\_tmp}, \\ - & \mathit{y\_FEAM},\mathit{u\_FEAM\_tmp},\\ - & \mathit{y\_SrvD},\mathit{u\_SrvD\_tmp}\footnote{Only if using ServoDyn Structural control with platform TMD.} ) % SrvD%PtfmStC only + & \mathit{y\_HD}, \mathit{u\_HD\_tmp}, \\ + & \mathit{y\_SD}, \mathit{u\_SD\_tmp}, \\ + & \mathit{y\_MAP}, \mathit{u\_MAP\_tmp}, \\ + & \mathit{y\_FEAM}, \mathit{u\_FEAM\_tmp},\\ + & \mathit{y\_SrvD}, \mathit{u\_SrvD\_tmp}\footnotemark ) % SrvD%PtfmStC only\footnotemark[\ref{FN1}] \end{aligned}$ \State @@ -258,7 +267,7 @@ \section{Input-Output Relationships} \State \State$\mathit{u\_BD}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ - \State$\mathit{u\_HD}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED},\mathit{y\_SD}}$ + \State$\mathit{u\_HD}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED, y\_SD}}$ \State$\mathit{u\_SD}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ \State$\mathit{u\_Orca}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ \State$\mathit{u\_ExtPtfm}($not accelerations$) \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ \State @@ -267,7 +276,7 @@ \section{Input-Output Relationships} \State $\mathit{u\_FEAM} \gets \Call{TransferMeshMotions}{\mathit{y\_ED}}$ \State $\mathit{u\_IceF} \gets \Call{TransferMeshMotions}{\mathit{y\_SD}}$ \State $\mathit{u\_IceD(:)} \gets \Call{TransferMeshMotions}{\mathit{y\_SD}}$ - \State $\mathit{u\_SrvD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED,y\_SD}}$\footnote{Only if using ServoDyn Structural control with platform TMD.} % For SrvD%PtfmStC + \State $\mathit{u\_SrvD} \gets \Call{TransferMeshMotions}{\mathit{y\_ED, y\_SD}}$\footnote{Only if using ServoDyn Structural control with platform or tower TMD and full ElastoDyn.} % For SrvD%PtfmStC \EndProcedure \end{algorithmic} @@ -339,22 +348,28 @@ \section{Solve Option 2 Improvements} \begin{algorithmic}[1] \Procedure{FAST\_AdvanceStates}{\null} -\State $\Call{ED\_UpdateStates}{\mathit{p\_ED},\mathit{u\_ED},\mathit{x\_ED},\mathit{xd\_ED},\mathit{z\_ED}}$ -\State $\mathit{y\_ED} \gets \Call{ED\_CalcOutput}{\mathit{p\_ED},\mathit{u\_ED},\mathit{x\_ED},\mathit{xd\_ED},\mathit{z\_ED}}$ +\State $\Call{ED\_UpdateStates}{\mathit{p\_ED, u\_ED, x\_ED, xd\_ED, z\_ED}}$ +\State $\mathit{y\_ED} \gets \Call{ED\_CalcOutput}{\mathit{p\_ED, u\_ED, x\_ED, xd\_ED, z\_ED}}$ +\State +\State $\Call{SED\_UpdateStates}{\mathit{p\_SED, u\_SED, x\_SED, xd\_SED, z\_SED}}$ +\State $\mathit{y\_SED} \gets \Call{SED\_CalcOutput}{\mathit{p\_SED, u\_SED, x\_SED, xd\_SED, z\_SED}}$ \State \State $\mathit{u\_BD}($hub and root motions$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED}}$ -\State $\Call{BD\_UpdateStates}{\mathit{p\_BD},\mathit{u\_BD},\mathit{x\_BD},\mathit{xd\_BD},\mathit{z\_BD}}$ -\State $\mathit{y\_BD} \gets \Call{BD\_CalcOutput}{\mathit{p\_BD},\mathit{u\_BD},\mathit{x\_BD},\mathit{xd\_BD},\mathit{z\_BD}}$ +\State $\Call{BD\_UpdateStates}{\mathit{p\_BD, u\_BD, x\_BD, xd\_BD, z\_BD}}$ +\State $\mathit{y\_BD} \gets \Call{BD\_CalcOutput}{\mathit{p\_BD, u\_BD, x\_BD, xd\_BD, z\_BD}}$ \State -\State $\mathit{u\_AD}($not InflowWind$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED},\mathit{y\_BD}}$ -\State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED},\mathit{y\_BD}$ at $\mathit{u\_AD}$ nodes$}$ -\State $\Call{IfW\_UpdateStates}{\mathit{p\_IfW},\mathit{u\_IfW},\mathit{x\_IfW},\mathit{xd\_IfW},\mathit{z\_IfW}}$ +\State $\mathit{u\_AD}($not InflowWind$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}}$ +\State $\mathit{u\_ADsk}($not InflowWind$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED}}$ +\State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}$ at $\mathit{u\_AD}$ nodes$}$ +\State $\Call{IfW\_UpdateStates}{\mathit{p\_IfW, u\_IfW, x\_IfW, xd\_IfW, z\_IfW}}$ \State $\mathit{y\_IfW} \gets \Call{IfW\_CalcOutput}{\mathit{u\_IfW}$ and other $\mathit{IfW}$ data structures$}$ \State \State $\mathit{u\_AD}($InflowWind only$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_IfW}}$ -\State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED},\mathit{y\_BD},\mathit{y\_IfW}}$ -\State $\Call{AD\_UpdateStates}{\mathit{p\_AD},\mathit{u\_AD},\mathit{x\_AD},\mathit{xd\_AD},\mathit{z\_AD}}$ -\State $\Call{SrvD\_UpdateStates}{\mathit{p\_SrvD},\mathit{u\_SrvD},\mathit{x\_SrvD},\mathit{xd\_SrvD},\mathit{z\_SrvD}}$ +\State $\mathit{u\_ADsk}($InflowWind only$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_IfW}}$ +\State $\mathit{u\_SrvD} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD, y\_IfW}}$ +\State $\Call{AD\_UpdateStates}{\mathit{p\_AD, u\_AD, x\_AD, xd\_AD, z\_AD}}$ +\State $\Call{ADsk\_UpdateStates}{\mathit{p\_ADsk, u\_ADsk, x\_ADsk, xd\_ADsk, z\_ADsk}}$ +\State $\Call{SrvD\_UpdateStates}{\mathit{p\_SrvD, u\_SrvD, x\_SrvD, xd\_SrvD, z\_SrvD}}$ \State \State All other modules (used in Solve Option 1) advance their states \EndProcedure From 25d9256c669e963d1626a45b47f784c57f7b38cd Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 16 Dec 2021 16:54:18 -0700 Subject: [PATCH 005/130] ROM: minor doc update --- .../OpenFAST_Algorithms.pdf | Bin 246581 -> 246564 bytes .../OpenFAST_Algorithms.tex | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.pdf b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.pdf index 8c3c2ba9cd14bb951b6e5e75206a49803b8a9527..59d20921f676082070ebc3d160c864888c956641 100644 GIT binary patch delta 3720 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 delta 3738 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 E3M+y?bpQYW diff --git a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex index 4cf872aa58..3e332bbd0d 100644 --- a/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex +++ b/docs/OtherSupporting/OpenFAST_Algorithms/OpenFAST_Algorithms.tex @@ -95,7 +95,7 @@ \section{Input-Output Relationships} % SolveOption2b_Inp2IfW \State $\mathit{y\_BD} \gets \Call{BD\_CalcOutput}{\mathit{p\_BD, u\_BD, x\_BD, xd\_BD, z\_BD}}$ \State $\mathit{u\_AD}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}}$ - \State $\mathit{u\_ADsk}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED, y\_BD}}$ + \State $\mathit{u\_ADsk}($no IfW$) \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED}}$ \State $\mathit{u\_IfW} \gets \Call{TransferOutputsToInputs}{\mathit{y\_ED, y\_SED} at \mathit{u\_AD} nodes}$ \State From ac901dfaf5836eb1940bda8438d2106c1d211d64 Mon Sep 17 00:00:00 2001 From: Emmanuel Branlard Date: Mon, 14 Feb 2022 11:26:55 -0700 Subject: [PATCH 006/130] ROM: adding documentation for SED --- docs/source/user/index.rst | 1 + .../user/simplified_elastodyn/index.rst | 26 +++++++ .../user/simplified_elastodyn/input_files.rst | 71 +++++++++++++++++++ .../user/simplified_elastodyn/theory.rst | 67 +++++++++++++++++ .../user/simplified_elastodyn/zrefs.rst | 11 +++ 5 files changed, 176 insertions(+) create mode 100644 docs/source/user/simplified_elastodyn/index.rst create mode 100644 docs/source/user/simplified_elastodyn/input_files.rst create mode 100644 docs/source/user/simplified_elastodyn/theory.rst create mode 100644 docs/source/user/simplified_elastodyn/zrefs.rst diff --git a/docs/source/user/index.rst b/docs/source/user/index.rst index 95125f5f2f..2bcb4b6a1c 100644 --- a/docs/source/user/index.rst +++ b/docs/source/user/index.rst @@ -52,6 +52,7 @@ Documentation covers usage of models, underlying theory, and in some cases modul HydroDyn InflowWind ServoDyn + Simplified ElastoDyn Structural Control C++ API FAST.Farm diff --git a/docs/source/user/simplified_elastodyn/index.rst b/docs/source/user/simplified_elastodyn/index.rst new file mode 100644 index 0000000000..d1a82d5d1f --- /dev/null +++ b/docs/source/user/simplified_elastodyn/index.rst @@ -0,0 +1,26 @@ +Simplified ElastoDyn +====================================== + + +This document describes the Simplified ElastoDyn (SED) module. +This module has the features the following: + +- The rotor is rigid +- One degree of freedom is used, representing the variable rotor speed +- No calculation of structural loads +- Possibility to be run with large time step +- A constant platform tilt angle +- Compatibility with AeroDyn and AeroDisk +- Compatibility with active control of torque and yaw (and pitch) + + + +.. only:: html + + +.. toctree:: + :maxdepth: 2 + + theory.rst + input_files.rst + zrefs.rst diff --git a/docs/source/user/simplified_elastodyn/input_files.rst b/docs/source/user/simplified_elastodyn/input_files.rst new file mode 100644 index 0000000000..f664fb8356 --- /dev/null +++ b/docs/source/user/simplified_elastodyn/input_files.rst @@ -0,0 +1,71 @@ +.. _sed_input-files: + +Input and Output Files +====================== + + +Units +----- + +SED uses the SI system (kg, m, s, N). + +.. _sed_input-file: + +Input file +---------- + + +.. code:: + + ------- SIMPLIFIED ELASTODYN INPUT FILE ---------------------------------------- + Comment + ---------------------- SIMULATION CONTROL -------------------------------------- + False Echo - Echo input data to ".ech" (flag) + 3 Method - Integration method: {1: RK4, 2: AB4, or 3: ABM4} (-) + "default" DT - Integration time step (s) + ---------------------- DEGREES OF FREEDOM -------------------------------------- + True GenDOF - Generator DOF (flag) + ---------------------- INITIAL CONDITIONS -------------------------------------- + 0 Azimuth - Initial azimuth angle for blades (degrees) + 0 BlPitch - Blades initial pitch (degrees) + 0.0 RotSpeed - Initial or fixed rotor speed (rpm) + 0 NacYaw - Initial or fixed nacelle-yaw angle (degrees) + 0 PtfmPitch - Fixed pitch tilt rotational displacement of platform (degrees) + ---------------------- TURBINE CONFIGURATION ----------------------------------- + 3 NumBl - Number of blades (-) + 63 TipRad - The distance from the rotor apex to the blade tip (meters) + 1.5 HubRad - The distance from the rotor apex to the blade root (meters) + -2.5 PreCone - Blades cone angle (degrees) + -5.0191 OverHang - Distance from yaw axis to rotor apex [3 blades] or teeter pin [2 blades] (meters) + -5 ShftTilt - Rotor shaft tilt angle (degrees) + 1.96256 Twr2Shft - Vertical distance from the tower-top to the rotor shaft (meters) + 87.6 TowerHt - Height of tower above ground level [onshore] or MSL [offshore] (meters) + ---------------------- MASS AND INERTIA ---------------------------------------- + 115926 RotIner - Rot inertia about rotor axis [blades + hub] (kg m^2) + 534.116 GenIner - Generator inertia about HSS (kg m^2) + ---------------------- DRIVETRAIN ---------------------------------------------- + 100 GBoxEff - Gearbox efficiency (%) + 97 GBRatio - Gearbox ratio (-) + ---------------------- OUTPUT -------------------------------------------------- + OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx for a listing of available output channels, (-) + "Azimuth" - Blades azimuth angle + "RotSpeed" - Low-speed shaft rotational speed + "RotAcc" - Low-speed shaft rotational acceleration + END of input file (the word "END" must appear in the first 3 columns of this last OutList line) + ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + + + +.. _sed_outputs: + +Outputs +------- + +The write outputs are: + - "Azimuth" : Blades azimuth angle (deg) between 0 and 2pi + - "RotSpeed": Low-speed shaft rotational speed (rpm) + - "RotAcc": Low-speed shaft rotational acceleration (rad/s^2) + - "GenSpeed": High-speed shaft rotational speed (rpm) + - "GenAcc": High-speed shaft rotational acceleration (rad/s^2) diff --git a/docs/source/user/simplified_elastodyn/theory.rst b/docs/source/user/simplified_elastodyn/theory.rst new file mode 100644 index 0000000000..806cbbfa55 --- /dev/null +++ b/docs/source/user/simplified_elastodyn/theory.rst @@ -0,0 +1,67 @@ +.. _sed-theory: + +Theory +============= + +In this module, the rotor is represented by a rigid disk. + + +The module has two states :math:`\psi` and :math:`\dot{\psi}`, corresponding to the azimuthal angle and the rotor speed. (Note: introducing the azimuthal angle as a state is optional, but convenient for coupling with AeroDyn. Such introduction should not have any influence on the time-step required since both equations are effictively decoupled.). +The state-space equations are: + +.. math:: :label: sed_stateEq + + \begin{aligned} + \dot{\psi} & = \dot{\psi} \\ + \ddot{\psi} & = \frac{1}{J_\text{DT}}\left( Q_g - Q_a + Q_b\right) + \end{aligned} + +where :math:`J_{DT}` is the total inertia of the drivetrain (blades+hub+generator), :math:`Q_g`, :math:`Q_a` and :math:`Q_b` are the generator, aerodynamic and brake torque respectively, all expressed on the low-speed-shaft (LSS) side. +The total inertia of the drivetrain is obtained as: + +.. math:: :label: sed_JDT + + J_\text{DT} = J_r + n_g^2 J_{g,HSS} + +where :math:`J_r` is the inertia of the rotor (blades+hub+"shaft"), +:math:`n_g` is the gear ratio of the gearbox +and :math:`J_{g,HSS}` is the inertia of the generator on the high-speed-shaft (HSS). +It is noted that OpenFAST considers the inertia of the shaft to be included in the "hub" (i.e. rotor). +The generator and brake torques on the LSS is obtained from the HSS as follows: + +.. math:: :label: QgLSS + + Q_g = n_g Q_{g,HSS} + ,\quad + Q_b = n_g Q_{b,HSS} + +.. + where :math:`\eta_{DT}` is the efficiency of the drivetrain. + Q_g = \frac{n_g}{\eta_{DT}} Q_{g,HSS} + +The initial conditions associated with equation :eq:`sed_stateEq` are: + +.. math:: :label: sed_stateInit + + \begin{aligned} + \psi & = \psi_0 \\ + \dot{\psi} & = \Omega_0 + \end{aligned} + +where :math:`\psi_0` is the initial azimuthal angle in rad and :math:`\Omega_0` is the initial rotor speed in rad/s. + + + +If the generator degrees of freedom is off, then the states are simply determined as follows: + + +.. math:: :label: sed_stateEqGenDOF + + + \begin{aligned} + \psi & = \psi_0 + \int_{0}^t \dot{\psi} dt = \psi_0 + \Omega_0 n \Delta t \\ + \dot{\psi} & = \Omega_0 + \end{aligned} + +where :math:`n` is the time step index and :math:`\Delta t` is the time step of the module. + diff --git a/docs/source/user/simplified_elastodyn/zrefs.rst b/docs/source/user/simplified_elastodyn/zrefs.rst new file mode 100644 index 0000000000..ae0bbde01d --- /dev/null +++ b/docs/source/user/simplified_elastodyn/zrefs.rst @@ -0,0 +1,11 @@ +.. only:: html + + References + ---------- + +.. bibliography:: bibliography.bib + :labelprefix: sed- + :keyprefix: sed- + + + From 301d01bc12884a8052aaa7eda7f79949d54dfd82 Mon Sep 17 00:00:00 2001 From: Emmanuel Branlard Date: Thu, 16 Dec 2021 21:30:51 -0700 Subject: [PATCH 007/130] SD: fix condition for potential interface joint bug --- modules/subdyn/src/SD_FEM.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/subdyn/src/SD_FEM.f90 b/modules/subdyn/src/SD_FEM.f90 index 3cbd83337f..e03a8a0991 100644 --- a/modules/subdyn/src/SD_FEM.f90 +++ b/modules/subdyn/src/SD_FEM.f90 @@ -370,7 +370,7 @@ SUBROUTINE SD_ReIndex_CreateNodesAndElems(Init,p, ErrStat, ErrMsg) return endif ! Check that rigid links are not connected to the interface - iInterf = FINDLOCI(Init%Joints(:,1), JointID ) + iInterf = FINDLOCI(p%Nodes_I(:,1), iJoint ) if (iInterf>=1) then CALL WrScr('[WARNING] There might be a bug when rigid links are connected to the interface nodes (mostly if cables are involved). The problematic member is MemberID='//TRIM(Num2LStr(mID))//' (which is a rigid link) involving joint JointID='// TRIM(Num2LStr(JointID))// ' (which is in an interface joint).') endif From 36230972a39a0f21850152c68a6d93877e51b5d6 Mon Sep 17 00:00:00 2001 From: Emmanuel Branlard Date: Mon, 27 Dec 2021 13:17:21 -0700 Subject: [PATCH 008/130] AD: fix yaw index for sine motion in driver --- modules/aerodyn/src/AeroDyn_Driver_Subs.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index 8e62f126e0..4082ad1422 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -902,7 +902,7 @@ subroutine Set_Mesh_Motion(nt,dvr,errStat,errMsg) wt%ptMesh%TranslationDisp(wt%degreeofFreedom,1) = wt%amplitude * sin(time * wt%frequency) wt%ptMesh%TranslationVel (wt%degreeofFreedom,1) = (wt%frequency) * wt%amplitude * cos(time * wt%frequency) wt%ptMesh%TranslationAcc (wt%degreeofFreedom,1) = -(wt%frequency)**2 * wt%amplitude * sin(time * wt%frequency) - elseif (any(wt%degreeOfFreedom==(/4,5,5/))) then + elseif (any(wt%degreeOfFreedom==(/4,5,6/))) then theta(1:3) = 0.0_ReKi theta(wt%degreeofFreedom-3) = wt%amplitude * sin(time * wt%frequency) wt%ptMesh%RotationVel (wt%degreeofFreedom-3,1) = (wt%frequency) * wt%amplitude * cos(time * wt%frequency) From b876951526b0de9fe1e683320029ca5ca2cef478 Mon Sep 17 00:00:00 2001 From: Emmanuel Branlard Date: Fri, 24 Dec 2021 11:15:45 -0700 Subject: [PATCH 009/130] FVW: fix FVW when no blades are present --- modules/aerodyn/src/FVW.f90 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/aerodyn/src/FVW.f90 b/modules/aerodyn/src/FVW.f90 index fec204bdda..1e0b97173f 100644 --- a/modules/aerodyn/src/FVW.f90 +++ b/modules/aerodyn/src/FVW.f90 @@ -450,8 +450,8 @@ SUBROUTINE FVW_SetParametersFromInputs( InitInp, p, ErrStat, ErrMsg ) enddo ! --- Distributing wings to rotors - p%nRotors = p%W(1)%iRotor - do iW=2,p%nWings + p%nRotors = 0 + do iW=1,p%nWings p%nRotors = max(p%nRotors,p%W(iW)%iRotor) end do ! Count number of blades per rotor @@ -838,7 +838,7 @@ subroutine FVW_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrSt integer(IntKi) :: ErrStat2 ! temporary error status of the operation character(ErrMsgLen) :: ErrMsg2 ! temporary error message integer(IntKi) :: nFWEff ! Number of farwake panels that are free at current time step - integer(IntKi) :: i,j,k,iW + integer(IntKi) :: i,j,k,iW,nP real(ReKi) :: visc_fact, age ! Viscosity factor for diffusion of reg param real(ReKi), dimension(3) :: VmeanFW, VmeanNW ! Mean velocity of the near wake and far wake @@ -874,18 +874,22 @@ subroutine FVW_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrSt ! --- Mean induced velocity over the near wake (NW) TODO, store per wing VmeanNW(1:3)=0 if (m%nNW >1) then + nP=0; do iW=1,size(m%W); do j=2,m%nNW+1; do k=1,size(m%W(iW)%Vind_NW,2); VmeanNW(1:3) = VmeanNW(1:3) + m%W(iW)%Vind_NW(1:3, k, j) + nP=nP+1; enddo; enddo; enddo; - VmeanNW(1:3) = VmeanNW(1:3) / (size(m%W)*m%nNW*size(m%W(1)%Vind_NW,2)) ! TODO TODO + VmeanNW(1:3) = VmeanNW(1:3) / nP endif ! --- Induced velocity over the free far wake (FWEff) VmeanFW(1:3)=0 if (nFWEff >0) then + nP=0 do iW=1,size(m%W); do j=1,nFWEff; do k=1,size(m%W(iW)%Vind_FW,2); VmeanFW(1:3) = VmeanFW(1:3) + m%W(iW)%Vind_FW(1:3, k, j) + nP=nP+1; enddo; enddo; enddo; - VmeanFW(1:3) = VmeanFW(1:3) / (size(m%W)*nFWEff*size(m%W(1)%Vind_FW,2)) ! TODO TODO + VmeanFW(1:3) = VmeanFW(1:3) / nP else VmeanFW=VmeanNW ! Since we convect the first FW point, we need a reasonable velocity there From 114442dda55592865fd101574f09b4cbc002b794 Mon Sep 17 00:00:00 2001 From: TAO Tao <42032942+tatesnow@users.noreply.github.com> Date: Thu, 30 Dec 2021 03:20:21 +0800 Subject: [PATCH 010/130] Corrected the description of SkewModFactor in Documentation (#951) --- docs/source/this_doc.rst | 2 +- docs/source/user/aerodyn/input.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/this_doc.rst b/docs/source/this_doc.rst index 53947475e7..78b3ffa5df 100644 --- a/docs/source/this_doc.rst +++ b/docs/source/this_doc.rst @@ -10,7 +10,7 @@ generated from both the `dev `_ branches whenever new commits are added. Clicking on the bar on the lower left corner of the page reveals a panel (see image below) containing options to select the branch -of the repository, download the documentation other formats (PFD, HTML, EPub), +of the repository, download the documentation other formats (PDF, HTML, EPub), and link to other relevant websites. .. image:: ../_static/docs_options.png diff --git a/docs/source/user/aerodyn/input.rst b/docs/source/user/aerodyn/input.rst index 32c1e993e1..631a17b88e 100644 --- a/docs/source/user/aerodyn/input.rst +++ b/docs/source/user/aerodyn/input.rst @@ -145,7 +145,7 @@ an additional skewed-wake correction. Set ``SkewMod`` to 2 to include the Pitt/Peters correction model. **The coupled model ``SkewMod= 3`` is not available in this version of AeroDyn.** -``SkewModFactor`` is used only when ``SkewMod = 1``. Enter a scaling factor to use +``SkewModFactor`` is used only when ``SkewMod = 2``. Enter a scaling factor to use in the Pitt/Peters correction model, or enter ``"default"`` to use the default value of :math:`\frac{15 \pi}{32}`. From 2de3079fd2bb7b7af4bec85f4acf729d4cbb270a Mon Sep 17 00:00:00 2001 From: Bonnie Jonkman Date: Wed, 19 Jan 2022 12:37:57 -0700 Subject: [PATCH 011/130] Update GH actions to update packages for ubuntu debug regression test (#971) --- .github/workflows/automated-dev-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 1e69ea7cd2..147e7fc78d 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -106,7 +106,7 @@ jobs: install_deps: brew install gcovr - os: ubuntu-20.04 FORTRAN_COMPILER: gfortran-10 - install_deps: sudo apt-get install -y gcovr + install_deps: sudo apt-get update && sudo apt-get install -y gcovr name: regression-test-debug-${{ matrix.os }}-${{ matrix.FORTRAN_COMPILER }} steps: From e1e4078d6e85306e6e7e0316c6f2dacfdd29a07c Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 25 Jan 2022 13:45:20 -0700 Subject: [PATCH 012/130] [BugFix] AD15 nacelle reference position was set to hub position --- modules/aerodyn/src/AeroDyn.f90 | 2 +- modules/aerodyn/src/AeroDyn_Registry.txt | 1 + modules/aerodyn/src/AeroDyn_Types.f90 | 13 +++++++++++++ modules/openfast-library/src/FAST_Subs.f90 | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index e5fb77ad21..7e7e7c4493 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -1031,7 +1031,7 @@ subroutine Init_u( u, p, p_AD, InputFileData, InitInp, errStat, errMsg ) if (errStat >= AbortErrLev) return ! set node initial position/orientation - position = InitInp%HubPosition + position = InitInp%NacellePosition position(1:2) = 0 call MeshPositionNode(u%NacelleMotion, 1, position, errStat2, errMsg2, orient=InitInp%NacelleOrientation) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 251e4227f9..490f757e83 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -42,6 +42,7 @@ typedef ^ RotInitInputType ReKi HubPosition {3} - - "X-Y-Z reference position of typedef ^ RotInitInputType R8Ki HubOrientation {3}{3} - - "DCM reference orientation of hub" - typedef ^ RotInitInputType ReKi BladeRootPosition {:}{:} - - "X-Y-Z reference position of each blade root (3 x NumBlades)" m typedef ^ RotInitInputType R8Ki BladeRootOrientation {:}{:}{:} - - "DCM reference orientation of blade roots (3x3 x NumBlades)" - +typedef ^ RotInitInputType R8Ki NacellePosition {3} - - "X-Y-Z reference position of hub" m typedef ^ RotInitInputType R8Ki NacelleOrientation {3}{3} - - "DCM reference orientation of nacelle" - typedef ^ RotInitInputType IntKi AeroProjMod - 0 - "Flag to switch between different projection models" - diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 0707dce2fb..ca314157ad 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -57,6 +57,7 @@ MODULE AeroDyn_Types REAL(R8Ki) , DIMENSION(1:3,1:3) :: HubOrientation !< DCM reference orientation of hub [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: BladeRootPosition !< X-Y-Z reference position of each blade root (3 x NumBlades) [m] REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: BladeRootOrientation !< DCM reference orientation of blade roots (3x3 x NumBlades) [-] + REAL(R8Ki) , DIMENSION(1:3) :: NacellePosition !< X-Y-Z reference position of hub [m] REAL(R8Ki) , DIMENSION(1:3,1:3) :: NacelleOrientation !< DCM reference orientation of nacelle [-] INTEGER(IntKi) :: AeroProjMod = 0 !< Flag to switch between different projection models [-] END TYPE RotInitInputType @@ -416,6 +417,7 @@ SUBROUTINE AD_CopyRotInitInputType( SrcRotInitInputTypeData, DstRotInitInputType END IF DstRotInitInputTypeData%BladeRootOrientation = SrcRotInitInputTypeData%BladeRootOrientation ENDIF + DstRotInitInputTypeData%NacellePosition = SrcRotInitInputTypeData%NacellePosition DstRotInitInputTypeData%NacelleOrientation = SrcRotInitInputTypeData%NacelleOrientation DstRotInitInputTypeData%AeroProjMod = SrcRotInitInputTypeData%AeroProjMod END SUBROUTINE AD_CopyRotInitInputType @@ -485,6 +487,7 @@ SUBROUTINE AD_PackRotInitInputType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Int_BufSz = Int_BufSz + 2*3 ! BladeRootOrientation upper/lower bounds for each dimension Db_BufSz = Db_BufSz + SIZE(InData%BladeRootOrientation) ! BladeRootOrientation END IF + Db_BufSz = Db_BufSz + SIZE(InData%NacellePosition) ! NacellePosition Db_BufSz = Db_BufSz + SIZE(InData%NacelleOrientation) ! NacelleOrientation Int_BufSz = Int_BufSz + 1 ! AeroProjMod IF ( Re_BufSz .GT. 0 ) THEN @@ -571,6 +574,10 @@ SUBROUTINE AD_PackRotInitInputType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, END DO END DO END IF + DO i1 = LBOUND(InData%NacellePosition,1), UBOUND(InData%NacellePosition,1) + DbKiBuf(Db_Xferred) = InData%NacellePosition(i1) + Db_Xferred = Db_Xferred + 1 + END DO DO i2 = LBOUND(InData%NacelleOrientation,2), UBOUND(InData%NacelleOrientation,2) DO i1 = LBOUND(InData%NacelleOrientation,1), UBOUND(InData%NacelleOrientation,1) DbKiBuf(Db_Xferred) = InData%NacelleOrientation(i1,i2) @@ -680,6 +687,12 @@ SUBROUTINE AD_UnPackRotInitInputType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSt END DO END DO END IF + i1_l = LBOUND(OutData%NacellePosition,1) + i1_u = UBOUND(OutData%NacellePosition,1) + DO i1 = LBOUND(OutData%NacellePosition,1), UBOUND(OutData%NacellePosition,1) + OutData%NacellePosition(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO i1_l = LBOUND(OutData%NacelleOrientation,1) i1_u = UBOUND(OutData%NacelleOrientation,1) i2_l = LBOUND(OutData%NacelleOrientation,2) diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 7a28e2cfc2..875d17a1e2 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -491,6 +491,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_AD%rotors(1)%HubPosition = ED%y%HubPtMotion%Position(:,1) Init%InData_AD%rotors(1)%HubOrientation = ED%y%HubPtMotion%RefOrientation(:,:,1) + Init%InData_AD%rotors(1)%NacellePosition = ED%y%NacelleMotion%Position(:,1) Init%InData_AD%rotors(1)%NacelleOrientation = ED%y%NacelleMotion%RefOrientation(:,:,1) do k=1,NumBl From 38759937e0bb6e2016806d8779beae540560bbdd Mon Sep 17 00:00:00 2001 From: Andy Platt Date: Mon, 31 Jan 2022 11:47:08 -0700 Subject: [PATCH 013/130] [BugFix] AD15 nacelle reference position was set to hub position #2 Forgot to remove an override of the position for the Nacelle mesh in PR #982. --- modules/aerodyn/src/AeroDyn.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 7e7e7c4493..36e7ce7a92 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -1032,7 +1032,7 @@ subroutine Init_u( u, p, p_AD, InputFileData, InitInp, errStat, errMsg ) ! set node initial position/orientation position = InitInp%NacellePosition - position(1:2) = 0 + call MeshPositionNode(u%NacelleMotion, 1, position, errStat2, errMsg2, orient=InitInp%NacelleOrientation) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) From cb53b222887e35ab4000c1dbd0d226ebe7ae9653 Mon Sep 17 00:00:00 2001 From: Emmanuel Branlard Date: Mon, 31 Jan 2022 13:06:58 -0700 Subject: [PATCH 014/130] AD-Driver-Doc: adding units for amplitude and frequency --- docs/source/user/aerodyn/driver.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/source/user/aerodyn/driver.rst b/docs/source/user/aerodyn/driver.rst index 6c37bdacce..a09e2e9373 100644 --- a/docs/source/user/aerodyn/driver.rst +++ b/docs/source/user/aerodyn/driver.rst @@ -242,8 +242,8 @@ An example of inputs for a sinusoidal surge motion is given below: ----- Turbine(1) Motion [used only when AnalysisType=1] -------------------------- 1 BaseMotionType(1) - Type of motion prescribed for this base {0: fixed, 1: Sinusoidal motion, 2: arbitrary motion} (flag) 1 DegreeOfFreedom(1) - {1:xg, 2:yg, 3:zg, 4:theta_xg, 5:theta_yg, 6:theta_zg} [used only when BaseMotionType=1] (flag) - 5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] - 0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) + 5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] (m or rad) + 0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) "unused" BaseMotionFileName(1) - Filename containing arbitrary base motion (19 columns: Time, x, y, z, theta_x, ..., alpha_z) [used only when BaseMotionType=2] @@ -313,7 +313,7 @@ When `DOF=0`, the turbine base is fixed. ----- Combined-Case Analysis [used only when AnalysisType=3 and numTubines=1] ------ 4 NumCases - Number of cases to run HWndSpeed PLExp RotSpd Pitch Yaw dT Tmax DOF Amplitude Frequency - (m/s) (-) (rpm) (deg) (deg) (s) (s) (-) (-) (Hz) + (m/s) (-) (rpm) (deg) (deg) (s) (s) (-) (m or rad) (Hz) 8. 0.0 6. 0. 0. 1.0 100 0 0 0.0 8. 0.0 6. 0. 0. 1.0 100 0 0 0.0 9. 0.1 7. 1. 0. 0.5 50 1 5.0 0.1 @@ -405,7 +405,6 @@ Examples of driver input files Working examples that use the different features of the driver are given in the r-test repository: -- (Temporary) `New driver branch `_ . - `Dev branch `_ . - `Main branch `_ . @@ -449,8 +448,8 @@ An example of an AeroDyn driver for a basic inflow, basic HAWT, and combined cas ----- Turbine(1) Motion [used only when AnalysisType=1] --------------------------------- 1 BaseMotionType(1) - Type of motion prescribed for this base {0: fixed, 1: Sinusoidal motion, 2: arbitrary motion} (flag) 1 DegreeOfFreedom(1) - {1:xg, 2:yg, 3:zg, 4:theta_xg, 5:theta_yg, 6:theta_zg} [used only when BaseMotionType=1] (flag) - 5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] - 0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] + 5.0 Amplitude(1) - Amplitude of sinusoidal motion [used only when BaseMotionType=1] (m or rad) + 0.1 Frequency(1) - Frequency of sinusoidal motion [used only when BaseMotionType=1] (Hz) "" BaseMotionFileName(1) - Filename containing arbitrary base motion (19 columns: Time, x, y, z, theta_x, ..., alpha_z) [used only when BaseMotionType=2] 0 NacYaw(1) - Yaw angle (about z_t) of the nacelle (deg) 7 RotSpeed(1) - Rotational speed of rotor in rotor coordinates (rpm) From 7546c48ea424d58ec02bd712a1e5b5265c6b0436 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 10 Feb 2022 11:04:07 -0700 Subject: [PATCH 015/130] [BugFix] BeamDyn nodal outputs occasionally segfaulted The cause was an index that never got set. So this could result in attempting to retrieve a value from the output mapping array using an out of bounds index (sometimes a very large negative number). This never appeared in gcc compiled versions, but occasionally would appear in certain intel compiled versions (others initialized the value apparently). --- modules/beamdyn/src/BeamDyn.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index a2ccb45f1b..260a937899 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -1062,6 +1062,7 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return p%NdIndx(1) = 1 + p%NdIndxInverse(1) = 1 p%OutNd2NdElem(:,1) = 1 ! note this is an array indx = 2 DO i=1,p%elem_total @@ -1119,6 +1120,7 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return p%NdIndx(1) = 1 + p%NdIndxInverse(1) = 1 p%OutNd2NdElem(:,1) = 1 ! note this is an array indx = 2 DO i=1,p%elem_total From 7fe8c5a3961236a0ec5e5ad22ec60d8ee9ecb6d2 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 14 Feb 2022 12:54:20 -0700 Subject: [PATCH 016/130] SED: add registry --- CMakeLists.txt | 1 + modules/simple-elastodyn/CMakeLists.txt | 34 + modules/simple-elastodyn/src/SED_Registry.txt | 117 + modules/simple-elastodyn/src/SED_Types.f90 | 3457 +++++++++++++++++ 4 files changed, 3609 insertions(+) create mode 100644 modules/simple-elastodyn/CMakeLists.txt create mode 100644 modules/simple-elastodyn/src/SED_Registry.txt create mode 100644 modules/simple-elastodyn/src/SED_Types.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 36f0a0ecc3..320a71debe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ set(OPENFAST_MODULES map wakedynamics awae + simple-elastodyn ) set(OPENFAST_REGISTRY_INCLUDES "" CACHE INTERNAL "Registry includes paths") diff --git a/modules/simple-elastodyn/CMakeLists.txt b/modules/simple-elastodyn/CMakeLists.txt new file mode 100644 index 0000000000..c77fea1092 --- /dev/null +++ b/modules/simple-elastodyn/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2016 National Renewable Energy Laboratory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if (GENERATE_TYPES) + generate_f90_types(src/SED_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/SED_Types.f90) +endif() + +set(SED_SOURCES + src/SED_Types.f90 + ) + #src/SED.f90 + #src/SED_IO.f90 + +add_library(sedlib ${SED_SOURCES}) +target_link_libraries(sedlib nwtclibs) + +install(TARGETS sedlib + EXPORT "${CMAKE_PROJECT_NAME}Libraries" + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) diff --git a/modules/simple-elastodyn/src/SED_Registry.txt b/modules/simple-elastodyn/src/SED_Registry.txt new file mode 100644 index 0000000000..9f2c51de43 --- /dev/null +++ b/modules/simple-elastodyn/src/SED_Registry.txt @@ -0,0 +1,117 @@ +################################################################################################################################### +# Registry for Simplified ElastoDyn in the FAST Modularization Framework +# This Registry file is used to create MODULE SED_Types which contains all of the user-defined types needed in Simplified ElastoDyn. +# It also contains copy, destroy, pack, and unpack routines associated with each defined data types. +# See the NWTC Programmer's Handbook for further information on the format/contents of this file. +# +# Entries are of the form +# +# +# Use ^ as a shortcut for the value in the same column from the previous line. +################################################################################################################################### +# ...... Include files (definitions from NWTC Library) ............................................................................ +include Registry_NWTC_Library.txt + + +# ..... Initialization data ....................................................................................................... +# SED input file +typedef SED/SED SED_InputFile LOGICAL EchoFlag - - - "Echo the input file" - +typedef ^ SED_InputFile R8Ki DeltaT - - - "Time step for module time integration" s +typedef ^ SED_InputFile IntKi IntMethod - - - "Integration method {1: RK4, 2: AB4, or 3: ABM4}" - +typedef ^ SED_InputFile LOGICAL GenDOF - - - "whether the generator is fixed or free" - +typedef ^ SED_InputFile R8Ki Azimuth - - - "Initial azimuth angle for blade 1" deg +typedef ^ SED_InputFile ReKi BlPitch - - - "Initial blade pitch angles" radians +typedef ^ SED_InputFile ReKi RotSpeed - - - "Initial or fixed rotor speed" RPM +typedef ^ SED_InputFile ReKi PtfmPitch - - - "Fixed pitch tilt rotational displacement of platform" deg +typedef ^ SED_InputFile IntKi NumBl - - - "Number of blades on the turbine" - +typedef ^ SED_InputFile ReKi TipRad - - - "Preconed blade-tip radius (distance from the rotor apex to the blade tip)" m +typedef ^ SED_InputFile ReKi HubRad - - - "Preconed hub radius (distance from the rotor apex to the blade root)" m +typedef ^ SED_InputFile ReKi PreCone - - - "Rotor precone angles" deg +typedef ^ SED_InputFile ReKi OverHang - - - "Distance from yaw axis to rotor apex or teeter pin" m +typedef ^ SED_InputFile ReKi ShftTilt - - - "Rotor shaft tilt angle" deg +typedef ^ SED_InputFile ReKi Twr2Shft - - - "Vertical distance from the tower-top to the rotor shaft" m +typedef ^ SED_InputFile ReKi TowerHt - - - "Height of tower above ground level [onshore] or MSL [offshore]" m +typedef ^ SED_InputFile ReKi RotIner - - - "Hub inertia about teeter axis (2-blader) or rotor axis (3-blader)" "kg m^2" +typedef ^ SED_InputFile ReKi GenIner - - - "Generator inertia about HSS" "kg m^2" +typedef ^ SED_InputFile ReKi GBEff - - - "Gearbox efficiency" "percent" +typedef ^ SED_InputFile ReKi GBRatio - - - "Gearbox ratio" - +typedef ^ SED_InputFile LOGICAL SumPrint - - - "Print summary data to .sum" - +typedef ^ SED_InputFile CHARACTER(ChanLen) OutList : - - "List of user-requested output channels" - + + +# ..... Initialization data ....................................................................................................... +# inputs for initialization: +typedef SED/SED InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - +typedef ^ InitInputType CHARACTER(1024) RootName - - - "RootName for writing output files" - + + +# outputs from initialization: +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputUnt {:} - - "Units of the output-to-file channels" - +typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - +typedef ^ InitOutputType IntKi NumBl - - - "Number of blades on the turbine" - +typedef ^ InitOutputType ReKi BlPitch {:} - - "Initial blade pitch angles" radians +typedef ^ InitOutputType ReKi BladeLength - - - "Blade length (for AeroDyn)" meters +typedef ^ InitOutputType ReKi TowerHeight - - - "Tower Height" meters +typedef ^ InitOutputType ReKi HubHt - - - "Height of the hub" meters +typedef ^ InitOutputType ReKi PlatformPos {6} - - "Initial platform position (6 DOFs)" +typedef ^ InitOutputType ReKi HubRad - - - "Preconed hub radius (distance from the rotor apex to the blade root)" m +typedef ^ InitOutputType ReKi RotSpeed - - - "Initial or fixed rotor speed" rad/s +typedef ^ InitOutputType LOGICAL isFixed_GenDOF - - - "whether the generator is fixed or free" - + + +# ..... Inputs .................................................................................................................... +# inputs on meshes: NONE +# inputs not on meshes: +typedef ^ InputType ReKi AeroTrq - - - "Aerodynamic torque" N-m +typedef ^ InputType ReKi HSSBrTrqC - - - "Commanded HSS brake torque" N-m +typedef ^ InputType ReKi GenTrq - - - "Electrical generator torque" N-m +typedef ^ InputType ReKi BlPitchCom {:} - 2pi "Commanded blade pitch angles" radians +typedef ^ InputType ReKi Yaw - - - "Yaw angle" rad +typedef ^ InputType ReKi YawRate - - - "Yaw rate" rad/s + + +# ..... Outputs ................................................................................................................... +# outputs not meshes: +typedef ^ OutputType MeshType BladeRootMotion {:} - - "For AeroDyn/BeamDyn: motions at the blade roots" - +typedef ^ OutputType MeshType HubPtMotion - - - "For AeroDyn and Lidar(InflowWind): motions of the hub" - +typedef ^ OutputType MeshType NacelleMotion - - - "For AeroDyn14 & ServoDyn/TMD: motions of the nacelle." - +typedef ^ OutputType MeshType TowerLn2Mesh - - - "Tower line2 mesh with positions/orientations/velocities/accelerations" - +typedef ^ OutputType MeshType PlatformPtMesh - - - "Platform reference point positions/orientations/velocities/accelerations" - +# outputs not on meshes: +typedef ^ OutputType ReKi LSSTipPxa - - 2pi "Rotor azimuth angle (position)" radians +typedef ^ OutputType ReKi RotSpeed - - - "Rotor azimuth angular speed" rad/s +typedef ^ OutputType ReKi HSS_Spd - - - "High-speed shaft (HSS) speed" rad/s +typedef ^ OutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" + + +# ..... States .................................................................................................................... +# continuous (differentiable) states: +typedef ^ ContinuousStateType R8Ki QT {:} - - "Current estimate of Q (displacement matrix) for each degree of freedom" - +typedef ^ ContinuousStateType ^ QDT {:} - - "Current estimate of QD (velocity matrix) for each degree of freedom" + +# Define discrete (nondifferentiable) states here: +typedef ^ DiscreteStateType ReKi DummyDiscreteState - - - "" - + +# Define constraint states here: +typedef ^ ConstraintStateType ReKi DummyConstrState - - - "" - + +# any other states +typedef ^ OtherStateType IntKi DummyOtherState - - - "" - + + +# ..... Parameters................................................................................................................. +# unchanging parameters: +typedef ^ ParameterType DbKi DeltaT - - - "Time step for module time integration" s +typedef ^ ParameterType IntKi IntMethod - - - "Integration method {1: RK4, 2: AB4, or 3: ABM4}" - +typedef ^ ParameterType ReKi J_DT - - - "Drivetrain inertia (blades+hub+shaft+generator)" "kgm^2" +typedef ^ ParameterType ReKi PtfmPitch - - - "Static platform tilt angle" rad +typedef ^ ParameterType MeshMapType mapPtf2Twr - - - "Mesh mapping from Ptfm to Tower line" - +typedef ^ ParameterType MeshMapType mapTwr2Nac - - - "Mesh mapping from Tower to Nacelle" - +typedef ^ ParameterType MeshMapType mapNac2Hub - - - "Mesh mapping from Nacelle to Hub" - +typedef ^ ParameterType LOGICAL isFixed_GenDOF - - - "whether the generator is fixed or free" - + + +# ..... Misc/Optimization variables................................................................................................. +typedef ^ MiscVarType IntKi DummyMiscVar - - - "" - + diff --git a/modules/simple-elastodyn/src/SED_Types.f90 b/modules/simple-elastodyn/src/SED_Types.f90 new file mode 100644 index 0000000000..c7d091f6a9 --- /dev/null +++ b/modules/simple-elastodyn/src/SED_Types.f90 @@ -0,0 +1,3457 @@ +!STARTOFREGISTRYGENERATEDFILE 'SED_Types.f90' +! +! WARNING This file is generated automatically by the FAST registry. +! Do not edit. Your changes to this file will be lost. +! +! FAST Registry +!********************************************************************************************************************************* +! SED_Types +!................................................................................................................................. +! This file is part of SED. +! +! Copyright (C) 2012-2016 National Renewable Energy Laboratory +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +! +! W A R N I N G : This file was automatically generated from the FAST registry. Changes made to this file may be lost. +! +!********************************************************************************************************************************* +!> This module contains the user-defined types needed in SED. It also contains copy, destroy, pack, and +!! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. +MODULE SED_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE NWTC_Library +IMPLICIT NONE +! ========= SED_InputFile ======= + TYPE, PUBLIC :: SED_InputFile + LOGICAL :: EchoFlag !< Echo the input file [-] + REAL(R8Ki) :: DeltaT !< Time step for module time integration [s] + INTEGER(IntKi) :: IntMethod !< Integration method {1: RK4, 2: AB4, or 3: ABM4} [-] + LOGICAL :: GenDOF !< whether the generator is fixed or free [-] + REAL(R8Ki) :: Azimuth !< Initial azimuth angle for blade 1 [deg] + REAL(ReKi) :: BlPitch !< Initial blade pitch angles [radians] + REAL(ReKi) :: RotSpeed !< Initial or fixed rotor speed [RPM] + REAL(ReKi) :: PtfmPitch !< Fixed pitch tilt rotational displacement of platform [deg] + INTEGER(IntKi) :: NumBl !< Number of blades on the turbine [-] + REAL(ReKi) :: TipRad !< Preconed blade-tip radius (distance from the rotor apex to the blade tip) [m] + REAL(ReKi) :: HubRad !< Preconed hub radius (distance from the rotor apex to the blade root) [m] + REAL(ReKi) :: PreCone !< Rotor precone angles [deg] + REAL(ReKi) :: OverHang !< Distance from yaw axis to rotor apex or teeter pin [m] + REAL(ReKi) :: ShftTilt !< Rotor shaft tilt angle [deg] + REAL(ReKi) :: Twr2Shft !< Vertical distance from the tower-top to the rotor shaft [m] + REAL(ReKi) :: TowerHt !< Height of tower above ground level [onshore] or MSL [offshore] [m] + REAL(ReKi) :: RotIner !< Hub inertia about teeter axis (2-blader) or rotor axis (3-blader) [kg m^2] + REAL(ReKi) :: GenIner !< Generator inertia about HSS [kg m^2] + REAL(ReKi) :: GBEff !< Gearbox efficiency [percent] + REAL(ReKi) :: GBRatio !< Gearbox ratio [-] + LOGICAL :: SumPrint !< Print summary data to .sum [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< List of user-requested output channels [-] + END TYPE SED_InputFile +! ======================= +! ========= SED_InitInputType ======= + TYPE, PUBLIC :: SED_InitInputType + CHARACTER(1024) :: InputFile !< Name of the input file [-] + CHARACTER(1024) :: RootName !< RootName for writing output files [-] + END TYPE SED_InitInputType +! ======================= +! ========= SED_InitOutputType ======= + TYPE, PUBLIC :: SED_InitOutputType + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Names of the output-to-file channels [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Units of the output-to-file channels [-] + TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] + INTEGER(IntKi) :: NumBl !< Number of blades on the turbine [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BlPitch !< Initial blade pitch angles [radians] + REAL(ReKi) :: BladeLength !< Blade length (for AeroDyn) [meters] + REAL(ReKi) :: TowerHeight !< Tower Height [meters] + REAL(ReKi) :: HubHt !< Height of the hub [meters] + REAL(ReKi) , DIMENSION(1:6) :: PlatformPos !< Initial platform position (6 DOFs) [-] + REAL(ReKi) :: HubRad !< Preconed hub radius (distance from the rotor apex to the blade root) [m] + REAL(ReKi) :: RotSpeed !< Initial or fixed rotor speed [rad/s] + LOGICAL :: isFixed_GenDOF !< whether the generator is fixed or free [-] + END TYPE SED_InitOutputType +! ======================= +! ========= SED_InputType ======= + TYPE, PUBLIC :: SED_InputType + REAL(ReKi) :: AeroTrq !< Aerodynamic torque [N-m] + REAL(ReKi) :: HSSBrTrqC !< Commanded HSS brake torque [N-m] + REAL(ReKi) :: GenTrq !< Electrical generator torque [N-m] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: BlPitchCom !< Commanded blade pitch angles [radians] + REAL(ReKi) :: Yaw !< Yaw angle [rad] + REAL(ReKi) :: YawRate !< Yaw rate [rad/s] + END TYPE SED_InputType +! ======================= +! ========= SED_OutputType ======= + TYPE, PUBLIC :: SED_OutputType + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: BladeRootMotion !< For AeroDyn/BeamDyn: motions at the blade roots [-] + TYPE(MeshType) :: HubPtMotion !< For AeroDyn and Lidar(InflowWind): motions of the hub [-] + TYPE(MeshType) :: NacelleMotion !< For AeroDyn14 & ServoDyn/TMD: motions of the nacelle. [-] + TYPE(MeshType) :: TowerLn2Mesh !< Tower line2 mesh with positions/orientations/velocities/accelerations [-] + TYPE(MeshType) :: PlatformPtMesh !< Platform reference point positions/orientations/velocities/accelerations [-] + REAL(ReKi) :: LSSTipPxa !< Rotor azimuth angle (position) [radians] + REAL(ReKi) :: RotSpeed !< Rotor azimuth angular speed [rad/s] + REAL(ReKi) :: HSS_Spd !< High-speed shaft (HSS) speed [rad/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< Data to be written to an output file: see WriteOutputHdr for names of each variable [see WriteOutputUnt] + END TYPE SED_OutputType +! ======================= +! ========= SED_ContinuousStateType ======= + TYPE, PUBLIC :: SED_ContinuousStateType + REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: QT !< Current estimate of Q (displacement matrix) for each degree of freedom [-] + REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: QDT !< Current estimate of QD (velocity matrix) for each degree of freedom [-] + END TYPE SED_ContinuousStateType +! ======================= +! ========= SED_DiscreteStateType ======= + TYPE, PUBLIC :: SED_DiscreteStateType + REAL(ReKi) :: DummyDiscreteState !< [-] + END TYPE SED_DiscreteStateType +! ======================= +! ========= SED_ConstraintStateType ======= + TYPE, PUBLIC :: SED_ConstraintStateType + REAL(ReKi) :: DummyConstrState !< [-] + END TYPE SED_ConstraintStateType +! ======================= +! ========= SED_OtherStateType ======= + TYPE, PUBLIC :: SED_OtherStateType + INTEGER(IntKi) :: DummyOtherState !< [-] + END TYPE SED_OtherStateType +! ======================= +! ========= SED_ParameterType ======= + TYPE, PUBLIC :: SED_ParameterType + REAL(DbKi) :: DeltaT !< Time step for module time integration [s] + INTEGER(IntKi) :: IntMethod !< Integration method {1: RK4, 2: AB4, or 3: ABM4} [-] + REAL(ReKi) :: J_DT !< Drivetrain inertia (blades+hub+shaft+generator) [kgm^2] + REAL(ReKi) :: PtfmPitch !< Static platform tilt angle [rad] + TYPE(MeshMapType) :: mapPtf2Twr !< Mesh mapping from Ptfm to Tower line [-] + TYPE(MeshMapType) :: mapTwr2Nac !< Mesh mapping from Tower to Nacelle [-] + TYPE(MeshMapType) :: mapNac2Hub !< Mesh mapping from Nacelle to Hub [-] + LOGICAL :: isFixed_GenDOF !< whether the generator is fixed or free [-] + END TYPE SED_ParameterType +! ======================= +! ========= SED_MiscVarType ======= + TYPE, PUBLIC :: SED_MiscVarType + INTEGER(IntKi) :: DummyMiscVar !< [-] + END TYPE SED_MiscVarType +! ======================= +CONTAINS + SUBROUTINE SED_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_InputFile), INTENT(IN) :: SrcInputFileData + TYPE(SED_InputFile), INTENT(INOUT) :: DstInputFileData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyInputFile' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInputFileData%EchoFlag = SrcInputFileData%EchoFlag + DstInputFileData%DeltaT = SrcInputFileData%DeltaT + DstInputFileData%IntMethod = SrcInputFileData%IntMethod + DstInputFileData%GenDOF = SrcInputFileData%GenDOF + DstInputFileData%Azimuth = SrcInputFileData%Azimuth + DstInputFileData%BlPitch = SrcInputFileData%BlPitch + DstInputFileData%RotSpeed = SrcInputFileData%RotSpeed + DstInputFileData%PtfmPitch = SrcInputFileData%PtfmPitch + DstInputFileData%NumBl = SrcInputFileData%NumBl + DstInputFileData%TipRad = SrcInputFileData%TipRad + DstInputFileData%HubRad = SrcInputFileData%HubRad + DstInputFileData%PreCone = SrcInputFileData%PreCone + DstInputFileData%OverHang = SrcInputFileData%OverHang + DstInputFileData%ShftTilt = SrcInputFileData%ShftTilt + DstInputFileData%Twr2Shft = SrcInputFileData%Twr2Shft + DstInputFileData%TowerHt = SrcInputFileData%TowerHt + DstInputFileData%RotIner = SrcInputFileData%RotIner + DstInputFileData%GenIner = SrcInputFileData%GenIner + DstInputFileData%GBEff = SrcInputFileData%GBEff + DstInputFileData%GBRatio = SrcInputFileData%GBRatio + DstInputFileData%SumPrint = SrcInputFileData%SumPrint +IF (ALLOCATED(SrcInputFileData%OutList)) THEN + i1_l = LBOUND(SrcInputFileData%OutList,1) + i1_u = UBOUND(SrcInputFileData%OutList,1) + IF (.NOT. ALLOCATED(DstInputFileData%OutList)) THEN + ALLOCATE(DstInputFileData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%OutList = SrcInputFileData%OutList +ENDIF + END SUBROUTINE SED_CopyInputFile + + SUBROUTINE SED_DestroyInputFile( InputFileData, ErrStat, ErrMsg ) + TYPE(SED_InputFile), INTENT(INOUT) :: InputFileData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyInputFile' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InputFileData%OutList)) THEN + DEALLOCATE(InputFileData%OutList) +ENDIF + END SUBROUTINE SED_DestroyInputFile + + SUBROUTINE SED_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_InputFile), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackInputFile' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! EchoFlag + Db_BufSz = Db_BufSz + 1 ! DeltaT + Int_BufSz = Int_BufSz + 1 ! IntMethod + Int_BufSz = Int_BufSz + 1 ! GenDOF + Db_BufSz = Db_BufSz + 1 ! Azimuth + Re_BufSz = Re_BufSz + 1 ! BlPitch + Re_BufSz = Re_BufSz + 1 ! RotSpeed + Re_BufSz = Re_BufSz + 1 ! PtfmPitch + Int_BufSz = Int_BufSz + 1 ! NumBl + Re_BufSz = Re_BufSz + 1 ! TipRad + Re_BufSz = Re_BufSz + 1 ! HubRad + Re_BufSz = Re_BufSz + 1 ! PreCone + Re_BufSz = Re_BufSz + 1 ! OverHang + Re_BufSz = Re_BufSz + 1 ! ShftTilt + Re_BufSz = Re_BufSz + 1 ! Twr2Shft + Re_BufSz = Re_BufSz + 1 ! TowerHt + Re_BufSz = Re_BufSz + 1 ! RotIner + Re_BufSz = Re_BufSz + 1 ! GenIner + Re_BufSz = Re_BufSz + 1 ! GBEff + Re_BufSz = Re_BufSz + 1 ! GBRatio + Int_BufSz = Int_BufSz + 1 ! SumPrint + Int_BufSz = Int_BufSz + 1 ! OutList allocated yes/no + IF ( ALLOCATED(InData%OutList) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! OutList upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%OutList)*LEN(InData%OutList) ! OutList + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = TRANSFER(InData%EchoFlag, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DeltaT + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%IntMethod + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%GenDOF, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%Azimuth + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%BlPitch + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotSpeed + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%PtfmPitch + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%NumBl + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TipRad + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%HubRad + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%PreCone + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%OverHang + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%ShftTilt + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Twr2Shft + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TowerHt + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotIner + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%GenIner + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%GBEff + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%GBRatio + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%SumPrint, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%OutList) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutList,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutList,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%OutList,1), UBOUND(InData%OutList,1) + DO I = 1, LEN(InData%OutList) + IntKiBuf(Int_Xferred) = ICHAR(InData%OutList(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + END SUBROUTINE SED_PackInputFile + + SUBROUTINE SED_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_InputFile), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackInputFile' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%EchoFlag = TRANSFER(IntKiBuf(Int_Xferred), OutData%EchoFlag) + Int_Xferred = Int_Xferred + 1 + OutData%DeltaT = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + OutData%IntMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%GenDOF = TRANSFER(IntKiBuf(Int_Xferred), OutData%GenDOF) + Int_Xferred = Int_Xferred + 1 + OutData%Azimuth = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + OutData%BlPitch = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RotSpeed = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%PtfmPitch = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%NumBl = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%TipRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%HubRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%PreCone = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%OverHang = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%ShftTilt = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Twr2Shft = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TowerHt = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RotIner = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%GenIner = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%GBEff = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%GBRatio = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SumPrint = TRANSFER(IntKiBuf(Int_Xferred), OutData%SumPrint) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutList not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%OutList)) DEALLOCATE(OutData%OutList) + ALLOCATE(OutData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%OutList,1), UBOUND(OutData%OutList,1) + DO I = 1, LEN(OutData%OutList) + OutData%OutList(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + END SUBROUTINE SED_UnPackInputFile + + SUBROUTINE SED_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_InitInputType), INTENT(IN) :: SrcInitInputData + TYPE(SED_InitInputType), INTENT(INOUT) :: DstInitInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyInitInput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInitInputData%InputFile = SrcInitInputData%InputFile + DstInitInputData%RootName = SrcInitInputData%RootName + END SUBROUTINE SED_CopyInitInput + + SUBROUTINE SED_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) + TYPE(SED_InitInputType), INTENT(INOUT) :: InitInputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyInitInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE SED_DestroyInitInput + + SUBROUTINE SED_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_InitInputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackInitInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1*LEN(InData%InputFile) ! InputFile + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DO I = 1, LEN(InData%InputFile) + IntKiBuf(Int_Xferred) = ICHAR(InData%InputFile(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END SUBROUTINE SED_PackInitInput + + SUBROUTINE SED_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_InitInputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackInitInput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + DO I = 1, LEN(OutData%InputFile) + OutData%InputFile(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%RootName) + OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END SUBROUTINE SED_UnPackInitInput + + SUBROUTINE SED_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_InitOutputType), INTENT(IN) :: SrcInitOutputData + TYPE(SED_InitOutputType), INTENT(INOUT) :: DstInitOutputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyInitOutput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcInitOutputData%WriteOutputHdr)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputHdr,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputHdr,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputHdr)) THEN + ALLOCATE(DstInitOutputData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputHdr = SrcInitOutputData%WriteOutputHdr +ENDIF +IF (ALLOCATED(SrcInitOutputData%WriteOutputUnt)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputUnt,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputUnt,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputUnt)) THEN + ALLOCATE(DstInitOutputData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputUnt = SrcInitOutputData%WriteOutputUnt +ENDIF + CALL NWTC_Library_Copyprogdesc( SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstInitOutputData%NumBl = SrcInitOutputData%NumBl +IF (ALLOCATED(SrcInitOutputData%BlPitch)) THEN + i1_l = LBOUND(SrcInitOutputData%BlPitch,1) + i1_u = UBOUND(SrcInitOutputData%BlPitch,1) + IF (.NOT. ALLOCATED(DstInitOutputData%BlPitch)) THEN + ALLOCATE(DstInitOutputData%BlPitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%BlPitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%BlPitch = SrcInitOutputData%BlPitch +ENDIF + DstInitOutputData%BladeLength = SrcInitOutputData%BladeLength + DstInitOutputData%TowerHeight = SrcInitOutputData%TowerHeight + DstInitOutputData%HubHt = SrcInitOutputData%HubHt + DstInitOutputData%PlatformPos = SrcInitOutputData%PlatformPos + DstInitOutputData%HubRad = SrcInitOutputData%HubRad + DstInitOutputData%RotSpeed = SrcInitOutputData%RotSpeed + DstInitOutputData%isFixed_GenDOF = SrcInitOutputData%isFixed_GenDOF + END SUBROUTINE SED_CopyInitOutput + + SUBROUTINE SED_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) + TYPE(SED_InitOutputType), INTENT(INOUT) :: InitOutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyInitOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InitOutputData%WriteOutputHdr)) THEN + DEALLOCATE(InitOutputData%WriteOutputHdr) +ENDIF +IF (ALLOCATED(InitOutputData%WriteOutputUnt)) THEN + DEALLOCATE(InitOutputData%WriteOutputUnt) +ENDIF + CALL NWTC_Library_Destroyprogdesc( InitOutputData%Ver, ErrStat, ErrMsg ) +IF (ALLOCATED(InitOutputData%BlPitch)) THEN + DEALLOCATE(InitOutputData%BlPitch) +ENDIF + END SUBROUTINE SED_DestroyInitOutput + + SUBROUTINE SED_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_InitOutputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackInitOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no + IF ( ALLOCATED(InData%WriteOutputHdr) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputHdr upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputHdr)*LEN(InData%WriteOutputHdr) ! WriteOutputHdr + END IF + Int_BufSz = Int_BufSz + 1 ! WriteOutputUnt allocated yes/no + IF ( ALLOCATED(InData%WriteOutputUnt) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputUnt upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputUnt)*LEN(InData%WriteOutputUnt) ! WriteOutputUnt + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! Ver: size of buffers for each call to pack subtype + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, .TRUE. ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Ver + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Ver + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Ver + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! NumBl + Int_BufSz = Int_BufSz + 1 ! BlPitch allocated yes/no + IF ( ALLOCATED(InData%BlPitch) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! BlPitch upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BlPitch) ! BlPitch + END IF + Re_BufSz = Re_BufSz + 1 ! BladeLength + Re_BufSz = Re_BufSz + 1 ! TowerHeight + Re_BufSz = Re_BufSz + 1 ! HubHt + Re_BufSz = Re_BufSz + SIZE(InData%PlatformPos) ! PlatformPos + Re_BufSz = Re_BufSz + 1 ! HubRad + Re_BufSz = Re_BufSz + 1 ! RotSpeed + Int_BufSz = Int_BufSz + 1 ! isFixed_GenDOF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%WriteOutputHdr) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputHdr,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputHdr,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputHdr,1), UBOUND(InData%WriteOutputHdr,1) + DO I = 1, LEN(InData%WriteOutputHdr) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputHdr(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( .NOT. ALLOCATED(InData%WriteOutputUnt) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputUnt,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputUnt,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputUnt,1), UBOUND(InData%WriteOutputUnt,1) + DO I = 1, LEN(InData%WriteOutputUnt) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputUnt(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, OnlySize ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IntKiBuf(Int_Xferred) = InData%NumBl + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%BlPitch) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BlPitch,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlPitch,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%BlPitch,1), UBOUND(InData%BlPitch,1) + ReKiBuf(Re_Xferred) = InData%BlPitch(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + ReKiBuf(Re_Xferred) = InData%BladeLength + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%TowerHeight + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%HubHt + Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%PlatformPos,1), UBOUND(InData%PlatformPos,1) + ReKiBuf(Re_Xferred) = InData%PlatformPos(i1) + Re_Xferred = Re_Xferred + 1 + END DO + ReKiBuf(Re_Xferred) = InData%HubRad + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotSpeed + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%isFixed_GenDOF, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_PackInitOutput + + SUBROUTINE SED_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_InitOutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackInitOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputHdr not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputHdr)) DEALLOCATE(OutData%WriteOutputHdr) + ALLOCATE(OutData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputHdr,1), UBOUND(OutData%WriteOutputHdr,1) + DO I = 1, LEN(OutData%WriteOutputHdr) + OutData%WriteOutputHdr(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputUnt not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputUnt)) DEALLOCATE(OutData%WriteOutputUnt) + ALLOCATE(OutData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputUnt,1), UBOUND(OutData%WriteOutputUnt,1) + DO I = 1, LEN(OutData%WriteOutputUnt) + OutData%WriteOutputUnt(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackprogdesc( Re_Buf, Db_Buf, Int_Buf, OutData%Ver, ErrStat2, ErrMsg2 ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%NumBl = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BlPitch not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%BlPitch)) DEALLOCATE(OutData%BlPitch) + ALLOCATE(OutData%BlPitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlPitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%BlPitch,1), UBOUND(OutData%BlPitch,1) + OutData%BlPitch(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + OutData%BladeLength = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%TowerHeight = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%HubHt = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%PlatformPos,1) + i1_u = UBOUND(OutData%PlatformPos,1) + DO i1 = LBOUND(OutData%PlatformPos,1), UBOUND(OutData%PlatformPos,1) + OutData%PlatformPos(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + OutData%HubRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RotSpeed = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%isFixed_GenDOF = TRANSFER(IntKiBuf(Int_Xferred), OutData%isFixed_GenDOF) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_UnPackInitOutput + + SUBROUTINE SED_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_InputType), INTENT(IN) :: SrcInputData + TYPE(SED_InputType), INTENT(INOUT) :: DstInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyInput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInputData%AeroTrq = SrcInputData%AeroTrq + DstInputData%HSSBrTrqC = SrcInputData%HSSBrTrqC + DstInputData%GenTrq = SrcInputData%GenTrq +IF (ALLOCATED(SrcInputData%BlPitchCom)) THEN + i1_l = LBOUND(SrcInputData%BlPitchCom,1) + i1_u = UBOUND(SrcInputData%BlPitchCom,1) + IF (.NOT. ALLOCATED(DstInputData%BlPitchCom)) THEN + ALLOCATE(DstInputData%BlPitchCom(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%BlPitchCom.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputData%BlPitchCom = SrcInputData%BlPitchCom +ENDIF + DstInputData%Yaw = SrcInputData%Yaw + DstInputData%YawRate = SrcInputData%YawRate + END SUBROUTINE SED_CopyInput + + SUBROUTINE SED_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(SED_InputType), INTENT(INOUT) :: InputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InputData%BlPitchCom)) THEN + DEALLOCATE(InputData%BlPitchCom) +ENDIF + END SUBROUTINE SED_DestroyInput + + SUBROUTINE SED_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_InputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! AeroTrq + Re_BufSz = Re_BufSz + 1 ! HSSBrTrqC + Re_BufSz = Re_BufSz + 1 ! GenTrq + Int_BufSz = Int_BufSz + 1 ! BlPitchCom allocated yes/no + IF ( ALLOCATED(InData%BlPitchCom) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! BlPitchCom upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%BlPitchCom) ! BlPitchCom + END IF + Re_BufSz = Re_BufSz + 1 ! Yaw + Re_BufSz = Re_BufSz + 1 ! YawRate + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%AeroTrq + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%HSSBrTrqC + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%GenTrq + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%BlPitchCom) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BlPitchCom,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlPitchCom,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%BlPitchCom,1), UBOUND(InData%BlPitchCom,1) + ReKiBuf(Re_Xferred) = InData%BlPitchCom(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + ReKiBuf(Re_Xferred) = InData%Yaw + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%YawRate + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_PackInput + + SUBROUTINE SED_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_InputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackInput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%AeroTrq = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%HSSBrTrqC = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%GenTrq = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BlPitchCom not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%BlPitchCom)) DEALLOCATE(OutData%BlPitchCom) + ALLOCATE(OutData%BlPitchCom(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlPitchCom.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%BlPitchCom,1), UBOUND(OutData%BlPitchCom,1) + OutData%BlPitchCom(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + OutData%Yaw = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%YawRate = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_UnPackInput + + SUBROUTINE SED_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_OutputType), INTENT(INOUT) :: SrcOutputData + TYPE(SED_OutputType), INTENT(INOUT) :: DstOutputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyOutput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcOutputData%BladeRootMotion)) THEN + i1_l = LBOUND(SrcOutputData%BladeRootMotion,1) + i1_u = UBOUND(SrcOutputData%BladeRootMotion,1) + IF (.NOT. ALLOCATED(DstOutputData%BladeRootMotion)) THEN + ALLOCATE(DstOutputData%BladeRootMotion(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%BladeRootMotion.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcOutputData%BladeRootMotion,1), UBOUND(SrcOutputData%BladeRootMotion,1) + CALL MeshCopy( SrcOutputData%BladeRootMotion(i1), DstOutputData%BladeRootMotion(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF + CALL MeshCopy( SrcOutputData%HubPtMotion, DstOutputData%HubPtMotion, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL MeshCopy( SrcOutputData%NacelleMotion, DstOutputData%NacelleMotion, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL MeshCopy( SrcOutputData%TowerLn2Mesh, DstOutputData%TowerLn2Mesh, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL MeshCopy( SrcOutputData%PlatformPtMesh, DstOutputData%PlatformPtMesh, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstOutputData%LSSTipPxa = SrcOutputData%LSSTipPxa + DstOutputData%RotSpeed = SrcOutputData%RotSpeed + DstOutputData%HSS_Spd = SrcOutputData%HSS_Spd +IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN + i1_l = LBOUND(SrcOutputData%WriteOutput,1) + i1_u = UBOUND(SrcOutputData%WriteOutput,1) + IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN + ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%WriteOutput = SrcOutputData%WriteOutput +ENDIF + END SUBROUTINE SED_CopyOutput + + SUBROUTINE SED_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(SED_OutputType), INTENT(INOUT) :: OutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(OutputData%BladeRootMotion)) THEN +DO i1 = LBOUND(OutputData%BladeRootMotion,1), UBOUND(OutputData%BladeRootMotion,1) + CALL MeshDestroy( OutputData%BladeRootMotion(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(OutputData%BladeRootMotion) +ENDIF + CALL MeshDestroy( OutputData%HubPtMotion, ErrStat, ErrMsg ) + CALL MeshDestroy( OutputData%NacelleMotion, ErrStat, ErrMsg ) + CALL MeshDestroy( OutputData%TowerLn2Mesh, ErrStat, ErrMsg ) + CALL MeshDestroy( OutputData%PlatformPtMesh, ErrStat, ErrMsg ) +IF (ALLOCATED(OutputData%WriteOutput)) THEN + DEALLOCATE(OutputData%WriteOutput) +ENDIF + END SUBROUTINE SED_DestroyOutput + + SUBROUTINE SED_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_OutputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! BladeRootMotion allocated yes/no + IF ( ALLOCATED(InData%BladeRootMotion) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! BladeRootMotion upper/lower bounds for each dimension + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + DO i1 = LBOUND(InData%BladeRootMotion,1), UBOUND(InData%BladeRootMotion,1) + Int_BufSz = Int_BufSz + 3 ! BladeRootMotion: size of buffers for each call to pack subtype + CALL MeshPack( InData%BladeRootMotion(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! BladeRootMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! BladeRootMotion + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! BladeRootMotion + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! BladeRootMotion + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 3 ! HubPtMotion: size of buffers for each call to pack subtype + CALL MeshPack( InData%HubPtMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! HubPtMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! HubPtMotion + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! HubPtMotion + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! HubPtMotion + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! NacelleMotion: size of buffers for each call to pack subtype + CALL MeshPack( InData%NacelleMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! NacelleMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! NacelleMotion + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! NacelleMotion + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! NacelleMotion + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! TowerLn2Mesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%TowerLn2Mesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! TowerLn2Mesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! TowerLn2Mesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! TowerLn2Mesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! TowerLn2Mesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! PlatformPtMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%PlatformPtMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! PlatformPtMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! PlatformPtMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! PlatformPtMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! PlatformPtMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Re_BufSz = Re_BufSz + 1 ! LSSTipPxa + Re_BufSz = Re_BufSz + 1 ! RotSpeed + Re_BufSz = Re_BufSz + 1 ! HSS_Spd + Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no + IF ( ALLOCATED(InData%WriteOutput) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%BladeRootMotion) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%BladeRootMotion,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BladeRootMotion,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%BladeRootMotion,1), UBOUND(InData%BladeRootMotion,1) + CALL MeshPack( InData%BladeRootMotion(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! BladeRootMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF + CALL MeshPack( InData%HubPtMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! HubPtMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL MeshPack( InData%NacelleMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! NacelleMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL MeshPack( InData%TowerLn2Mesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! TowerLn2Mesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL MeshPack( InData%PlatformPtMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! PlatformPtMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + ReKiBuf(Re_Xferred) = InData%LSSTipPxa + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotSpeed + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%HSS_Spd + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) + ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE SED_PackOutput + + SUBROUTINE SED_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BladeRootMotion not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%BladeRootMotion)) DEALLOCATE(OutData%BladeRootMotion) + ALLOCATE(OutData%BladeRootMotion(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BladeRootMotion.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%BladeRootMotion,1), UBOUND(OutData%BladeRootMotion,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%BladeRootMotion(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! BladeRootMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%HubPtMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! HubPtMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%NacelleMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! NacelleMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%TowerLn2Mesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! TowerLn2Mesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%PlatformPtMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! PlatformPtMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%LSSTipPxa = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%RotSpeed = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%HSS_Spd = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) + ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) + OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE SED_UnPackOutput + + SUBROUTINE SED_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(SED_ContinuousStateType), INTENT(INOUT) :: DstContStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyContState' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcContStateData%QT)) THEN + i1_l = LBOUND(SrcContStateData%QT,1) + i1_u = UBOUND(SrcContStateData%QT,1) + IF (.NOT. ALLOCATED(DstContStateData%QT)) THEN + ALLOCATE(DstContStateData%QT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%QT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%QT = SrcContStateData%QT +ENDIF +IF (ALLOCATED(SrcContStateData%QDT)) THEN + i1_l = LBOUND(SrcContStateData%QDT,1) + i1_u = UBOUND(SrcContStateData%QDT,1) + IF (.NOT. ALLOCATED(DstContStateData%QDT)) THEN + ALLOCATE(DstContStateData%QDT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstContStateData%QDT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstContStateData%QDT = SrcContStateData%QDT +ENDIF + END SUBROUTINE SED_CopyContState + + SUBROUTINE SED_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(SED_ContinuousStateType), INTENT(INOUT) :: ContStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyContState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ContStateData%QT)) THEN + DEALLOCATE(ContStateData%QT) +ENDIF +IF (ALLOCATED(ContStateData%QDT)) THEN + DEALLOCATE(ContStateData%QDT) +ENDIF + END SUBROUTINE SED_DestroyContState + + SUBROUTINE SED_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_ContinuousStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackContState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! QT allocated yes/no + IF ( ALLOCATED(InData%QT) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! QT upper/lower bounds for each dimension + Db_BufSz = Db_BufSz + SIZE(InData%QT) ! QT + END IF + Int_BufSz = Int_BufSz + 1 ! QDT allocated yes/no + IF ( ALLOCATED(InData%QDT) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! QDT upper/lower bounds for each dimension + Db_BufSz = Db_BufSz + SIZE(InData%QDT) ! QDT + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%QT) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%QT,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%QT,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%QT,1), UBOUND(InData%QT,1) + DbKiBuf(Db_Xferred) = InData%QT(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%QDT) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%QDT,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%QDT,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%QDT,1), UBOUND(InData%QDT,1) + DbKiBuf(Db_Xferred) = InData%QDT(i1) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + END SUBROUTINE SED_PackContState + + SUBROUTINE SED_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_ContinuousStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackContState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! QT not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%QT)) DEALLOCATE(OutData%QT) + ALLOCATE(OutData%QT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%QT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%QT,1), UBOUND(OutData%QT,1) + OutData%QT(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! QDT not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%QDT)) DEALLOCATE(OutData%QDT) + ALLOCATE(OutData%QDT(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%QDT.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%QDT,1), UBOUND(OutData%QDT,1) + OutData%QDT(i1) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END IF + END SUBROUTINE SED_UnPackContState + + SUBROUTINE SED_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(SED_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyDiscState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstDiscStateData%DummyDiscreteState = SrcDiscStateData%DummyDiscreteState + END SUBROUTINE SED_CopyDiscState + + SUBROUTINE SED_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(SED_DiscreteStateType), INTENT(INOUT) :: DiscStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyDiscState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE SED_DestroyDiscState + + SUBROUTINE SED_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_DiscreteStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackDiscState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyDiscreteState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyDiscreteState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_PackDiscState + + SUBROUTINE SED_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_DiscreteStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackDiscState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyDiscreteState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_UnPackDiscState + + SUBROUTINE SED_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_ConstraintStateType), INTENT(IN) :: SrcConstrStateData + TYPE(SED_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyConstrState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState + END SUBROUTINE SED_CopyConstrState + + SUBROUTINE SED_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) + TYPE(SED_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyConstrState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE SED_DestroyConstrState + + SUBROUTINE SED_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_ConstraintStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackConstrState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyConstrState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyConstrState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_PackConstrState + + SUBROUTINE SED_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_ConstraintStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackConstrState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyConstrState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE SED_UnPackConstrState + + SUBROUTINE SED_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_OtherStateType), INTENT(IN) :: SrcOtherStateData + TYPE(SED_OtherStateType), INTENT(INOUT) :: DstOtherStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyOtherState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstOtherStateData%DummyOtherState = SrcOtherStateData%DummyOtherState + END SUBROUTINE SED_CopyOtherState + + SUBROUTINE SED_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) + TYPE(SED_OtherStateType), INTENT(INOUT) :: OtherStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyOtherState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE SED_DestroyOtherState + + SUBROUTINE SED_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_OtherStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackOtherState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! DummyOtherState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = InData%DummyOtherState + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_PackOtherState + + SUBROUTINE SED_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_OtherStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackOtherState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyOtherState = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_UnPackOtherState + + SUBROUTINE SED_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_ParameterType), INTENT(INOUT) :: SrcParamData + TYPE(SED_ParameterType), INTENT(INOUT) :: DstParamData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyParam' +! + ErrStat = ErrID_None + ErrMsg = "" + DstParamData%DeltaT = SrcParamData%DeltaT + DstParamData%IntMethod = SrcParamData%IntMethod + DstParamData%J_DT = SrcParamData%J_DT + DstParamData%PtfmPitch = SrcParamData%PtfmPitch + CALL NWTC_Library_Copymeshmaptype( SrcParamData%mapPtf2Twr, DstParamData%mapPtf2Twr, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL NWTC_Library_Copymeshmaptype( SrcParamData%mapTwr2Nac, DstParamData%mapTwr2Nac, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + CALL NWTC_Library_Copymeshmaptype( SrcParamData%mapNac2Hub, DstParamData%mapNac2Hub, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstParamData%isFixed_GenDOF = SrcParamData%isFixed_GenDOF + END SUBROUTINE SED_CopyParam + + SUBROUTINE SED_DestroyParam( ParamData, ErrStat, ErrMsg ) + TYPE(SED_ParameterType), INTENT(INOUT) :: ParamData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyParam' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + CALL NWTC_Library_Destroymeshmaptype( ParamData%mapPtf2Twr, ErrStat, ErrMsg ) + CALL NWTC_Library_Destroymeshmaptype( ParamData%mapTwr2Nac, ErrStat, ErrMsg ) + CALL NWTC_Library_Destroymeshmaptype( ParamData%mapNac2Hub, ErrStat, ErrMsg ) + END SUBROUTINE SED_DestroyParam + + SUBROUTINE SED_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_ParameterType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackParam' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Db_BufSz = Db_BufSz + 1 ! DeltaT + Int_BufSz = Int_BufSz + 1 ! IntMethod + Re_BufSz = Re_BufSz + 1 ! J_DT + Re_BufSz = Re_BufSz + 1 ! PtfmPitch + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! mapPtf2Twr: size of buffers for each call to pack subtype + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapPtf2Twr, ErrStat2, ErrMsg2, .TRUE. ) ! mapPtf2Twr + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! mapPtf2Twr + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! mapPtf2Twr + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! mapPtf2Twr + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! mapTwr2Nac: size of buffers for each call to pack subtype + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapTwr2Nac, ErrStat2, ErrMsg2, .TRUE. ) ! mapTwr2Nac + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! mapTwr2Nac + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! mapTwr2Nac + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! mapTwr2Nac + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 3 ! mapNac2Hub: size of buffers for each call to pack subtype + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapNac2Hub, ErrStat2, ErrMsg2, .TRUE. ) ! mapNac2Hub + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! mapNac2Hub + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! mapNac2Hub + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! mapNac2Hub + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! isFixed_GenDOF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DbKiBuf(Db_Xferred) = InData%DeltaT + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%IntMethod + Int_Xferred = Int_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%J_DT + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%PtfmPitch + Re_Xferred = Re_Xferred + 1 + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapPtf2Twr, ErrStat2, ErrMsg2, OnlySize ) ! mapPtf2Twr + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapTwr2Nac, ErrStat2, ErrMsg2, OnlySize ) ! mapTwr2Nac + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%mapNac2Hub, ErrStat2, ErrMsg2, OnlySize ) ! mapNac2Hub + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IntKiBuf(Int_Xferred) = TRANSFER(InData%isFixed_GenDOF, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_PackParam + + SUBROUTINE SED_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_ParameterType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackParam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DeltaT = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%IntMethod = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%J_DT = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%PtfmPitch = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackmeshmaptype( Re_Buf, Db_Buf, Int_Buf, OutData%mapPtf2Twr, ErrStat2, ErrMsg2 ) ! mapPtf2Twr + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackmeshmaptype( Re_Buf, Db_Buf, Int_Buf, OutData%mapTwr2Nac, ErrStat2, ErrMsg2 ) ! mapTwr2Nac + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackmeshmaptype( Re_Buf, Db_Buf, Int_Buf, OutData%mapNac2Hub, ErrStat2, ErrMsg2 ) ! mapNac2Hub + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%isFixed_GenDOF = TRANSFER(IntKiBuf(Int_Xferred), OutData%isFixed_GenDOF) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_UnPackParam + + SUBROUTINE SED_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) + TYPE(SED_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(SED_MiscVarType), INTENT(INOUT) :: DstMiscData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_CopyMisc' +! + ErrStat = ErrID_None + ErrMsg = "" + DstMiscData%DummyMiscVar = SrcMiscData%DummyMiscVar + END SUBROUTINE SED_CopyMisc + + SUBROUTINE SED_DestroyMisc( MiscData, ErrStat, ErrMsg ) + TYPE(SED_MiscVarType), INTENT(INOUT) :: MiscData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'SED_DestroyMisc' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE SED_DestroyMisc + + SUBROUTINE SED_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(SED_MiscVarType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_PackMisc' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! DummyMiscVar + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = InData%DummyMiscVar + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_PackMisc + + SUBROUTINE SED_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(SED_MiscVarType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SED_UnPackMisc' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyMiscVar = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE SED_UnPackMisc + + + SUBROUTINE SED_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(SED_InputType), INTENT(IN) :: u(:) ! Input at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Inputs + TYPE(SED_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Input_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(u)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(u)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(u) - 1 + IF ( order .eq. 0 ) THEN + CALL SED_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL SED_Input_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL SED_Input_ExtrapInterp2(u(1), u(2), u(3), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(u) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE SED_Input_ExtrapInterp + + + SUBROUTINE SED_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(SED_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 + TYPE(SED_InputType), INTENT(IN) :: u2 ! Input at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs + TYPE(SED_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Input_ExtrapInterp1' + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / t(2) + b = -(u1%AeroTrq - u2%AeroTrq) + u_out%AeroTrq = u1%AeroTrq + b * ScaleFactor + b = -(u1%HSSBrTrqC - u2%HSSBrTrqC) + u_out%HSSBrTrqC = u1%HSSBrTrqC + b * ScaleFactor + b = -(u1%GenTrq - u2%GenTrq) + u_out%GenTrq = u1%GenTrq + b * ScaleFactor +IF (ALLOCATED(u_out%BlPitchCom) .AND. ALLOCATED(u1%BlPitchCom)) THEN + DO i1 = LBOUND(u_out%BlPitchCom,1),UBOUND(u_out%BlPitchCom,1) + CALL Angles_ExtrapInterp( u1%BlPitchCom(i1), u2%BlPitchCom(i1), tin, u_out%BlPitchCom(i1), tin_out ) + END DO +END IF ! check if allocated + b = -(u1%Yaw - u2%Yaw) + u_out%Yaw = u1%Yaw + b * ScaleFactor + b = -(u1%YawRate - u2%YawRate) + u_out%YawRate = u1%YawRate + b * ScaleFactor + END SUBROUTINE SED_Input_ExtrapInterp1 + + + SUBROUTINE SED_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(SED_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 > t3 + TYPE(SED_InputType), INTENT(IN) :: u2 ! Input at t2 > t3 + TYPE(SED_InputType), INTENT(IN) :: u3 ! Input at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs + TYPE(SED_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: c ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Input_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) + b = (t(3)**2*(u1%AeroTrq - u2%AeroTrq) + t(2)**2*(-u1%AeroTrq + u3%AeroTrq))* scaleFactor + c = ( (t(2)-t(3))*u1%AeroTrq + t(3)*u2%AeroTrq - t(2)*u3%AeroTrq ) * scaleFactor + u_out%AeroTrq = u1%AeroTrq + b + c * t_out + b = (t(3)**2*(u1%HSSBrTrqC - u2%HSSBrTrqC) + t(2)**2*(-u1%HSSBrTrqC + u3%HSSBrTrqC))* scaleFactor + c = ( (t(2)-t(3))*u1%HSSBrTrqC + t(3)*u2%HSSBrTrqC - t(2)*u3%HSSBrTrqC ) * scaleFactor + u_out%HSSBrTrqC = u1%HSSBrTrqC + b + c * t_out + b = (t(3)**2*(u1%GenTrq - u2%GenTrq) + t(2)**2*(-u1%GenTrq + u3%GenTrq))* scaleFactor + c = ( (t(2)-t(3))*u1%GenTrq + t(3)*u2%GenTrq - t(2)*u3%GenTrq ) * scaleFactor + u_out%GenTrq = u1%GenTrq + b + c * t_out +IF (ALLOCATED(u_out%BlPitchCom) .AND. ALLOCATED(u1%BlPitchCom)) THEN + DO i1 = LBOUND(u_out%BlPitchCom,1),UBOUND(u_out%BlPitchCom,1) + CALL Angles_ExtrapInterp( u1%BlPitchCom(i1), u2%BlPitchCom(i1), u3%BlPitchCom(i1), tin, u_out%BlPitchCom(i1), tin_out ) + END DO +END IF ! check if allocated + b = (t(3)**2*(u1%Yaw - u2%Yaw) + t(2)**2*(-u1%Yaw + u3%Yaw))* scaleFactor + c = ( (t(2)-t(3))*u1%Yaw + t(3)*u2%Yaw - t(2)*u3%Yaw ) * scaleFactor + u_out%Yaw = u1%Yaw + b + c * t_out + b = (t(3)**2*(u1%YawRate - u2%YawRate) + t(2)**2*(-u1%YawRate + u3%YawRate))* scaleFactor + c = ( (t(2)-t(3))*u1%YawRate + t(3)*u2%YawRate - t(2)*u3%YawRate ) * scaleFactor + u_out%YawRate = u1%YawRate + b + c * t_out + END SUBROUTINE SED_Input_ExtrapInterp2 + + + SUBROUTINE SED_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is given by the size of y +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(SED_OutputType), INTENT(INOUT) :: y(:) ! Output at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Outputs + TYPE(SED_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Output_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(y)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(y)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(y) - 1 + IF ( order .eq. 0 ) THEN + CALL SED_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL SED_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL SED_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(y) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE SED_Output_ExtrapInterp + + + SUBROUTINE SED_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = y1, f(t2) = y2 +! +!.................................................................................................................................. + + TYPE(SED_OutputType), INTENT(INOUT) :: y1 ! Output at t1 > t2 + TYPE(SED_OutputType), INTENT(INOUT) :: y2 ! Output at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs + TYPE(SED_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Output_ExtrapInterp1' + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / t(2) +IF (ALLOCATED(y_out%BladeRootMotion) .AND. ALLOCATED(y1%BladeRootMotion)) THEN + DO i1 = LBOUND(y_out%BladeRootMotion,1),UBOUND(y_out%BladeRootMotion,1) + CALL MeshExtrapInterp1(y1%BladeRootMotion(i1), y2%BladeRootMotion(i1), tin, y_out%BladeRootMotion(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated + CALL MeshExtrapInterp1(y1%HubPtMotion, y2%HubPtMotion, tin, y_out%HubPtMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp1(y1%NacelleMotion, y2%NacelleMotion, tin, y_out%NacelleMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp1(y1%TowerLn2Mesh, y2%TowerLn2Mesh, tin, y_out%TowerLn2Mesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp1(y1%PlatformPtMesh, y2%PlatformPtMesh, tin, y_out%PlatformPtMesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL Angles_ExtrapInterp( y1%LSSTipPxa, y2%LSSTipPxa, tin, y_out%LSSTipPxa, tin_out ) + b = -(y1%RotSpeed - y2%RotSpeed) + y_out%RotSpeed = y1%RotSpeed + b * ScaleFactor + b = -(y1%HSS_Spd - y2%HSS_Spd) + y_out%HSS_Spd = y1%HSS_Spd + b * ScaleFactor +IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) + b = -(y1%WriteOutput(i1) - y2%WriteOutput(i1)) + y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b * ScaleFactor + END DO +END IF ! check if allocated + END SUBROUTINE SED_Output_ExtrapInterp1 + + + SUBROUTINE SED_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 +! +!.................................................................................................................................. + + TYPE(SED_OutputType), INTENT(INOUT) :: y1 ! Output at t1 > t2 > t3 + TYPE(SED_OutputType), INTENT(INOUT) :: y2 ! Output at t2 > t3 + TYPE(SED_OutputType), INTENT(INOUT) :: y3 ! Output at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs + TYPE(SED_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: c ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'SED_Output_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) +IF (ALLOCATED(y_out%BladeRootMotion) .AND. ALLOCATED(y1%BladeRootMotion)) THEN + DO i1 = LBOUND(y_out%BladeRootMotion,1),UBOUND(y_out%BladeRootMotion,1) + CALL MeshExtrapInterp2(y1%BladeRootMotion(i1), y2%BladeRootMotion(i1), y3%BladeRootMotion(i1), tin, y_out%BladeRootMotion(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated + CALL MeshExtrapInterp2(y1%HubPtMotion, y2%HubPtMotion, y3%HubPtMotion, tin, y_out%HubPtMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp2(y1%NacelleMotion, y2%NacelleMotion, y3%NacelleMotion, tin, y_out%NacelleMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp2(y1%TowerLn2Mesh, y2%TowerLn2Mesh, y3%TowerLn2Mesh, tin, y_out%TowerLn2Mesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp2(y1%PlatformPtMesh, y2%PlatformPtMesh, y3%PlatformPtMesh, tin, y_out%PlatformPtMesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL Angles_ExtrapInterp( y1%LSSTipPxa, y2%LSSTipPxa, y3%LSSTipPxa, tin, y_out%LSSTipPxa, tin_out ) + b = (t(3)**2*(y1%RotSpeed - y2%RotSpeed) + t(2)**2*(-y1%RotSpeed + y3%RotSpeed))* scaleFactor + c = ( (t(2)-t(3))*y1%RotSpeed + t(3)*y2%RotSpeed - t(2)*y3%RotSpeed ) * scaleFactor + y_out%RotSpeed = y1%RotSpeed + b + c * t_out + b = (t(3)**2*(y1%HSS_Spd - y2%HSS_Spd) + t(2)**2*(-y1%HSS_Spd + y3%HSS_Spd))* scaleFactor + c = ( (t(2)-t(3))*y1%HSS_Spd + t(3)*y2%HSS_Spd - t(2)*y3%HSS_Spd ) * scaleFactor + y_out%HSS_Spd = y1%HSS_Spd + b + c * t_out +IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) + b = (t(3)**2*(y1%WriteOutput(i1) - y2%WriteOutput(i1)) + t(2)**2*(-y1%WriteOutput(i1) + y3%WriteOutput(i1)))* scaleFactor + c = ( (t(2)-t(3))*y1%WriteOutput(i1) + t(3)*y2%WriteOutput(i1) - t(2)*y3%WriteOutput(i1) ) * scaleFactor + y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b + c * t_out + END DO +END IF ! check if allocated + END SUBROUTINE SED_Output_ExtrapInterp2 + +END MODULE SED_Types +!ENDOFREGISTRYGENERATEDFILE From 9efed89eda3c0f9a622cba63581dd5da757af630 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 14 Feb 2022 13:18:46 -0700 Subject: [PATCH 017/130] ADsk: rough in some docs on input file --- docs/source/user/aerodisk/index.rst | 15 ++++++ docs/source/user/aerodisk/input_files.rst | 66 +++++++++++++++++++++++ docs/source/user/aerodisk/zrefs.rst | 11 ++++ docs/source/user/index.rst | 1 + 4 files changed, 93 insertions(+) create mode 100644 docs/source/user/aerodisk/index.rst create mode 100644 docs/source/user/aerodisk/input_files.rst create mode 100644 docs/source/user/aerodisk/zrefs.rst diff --git a/docs/source/user/aerodisk/index.rst b/docs/source/user/aerodisk/index.rst new file mode 100644 index 0000000000..8c7c65706a --- /dev/null +++ b/docs/source/user/aerodisk/index.rst @@ -0,0 +1,15 @@ +AeroDisk +======== + + +This document describes the AeroDisk (ADsk) module. + + +.. only:: html + + +.. toctree:: + :maxdepth: 2 + + input_files.rst + zrefs.rst diff --git a/docs/source/user/aerodisk/input_files.rst b/docs/source/user/aerodisk/input_files.rst new file mode 100644 index 0000000000..d50cac0983 --- /dev/null +++ b/docs/source/user/aerodisk/input_files.rst @@ -0,0 +1,66 @@ +.. _adsk_input-files: + +Input and Output Files +====================== + + +Units +----- + +AeroDisk uses the SI system (kg, m, s, N). + +.. _adsk_input-file: + +Input file +---------- + + +.. code:: + + --- AERO DISK INPUT FILE ------- + Sample actuator disk input file + --- ENVIRONMENTAL CONDITIONS --- + 1.225 AirDens - Air density (kg/m^3) (or "default") + --- ACTUATOR DISK PROPERTIES --- + 63.0 RotRad - Rotor radius (m) (or "default") + "RtSpd,VRel,Skew,Pitch" InColNames - Input column headers (string) {may include a combination of "TSR, RtSpd, VRel, Pitch, Skew"} (up to 4 columns) [choose TSR or RtSpd,VRel; if Skew is absent, Skew is modeled as (COS(Skew))^2] + 9,1,1,1 InColDims - Number of values in each column (-) (must have same number of columns as InColName) [each >=2] + RtSpd VRel Skew Pitch C_Fx C_Fy C_Fz C_Mx C_My C_Mz + (rpm) (m/s) (deg) (deg) (-) (-) (-) (-) (-) (-) + -20.0 0.0 0.0 0.0 + -15.0 0.0 0.0 0.0 + -10.0 0.0 0.0 0.0 + -5.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 + 5.0 0.0 0.0 0.0 + 10.0 0.0 0.0 0.0 + 15.0 0.0 0.0 0.0 + 20.0 0.0 0.0 0.0 + --- OUTPUTS -------------------- + OutList - The next line(s) contains a list of output parameters. See OutListParameters.xlsx for a listing of available output channels, (-) + END of input file (the word "END" must appear in the first 3 columns of this last OutList line) + -------------------------------- + + + + + + +.. _adsk_outputs: + +Outputs +------- + +The write outputs are: + - "ADSpeed": Actuator disk rotational speed (rpm) + - "ADTSR": Actuator disk tip-speed ratio (-) + - "ADPitch": Actuator-disk collective blade-pitch angle (deg) + - "ADVWindx, ADVWindy, ADVWindz": Actuator-disk-averaged wind velocity in the local coordinate system (m/s) + - "ADSTVx, ADSTVy, ADSTVz": Actuator-disk structural translational velocity in the local coordinate system (m/s) + - "ADVRel": Actuator-disk-averaged relative wind speed (m/s) + - "ADSkew": Actuator-disk inflow-skew angle (deg) + - "ADCp, ADCt, ADCq": Actuator-disk power, thrust, and torque coefficients (-) + - "ADFx, ADFy, ADFz": Actuator disk aerodynamic force loads in the local coordinate system (N) + - "ADMx, ADMy, ADMz": Actuator disk aerodynamic moment loads in the local coordinate system (N-m) + - "ADPower": Actuator disk power (W) + diff --git a/docs/source/user/aerodisk/zrefs.rst b/docs/source/user/aerodisk/zrefs.rst new file mode 100644 index 0000000000..6606cb7ce6 --- /dev/null +++ b/docs/source/user/aerodisk/zrefs.rst @@ -0,0 +1,11 @@ +.. only:: html + + References + ---------- + +.. bibliography:: bibliography.bib + :labelprefix: adsk- + :keyprefix: adsk- + + + diff --git a/docs/source/user/index.rst b/docs/source/user/index.rst index 2bcb4b6a1c..ee9cc84f75 100644 --- a/docs/source/user/index.rst +++ b/docs/source/user/index.rst @@ -45,6 +45,7 @@ Documentation covers usage of models, underlying theory, and in some cases modul AeroDyn OLAF Aeroacoustics + AeroDisk BeamDyn SubDyn ExtPtfm From 2a4df4465de7223c47e2f5ae0340b70721661be9 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 14 Feb 2022 14:37:05 -0700 Subject: [PATCH 018/130] ADsk: add registry and update cmake --- CMakeLists.txt | 1 + modules/aerodisk/CMakeLists.txt | 34 + modules/aerodisk/src/AeroDisk_Registry.txt | 119 + modules/aerodisk/src/AeroDisk_Types.f90 | 4190 ++++++++++++++++++++ 4 files changed, 4344 insertions(+) create mode 100644 modules/aerodisk/CMakeLists.txt create mode 100644 modules/aerodisk/src/AeroDisk_Registry.txt create mode 100644 modules/aerodisk/src/AeroDisk_Types.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 320a71debe..9cec484e8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,6 +143,7 @@ set(OPENFAST_MODULES wakedynamics awae simple-elastodyn + aerodisk ) set(OPENFAST_REGISTRY_INCLUDES "" CACHE INTERNAL "Registry includes paths") diff --git a/modules/aerodisk/CMakeLists.txt b/modules/aerodisk/CMakeLists.txt new file mode 100644 index 0000000000..b5c444717b --- /dev/null +++ b/modules/aerodisk/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2016 National Renewable Energy Laboratory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if (GENERATE_TYPES) + generate_f90_types(src/AeroDisk_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/AeroDisk_Types.f90) +endif() + +set(ADSK_SOURCES + src/AeroDisk_Types.f90 + ) + #src/AeroDisk.f90 + #src/AeroDisk_IO.f90 + +add_library(aerodisklib ${ADSK_SOURCES}) +target_link_libraries(aerodisklib nwtclibs) + +install(TARGETS aerodisklib + EXPORT "${CMAKE_PROJECT_NAME}Libraries" + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) diff --git a/modules/aerodisk/src/AeroDisk_Registry.txt b/modules/aerodisk/src/AeroDisk_Registry.txt new file mode 100644 index 0000000000..ae02501bd4 --- /dev/null +++ b/modules/aerodisk/src/AeroDisk_Registry.txt @@ -0,0 +1,119 @@ +################################################################################################################################### +# Registry for Simplified ElastoDyn in the FAST Modularization Framework +# This Registry file is used to create MODULE ADsk_Types which contains all of the user-defined types needed in Simplified ElastoDyn. +# It also contains copy, destroy, pack, and unpack routines associated with each defined data types. +# See the NWTC Programmer's Handbook for further information on the format/contents of this file. +# +# Entries are of the form +# +# +# Use ^ as a shortcut for the value in the same column from the previous line. +################################################################################################################################### +# ...... Include files (definitions from NWTC Library) ............................................................................ +include Registry_NWTC_Library.txt + + +# ..... Initialization data ....................................................................................................... +# ADsk input file +typedef AeroDisk/ADsk ADsk_InputFile LOGICAL EchoFlag - - - "Echo the input file" - +typedef ^ ADsk_InputFile R8Ki DeltaT - - - "Time step for module time integration" s +typedef ^ ADsk_InputFile LOGICAL SumPrint - - - "Print summary data to .sum" - +typedef ^ ADsk_InputFile CHARACTER(ChanLen) OutList : - - "List of user-requested output channels" - +typedef ^ ADsk_InputFile IntKi N_RtSpd - - - "Number of rotor speeds in tables" - +typedef ^ ADsk_InputFile IntKi N_VRel - - - "Number of rotor inflow wind speeds in tables" - +typedef ^ ADsk_InputFile IntKi N_Pitch - - - "Number of rotor-collective blade-pitch angles in tables" - +typedef ^ ADsk_InputFile IntKi N_Skew - - - "Number of rotor inflow-skew angles in tables" - +typedef ^ ADsk_InputFile ReKi TSR {:} - - "Rotor TSR values in tables" - +typedef ^ ADsk_InputFile ReKi RtSpd {:} - - "Rotor speed values in tables" rad/s +typedef ^ ADsk_InputFile ReKi VRel {:} - - "Rotor inflow wind speeds tables" m/s +typedef ^ ADsk_InputFile ReKi Pitch {:} - - "Rotor-collective blade-pitch anges in tables" rad +typedef ^ ADsk_InputFile ReKi Skew {:} - - "Rotor inflow-skew values in tables" rad +typedef ^ ADsk_InputFile ReKi C_fx {:}{:}{:}{:} - - "Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_InputFile ReKi C_fy {:}{:}{:}{:} - - "Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_InputFile ReKi C_fz {:}{:}{:}{:} - - "Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_InputFile ReKi C_mx {:}{:}{:}{:} - - "Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_InputFile ReKi C_my {:}{:}{:}{:} - - "Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_InputFile ReKi C_mz {:}{:}{:}{:} - - "Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - + + + +# ..... Initialization data ....................................................................................................... +# inputs for initialization: +typedef ^ InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - +typedef ^ InitInputType CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ InitInputType ReKi RotorRad - - - "Rotor radius" m +typedef ^ InitInputType ReKi HubPosition {3} - - "Hub position -- center of rotor" m +typedef ^ InitInputType R8Ki HubOrientation {3}{3} - - "Hub orientation" - +typedef ^ InitInputType ReKi defPatm - - - "Default atmospheric pressure from the driver; may be overwritten" Pa + + +# outputs from initialization: +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputUnt {:} - - "Units of the output-to-file channels" - +typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - + + +# ..... Inputs .................................................................................................................... +# inputs on meshes: NONE +# inputs not on meshes: +typedef ^ InputType MeshType HubMotion - - - "Hub motion" - +typedef ^ InputType ReKi RotSpeed - - - "Rotor speed" "rad/s" +typedef ^ InputType ReKi BlPitch - - 2pi "blade pitch" "rad" +typedef ^ InputType ReKi VWind {3} - - "Rotor average wind speed" "m/s" + + + +# ..... Outputs ................................................................................................................... +# outputs on meshes: +typedef ^ OutputType MeshType AeroLoads - - - "Mesh containing the forces and moments from the aero loading" - +#TODO: any mesh for visualization of blades/rotor disk? +# outputs not on meshes: +typedef ^ OutputType ReKi YawErr - - - "Nacelle-yaw error, i.e., the angle about positive Z from the rotor centerline to the rotor-disk-averaged relative wind velocity (ambient + rotor motion), both projected onto the horizontal plane" rad +typedef ^ OutputType ReKi SkewAngle - - - "Azimuth angle (from the nominally vertical axis in the disk plane, Z_disk ) to the vector about which the inflow skew angle is defined, i.e., the angle about positive X_disk from Z_disk to the vector about which the positive inflow skew angle is defined " rad +typedef ^ OutputType ReKi ChiSkew - - - "Inflow skew angle" rad +typedef ^ OutputType ReKi VRel - - - "Rotor-disk-averaged relative wind speed (ambient + rotor motion), normal to disk" m/s +typedef ^ OutputType ReKi Ct - - - "Thrust force coefficient (normal to disk)" - +typedef ^ OutputType ReKi Cq - - - "Torque coefficient (normal to disk)" - +typedef ^ OutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" + + +# ..... States .................................................................................................................... +# continuous (differentiable) states: +typedef ^ ContinuousStateType ReKi DummyContState - - - "" - + +# Define discrete (nondifferentiable) states here: +typedef ^ DiscreteStateType ReKi DummyDiscreteState - - - "" - + +# Define constraint states here: +typedef ^ ConstraintStateType ReKi DummyConstrState - - - "" - + +# any other states +typedef ^ OtherStateType IntKi DummyOtherState - - - "" - + + +# ..... Parameters................................................................................................................. +# unchanging parameters: +typedef ^ ParameterType DbKi DeltaT - - - "Time step for module time integration" s +typedef ^ ParameterType ReKi RotorRad - - - "Rotor radius" m +typedef ^ ParameterType ReKi halfRhoA - - - "half air density times rotor swept area" "kg/m" +typedef ^ ParameterType IntKi N_TSR - - - "Number of rotor tip-speed ratios in tables" - +typedef ^ ParameterType IntKi N_RtSpd - - - "Number of rotor speeds in tables" - +typedef ^ ParameterType IntKi N_VRel - - - "Number of rotor inflow wind speeds in tables" - +typedef ^ ParameterType IntKi N_Pitch - - - "Number of rotor-collective blade-pitch angles in tables" - +typedef ^ ParameterType IntKi N_Skew - - - "Number of rotor inflow-skew angles in tables" - +typedef ^ ParameterType ReKi TSR {:} - - "Rotor TSR values in tables" - +typedef ^ ParameterType ReKi RtSpd {:} - - "Rotor speed values in tables" rad/s +typedef ^ ParameterType ReKi VRel {:} - - "Rotor inflow wind speeds tables" m/s +typedef ^ ParameterType ReKi Pitch {:} - - "Rotor-collective blade-pitch anges in tables" rad +typedef ^ ParameterType ReKi Skew {:} - - "Rotor inflow-skew values in tables" rad +typedef ^ ParameterType ReKi C_fx {:}{:}{:}{:} - - "Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ParameterType ReKi C_fy {:}{:}{:}{:} - - "Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ParameterType ReKi C_fz {:}{:}{:}{:} - - "Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ParameterType ReKi C_mx {:}{:}{:}{:} - - "Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ParameterType ReKi C_my {:}{:}{:}{:} - - "Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ParameterType ReKi C_mz {:}{:}{:}{:} - - "Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - + + +# ..... Misc/Optimization variables................................................................................................. +typedef ^ MiscVarType IntKi DummyMiscVar - - - "" - + diff --git a/modules/aerodisk/src/AeroDisk_Types.f90 b/modules/aerodisk/src/AeroDisk_Types.f90 new file mode 100644 index 0000000000..81eb3144b4 --- /dev/null +++ b/modules/aerodisk/src/AeroDisk_Types.f90 @@ -0,0 +1,4190 @@ +!STARTOFREGISTRYGENERATEDFILE 'AeroDisk_Types.f90' +! +! WARNING This file is generated automatically by the FAST registry. +! Do not edit. Your changes to this file will be lost. +! +! FAST Registry +!********************************************************************************************************************************* +! AeroDisk_Types +!................................................................................................................................. +! This file is part of AeroDisk. +! +! Copyright (C) 2012-2016 National Renewable Energy Laboratory +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +! +! W A R N I N G : This file was automatically generated from the FAST registry. Changes made to this file may be lost. +! +!********************************************************************************************************************************* +!> This module contains the user-defined types needed in AeroDisk. It also contains copy, destroy, pack, and +!! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. +MODULE AeroDisk_Types +!--------------------------------------------------------------------------------------------------------------------------------- +USE NWTC_Library +IMPLICIT NONE +! ========= ADsk_InputFile ======= + TYPE, PUBLIC :: ADsk_InputFile + LOGICAL :: EchoFlag !< Echo the input file [-] + REAL(R8Ki) :: DeltaT !< Time step for module time integration [s] + LOGICAL :: SumPrint !< Print summary data to .sum [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< List of user-requested output channels [-] + INTEGER(IntKi) :: N_RtSpd !< Number of rotor speeds in tables [-] + INTEGER(IntKi) :: N_VRel !< Number of rotor inflow wind speeds in tables [-] + INTEGER(IntKi) :: N_Pitch !< Number of rotor-collective blade-pitch angles in tables [-] + INTEGER(IntKi) :: N_Skew !< Number of rotor inflow-skew angles in tables [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TSR !< Rotor TSR values in tables [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RtSpd !< Rotor speed values in tables [rad/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: VRel !< Rotor inflow wind speeds tables [m/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Rotor-collective blade-pitch anges in tables [rad] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Skew !< Rotor inflow-skew values in tables [rad] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fx !< Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fy !< Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fz !< Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mx !< Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_my !< Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mz !< Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + END TYPE ADsk_InputFile +! ======================= +! ========= ADsk_InitInputType ======= + TYPE, PUBLIC :: ADsk_InitInputType + CHARACTER(1024) :: InputFile !< Name of the input file [-] + CHARACTER(1024) :: RootName !< RootName for writing output files [-] + REAL(ReKi) :: RotorRad !< Rotor radius [m] + REAL(ReKi) , DIMENSION(1:3) :: HubPosition !< Hub position -- center of rotor [m] + REAL(R8Ki) , DIMENSION(1:3,1:3) :: HubOrientation !< Hub orientation [-] + REAL(ReKi) :: defPatm !< Default atmospheric pressure from the driver; may be overwritten [Pa] + END TYPE ADsk_InitInputType +! ======================= +! ========= ADsk_InitOutputType ======= + TYPE, PUBLIC :: ADsk_InitOutputType + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Names of the output-to-file channels [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Units of the output-to-file channels [-] + TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] + END TYPE ADsk_InitOutputType +! ======================= +! ========= ADsk_InputType ======= + TYPE, PUBLIC :: ADsk_InputType + TYPE(MeshType) :: HubMotion !< Hub motion [-] + REAL(ReKi) :: RotSpeed !< Rotor speed [rad/s] + REAL(ReKi) :: BlPitch !< blade pitch [rad] + REAL(ReKi) , DIMENSION(1:3) :: VWind !< Rotor average wind speed [m/s] + END TYPE ADsk_InputType +! ======================= +! ========= ADsk_OutputType ======= + TYPE, PUBLIC :: ADsk_OutputType + TYPE(MeshType) :: AeroLoads !< Mesh containing the forces and moments from the aero loading [-] + REAL(ReKi) :: YawErr !< Nacelle-yaw error, i.e., the angle about positive Z from the rotor centerline to the rotor-disk-averaged relative wind velocity (ambient + rotor motion), both projected onto the horizontal plane [rad] + REAL(ReKi) :: SkewAngle !< Azimuth angle (from the nominally vertical axis in the disk plane, Z_disk ) to the vector about which the inflow skew angle is defined, i.e., the angle about positive X_disk from Z_disk to the vector about which the positive inflow skew angle is defined [rad] + REAL(ReKi) :: ChiSkew !< Inflow skew angle [rad] + REAL(ReKi) :: VRel !< Rotor-disk-averaged relative wind speed (ambient + rotor motion), normal to disk [m/s] + REAL(ReKi) :: Ct !< Thrust force coefficient (normal to disk) [-] + REAL(ReKi) :: Cq !< Torque coefficient (normal to disk) [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< Data to be written to an output file: see WriteOutputHdr for names of each variable [see WriteOutputUnt] + END TYPE ADsk_OutputType +! ======================= +! ========= ADsk_ContinuousStateType ======= + TYPE, PUBLIC :: ADsk_ContinuousStateType + REAL(ReKi) :: DummyContState !< [-] + END TYPE ADsk_ContinuousStateType +! ======================= +! ========= ADsk_DiscreteStateType ======= + TYPE, PUBLIC :: ADsk_DiscreteStateType + REAL(ReKi) :: DummyDiscreteState !< [-] + END TYPE ADsk_DiscreteStateType +! ======================= +! ========= ADsk_ConstraintStateType ======= + TYPE, PUBLIC :: ADsk_ConstraintStateType + REAL(ReKi) :: DummyConstrState !< [-] + END TYPE ADsk_ConstraintStateType +! ======================= +! ========= ADsk_OtherStateType ======= + TYPE, PUBLIC :: ADsk_OtherStateType + INTEGER(IntKi) :: DummyOtherState !< [-] + END TYPE ADsk_OtherStateType +! ======================= +! ========= ADsk_ParameterType ======= + TYPE, PUBLIC :: ADsk_ParameterType + REAL(DbKi) :: DeltaT !< Time step for module time integration [s] + REAL(ReKi) :: RotorRad !< Rotor radius [m] + REAL(ReKi) :: halfRhoA !< half air density times rotor swept area [kg/m] + INTEGER(IntKi) :: N_TSR !< Number of rotor tip-speed ratios in tables [-] + INTEGER(IntKi) :: N_RtSpd !< Number of rotor speeds in tables [-] + INTEGER(IntKi) :: N_VRel !< Number of rotor inflow wind speeds in tables [-] + INTEGER(IntKi) :: N_Pitch !< Number of rotor-collective blade-pitch angles in tables [-] + INTEGER(IntKi) :: N_Skew !< Number of rotor inflow-skew angles in tables [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TSR !< Rotor TSR values in tables [-] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RtSpd !< Rotor speed values in tables [rad/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: VRel !< Rotor inflow wind speeds tables [m/s] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Rotor-collective blade-pitch anges in tables [rad] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Skew !< Rotor inflow-skew values in tables [rad] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fx !< Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fy !< Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fz !< Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mx !< Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_my !< Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mz !< Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + END TYPE ADsk_ParameterType +! ======================= +! ========= ADsk_MiscVarType ======= + TYPE, PUBLIC :: ADsk_MiscVarType + INTEGER(IntKi) :: DummyMiscVar !< [-] + END TYPE ADsk_MiscVarType +! ======================= +CONTAINS + SUBROUTINE ADsk_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InputFile), INTENT(IN) :: SrcInputFileData + TYPE(ADsk_InputFile), INTENT(INOUT) :: DstInputFileData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInputFile' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInputFileData%EchoFlag = SrcInputFileData%EchoFlag + DstInputFileData%DeltaT = SrcInputFileData%DeltaT + DstInputFileData%SumPrint = SrcInputFileData%SumPrint +IF (ALLOCATED(SrcInputFileData%OutList)) THEN + i1_l = LBOUND(SrcInputFileData%OutList,1) + i1_u = UBOUND(SrcInputFileData%OutList,1) + IF (.NOT. ALLOCATED(DstInputFileData%OutList)) THEN + ALLOCATE(DstInputFileData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%OutList = SrcInputFileData%OutList +ENDIF + DstInputFileData%N_RtSpd = SrcInputFileData%N_RtSpd + DstInputFileData%N_VRel = SrcInputFileData%N_VRel + DstInputFileData%N_Pitch = SrcInputFileData%N_Pitch + DstInputFileData%N_Skew = SrcInputFileData%N_Skew +IF (ALLOCATED(SrcInputFileData%TSR)) THEN + i1_l = LBOUND(SrcInputFileData%TSR,1) + i1_u = UBOUND(SrcInputFileData%TSR,1) + IF (.NOT. ALLOCATED(DstInputFileData%TSR)) THEN + ALLOCATE(DstInputFileData%TSR(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%TSR.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%TSR = SrcInputFileData%TSR +ENDIF +IF (ALLOCATED(SrcInputFileData%RtSpd)) THEN + i1_l = LBOUND(SrcInputFileData%RtSpd,1) + i1_u = UBOUND(SrcInputFileData%RtSpd,1) + IF (.NOT. ALLOCATED(DstInputFileData%RtSpd)) THEN + ALLOCATE(DstInputFileData%RtSpd(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%RtSpd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%RtSpd = SrcInputFileData%RtSpd +ENDIF +IF (ALLOCATED(SrcInputFileData%VRel)) THEN + i1_l = LBOUND(SrcInputFileData%VRel,1) + i1_u = UBOUND(SrcInputFileData%VRel,1) + IF (.NOT. ALLOCATED(DstInputFileData%VRel)) THEN + ALLOCATE(DstInputFileData%VRel(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%VRel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%VRel = SrcInputFileData%VRel +ENDIF +IF (ALLOCATED(SrcInputFileData%Pitch)) THEN + i1_l = LBOUND(SrcInputFileData%Pitch,1) + i1_u = UBOUND(SrcInputFileData%Pitch,1) + IF (.NOT. ALLOCATED(DstInputFileData%Pitch)) THEN + ALLOCATE(DstInputFileData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%Pitch = SrcInputFileData%Pitch +ENDIF +IF (ALLOCATED(SrcInputFileData%Skew)) THEN + i1_l = LBOUND(SrcInputFileData%Skew,1) + i1_u = UBOUND(SrcInputFileData%Skew,1) + IF (.NOT. ALLOCATED(DstInputFileData%Skew)) THEN + ALLOCATE(DstInputFileData%Skew(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%Skew.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%Skew = SrcInputFileData%Skew +ENDIF +IF (ALLOCATED(SrcInputFileData%C_fx)) THEN + i1_l = LBOUND(SrcInputFileData%C_fx,1) + i1_u = UBOUND(SrcInputFileData%C_fx,1) + i2_l = LBOUND(SrcInputFileData%C_fx,2) + i2_u = UBOUND(SrcInputFileData%C_fx,2) + i3_l = LBOUND(SrcInputFileData%C_fx,3) + i3_u = UBOUND(SrcInputFileData%C_fx,3) + i4_l = LBOUND(SrcInputFileData%C_fx,4) + i4_u = UBOUND(SrcInputFileData%C_fx,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_fx)) THEN + ALLOCATE(DstInputFileData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_fx = SrcInputFileData%C_fx +ENDIF +IF (ALLOCATED(SrcInputFileData%C_fy)) THEN + i1_l = LBOUND(SrcInputFileData%C_fy,1) + i1_u = UBOUND(SrcInputFileData%C_fy,1) + i2_l = LBOUND(SrcInputFileData%C_fy,2) + i2_u = UBOUND(SrcInputFileData%C_fy,2) + i3_l = LBOUND(SrcInputFileData%C_fy,3) + i3_u = UBOUND(SrcInputFileData%C_fy,3) + i4_l = LBOUND(SrcInputFileData%C_fy,4) + i4_u = UBOUND(SrcInputFileData%C_fy,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_fy)) THEN + ALLOCATE(DstInputFileData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_fy = SrcInputFileData%C_fy +ENDIF +IF (ALLOCATED(SrcInputFileData%C_fz)) THEN + i1_l = LBOUND(SrcInputFileData%C_fz,1) + i1_u = UBOUND(SrcInputFileData%C_fz,1) + i2_l = LBOUND(SrcInputFileData%C_fz,2) + i2_u = UBOUND(SrcInputFileData%C_fz,2) + i3_l = LBOUND(SrcInputFileData%C_fz,3) + i3_u = UBOUND(SrcInputFileData%C_fz,3) + i4_l = LBOUND(SrcInputFileData%C_fz,4) + i4_u = UBOUND(SrcInputFileData%C_fz,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_fz)) THEN + ALLOCATE(DstInputFileData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_fz = SrcInputFileData%C_fz +ENDIF +IF (ALLOCATED(SrcInputFileData%C_mx)) THEN + i1_l = LBOUND(SrcInputFileData%C_mx,1) + i1_u = UBOUND(SrcInputFileData%C_mx,1) + i2_l = LBOUND(SrcInputFileData%C_mx,2) + i2_u = UBOUND(SrcInputFileData%C_mx,2) + i3_l = LBOUND(SrcInputFileData%C_mx,3) + i3_u = UBOUND(SrcInputFileData%C_mx,3) + i4_l = LBOUND(SrcInputFileData%C_mx,4) + i4_u = UBOUND(SrcInputFileData%C_mx,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_mx)) THEN + ALLOCATE(DstInputFileData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_mx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_mx = SrcInputFileData%C_mx +ENDIF +IF (ALLOCATED(SrcInputFileData%C_my)) THEN + i1_l = LBOUND(SrcInputFileData%C_my,1) + i1_u = UBOUND(SrcInputFileData%C_my,1) + i2_l = LBOUND(SrcInputFileData%C_my,2) + i2_u = UBOUND(SrcInputFileData%C_my,2) + i3_l = LBOUND(SrcInputFileData%C_my,3) + i3_u = UBOUND(SrcInputFileData%C_my,3) + i4_l = LBOUND(SrcInputFileData%C_my,4) + i4_u = UBOUND(SrcInputFileData%C_my,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_my)) THEN + ALLOCATE(DstInputFileData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_my.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_my = SrcInputFileData%C_my +ENDIF +IF (ALLOCATED(SrcInputFileData%C_mz)) THEN + i1_l = LBOUND(SrcInputFileData%C_mz,1) + i1_u = UBOUND(SrcInputFileData%C_mz,1) + i2_l = LBOUND(SrcInputFileData%C_mz,2) + i2_u = UBOUND(SrcInputFileData%C_mz,2) + i3_l = LBOUND(SrcInputFileData%C_mz,3) + i3_u = UBOUND(SrcInputFileData%C_mz,3) + i4_l = LBOUND(SrcInputFileData%C_mz,4) + i4_u = UBOUND(SrcInputFileData%C_mz,4) + IF (.NOT. ALLOCATED(DstInputFileData%C_mz)) THEN + ALLOCATE(DstInputFileData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_mz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%C_mz = SrcInputFileData%C_mz +ENDIF + END SUBROUTINE ADsk_CopyInputFile + + SUBROUTINE ADsk_DestroyInputFile( InputFileData, ErrStat, ErrMsg ) + TYPE(ADsk_InputFile), INTENT(INOUT) :: InputFileData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInputFile' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InputFileData%OutList)) THEN + DEALLOCATE(InputFileData%OutList) +ENDIF +IF (ALLOCATED(InputFileData%TSR)) THEN + DEALLOCATE(InputFileData%TSR) +ENDIF +IF (ALLOCATED(InputFileData%RtSpd)) THEN + DEALLOCATE(InputFileData%RtSpd) +ENDIF +IF (ALLOCATED(InputFileData%VRel)) THEN + DEALLOCATE(InputFileData%VRel) +ENDIF +IF (ALLOCATED(InputFileData%Pitch)) THEN + DEALLOCATE(InputFileData%Pitch) +ENDIF +IF (ALLOCATED(InputFileData%Skew)) THEN + DEALLOCATE(InputFileData%Skew) +ENDIF +IF (ALLOCATED(InputFileData%C_fx)) THEN + DEALLOCATE(InputFileData%C_fx) +ENDIF +IF (ALLOCATED(InputFileData%C_fy)) THEN + DEALLOCATE(InputFileData%C_fy) +ENDIF +IF (ALLOCATED(InputFileData%C_fz)) THEN + DEALLOCATE(InputFileData%C_fz) +ENDIF +IF (ALLOCATED(InputFileData%C_mx)) THEN + DEALLOCATE(InputFileData%C_mx) +ENDIF +IF (ALLOCATED(InputFileData%C_my)) THEN + DEALLOCATE(InputFileData%C_my) +ENDIF +IF (ALLOCATED(InputFileData%C_mz)) THEN + DEALLOCATE(InputFileData%C_mz) +ENDIF + END SUBROUTINE ADsk_DestroyInputFile + + SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_InputFile), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInputFile' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! EchoFlag + Db_BufSz = Db_BufSz + 1 ! DeltaT + Int_BufSz = Int_BufSz + 1 ! SumPrint + Int_BufSz = Int_BufSz + 1 ! OutList allocated yes/no + IF ( ALLOCATED(InData%OutList) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! OutList upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%OutList)*LEN(InData%OutList) ! OutList + END IF + Int_BufSz = Int_BufSz + 1 ! N_RtSpd + Int_BufSz = Int_BufSz + 1 ! N_VRel + Int_BufSz = Int_BufSz + 1 ! N_Pitch + Int_BufSz = Int_BufSz + 1 ! N_Skew + Int_BufSz = Int_BufSz + 1 ! TSR allocated yes/no + IF ( ALLOCATED(InData%TSR) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! TSR upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%TSR) ! TSR + END IF + Int_BufSz = Int_BufSz + 1 ! RtSpd allocated yes/no + IF ( ALLOCATED(InData%RtSpd) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! RtSpd upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%RtSpd) ! RtSpd + END IF + Int_BufSz = Int_BufSz + 1 ! VRel allocated yes/no + IF ( ALLOCATED(InData%VRel) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VRel upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%VRel) ! VRel + END IF + Int_BufSz = Int_BufSz + 1 ! Pitch allocated yes/no + IF ( ALLOCATED(InData%Pitch) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Pitch upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Pitch) ! Pitch + END IF + Int_BufSz = Int_BufSz + 1 ! Skew allocated yes/no + IF ( ALLOCATED(InData%Skew) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Skew upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Skew) ! Skew + END IF + Int_BufSz = Int_BufSz + 1 ! C_fx allocated yes/no + IF ( ALLOCATED(InData%C_fx) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fx) ! C_fx + END IF + Int_BufSz = Int_BufSz + 1 ! C_fy allocated yes/no + IF ( ALLOCATED(InData%C_fy) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fy upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fy) ! C_fy + END IF + Int_BufSz = Int_BufSz + 1 ! C_fz allocated yes/no + IF ( ALLOCATED(InData%C_fz) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fz) ! C_fz + END IF + Int_BufSz = Int_BufSz + 1 ! C_mx allocated yes/no + IF ( ALLOCATED(InData%C_mx) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_mx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_mx) ! C_mx + END IF + Int_BufSz = Int_BufSz + 1 ! C_my allocated yes/no + IF ( ALLOCATED(InData%C_my) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_my upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_my) ! C_my + END IF + Int_BufSz = Int_BufSz + 1 ! C_mz allocated yes/no + IF ( ALLOCATED(InData%C_mz) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_mz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_mz) ! C_mz + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = TRANSFER(InData%EchoFlag, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DeltaT + Db_Xferred = Db_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%SumPrint, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%OutList) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutList,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutList,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%OutList,1), UBOUND(InData%OutList,1) + DO I = 1, LEN(InData%OutList) + IntKiBuf(Int_Xferred) = ICHAR(InData%OutList(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IntKiBuf(Int_Xferred) = InData%N_RtSpd + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_VRel + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_Pitch + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_Skew + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%TSR) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%TSR,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TSR,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%TSR,1), UBOUND(InData%TSR,1) + ReKiBuf(Re_Xferred) = InData%TSR(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%RtSpd) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%RtSpd,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RtSpd,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%RtSpd,1), UBOUND(InData%RtSpd,1) + ReKiBuf(Re_Xferred) = InData%RtSpd(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%VRel) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%VRel,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VRel,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%VRel,1), UBOUND(InData%VRel,1) + ReKiBuf(Re_Xferred) = InData%VRel(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Pitch) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Pitch,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Pitch,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Pitch,1), UBOUND(InData%Pitch,1) + ReKiBuf(Re_Xferred) = InData%Pitch(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Skew) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Skew,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Skew,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Skew,1), UBOUND(InData%Skew,1) + ReKiBuf(Re_Xferred) = InData%Skew(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fx,4), UBOUND(InData%C_fx,4) + DO i3 = LBOUND(InData%C_fx,3), UBOUND(InData%C_fx,3) + DO i2 = LBOUND(InData%C_fx,2), UBOUND(InData%C_fx,2) + DO i1 = LBOUND(InData%C_fx,1), UBOUND(InData%C_fx,1) + ReKiBuf(Re_Xferred) = InData%C_fx(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fy) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fy,4), UBOUND(InData%C_fy,4) + DO i3 = LBOUND(InData%C_fy,3), UBOUND(InData%C_fy,3) + DO i2 = LBOUND(InData%C_fy,2), UBOUND(InData%C_fy,2) + DO i1 = LBOUND(InData%C_fy,1), UBOUND(InData%C_fy,1) + ReKiBuf(Re_Xferred) = InData%C_fy(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fz) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fz,4), UBOUND(InData%C_fz,4) + DO i3 = LBOUND(InData%C_fz,3), UBOUND(InData%C_fz,3) + DO i2 = LBOUND(InData%C_fz,2), UBOUND(InData%C_fz,2) + DO i1 = LBOUND(InData%C_fz,1), UBOUND(InData%C_fz,1) + ReKiBuf(Re_Xferred) = InData%C_fz(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_mx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_mx,4), UBOUND(InData%C_mx,4) + DO i3 = LBOUND(InData%C_mx,3), UBOUND(InData%C_mx,3) + DO i2 = LBOUND(InData%C_mx,2), UBOUND(InData%C_mx,2) + DO i1 = LBOUND(InData%C_mx,1), UBOUND(InData%C_mx,1) + ReKiBuf(Re_Xferred) = InData%C_mx(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_my) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_my,4), UBOUND(InData%C_my,4) + DO i3 = LBOUND(InData%C_my,3), UBOUND(InData%C_my,3) + DO i2 = LBOUND(InData%C_my,2), UBOUND(InData%C_my,2) + DO i1 = LBOUND(InData%C_my,1), UBOUND(InData%C_my,1) + ReKiBuf(Re_Xferred) = InData%C_my(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_mz) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_mz,4), UBOUND(InData%C_mz,4) + DO i3 = LBOUND(InData%C_mz,3), UBOUND(InData%C_mz,3) + DO i2 = LBOUND(InData%C_mz,2), UBOUND(InData%C_mz,2) + DO i1 = LBOUND(InData%C_mz,1), UBOUND(InData%C_mz,1) + ReKiBuf(Re_Xferred) = InData%C_mz(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE ADsk_PackInputFile + + SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_InputFile), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInputFile' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%EchoFlag = TRANSFER(IntKiBuf(Int_Xferred), OutData%EchoFlag) + Int_Xferred = Int_Xferred + 1 + OutData%DeltaT = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + OutData%SumPrint = TRANSFER(IntKiBuf(Int_Xferred), OutData%SumPrint) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutList not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%OutList)) DEALLOCATE(OutData%OutList) + ALLOCATE(OutData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%OutList,1), UBOUND(OutData%OutList,1) + DO I = 1, LEN(OutData%OutList) + OutData%OutList(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + OutData%N_RtSpd = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_VRel = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_Pitch = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_Skew = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TSR not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%TSR)) DEALLOCATE(OutData%TSR) + ALLOCATE(OutData%TSR(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%TSR.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%TSR,1), UBOUND(OutData%TSR,1) + OutData%TSR(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RtSpd not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%RtSpd)) DEALLOCATE(OutData%RtSpd) + ALLOCATE(OutData%RtSpd(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RtSpd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%RtSpd,1), UBOUND(OutData%RtSpd,1) + OutData%RtSpd(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VRel not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%VRel)) DEALLOCATE(OutData%VRel) + ALLOCATE(OutData%VRel(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VRel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VRel,1), UBOUND(OutData%VRel,1) + OutData%VRel(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Pitch not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Pitch)) DEALLOCATE(OutData%Pitch) + ALLOCATE(OutData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Pitch,1), UBOUND(OutData%Pitch,1) + OutData%Pitch(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Skew not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Skew)) DEALLOCATE(OutData%Skew) + ALLOCATE(OutData%Skew(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Skew.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Skew,1), UBOUND(OutData%Skew,1) + OutData%Skew(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fx)) DEALLOCATE(OutData%C_fx) + ALLOCATE(OutData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fx,4), UBOUND(OutData%C_fx,4) + DO i3 = LBOUND(OutData%C_fx,3), UBOUND(OutData%C_fx,3) + DO i2 = LBOUND(OutData%C_fx,2), UBOUND(OutData%C_fx,2) + DO i1 = LBOUND(OutData%C_fx,1), UBOUND(OutData%C_fx,1) + OutData%C_fx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fy not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fy)) DEALLOCATE(OutData%C_fy) + ALLOCATE(OutData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fy,4), UBOUND(OutData%C_fy,4) + DO i3 = LBOUND(OutData%C_fy,3), UBOUND(OutData%C_fy,3) + DO i2 = LBOUND(OutData%C_fy,2), UBOUND(OutData%C_fy,2) + DO i1 = LBOUND(OutData%C_fy,1), UBOUND(OutData%C_fy,1) + OutData%C_fy(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fz not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fz)) DEALLOCATE(OutData%C_fz) + ALLOCATE(OutData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fz,4), UBOUND(OutData%C_fz,4) + DO i3 = LBOUND(OutData%C_fz,3), UBOUND(OutData%C_fz,3) + DO i2 = LBOUND(OutData%C_fz,2), UBOUND(OutData%C_fz,2) + DO i1 = LBOUND(OutData%C_fz,1), UBOUND(OutData%C_fz,1) + OutData%C_fz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_mx)) DEALLOCATE(OutData%C_mx) + ALLOCATE(OutData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_mx,4), UBOUND(OutData%C_mx,4) + DO i3 = LBOUND(OutData%C_mx,3), UBOUND(OutData%C_mx,3) + DO i2 = LBOUND(OutData%C_mx,2), UBOUND(OutData%C_mx,2) + DO i1 = LBOUND(OutData%C_mx,1), UBOUND(OutData%C_mx,1) + OutData%C_mx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_my not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_my)) DEALLOCATE(OutData%C_my) + ALLOCATE(OutData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_my.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_my,4), UBOUND(OutData%C_my,4) + DO i3 = LBOUND(OutData%C_my,3), UBOUND(OutData%C_my,3) + DO i2 = LBOUND(OutData%C_my,2), UBOUND(OutData%C_my,2) + DO i1 = LBOUND(OutData%C_my,1), UBOUND(OutData%C_my,1) + OutData%C_my(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mz not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_mz)) DEALLOCATE(OutData%C_mz) + ALLOCATE(OutData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_mz,4), UBOUND(OutData%C_mz,4) + DO i3 = LBOUND(OutData%C_mz,3), UBOUND(OutData%C_mz,3) + DO i2 = LBOUND(OutData%C_mz,2), UBOUND(OutData%C_mz,2) + DO i1 = LBOUND(OutData%C_mz,1), UBOUND(OutData%C_mz,1) + OutData%C_mz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE ADsk_UnPackInputFile + + SUBROUTINE ADsk_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InitInputType), INTENT(IN) :: SrcInitInputData + TYPE(ADsk_InitInputType), INTENT(INOUT) :: DstInitInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitInput' +! + ErrStat = ErrID_None + ErrMsg = "" + DstInitInputData%InputFile = SrcInitInputData%InputFile + DstInitInputData%RootName = SrcInitInputData%RootName + DstInitInputData%RotorRad = SrcInitInputData%RotorRad + DstInitInputData%HubPosition = SrcInitInputData%HubPosition + DstInitInputData%HubOrientation = SrcInitInputData%HubOrientation + DstInitInputData%defPatm = SrcInitInputData%defPatm + END SUBROUTINE ADsk_CopyInitInput + + SUBROUTINE ADsk_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) + TYPE(ADsk_InitInputType), INTENT(INOUT) :: InitInputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyInitInput + + SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_InitInputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1*LEN(InData%InputFile) ! InputFile + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Re_BufSz = Re_BufSz + 1 ! RotorRad + Re_BufSz = Re_BufSz + SIZE(InData%HubPosition) ! HubPosition + Db_BufSz = Db_BufSz + SIZE(InData%HubOrientation) ! HubOrientation + Re_BufSz = Re_BufSz + 1 ! defPatm + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DO I = 1, LEN(InData%InputFile) + IntKiBuf(Int_Xferred) = ICHAR(InData%InputFile(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + ReKiBuf(Re_Xferred) = InData%RotorRad + Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%HubPosition,1), UBOUND(InData%HubPosition,1) + ReKiBuf(Re_Xferred) = InData%HubPosition(i1) + Re_Xferred = Re_Xferred + 1 + END DO + DO i2 = LBOUND(InData%HubOrientation,2), UBOUND(InData%HubOrientation,2) + DO i1 = LBOUND(InData%HubOrientation,1), UBOUND(InData%HubOrientation,1) + DbKiBuf(Db_Xferred) = InData%HubOrientation(i1,i2) + Db_Xferred = Db_Xferred + 1 + END DO + END DO + ReKiBuf(Re_Xferred) = InData%defPatm + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_PackInitInput + + SUBROUTINE ADsk_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_InitInputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitInput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + DO I = 1, LEN(OutData%InputFile) + OutData%InputFile(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%RootName) + OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + OutData%RotorRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%HubPosition,1) + i1_u = UBOUND(OutData%HubPosition,1) + DO i1 = LBOUND(OutData%HubPosition,1), UBOUND(OutData%HubPosition,1) + OutData%HubPosition(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + i1_l = LBOUND(OutData%HubOrientation,1) + i1_u = UBOUND(OutData%HubOrientation,1) + i2_l = LBOUND(OutData%HubOrientation,2) + i2_u = UBOUND(OutData%HubOrientation,2) + DO i2 = LBOUND(OutData%HubOrientation,2), UBOUND(OutData%HubOrientation,2) + DO i1 = LBOUND(OutData%HubOrientation,1), UBOUND(OutData%HubOrientation,1) + OutData%HubOrientation(i1,i2) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END DO + OutData%defPatm = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_UnPackInitInput + + SUBROUTINE ADsk_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InitOutputType), INTENT(IN) :: SrcInitOutputData + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: DstInitOutputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitOutput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcInitOutputData%WriteOutputHdr)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputHdr,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputHdr,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputHdr)) THEN + ALLOCATE(DstInitOutputData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputHdr = SrcInitOutputData%WriteOutputHdr +ENDIF +IF (ALLOCATED(SrcInitOutputData%WriteOutputUnt)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputUnt,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputUnt,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputUnt)) THEN + ALLOCATE(DstInitOutputData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputUnt = SrcInitOutputData%WriteOutputUnt +ENDIF + CALL NWTC_Library_Copyprogdesc( SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + END SUBROUTINE ADsk_CopyInitOutput + + SUBROUTINE ADsk_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: InitOutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(InitOutputData%WriteOutputHdr)) THEN + DEALLOCATE(InitOutputData%WriteOutputHdr) +ENDIF +IF (ALLOCATED(InitOutputData%WriteOutputUnt)) THEN + DEALLOCATE(InitOutputData%WriteOutputUnt) +ENDIF + CALL NWTC_Library_Destroyprogdesc( InitOutputData%Ver, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInitOutput + + SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_InitOutputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no + IF ( ALLOCATED(InData%WriteOutputHdr) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputHdr upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputHdr)*LEN(InData%WriteOutputHdr) ! WriteOutputHdr + END IF + Int_BufSz = Int_BufSz + 1 ! WriteOutputUnt allocated yes/no + IF ( ALLOCATED(InData%WriteOutputUnt) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputUnt upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputUnt)*LEN(InData%WriteOutputUnt) ! WriteOutputUnt + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! Ver: size of buffers for each call to pack subtype + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, .TRUE. ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! Ver + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! Ver + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! Ver + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%WriteOutputHdr) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputHdr,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputHdr,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputHdr,1), UBOUND(InData%WriteOutputHdr,1) + DO I = 1, LEN(InData%WriteOutputHdr) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputHdr(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( .NOT. ALLOCATED(InData%WriteOutputUnt) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputUnt,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputUnt,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputUnt,1), UBOUND(InData%WriteOutputUnt,1) + DO I = 1, LEN(InData%WriteOutputUnt) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputUnt(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, OnlySize ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END SUBROUTINE ADsk_PackInitOutput + + SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputHdr not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputHdr)) DEALLOCATE(OutData%WriteOutputHdr) + ALLOCATE(OutData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputHdr,1), UBOUND(OutData%WriteOutputHdr,1) + DO I = 1, LEN(OutData%WriteOutputHdr) + OutData%WriteOutputHdr(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputUnt not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputUnt)) DEALLOCATE(OutData%WriteOutputUnt) + ALLOCATE(OutData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputUnt,1), UBOUND(OutData%WriteOutputUnt,1) + DO I = 1, LEN(OutData%WriteOutputUnt) + OutData%WriteOutputUnt(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackprogdesc( Re_Buf, Db_Buf, Int_Buf, OutData%Ver, ErrStat2, ErrMsg2 ) ! Ver + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END SUBROUTINE ADsk_UnPackInitOutput + + SUBROUTINE ADsk_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InputType), INTENT(INOUT) :: SrcInputData + TYPE(ADsk_InputType), INTENT(INOUT) :: DstInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInput' +! + ErrStat = ErrID_None + ErrMsg = "" + CALL MeshCopy( SrcInputData%HubMotion, DstInputData%HubMotion, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstInputData%RotSpeed = SrcInputData%RotSpeed + DstInputData%BlPitch = SrcInputData%BlPitch + DstInputData%VWind = SrcInputData%VWind + END SUBROUTINE ADsk_CopyInput + + SUBROUTINE ADsk_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(ADsk_InputType), INTENT(INOUT) :: InputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + CALL MeshDestroy( InputData%HubMotion, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInput + + SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_InputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! HubMotion: size of buffers for each call to pack subtype + CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! HubMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! HubMotion + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! HubMotion + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! HubMotion + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Re_BufSz = Re_BufSz + 1 ! RotSpeed + Re_BufSz = Re_BufSz + 1 ! BlPitch + Re_BufSz = Re_BufSz + SIZE(InData%VWind) ! VWind + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! HubMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + ReKiBuf(Re_Xferred) = InData%RotSpeed + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%BlPitch + Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%VWind,1), UBOUND(InData%VWind,1) + ReKiBuf(Re_Xferred) = InData%VWind(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE ADsk_PackInput + + SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_InputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! HubMotion + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%RotSpeed = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%BlPitch = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%VWind,1) + i1_u = UBOUND(OutData%VWind,1) + DO i1 = LBOUND(OutData%VWind,1), UBOUND(OutData%VWind,1) + OutData%VWind(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE ADsk_UnPackInput + + SUBROUTINE ADsk_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_OutputType), INTENT(INOUT) :: SrcOutputData + TYPE(ADsk_OutputType), INTENT(INOUT) :: DstOutputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyOutput' +! + ErrStat = ErrID_None + ErrMsg = "" + CALL MeshCopy( SrcOutputData%AeroLoads, DstOutputData%AeroLoads, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstOutputData%YawErr = SrcOutputData%YawErr + DstOutputData%SkewAngle = SrcOutputData%SkewAngle + DstOutputData%ChiSkew = SrcOutputData%ChiSkew + DstOutputData%VRel = SrcOutputData%VRel + DstOutputData%Ct = SrcOutputData%Ct + DstOutputData%Cq = SrcOutputData%Cq +IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN + i1_l = LBOUND(SrcOutputData%WriteOutput,1) + i1_u = UBOUND(SrcOutputData%WriteOutput,1) + IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN + ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%WriteOutput = SrcOutputData%WriteOutput +ENDIF + END SUBROUTINE ADsk_CopyOutput + + SUBROUTINE ADsk_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(ADsk_OutputType), INTENT(INOUT) :: OutputData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyOutput' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + CALL MeshDestroy( OutputData%AeroLoads, ErrStat, ErrMsg ) +IF (ALLOCATED(OutputData%WriteOutput)) THEN + DEALLOCATE(OutputData%WriteOutput) +ENDIF + END SUBROUTINE ADsk_DestroyOutput + + SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_OutputType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackOutput' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! AeroLoads: size of buffers for each call to pack subtype + CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! AeroLoads + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! AeroLoads + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! AeroLoads + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Re_BufSz = Re_BufSz + 1 ! YawErr + Re_BufSz = Re_BufSz + 1 ! SkewAngle + Re_BufSz = Re_BufSz + 1 ! ChiSkew + Re_BufSz = Re_BufSz + 1 ! VRel + Re_BufSz = Re_BufSz + 1 ! Ct + Re_BufSz = Re_BufSz + 1 ! Cq + Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no + IF ( ALLOCATED(InData%WriteOutput) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + ReKiBuf(Re_Xferred) = InData%YawErr + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%SkewAngle + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%ChiSkew + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%VRel + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Ct + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Cq + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) + ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE ADsk_PackOutput + + SUBROUTINE ADsk_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%YawErr = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SkewAngle = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%ChiSkew = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%VRel = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Ct = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Cq = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) + ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) + OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE ADsk_UnPackOutput + + SUBROUTINE ADsk_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: DstContStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyContState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstContStateData%DummyContState = SrcContStateData%DummyContState + END SUBROUTINE ADsk_CopyContState + + SUBROUTINE ADsk_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: ContStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyContState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyContState + + SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_ContinuousStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackContState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyContState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyContState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_PackContState + + SUBROUTINE ADsk_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackContState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyContState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_UnPackContState + + SUBROUTINE ADsk_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyDiscState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstDiscStateData%DummyDiscreteState = SrcDiscStateData%DummyDiscreteState + END SUBROUTINE ADsk_CopyDiscState + + SUBROUTINE ADsk_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DiscStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyDiscState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyDiscState + + SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_DiscreteStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackDiscState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyDiscreteState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyDiscreteState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_PackDiscState + + SUBROUTINE ADsk_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackDiscState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyDiscreteState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_UnPackDiscState + + SUBROUTINE ADsk_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_ConstraintStateType), INTENT(IN) :: SrcConstrStateData + TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyConstrState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState + END SUBROUTINE ADsk_CopyConstrState + + SUBROUTINE ADsk_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) + TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyConstrState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyConstrState + + SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_ConstraintStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackConstrState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyConstrState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyConstrState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_PackConstrState + + SUBROUTINE ADsk_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackConstrState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyConstrState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_UnPackConstrState + + SUBROUTINE ADsk_CopyOtherState( SrcOtherStateData, DstOtherStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_OtherStateType), INTENT(IN) :: SrcOtherStateData + TYPE(ADsk_OtherStateType), INTENT(INOUT) :: DstOtherStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyOtherState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstOtherStateData%DummyOtherState = SrcOtherStateData%DummyOtherState + END SUBROUTINE ADsk_CopyOtherState + + SUBROUTINE ADsk_DestroyOtherState( OtherStateData, ErrStat, ErrMsg ) + TYPE(ADsk_OtherStateType), INTENT(INOUT) :: OtherStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyOtherState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyOtherState + + SUBROUTINE ADsk_PackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_OtherStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackOtherState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! DummyOtherState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = InData%DummyOtherState + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE ADsk_PackOtherState + + SUBROUTINE ADsk_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_OtherStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackOtherState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyOtherState = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE ADsk_UnPackOtherState + + SUBROUTINE ADsk_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_ParameterType), INTENT(IN) :: SrcParamData + TYPE(ADsk_ParameterType), INTENT(INOUT) :: DstParamData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyParam' +! + ErrStat = ErrID_None + ErrMsg = "" + DstParamData%DeltaT = SrcParamData%DeltaT + DstParamData%RotorRad = SrcParamData%RotorRad + DstParamData%halfRhoA = SrcParamData%halfRhoA + DstParamData%N_TSR = SrcParamData%N_TSR + DstParamData%N_RtSpd = SrcParamData%N_RtSpd + DstParamData%N_VRel = SrcParamData%N_VRel + DstParamData%N_Pitch = SrcParamData%N_Pitch + DstParamData%N_Skew = SrcParamData%N_Skew +IF (ALLOCATED(SrcParamData%TSR)) THEN + i1_l = LBOUND(SrcParamData%TSR,1) + i1_u = UBOUND(SrcParamData%TSR,1) + IF (.NOT. ALLOCATED(DstParamData%TSR)) THEN + ALLOCATE(DstParamData%TSR(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%TSR.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%TSR = SrcParamData%TSR +ENDIF +IF (ALLOCATED(SrcParamData%RtSpd)) THEN + i1_l = LBOUND(SrcParamData%RtSpd,1) + i1_u = UBOUND(SrcParamData%RtSpd,1) + IF (.NOT. ALLOCATED(DstParamData%RtSpd)) THEN + ALLOCATE(DstParamData%RtSpd(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%RtSpd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%RtSpd = SrcParamData%RtSpd +ENDIF +IF (ALLOCATED(SrcParamData%VRel)) THEN + i1_l = LBOUND(SrcParamData%VRel,1) + i1_u = UBOUND(SrcParamData%VRel,1) + IF (.NOT. ALLOCATED(DstParamData%VRel)) THEN + ALLOCATE(DstParamData%VRel(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%VRel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%VRel = SrcParamData%VRel +ENDIF +IF (ALLOCATED(SrcParamData%Pitch)) THEN + i1_l = LBOUND(SrcParamData%Pitch,1) + i1_u = UBOUND(SrcParamData%Pitch,1) + IF (.NOT. ALLOCATED(DstParamData%Pitch)) THEN + ALLOCATE(DstParamData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Pitch = SrcParamData%Pitch +ENDIF +IF (ALLOCATED(SrcParamData%Skew)) THEN + i1_l = LBOUND(SrcParamData%Skew,1) + i1_u = UBOUND(SrcParamData%Skew,1) + IF (.NOT. ALLOCATED(DstParamData%Skew)) THEN + ALLOCATE(DstParamData%Skew(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Skew.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%Skew = SrcParamData%Skew +ENDIF +IF (ALLOCATED(SrcParamData%C_fx)) THEN + i1_l = LBOUND(SrcParamData%C_fx,1) + i1_u = UBOUND(SrcParamData%C_fx,1) + i2_l = LBOUND(SrcParamData%C_fx,2) + i2_u = UBOUND(SrcParamData%C_fx,2) + i3_l = LBOUND(SrcParamData%C_fx,3) + i3_u = UBOUND(SrcParamData%C_fx,3) + i4_l = LBOUND(SrcParamData%C_fx,4) + i4_u = UBOUND(SrcParamData%C_fx,4) + IF (.NOT. ALLOCATED(DstParamData%C_fx)) THEN + ALLOCATE(DstParamData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_fx = SrcParamData%C_fx +ENDIF +IF (ALLOCATED(SrcParamData%C_fy)) THEN + i1_l = LBOUND(SrcParamData%C_fy,1) + i1_u = UBOUND(SrcParamData%C_fy,1) + i2_l = LBOUND(SrcParamData%C_fy,2) + i2_u = UBOUND(SrcParamData%C_fy,2) + i3_l = LBOUND(SrcParamData%C_fy,3) + i3_u = UBOUND(SrcParamData%C_fy,3) + i4_l = LBOUND(SrcParamData%C_fy,4) + i4_u = UBOUND(SrcParamData%C_fy,4) + IF (.NOT. ALLOCATED(DstParamData%C_fy)) THEN + ALLOCATE(DstParamData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_fy = SrcParamData%C_fy +ENDIF +IF (ALLOCATED(SrcParamData%C_fz)) THEN + i1_l = LBOUND(SrcParamData%C_fz,1) + i1_u = UBOUND(SrcParamData%C_fz,1) + i2_l = LBOUND(SrcParamData%C_fz,2) + i2_u = UBOUND(SrcParamData%C_fz,2) + i3_l = LBOUND(SrcParamData%C_fz,3) + i3_u = UBOUND(SrcParamData%C_fz,3) + i4_l = LBOUND(SrcParamData%C_fz,4) + i4_u = UBOUND(SrcParamData%C_fz,4) + IF (.NOT. ALLOCATED(DstParamData%C_fz)) THEN + ALLOCATE(DstParamData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_fz = SrcParamData%C_fz +ENDIF +IF (ALLOCATED(SrcParamData%C_mx)) THEN + i1_l = LBOUND(SrcParamData%C_mx,1) + i1_u = UBOUND(SrcParamData%C_mx,1) + i2_l = LBOUND(SrcParamData%C_mx,2) + i2_u = UBOUND(SrcParamData%C_mx,2) + i3_l = LBOUND(SrcParamData%C_mx,3) + i3_u = UBOUND(SrcParamData%C_mx,3) + i4_l = LBOUND(SrcParamData%C_mx,4) + i4_u = UBOUND(SrcParamData%C_mx,4) + IF (.NOT. ALLOCATED(DstParamData%C_mx)) THEN + ALLOCATE(DstParamData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_mx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_mx = SrcParamData%C_mx +ENDIF +IF (ALLOCATED(SrcParamData%C_my)) THEN + i1_l = LBOUND(SrcParamData%C_my,1) + i1_u = UBOUND(SrcParamData%C_my,1) + i2_l = LBOUND(SrcParamData%C_my,2) + i2_u = UBOUND(SrcParamData%C_my,2) + i3_l = LBOUND(SrcParamData%C_my,3) + i3_u = UBOUND(SrcParamData%C_my,3) + i4_l = LBOUND(SrcParamData%C_my,4) + i4_u = UBOUND(SrcParamData%C_my,4) + IF (.NOT. ALLOCATED(DstParamData%C_my)) THEN + ALLOCATE(DstParamData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_my.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_my = SrcParamData%C_my +ENDIF +IF (ALLOCATED(SrcParamData%C_mz)) THEN + i1_l = LBOUND(SrcParamData%C_mz,1) + i1_u = UBOUND(SrcParamData%C_mz,1) + i2_l = LBOUND(SrcParamData%C_mz,2) + i2_u = UBOUND(SrcParamData%C_mz,2) + i3_l = LBOUND(SrcParamData%C_mz,3) + i3_u = UBOUND(SrcParamData%C_mz,3) + i4_l = LBOUND(SrcParamData%C_mz,4) + i4_u = UBOUND(SrcParamData%C_mz,4) + IF (.NOT. ALLOCATED(DstParamData%C_mz)) THEN + ALLOCATE(DstParamData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_mz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstParamData%C_mz = SrcParamData%C_mz +ENDIF + END SUBROUTINE ADsk_CopyParam + + SUBROUTINE ADsk_DestroyParam( ParamData, ErrStat, ErrMsg ) + TYPE(ADsk_ParameterType), INTENT(INOUT) :: ParamData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyParam' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(ParamData%TSR)) THEN + DEALLOCATE(ParamData%TSR) +ENDIF +IF (ALLOCATED(ParamData%RtSpd)) THEN + DEALLOCATE(ParamData%RtSpd) +ENDIF +IF (ALLOCATED(ParamData%VRel)) THEN + DEALLOCATE(ParamData%VRel) +ENDIF +IF (ALLOCATED(ParamData%Pitch)) THEN + DEALLOCATE(ParamData%Pitch) +ENDIF +IF (ALLOCATED(ParamData%Skew)) THEN + DEALLOCATE(ParamData%Skew) +ENDIF +IF (ALLOCATED(ParamData%C_fx)) THEN + DEALLOCATE(ParamData%C_fx) +ENDIF +IF (ALLOCATED(ParamData%C_fy)) THEN + DEALLOCATE(ParamData%C_fy) +ENDIF +IF (ALLOCATED(ParamData%C_fz)) THEN + DEALLOCATE(ParamData%C_fz) +ENDIF +IF (ALLOCATED(ParamData%C_mx)) THEN + DEALLOCATE(ParamData%C_mx) +ENDIF +IF (ALLOCATED(ParamData%C_my)) THEN + DEALLOCATE(ParamData%C_my) +ENDIF +IF (ALLOCATED(ParamData%C_mz)) THEN + DEALLOCATE(ParamData%C_mz) +ENDIF + END SUBROUTINE ADsk_DestroyParam + + SUBROUTINE ADsk_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_ParameterType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackParam' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Db_BufSz = Db_BufSz + 1 ! DeltaT + Re_BufSz = Re_BufSz + 1 ! RotorRad + Re_BufSz = Re_BufSz + 1 ! halfRhoA + Int_BufSz = Int_BufSz + 1 ! N_TSR + Int_BufSz = Int_BufSz + 1 ! N_RtSpd + Int_BufSz = Int_BufSz + 1 ! N_VRel + Int_BufSz = Int_BufSz + 1 ! N_Pitch + Int_BufSz = Int_BufSz + 1 ! N_Skew + Int_BufSz = Int_BufSz + 1 ! TSR allocated yes/no + IF ( ALLOCATED(InData%TSR) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! TSR upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%TSR) ! TSR + END IF + Int_BufSz = Int_BufSz + 1 ! RtSpd allocated yes/no + IF ( ALLOCATED(InData%RtSpd) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! RtSpd upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%RtSpd) ! RtSpd + END IF + Int_BufSz = Int_BufSz + 1 ! VRel allocated yes/no + IF ( ALLOCATED(InData%VRel) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VRel upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%VRel) ! VRel + END IF + Int_BufSz = Int_BufSz + 1 ! Pitch allocated yes/no + IF ( ALLOCATED(InData%Pitch) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Pitch upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Pitch) ! Pitch + END IF + Int_BufSz = Int_BufSz + 1 ! Skew allocated yes/no + IF ( ALLOCATED(InData%Skew) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Skew upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Skew) ! Skew + END IF + Int_BufSz = Int_BufSz + 1 ! C_fx allocated yes/no + IF ( ALLOCATED(InData%C_fx) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fx) ! C_fx + END IF + Int_BufSz = Int_BufSz + 1 ! C_fy allocated yes/no + IF ( ALLOCATED(InData%C_fy) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fy upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fy) ! C_fy + END IF + Int_BufSz = Int_BufSz + 1 ! C_fz allocated yes/no + IF ( ALLOCATED(InData%C_fz) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_fz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_fz) ! C_fz + END IF + Int_BufSz = Int_BufSz + 1 ! C_mx allocated yes/no + IF ( ALLOCATED(InData%C_mx) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_mx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_mx) ! C_mx + END IF + Int_BufSz = Int_BufSz + 1 ! C_my allocated yes/no + IF ( ALLOCATED(InData%C_my) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_my upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_my) ! C_my + END IF + Int_BufSz = Int_BufSz + 1 ! C_mz allocated yes/no + IF ( ALLOCATED(InData%C_mz) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! C_mz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_mz) ! C_mz + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + DbKiBuf(Db_Xferred) = InData%DeltaT + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotorRad + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%halfRhoA + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_TSR + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_RtSpd + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_VRel + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_Pitch + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = InData%N_Skew + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%TSR) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%TSR,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TSR,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%TSR,1), UBOUND(InData%TSR,1) + ReKiBuf(Re_Xferred) = InData%TSR(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%RtSpd) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%RtSpd,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RtSpd,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%RtSpd,1), UBOUND(InData%RtSpd,1) + ReKiBuf(Re_Xferred) = InData%RtSpd(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%VRel) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%VRel,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VRel,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%VRel,1), UBOUND(InData%VRel,1) + ReKiBuf(Re_Xferred) = InData%VRel(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Pitch) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Pitch,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Pitch,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Pitch,1), UBOUND(InData%Pitch,1) + ReKiBuf(Re_Xferred) = InData%Pitch(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%Skew) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Skew,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Skew,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Skew,1), UBOUND(InData%Skew,1) + ReKiBuf(Re_Xferred) = InData%Skew(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fx,4), UBOUND(InData%C_fx,4) + DO i3 = LBOUND(InData%C_fx,3), UBOUND(InData%C_fx,3) + DO i2 = LBOUND(InData%C_fx,2), UBOUND(InData%C_fx,2) + DO i1 = LBOUND(InData%C_fx,1), UBOUND(InData%C_fx,1) + ReKiBuf(Re_Xferred) = InData%C_fx(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fy) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fy,4), UBOUND(InData%C_fy,4) + DO i3 = LBOUND(InData%C_fy,3), UBOUND(InData%C_fy,3) + DO i2 = LBOUND(InData%C_fy,2), UBOUND(InData%C_fy,2) + DO i1 = LBOUND(InData%C_fy,1), UBOUND(InData%C_fy,1) + ReKiBuf(Re_Xferred) = InData%C_fy(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_fz) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_fz,4), UBOUND(InData%C_fz,4) + DO i3 = LBOUND(InData%C_fz,3), UBOUND(InData%C_fz,3) + DO i2 = LBOUND(InData%C_fz,2), UBOUND(InData%C_fz,2) + DO i1 = LBOUND(InData%C_fz,1), UBOUND(InData%C_fz,1) + ReKiBuf(Re_Xferred) = InData%C_fz(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_mx) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_mx,4), UBOUND(InData%C_mx,4) + DO i3 = LBOUND(InData%C_mx,3), UBOUND(InData%C_mx,3) + DO i2 = LBOUND(InData%C_mx,2), UBOUND(InData%C_mx,2) + DO i1 = LBOUND(InData%C_mx,1), UBOUND(InData%C_mx,1) + ReKiBuf(Re_Xferred) = InData%C_mx(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_my) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_my,4), UBOUND(InData%C_my,4) + DO i3 = LBOUND(InData%C_my,3), UBOUND(InData%C_my,3) + DO i2 = LBOUND(InData%C_my,2), UBOUND(InData%C_my,2) + DO i1 = LBOUND(InData%C_my,1), UBOUND(InData%C_my,1) + ReKiBuf(Re_Xferred) = InData%C_my(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%C_mz) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%C_mz,4), UBOUND(InData%C_mz,4) + DO i3 = LBOUND(InData%C_mz,3), UBOUND(InData%C_mz,3) + DO i2 = LBOUND(InData%C_mz,2), UBOUND(InData%C_mz,2) + DO i1 = LBOUND(InData%C_mz,1), UBOUND(InData%C_mz,1) + ReKiBuf(Re_Xferred) = InData%C_mz(i1,i2,i3,i4) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE ADsk_PackParam + + SUBROUTINE ADsk_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_ParameterType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 + INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 + INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackParam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DeltaT = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 + OutData%RotorRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%halfRhoA = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%N_TSR = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_RtSpd = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_VRel = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_Pitch = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + OutData%N_Skew = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TSR not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%TSR)) DEALLOCATE(OutData%TSR) + ALLOCATE(OutData%TSR(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%TSR.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%TSR,1), UBOUND(OutData%TSR,1) + OutData%TSR(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RtSpd not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%RtSpd)) DEALLOCATE(OutData%RtSpd) + ALLOCATE(OutData%RtSpd(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RtSpd.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%RtSpd,1), UBOUND(OutData%RtSpd,1) + OutData%RtSpd(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VRel not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%VRel)) DEALLOCATE(OutData%VRel) + ALLOCATE(OutData%VRel(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VRel.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VRel,1), UBOUND(OutData%VRel,1) + OutData%VRel(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Pitch not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Pitch)) DEALLOCATE(OutData%Pitch) + ALLOCATE(OutData%Pitch(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Pitch.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Pitch,1), UBOUND(OutData%Pitch,1) + OutData%Pitch(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Skew not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Skew)) DEALLOCATE(OutData%Skew) + ALLOCATE(OutData%Skew(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Skew.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Skew,1), UBOUND(OutData%Skew,1) + OutData%Skew(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fx)) DEALLOCATE(OutData%C_fx) + ALLOCATE(OutData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fx,4), UBOUND(OutData%C_fx,4) + DO i3 = LBOUND(OutData%C_fx,3), UBOUND(OutData%C_fx,3) + DO i2 = LBOUND(OutData%C_fx,2), UBOUND(OutData%C_fx,2) + DO i1 = LBOUND(OutData%C_fx,1), UBOUND(OutData%C_fx,1) + OutData%C_fx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fy not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fy)) DEALLOCATE(OutData%C_fy) + ALLOCATE(OutData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fy.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fy,4), UBOUND(OutData%C_fy,4) + DO i3 = LBOUND(OutData%C_fy,3), UBOUND(OutData%C_fy,3) + DO i2 = LBOUND(OutData%C_fy,2), UBOUND(OutData%C_fy,2) + DO i1 = LBOUND(OutData%C_fy,1), UBOUND(OutData%C_fy,1) + OutData%C_fy(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fz not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_fz)) DEALLOCATE(OutData%C_fz) + ALLOCATE(OutData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_fz,4), UBOUND(OutData%C_fz,4) + DO i3 = LBOUND(OutData%C_fz,3), UBOUND(OutData%C_fz,3) + DO i2 = LBOUND(OutData%C_fz,2), UBOUND(OutData%C_fz,2) + DO i1 = LBOUND(OutData%C_fz,1), UBOUND(OutData%C_fz,1) + OutData%C_fz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mx not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_mx)) DEALLOCATE(OutData%C_mx) + ALLOCATE(OutData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mx.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_mx,4), UBOUND(OutData%C_mx,4) + DO i3 = LBOUND(OutData%C_mx,3), UBOUND(OutData%C_mx,3) + DO i2 = LBOUND(OutData%C_mx,2), UBOUND(OutData%C_mx,2) + DO i1 = LBOUND(OutData%C_mx,1), UBOUND(OutData%C_mx,1) + OutData%C_mx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_my not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_my)) DEALLOCATE(OutData%C_my) + ALLOCATE(OutData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_my.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_my,4), UBOUND(OutData%C_my,4) + DO i3 = LBOUND(OutData%C_my,3), UBOUND(OutData%C_my,3) + DO i2 = LBOUND(OutData%C_my,2), UBOUND(OutData%C_my,2) + DO i1 = LBOUND(OutData%C_my,1), UBOUND(OutData%C_my,1) + OutData%C_my(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mz not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_mz)) DEALLOCATE(OutData%C_mz) + ALLOCATE(OutData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mz.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%C_mz,4), UBOUND(OutData%C_mz,4) + DO i3 = LBOUND(OutData%C_mz,3), UBOUND(OutData%C_mz,3) + DO i2 = LBOUND(OutData%C_mz,2), UBOUND(OutData%C_mz,2) + DO i1 = LBOUND(OutData%C_mz,1), UBOUND(OutData%C_mz,1) + OutData%C_mz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO + END DO + END IF + END SUBROUTINE ADsk_UnPackParam + + SUBROUTINE ADsk_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(ADsk_MiscVarType), INTENT(INOUT) :: DstMiscData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyMisc' +! + ErrStat = ErrID_None + ErrMsg = "" + DstMiscData%DummyMiscVar = SrcMiscData%DummyMiscVar + END SUBROUTINE ADsk_CopyMisc + + SUBROUTINE ADsk_DestroyMisc( MiscData, ErrStat, ErrMsg ) + TYPE(ADsk_MiscVarType), INTENT(INOUT) :: MiscData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyMisc' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyMisc + + SUBROUTINE ADsk_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_MiscVarType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackMisc' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! DummyMiscVar + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IntKiBuf(Int_Xferred) = InData%DummyMiscVar + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE ADsk_PackMisc + + SUBROUTINE ADsk_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_MiscVarType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackMisc' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyMiscVar = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE ADsk_UnPackMisc + + + SUBROUTINE ADsk_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(ADsk_InputType), INTENT(INOUT) :: u(:) ! Input at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Inputs + TYPE(ADsk_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Input_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(u)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(u)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(u) - 1 + IF ( order .eq. 0 ) THEN + CALL ADsk_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL ADsk_Input_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL ADsk_Input_ExtrapInterp2(u(1), u(2), u(3), t, u_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(u) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE ADsk_Input_ExtrapInterp + + + SUBROUTINE ADsk_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = u1, f(t2) = u2 +! +!.................................................................................................................................. + + TYPE(ADsk_InputType), INTENT(INOUT) :: u1 ! Input at t1 > t2 + TYPE(ADsk_InputType), INTENT(INOUT) :: u2 ! Input at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs + TYPE(ADsk_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Input_ExtrapInterp1' + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / t(2) + CALL MeshExtrapInterp1(u1%HubMotion, u2%HubMotion, tin, u_out%HubMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + b = -(u1%RotSpeed - u2%RotSpeed) + u_out%RotSpeed = u1%RotSpeed + b * ScaleFactor + CALL Angles_ExtrapInterp( u1%BlPitch, u2%BlPitch, tin, u_out%BlPitch, tin_out ) + DO i1 = LBOUND(u_out%VWind,1),UBOUND(u_out%VWind,1) + b = -(u1%VWind(i1) - u2%VWind(i1)) + u_out%VWind(i1) = u1%VWind(i1) + b * ScaleFactor + END DO + END SUBROUTINE ADsk_Input_ExtrapInterp1 + + + SUBROUTINE ADsk_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time +! values of u (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = u1, f(t2) = u2, f(t3) = u3 +! +!.................................................................................................................................. + + TYPE(ADsk_InputType), INTENT(INOUT) :: u1 ! Input at t1 > t2 > t3 + TYPE(ADsk_InputType), INTENT(INOUT) :: u2 ! Input at t2 > t3 + TYPE(ADsk_InputType), INTENT(INOUT) :: u3 ! Input at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs + TYPE(ADsk_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Inputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: c ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Input_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) + CALL MeshExtrapInterp2(u1%HubMotion, u2%HubMotion, u3%HubMotion, tin, u_out%HubMotion, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + b = (t(3)**2*(u1%RotSpeed - u2%RotSpeed) + t(2)**2*(-u1%RotSpeed + u3%RotSpeed))* scaleFactor + c = ( (t(2)-t(3))*u1%RotSpeed + t(3)*u2%RotSpeed - t(2)*u3%RotSpeed ) * scaleFactor + u_out%RotSpeed = u1%RotSpeed + b + c * t_out + CALL Angles_ExtrapInterp( u1%BlPitch, u2%BlPitch, u3%BlPitch, tin, u_out%BlPitch, tin_out ) + DO i1 = LBOUND(u_out%VWind,1),UBOUND(u_out%VWind,1) + b = (t(3)**2*(u1%VWind(i1) - u2%VWind(i1)) + t(2)**2*(-u1%VWind(i1) + u3%VWind(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%VWind(i1) + t(3)*u2%VWind(i1) - t(2)*u3%VWind(i1) ) * scaleFactor + u_out%VWind(i1) = u1%VWind(i1) + b + c * t_out + END DO + END SUBROUTINE ADsk_Input_ExtrapInterp2 + + + SUBROUTINE ADsk_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is given by the size of y +! +! expressions below based on either +! +! f(t) = a +! f(t) = a + b * t, or +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 (as appropriate) +! +!.................................................................................................................................. + + TYPE(ADsk_OutputType), INTENT(INOUT) :: y(:) ! Output at t1 > t2 > t3 + REAL(DbKi), INTENT(IN ) :: t(:) ! Times associated with the Outputs + TYPE(ADsk_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: t_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Output_ExtrapInterp' + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + if ( size(t) .ne. size(y)) then + CALL SetErrStat(ErrID_Fatal,'size(t) must equal size(y)',ErrStat,ErrMsg,RoutineName) + RETURN + endif + order = SIZE(y) - 1 + IF ( order .eq. 0 ) THEN + CALL ADsk_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 1 ) THEN + CALL ADsk_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE IF ( order .eq. 2 ) THEN + CALL ADsk_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ELSE + CALL SetErrStat(ErrID_Fatal,'size(y) must be less than 4 (order must be less than 3).',ErrStat,ErrMsg,RoutineName) + RETURN + ENDIF + END SUBROUTINE ADsk_Output_ExtrapInterp + + + SUBROUTINE ADsk_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 1. +! +! f(t) = a + b * t, or +! +! where a and b are determined as the solution to +! f(t1) = y1, f(t2) = y2 +! +!.................................................................................................................................. + + TYPE(ADsk_OutputType), INTENT(INOUT) :: y1 ! Output at t1 > t2 + TYPE(ADsk_OutputType), INTENT(INOUT) :: y2 ! Output at t2 + REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs + TYPE(ADsk_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(2) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Output_ExtrapInterp1' + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / t(2) + CALL MeshExtrapInterp1(y1%AeroLoads, y2%AeroLoads, tin, y_out%AeroLoads, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + b = -(y1%YawErr - y2%YawErr) + y_out%YawErr = y1%YawErr + b * ScaleFactor + b = -(y1%SkewAngle - y2%SkewAngle) + y_out%SkewAngle = y1%SkewAngle + b * ScaleFactor + b = -(y1%ChiSkew - y2%ChiSkew) + y_out%ChiSkew = y1%ChiSkew + b * ScaleFactor + b = -(y1%VRel - y2%VRel) + y_out%VRel = y1%VRel + b * ScaleFactor + b = -(y1%Ct - y2%Ct) + y_out%Ct = y1%Ct + b * ScaleFactor + b = -(y1%Cq - y2%Cq) + y_out%Cq = y1%Cq + b * ScaleFactor +IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) + b = -(y1%WriteOutput(i1) - y2%WriteOutput(i1)) + y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b * ScaleFactor + END DO +END IF ! check if allocated + END SUBROUTINE ADsk_Output_ExtrapInterp1 + + + SUBROUTINE ADsk_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) +! +! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time +! values of y (which has values associated with times in t). Order of the interpolation is 2. +! +! expressions below based on either +! +! f(t) = a + b * t + c * t**2 +! +! where a, b and c are determined as the solution to +! f(t1) = y1, f(t2) = y2, f(t3) = y3 +! +!.................................................................................................................................. + + TYPE(ADsk_OutputType), INTENT(INOUT) :: y1 ! Output at t1 > t2 > t3 + TYPE(ADsk_OutputType), INTENT(INOUT) :: y2 ! Output at t2 > t3 + TYPE(ADsk_OutputType), INTENT(INOUT) :: y3 ! Output at t3 + REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs + TYPE(ADsk_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + ! local variables + REAL(DbKi) :: t(3) ! Times associated with the Outputs + REAL(DbKi) :: t_out ! Time to which to be extrap/interpd + INTEGER(IntKi) :: order ! order of polynomial fit (max 2) + REAL(DbKi) :: b ! temporary for extrapolation/interpolation + REAL(DbKi) :: c ! temporary for extrapolation/interpolation + REAL(DbKi) :: ScaleFactor ! temporary for extrapolation/interpolation + INTEGER(IntKi) :: ErrStat2 ! local errors + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_Output_ExtrapInterp2' + INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts + INTEGER :: i1 ! dim1 counter variable for arrays + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + ! we'll subtract a constant from the times to resolve some + ! numerical issues when t gets large (and to simplify the equations) + t = tin - tin(1) + t_out = tin_out - tin(1) + + IF ( EqualRealNos( t(1), t(2) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(2) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(2), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(2) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + ELSE IF ( EqualRealNos( t(1), t(3) ) ) THEN + CALL SetErrStat(ErrID_Fatal, 't(1) must not equal t(3) to avoid a division-by-zero error.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + + ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) + CALL MeshExtrapInterp2(y1%AeroLoads, y2%AeroLoads, y3%AeroLoads, tin, y_out%AeroLoads, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + b = (t(3)**2*(y1%YawErr - y2%YawErr) + t(2)**2*(-y1%YawErr + y3%YawErr))* scaleFactor + c = ( (t(2)-t(3))*y1%YawErr + t(3)*y2%YawErr - t(2)*y3%YawErr ) * scaleFactor + y_out%YawErr = y1%YawErr + b + c * t_out + b = (t(3)**2*(y1%SkewAngle - y2%SkewAngle) + t(2)**2*(-y1%SkewAngle + y3%SkewAngle))* scaleFactor + c = ( (t(2)-t(3))*y1%SkewAngle + t(3)*y2%SkewAngle - t(2)*y3%SkewAngle ) * scaleFactor + y_out%SkewAngle = y1%SkewAngle + b + c * t_out + b = (t(3)**2*(y1%ChiSkew - y2%ChiSkew) + t(2)**2*(-y1%ChiSkew + y3%ChiSkew))* scaleFactor + c = ( (t(2)-t(3))*y1%ChiSkew + t(3)*y2%ChiSkew - t(2)*y3%ChiSkew ) * scaleFactor + y_out%ChiSkew = y1%ChiSkew + b + c * t_out + b = (t(3)**2*(y1%VRel - y2%VRel) + t(2)**2*(-y1%VRel + y3%VRel))* scaleFactor + c = ( (t(2)-t(3))*y1%VRel + t(3)*y2%VRel - t(2)*y3%VRel ) * scaleFactor + y_out%VRel = y1%VRel + b + c * t_out + b = (t(3)**2*(y1%Ct - y2%Ct) + t(2)**2*(-y1%Ct + y3%Ct))* scaleFactor + c = ( (t(2)-t(3))*y1%Ct + t(3)*y2%Ct - t(2)*y3%Ct ) * scaleFactor + y_out%Ct = y1%Ct + b + c * t_out + b = (t(3)**2*(y1%Cq - y2%Cq) + t(2)**2*(-y1%Cq + y3%Cq))* scaleFactor + c = ( (t(2)-t(3))*y1%Cq + t(3)*y2%Cq - t(2)*y3%Cq ) * scaleFactor + y_out%Cq = y1%Cq + b + c * t_out +IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN + DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) + b = (t(3)**2*(y1%WriteOutput(i1) - y2%WriteOutput(i1)) + t(2)**2*(-y1%WriteOutput(i1) + y3%WriteOutput(i1)))* scaleFactor + c = ( (t(2)-t(3))*y1%WriteOutput(i1) + t(3)*y2%WriteOutput(i1) - t(2)*y3%WriteOutput(i1) ) * scaleFactor + y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b + c * t_out + END DO +END IF ! check if allocated + END SUBROUTINE ADsk_Output_ExtrapInterp2 + +END MODULE AeroDisk_Types +!ENDOFREGISTRYGENERATEDFILE From 2c594621eda1dd8108a7bd7a5d63d7b74c3cc709 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 15 Feb 2022 13:51:11 -0700 Subject: [PATCH 019/130] ADsk: add rough code placeholders and rough driver placeholder It all compiles, but does nothing --- modules/aerodisk/CMakeLists.txt | 15 +- modules/aerodisk/src/AeroDisk.f90 | 320 +++++ modules/aerodisk/src/AeroDisk_IO.f90 | 52 + .../aerodisk/src/AeroDisk_Output_Params.f90 | 5 + modules/aerodisk/src/AeroDisk_Registry.txt | 1 + modules/aerodisk/src/AeroDisk_Types.f90 | 7 + .../aerodisk/src/driver/AeroDisk_Driver.f90 | 342 +++++ .../src/driver/AeroDisk_Driver_Subs.f90 | 1126 +++++++++++++++++ .../src/driver/AeroDisk_Driver_Types.f90 | 69 + 9 files changed, 1934 insertions(+), 3 deletions(-) create mode 100644 modules/aerodisk/src/AeroDisk.f90 create mode 100644 modules/aerodisk/src/AeroDisk_IO.f90 create mode 100644 modules/aerodisk/src/AeroDisk_Output_Params.f90 create mode 100644 modules/aerodisk/src/driver/AeroDisk_Driver.f90 create mode 100644 modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 create mode 100644 modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 diff --git a/modules/aerodisk/CMakeLists.txt b/modules/aerodisk/CMakeLists.txt index b5c444717b..778ab6669e 100644 --- a/modules/aerodisk/CMakeLists.txt +++ b/modules/aerodisk/CMakeLists.txt @@ -20,14 +20,23 @@ endif() set(ADSK_SOURCES src/AeroDisk_Types.f90 + src/AeroDisk_Output_Params.f90 + src/AeroDisk_IO.f90 + src/AeroDisk.f90 ) - #src/AeroDisk.f90 - #src/AeroDisk_IO.f90 add_library(aerodisklib ${ADSK_SOURCES}) target_link_libraries(aerodisklib nwtclibs) -install(TARGETS aerodisklib +set(AERODISK_DRIVER_SOURCES + src/driver/AeroDisk_Driver_Types.f90 + src/driver/AeroDisk_Driver_Subs.f90 + src/driver/AeroDisk_Driver.f90 +) +add_executable(aerodisk_driver ${AERODISK_DRIVER_SOURCES}) +target_link_libraries(aerodisk_driver aerodisklib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) + +install(TARGETS aerodisklib aerodisk_driver EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/modules/aerodisk/src/AeroDisk.f90 b/modules/aerodisk/src/AeroDisk.f90 new file mode 100644 index 0000000000..10eacd6be4 --- /dev/null +++ b/modules/aerodisk/src/AeroDisk.f90 @@ -0,0 +1,320 @@ +!********************************************************************************************************************************** +!> ## AeroDisk +!! The AeroDisk module solves a quasi-steady actuator disk representation of the rotor to calculate the 3 forces and 3 moments of +!! the rotor dependent on the tip-speed ratio (TSR), rotor speed (RotSpeed), relative wind velocity vector (VRel), and the rotor- +!! collective blade-pitch (BlPitch). +!! +! .................................................................................................................................. +!! ## LICENSING +!! Copyright (C) 2022 National Renewable Energy Laboratory +!! +!! This file is part of AeroDisk. +!! +!! Licensed under the Apache License, Version 2.0 (the "License"); +!! you may not use this file except in compliance with the License. +!! You may obtain a copy of the License at +!! +!! http://www.apache.org/licenses/LICENSE-2.0 +!! +!! Unless required by applicable law or agreed to in writing, software +!! distributed under the License is distributed on an "AS IS" BASIS, +!! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +!! See the License for the specific language governing permissions and +!! limitations under the License. +!********************************************************************************************************************************** +MODULE AeroDisk + + USE AeroDisk_Types + USE AeroDisk_IO + USE NWTC_Library + + implicit none + private + type(ProgDesc), parameter :: ADsk_Ver = ProgDesc( 'AeroDisk', 'v1.00.00', '15-Feb-2022' ) + + public :: ADsk_Init + public :: ADsk_End + public :: ADsk_UpdateStates + public :: ADsk_CalcOutput + public :: ADsk_CalcContStateDeriv + + ! Linearization is not supported by this module, so the following routines are omitted + !public :: ADsk_CalcConstrStateResidual + !public :: ADsk_UpdateDiscState + !public :: ADsk_JacobianPInput + !public :: ADsk_JacobianPContState + !public :: ADsk_JacobianPDiscState + !public :: ADsk_JacobianPConstrState + !public :: ADsk_GetOP + +CONTAINS + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> Initialize the AeroDisk module: +!! - load settings (passed or from file) +!! - setup meshes +!! - initialize outputs and other data storage +SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut, ErrStat, ErrMsg ) + type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine + type(ADsk_InputType), intent( out) :: u !< An initial guess for the input; input mesh must be defined + type(ADsk_ParameterType), intent( out) :: p !< Parameters + type(ADsk_ContinuousStateType), intent( out) :: x !< Initial continuous states + type(ADsk_DiscreteStateType), intent( out) :: xd !< Initial discrete states + type(ADsk_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states + type(ADsk_OtherStateType), intent( out) :: OtherState !< Initial other states (logical, etc) + type(ADsk_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated) + type(ADsk_MiscVarType), intent( out) :: m !< Misc variables for optimization (not copied in glue code) + real(DbKi), intent(inout) :: Interval !< Coupling interval in seconds: the rate that + type(ADsk_InitOutputType), intent( out) :: InitOut !< Output for initialization routine + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: NumOuts ! number of outputs; would probably be in the parameter type + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'ADsk_Init' + + ! Initialize variables + ErrStat = ErrID_None + ErrMsg = "" + NumOuts = 2 + + ! Initialize the NWTC Subroutine Library + call NWTC_Init( ) + + ! Display the module information + call DispNVD( ADsk_Ver ) + + ! Define parameters here: + p%DeltaT = Interval + + ! Define initial system states here: +! x%DummyContState = 0.0_ReKi +! xd%DummyDiscState = 0.0_ReKi +! z%DummyConstrState = 0.0_ReKi +! OtherState%DummyOtherState = 0.0_ReKi + + ! Define optimization variables here: + m%DummyMiscVar = 0.0_ReKi + + ! Define initial guess for the system inputs here: +! u%DummyInput = 0.0_ReKi + +! call SetOutParams() + + ! Define system output initializations (set up mesh) here: + call AllocAry( y%WriteOutput, NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; + y%WriteOutput = 0 + + ! Define initialization-routine output here: + call AllocAry(InitOut%WriteOutputHdr,NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%WriteOutputUnt,NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; + InitOut%WriteOutputHdr = (/ 'Time ', 'Column2' /) + InitOut%WriteOutputUnt = (/ '(s)', '(-)' /) + + +!FIXME: any logic around this? + !Interval = p%DeltaT + + + if (InitInp%Linearize) then + CALL SetErrStat( ErrID_Fatal, 'AeroDisk cannot perform linearization analysis.', ErrStat, ErrMsg, RoutineName) + end if + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE ADsk_Init + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine is called at the end of the simulation. +SUBROUTINE ADsk_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) + type(ADsk_InputType), intent(inout) :: u !< System inputs + type(ADsk_ParameterType), intent(inout) :: p !< Parameters + type(ADsk_ContinuousStateType), intent(inout) :: x !< Continuous states + type(ADsk_DiscreteStateType), intent(inout) :: xd !< Discrete states + type(ADsk_ConstraintStateType), intent(inout) :: z !< Constraint states + type(ADsk_OtherStateType), intent(inout) :: OtherState !< Other states + type(ADsk_OutputType), intent(inout) :: y !< System outputs + type(ADsk_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'ADsk_End' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + !! Place any last minute operations or calculations here: + + !! Close files here (but because of checkpoint-restart capability, it is not recommended to have files open during the simulation): + + ! Destroy the input data: + call ADsk_DestroyInput( u, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the parameter data: + call ADsk_DestroyParam( p, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the state data: + call ADsk_DestroyContState( x, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call ADsk_DestroyDiscState( xd, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call ADsk_DestroyConstrState( z, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call ADsk_DestroyOtherState( OtherState, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the output data: + call ADsk_DestroyOutput( y, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the misc data: + call ADsk_DestroyMisc( m, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) +END SUBROUTINE ADsk_End + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a loose coupling routine for solving constraint states, integrating continuous states, and updating discrete and other +!! states. Continuous, constraint, discrete, and other states are updated to values at t + Interval. +SUBROUTINE ADsk_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< Current step of the simulation: t = n*Interval + type(ADsk_InputType), intent(inout) :: Inputs(:) !< Inputs at InputTimes (output for mesh connect) + real(DbKi), intent(in ) :: InputTimes(:) !< Times in seconds associated with Inputs + type(ADsk_ParameterType), intent(in ) :: p !< Parameters + type(ADsk_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; + type(ADsk_DiscreteStateType), intent(inout) :: xd !< Input: Discrete states at t; + type(ADsk_ConstraintStateType), intent(inout) :: z !< Input: Constraint states at t; + type(ADsk_OtherStateType), intent(inout) :: OtherState !< Other states: Other states at t; + type(ADsk_MiscVarType), intent(inout) :: m !< Misc variables for optimization + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables + type(ADsk_ContinuousStateType) :: dxdt ! Continuous state derivatives at t + type(ADsk_InputType) :: u ! Instantaneous inputs + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'ADsk_UpdateStates' + + ! Initialize variables + ErrStat = ErrID_None ! no error has occurred + ErrMsg = "" + + ! Get the inputs at time t, based on the array of values sent by the glue code: + ! before calling ExtrapInterp routine, memory in u must be allocated; we can do that with a copy: + call ADsk_CopyInput( Inputs(1), u, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + + call ADsk_Input_ExtrapInterp( Inputs, InputTimes, u, t, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Get first time derivatives of continuous states (dxdt): + call ADsk_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Integrate (update) continuous states (x) here: + !x = function of dxdt and x + + ! Destroy local variables before returning + call cleanup() + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine Cleanup() + ! Destroy data to prevent memory leaks + call ADsk_DestroyInput( u, ErrStat2, ErrMsg2) + call ADsk_DestroyContState( dxdt, ErrStat2, ErrMsg2) + end subroutine Cleanup +end subroutine ADsk_UpdateStates + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a routine for computing outputs, used in both loose and tight coupling. +SUBROUTINE ADsk_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(ADsk_InputType), intent(in ) :: u !< Inputs at t + type(ADsk_ParameterType), intent(in ) :: p !< Parameters + type(ADsk_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(ADsk_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(ADsk_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(ADsk_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(ADsk_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(ADsk_OutputType), intent(inout) :: y !< Outputs computed at t (Input only for mesh) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'ADsk_CalcOutput' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + ! Compute outputs here: + !y%DummyOutput = 2.0_ReKi + + y%WriteOutput(1) = REAL(t,ReKi) + y%WriteOutput(2) = 1.0_ReKi + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE ADsk_CalcOutput + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a tight coupling routine for computing derivatives of continuous states. +SUBROUTINE ADsk_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(ADsk_InputType), intent(in ) :: u !< Inputs at t + type(ADsk_ParameterType), intent(in ) :: p !< Parameters + type(ADsk_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(ADsk_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(ADsk_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(ADsk_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(ADsk_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(ADsk_ContinuousStateType), intent( out) :: dxdt !< Continuous state derivatives at t + INTEGER(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'ADsk_CalcContStateDeriv' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + ! Compute the first time derivatives of the continuous states here: + !dxdt%DummyContState = 0.0_ReKi + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE ADsk_CalcContStateDeriv + + +END MODULE AeroDisk +!********************************************************************************************************************************** diff --git a/modules/aerodisk/src/AeroDisk_IO.f90 b/modules/aerodisk/src/AeroDisk_IO.f90 new file mode 100644 index 0000000000..5ee01c45f3 --- /dev/null +++ b/modules/aerodisk/src/AeroDisk_IO.f90 @@ -0,0 +1,52 @@ +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2020 National Renewable Energy Laboratory +! +! This file is part of AeroDisk +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +!********************************************************************************************************************************** +MODULE AeroDisk_IO + + USE AeroDisk_Types + USE AeroDisk_Output_Params + USE NWTC_Library + + implicit none + + +contains + +SUBROUTINE ADsk_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) + type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization + type(ADsk_InputFile), intent(inout) :: InputFileData !< The data for initialization + integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine + character(*), intent( out) :: ErrMsg !< Error message from this subroutine + integer(IntKi) :: ErrStat2 !< Temporary error status for subroutine and function calls + character(ErrMsgLen) :: ErrMsg2 !< Temporary error message for subroutine and function calls + integer(IntKi) :: I !< Generic counter + character(*), parameter :: RoutineName="ADsk_ValidateInput" + integer(IntKi) :: IOS !< Temporary error status + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + +END SUBROUTINE ADsk_ValidateInput + + +!FIXME: add SetOutParam here + + +END MODULE AeroDisk_IO + diff --git a/modules/aerodisk/src/AeroDisk_Output_Params.f90 b/modules/aerodisk/src/AeroDisk_Output_Params.f90 new file mode 100644 index 0000000000..64f679d7fb --- /dev/null +++ b/modules/aerodisk/src/AeroDisk_Output_Params.f90 @@ -0,0 +1,5 @@ +!> The parameters in this code are from the MATLAB autogeneration scripts. Do not manually edit unless also editing the OutListParamters.xls AeroDisk tab. +module AeroDisk_Output_Params + use NWTC_Library + +end module AeroDisk_Output_Params diff --git a/modules/aerodisk/src/AeroDisk_Registry.txt b/modules/aerodisk/src/AeroDisk_Registry.txt index ae02501bd4..f58145be4f 100644 --- a/modules/aerodisk/src/AeroDisk_Registry.txt +++ b/modules/aerodisk/src/AeroDisk_Registry.txt @@ -45,6 +45,7 @@ typedef ^ InitInputType ReKi RotorRad - - typedef ^ InitInputType ReKi HubPosition {3} - - "Hub position -- center of rotor" m typedef ^ InitInputType R8Ki HubOrientation {3}{3} - - "Hub orientation" - typedef ^ InitInputType ReKi defPatm - - - "Default atmospheric pressure from the driver; may be overwritten" Pa +typedef ^ InitInputType LOGICAL Linearize - .false. - "this module cannot be linearized at present" - # outputs from initialization: diff --git a/modules/aerodisk/src/AeroDisk_Types.f90 b/modules/aerodisk/src/AeroDisk_Types.f90 index 81eb3144b4..f1ae10d699 100644 --- a/modules/aerodisk/src/AeroDisk_Types.f90 +++ b/modules/aerodisk/src/AeroDisk_Types.f90 @@ -64,6 +64,7 @@ MODULE AeroDisk_Types REAL(ReKi) , DIMENSION(1:3) :: HubPosition !< Hub position -- center of rotor [m] REAL(R8Ki) , DIMENSION(1:3,1:3) :: HubOrientation !< Hub orientation [-] REAL(ReKi) :: defPatm !< Default atmospheric pressure from the driver; may be overwritten [Pa] + LOGICAL :: Linearize = .false. !< this module cannot be linearized at present [-] END TYPE ADsk_InitInputType ! ======================= ! ========= ADsk_InitOutputType ======= @@ -1189,6 +1190,7 @@ SUBROUTINE ADsk_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, Err DstInitInputData%HubPosition = SrcInitInputData%HubPosition DstInitInputData%HubOrientation = SrcInitInputData%HubOrientation DstInitInputData%defPatm = SrcInitInputData%defPatm + DstInitInputData%Linearize = SrcInitInputData%Linearize END SUBROUTINE ADsk_CopyInitInput SUBROUTINE ADsk_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) @@ -1243,6 +1245,7 @@ SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = Re_BufSz + SIZE(InData%HubPosition) ! HubPosition Db_BufSz = Db_BufSz + SIZE(InData%HubOrientation) ! HubOrientation Re_BufSz = Re_BufSz + 1 ! defPatm + Int_BufSz = Int_BufSz + 1 ! Linearize IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1292,6 +1295,8 @@ SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM END DO ReKiBuf(Re_Xferred) = InData%defPatm Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%Linearize, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE ADsk_PackInitInput SUBROUTINE ADsk_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -1350,6 +1355,8 @@ SUBROUTINE ADsk_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E END DO OutData%defPatm = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%Linearize = TRANSFER(IntKiBuf(Int_Xferred), OutData%Linearize) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE ADsk_UnPackInitInput SUBROUTINE ADsk_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver.f90 new file mode 100644 index 0000000000..71d4365864 --- /dev/null +++ b/modules/aerodisk/src/driver/AeroDisk_Driver.f90 @@ -0,0 +1,342 @@ +!********************************************************************************************************************************** +!> ## AeroDisk_DriverCode: This code tests the AeroDisk module +!!.................................................................................................................................. +!! LICENSING +!! Copyright (C) 2012, 2015 National Renewable Energy Laboratory +!! +!! This file is part of AeroDisk. +!! +!! Licensed under the Apache License, Version 2.0 (the "License"); +!! you may not use this file except in compliance with the License. +!! You may obtain a copy of the License at +!! +!! http://www.apache.org/licenses/LICENSE-2.0 +!! +!! Unless required by applicable law or agreed to in writing, software +!! distributed under the License is distributed on an "AS IS" BASIS, +!! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +!! See the License for the specific language governing permissions and +!! limitations under the License. +!********************************************************************************************************************************** +PROGRAM AeroDisk_Driver + + USE NWTC_Library + USE VersionInfo + USE AeroDisk + USE AeroDisk_Types + USE AeroDisk_Driver_Subs + USE AeroDisk_Driver_Types + + IMPLICIT NONE + + TYPE( ProgDesc ), PARAMETER :: ProgInfo = ProgDesc("ADsk_Driver","","") + INTEGER(IntKi) :: ADskDriver_Verbose = 5 ! Verbose level. 0 = none, 5 = some, 10 = lots + + + + integer(IntKi), parameter :: NumInp = 1 !< Number of inputs sent to AeroDisk_UpdateStates + + ! Program variables + real(DbKi) :: Time !< Variable for storing time, in seconds + real(DbKi) :: TimeInterval !< Interval between time steps, in seconds + real(DbKi) :: TStart !< Time to start + real(DbKi) :: TMax !< Maximum time if found by default + integer(IntKi) :: NumTSteps !< number of timesteps + logical :: TimeIntervalFound !< Interval between time steps, in seconds + real(DbKi) :: InputTime(NumInp) !< Variable for storing time associated with inputs, in seconds + real(R8Ki), allocatable :: DisplacementList(:,:) !< List of displacements and times to apply {idx 1 = time step, idx 2 = [T, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z]} + + type(ADsk_InitInputType) :: InitInData !< Input data for initialization + type(ADsk_InitOutputType) :: InitOutData !< Output data from initialization + + type(ADsk_ContinuousStateType) :: x !< Continuous states + type(ADsk_DiscreteStateType) :: xd !< Discrete states + type(ADsk_ConstraintStateType) :: z !< Constraint states + type(ADsk_ConstraintStateType) :: Z_residual !< Residual of the constraint state functions (Z) + type(ADsk_OtherStateType) :: OtherState !< Other states + type(ADsk_MiscVarType) :: misc !< Optimization variables + + type(ADsk_ParameterType) :: p !< Parameters + type(ADsk_InputType) :: u(NumInp) !< System inputs + type(ADsk_OutputType) :: y !< System outputs + + ! Local variables for this code + TYPE(ADskDriver_Flags) :: CLSettingsFlags ! Flags indicating which command line arguments were specified + TYPE(ADskDriver_Settings) :: CLSettings ! Command line arguments passed in + TYPE(ADskDriver_Flags) :: SettingsFlags ! Flags indicating which settings were specified (includes CL and ipt file) + TYPE(ADskDriver_Settings) :: Settings ! Driver settings + REAL(DbKi) :: Timer(1:2) ! Keep track of how long this takes to run + + ! Data transfer + real(R8Ki) :: Force(6) + real(R8Ki) :: Displacement(6) + real(R8Ki) :: Theta(3) + + INTEGER(IntKi) :: n !< Loop counter (for time step) + integer(IntKi) :: i !< generic loop counter + integer(IntKi) :: DimIdx !< Index of current dimension + integer(IntKi) :: TmpIdx(6) !< Index of last point accessed by dimension + INTEGER(IntKi) :: ErrStat !< Status of error message + CHARACTER(ErrMsgLen) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + CHARACTER(200) :: git_commit ! String containing the current git commit hash + TYPE(ProgDesc), PARAMETER :: version = ProgDesc( 'AeroDisk Driver', '', '' ) ! The version number of this program. + integer(IntKi) :: DvrOut + character(1024) :: OutputFileRootName + + + ! initialize library + call NWTC_Init + call DispNVD(ProgInfo) + DvrOut=-1 ! Set output unit to negative + + ! Display the copyright notice + CALL DispCopyrightLicense( version%Name ) + ! Obtain OpenFAST git commit hash + git_commit = QueryGitVersion() + ! Tell our users what they're running + CALL WrScr( ' Running '//GetNVD( version )//' a part of OpenFAST - '//TRIM(git_Commit)//NewLine//' linked with '//TRIM( GetNVD( NWTC_Ver ))//NewLine ) + + ! Start the timer + call CPU_TIME( Timer(1) ) + + ! Initialize the driver settings to their default values (same as the CL -- command line -- values) + call InitSettingsFlags( ProgInfo, CLSettings, CLSettingsFlags ) + Settings = CLSettings + SettingsFlags = CLSettingsFlags + + ! Parse the input line + call RetrieveArgs( CLSettings, CLSettingsFlags, ErrStat, ErrMsg ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL ProgAbort( ErrMsg ) + ELSEIF ( ErrStat /= 0 ) THEN + CALL WrScr( NewLine//ErrMsg ) + ErrStat = ErrID_None + ENDIF + + ! Check if we are doing verbose error reporting + IF ( CLSettingsFlags%VVerbose ) ADskDriver_Verbose = 10_IntKi + IF ( CLSettingsFlags%Verbose ) ADskDriver_Verbose = 7_IntKi + + ! Verbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr('--- Settings from the command line: ---') + CALL printSettings( CLSettingsFlags, CLSettings ) + CALL WrSCr(NewLine) + ENDIF + + ! Verbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr('--- Driver settings (before reading driver ipt file): ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + + ! Copy the input file information from the CLSettings to the Settings. + ! At this point only one input file type can be set. + IF ( CLSettingsFlags%DvrIptFile ) THEN + SettingsFlags%DvrIptFile = CLSettingsFlags%DvrIptFile + Settings%DvrIptFileName = CLSettings%DvrIptFileName + ELSE + SettingsFlags%ADskIptFile = CLSettingsFlags%ADskIptFile + Settings%ADskIptFileName = CLSettings%ADskIptFileName + ENDIF + + ! If the filename given was not the ADsk input file (-ifw option), then it is treated + ! as the driver input file (flag should be set correctly by RetrieveArgs). So, we must + ! open this. + IF ( SettingsFlags%DvrIptFile ) THEN + + ! Read the driver input file + CALL ReadDvrIptFile( CLSettings%DvrIptFileName, SettingsFlags, Settings, ProgInfo, ErrStat, ErrMsg ) + call CheckErr('') + + ! VVerbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr(NewLine//'--- Driver settings after reading the driver ipt file: ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + ! VVerbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) CALL WrScr('Updating driver settings with command line arguments') + + ELSE + + ! VVerbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) CALL WrScr('No driver input file used. Updating driver settings with command line arguments') + + ENDIF + + ! Since there were no settings picked up from the driver input file, we need to copy over all + ! the CLSettings into the regular Settings. The SettingsFlags%DvrIptFile is a flag indicating + ! if the driver input file read. + CALL UpdateSettingsWithCL( SettingsFlags, Settings, CLSettingsFlags, CLSettings, SettingsFlags%DvrIptFile, ErrStat, ErrMsg ) + call CheckErr('') + + ! Verbose error reporting + IF ( ADskDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr(NewLine//'--- Driver settings after copying over CL settings: ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + + !------------------------------------------ + ! Read DisplacementList from InputDispFile + ! NOTE: DiplacementList is arranged for speed in interpolation + ! -- index 1 = time step + ! -- index 2 = [T, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z] + !------------------------------------------ + if ( SettingsFlags%InputDispFile ) then + call ReadInputDispFile( Settings%InputDispFile, DisplacementList, ErrStat, ErrMsg ) + call CheckErr('') + + if ( ADskDriver_Verbose >= 10_IntKi ) call WrScr('Input Displacements given for '//trim(Num2LStr(size(DisplacementList,1)))// & + ' time steps from T = '//trim(Num2LStr(DisplacementList(1,1)))//' to '//trim(Num2LStr(DisplacementList(size(DisplacementList,1),1)))//' seconds.') + endif + + + !------------------------------------------ + ! Logic for timestep and total time for sim. + !------------------------------------------ + if ( SettingsFlags%TStart ) then + TStart = Settings%TStart + else + TStart = 0.0_DbKi + ! TODO: if using the input file, could start at the initial time given there (set the TStart with a "default" input option) + endif + + + + TimeIntervalFound=.true. ! If specified or default value set + ! DT - timestep. If default was specified, then calculate default level. + if ( SettingsFlags%DTdefault ) then + if ( SettingsFlags%InputDispFile ) then + ! Set a value to start with (something larger than any expected DT). + TimeIntervalFound=.false. + TimeInterval=1000.0_DbKi + ! Step through all lines to get smallest DT + do n=min(2,size(DisplacementList,1)),size(DisplacementList,1) ! Start at 2nd point (min to avoid stepping over end for single line files) + TimeInterval=min(TimeInterval, real(DisplacementList(n,1)-DisplacementList(n-1,1), DbKi)) + TimeIntervalFound=.true. + enddo + if (TimeIntervalFound) then + call WrScr('Using smallest DT from data file: '//trim(Num2LStr(TimeInterval))//' seconds.') + else + call WrScr('No time timesteps found in input displacement file. Using only one timestep.') + endif + else + ! set default level. NOTE: the REDWIN dll does not use any form of timestep, so this is merely for bookkeeping. + TimeInterval = 0.01_DbKi + call WrScr('Setting default timestep to '//trim(Num2LStr(TimeInterval))//' seconds.') + endif + endif + + + ! TMax and NumTSteps from input file or from the value specified (specified overrides) + if ( SettingsFlags%NumTimeStepsDefault ) then + if ( SettingsFlags%InputDispFile ) then + TMax = real(DisplacementList(size(DisplacementList,1),1), DbKi) + NumTSteps = ceiling( TMax / TimeInterval ) + else ! Do one timestep + NumTSteps = 1_IntKi + TMax = TimeInterval * NumTSteps + endif + elseif ( SettingsFlags%NumTimeSteps ) then ! Override with number of timesteps + TMax = TimeInterval * Settings%NumTimeSteps + TStart + NumTSteps = Settings%NumTimeSteps + else + NumTSteps = 1_IntKi + TMax = TimeInterval * NumTSteps + endif + + + + ! Routines called in initialization + !............................................................................................................................... + + InitInData%InputFile = Settings%ADskIptFileName + + ! Initialize the module + CALL ADsk_Init( InitInData, u(1), p, x, xd, z, OtherState, y, misc, TimeInterval, InitOutData, ErrStat, ErrMsg ) + IF ( ErrStat /= ErrID_None ) THEN ! Check if there was an error and do something about it if necessary + CALL WrScr( 'After Init: '//ErrMsg ) + if ( ErrStat >= AbortErrLev ) call ProgEnd() + END IF + + ! Set the output file + call GetRoot(Settings%ADskIptFileName,OutputFileRootName) + call Dvr_InitializeOutputFile(DvrOut, InitOutData, OutputFileRootName, ErrStat, ErrMsg) + call CheckErr('Setting output file'); + + ! Destroy initialization data + CALL ADsk_DestroyInitInput( InitInData, ErrStat, ErrMsg ) + CALL ADsk_DestroyInitOutput( InitOutData, ErrStat, ErrMsg ) + + + + ! Routines called in loose coupling -- the glue code may implement this in various ways + !............................................................................................................................... + + + TmpIdx(1:6) = 0_IntKi + + DO n = 0,NumTSteps + Time = n*TimeInterval+TStart + InputTime(1) = Time + + ! interpolate into the input data to get the displacement. Set this as u then run + if ( SettingsFlags%InputDispFile ) then +! do i=1,u(1)%SoilMesh%NNodes +! ! InterpStpReal( X, Xary, Yary, indx, size) +! do DimIdx=1,3 +! u(1)%SoilMesh%TranslationDisp(DimIdx,i) = InterpStpReal8( real(Time,R8Ki), DisplacementList(:,1), DisplacementList(:,DimIdx+1), TmpIdx(DimIdx), size(DisplacementList,1) ) +! enddo +! do DimIdx=1,3 +! Theta(DimIdx) = InterpStpReal8( real(Time,R8Ki), DisplacementList(:,1), DisplacementList(:,DimIdx+4), TmpIdx(DimIdx), size(DisplacementList,1) ) +! enddo +! u(1)%SoilMesh%Orientation(1:3,1:3,i) = EulerConstruct(Theta) +! enddo + endif + + ! Calculate outputs at n + CALL ADsk_CalcOutput( Time, u(1), p, x, xd, z, OtherState, y, misc, ErrStat, ErrMsg ); + call CheckErr('After CalcOutput: '); + + ! There are no states to update in AeroDisk, but for completeness we add this. + ! Get state variables at next step: INPUT at step n, OUTPUT at step n + 1 + CALL ADsk_UpdateStates( Time, n, u, InputTime, p, x, xd, z, OtherState, misc, ErrStat, ErrMsg ); + call CheckErr(''); + + !call Dvr_WriteOutputLine(Time,DvrOut,p%OutFmt,y) + call Dvr_WriteOutputLine(Time,DvrOut,"ES20.12E2",y) + END DO + + + + + !............................................................................................................................... + ! Routine to terminate program execution + !............................................................................................................................... + if (DvrOut>0) close(DvrOut) + CALL ADsk_End( u(1), p, x, xd, z, OtherState, y, misc, ErrStat, ErrMsg ) + + IF ( ErrStat /= ErrID_None ) THEN + CALL WrScr( 'After End: '//ErrMsg ) + END IF + +CONTAINS + subroutine CheckErr(Text) + character(*), intent(in) :: Text + IF ( ErrStat /= ErrID_None ) THEN ! Check if there was an error and do something about it if necessary + CALL WrScr( Text//ErrMsg ) + if ( ErrStat >= AbortErrLev ) call ProgEnd() + END IF + end subroutine CheckErr + subroutine ProgEnd() + ! Placeholder for moment + Call ProgAbort('Fatal error encountered. Ending.') + end subroutine ProgEnd +END PROGRAM AeroDisk_Driver diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 new file mode 100644 index 0000000000..a955eebec6 --- /dev/null +++ b/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 @@ -0,0 +1,1126 @@ +!********************************************************************************************************************************** +! +! MODULE: AeroDisk_Driver_Subs - This module contains subroutines used by the AeroDisk Driver program +! +!********************************************************************************************************************************** +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2020 National Renewable Energy Laboratory +! +! This file is part of AeroDisk. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +!********************************************************************************************************************************** +MODULE AeroDisk_Driver_Subs + + USE NWTC_Library + USE AeroDisk_Driver_Types + IMPLICIT NONE + +! NOTE: This is loosely based on the InflowWind driver code. + +CONTAINS +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> Print out help information +SUBROUTINE DispHelpText() + ! Statement about usage + CALL WrScr("") + CALL WrScr(" Syntax: AeroDisk_Driver [options]") + CALL WrScr("") + CALL WrScr(" where: -- Name of driver input file to use") + CALL WrScr(" options: "//SWChar//"adsk -- treat as name of AeroDisk input file") + CALL WrScr(" (no driver input file)") + CALL WrScr("") + CALL WrScr(" The following options will overwrite values in the driver input file:") + CALL WrScr(" "//SwChar//"DT[#] -- timestep ") + CALL WrScr(" "//SwChar//"TStart[#] -- start time ") + CALL WrScr(" "//SwChar//"TSteps[#] -- number of timesteps ") + CALL WrScr(" "//SwChar//"v -- verbose output ") + CALL WrScr(" "//SwChar//"vv -- very verbose output ") + CALL WrScr(" "//SwChar//"NonLinear -- only return non-linear portion of reaction force") + CALL WrScr(" "//SwChar//"help -- print this help menu and exit") + CALL WrScr("") + CALL WrScr(" Notes:") + CALL WrScr(" -- Options are not case sensitive.") + CALL WrScr("") +!FIXME: update this +END SUBROUTINE DispHelpText + + +subroutine InitSettingsFlags( ProgInfo, CLSettings, CLFlags ) + implicit none + ! Storing the arguments + type( ProgDesc ), intent(in ) :: ProgInfo + type( ADskDriver_Settings ), intent( out) :: CLSettings !< Command line arguments passed in + type( ADskDriver_Flags ), intent( out) :: CLFlags !< Flags indicating which command line arguments were specified + + ! Set some CLSettings to null/default values + CLSettings%DvrIptFileName = "" ! No input name name until set + CLSettings%ADskIptFileName = "" ! No ADsk input file name until set + CLSettings%InputDispFile = "" ! No ADsk input displacement timeseries file name until set + CLSettings%NumTimeSteps = 0_IntKi + CLSettings%DT = 0.0_DbKi + CLSettings%TStart = 0.0_ReKi + CLSettings%ProgInfo = ProgInfo ! Driver info + + ! Set some CLFlags to null/default values + CLFlags%DvrIptFile = .FALSE. ! Driver input filename given as command line argument + CLFlags%ADskIptFile = .FALSE. ! AeroDisk input filename given as command line argument + CLFlags%InputDispFile = .FALSE. ! No ADsk input displacement timeseries file name until set + CLFlags%TStart = .FALSE. ! specified time to start at + CLFlags%NumTimeSteps = .FALSE. ! specified a number of timesteps + CLFlags%NumTimeStepsDefault = .FALSE. ! specified 'DEFAULT' for number of timesteps + CLFlags%DT = .FALSE. ! specified a resolution in time + CLFlags%DTDefault = .FALSE. ! specified 'DEFAULT' for resolution in time + CLFlags%Verbose = .FALSE. ! Turn on verbose error reporting? + CLFlags%VVerbose = .FALSE. ! Turn on very verbose error reporting? + +end subroutine InitSettingsFlags + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> This subroutine retrieves the command line arguments and passes them to the +!! AeroDisk_driver_subs::parsearg routine for processing. +SUBROUTINE RetrieveArgs( CLSettings, CLFlags, ErrStat, ErrMsg ) + ! Storing the arguments + type( ADskDriver_Flags ), intent( out) :: CLFlags !< Flags indicating which command line arguments were specified + type( ADskDriver_Settings ), intent( out) :: CLSettings !< Command line arguments passed in + integer(IntKi), intent( out) :: ErrStat + CHARACTER(*), intent( out) :: ErrMsg + + ! Local variable + integer(IntKi) :: i !< Generic counter + character(1024) :: Arg !< argument given + character(1024) :: ArgUC !< Upper case argument to check + integer(IntKi) :: NumInputArgs !< Number of argements passed in from command line + logical :: adskFlag !< The -adsk flag was set + character(1024) :: FileName !< Filename from the command line. + logical :: FileNameGiven !< Flag indicating if a filename was given. + integer(IntKi) :: ErrStatTmp !< Temporary error status (for calls) + character(1024) :: ErrMsgTmp !< Temporary error message (for calls) + + ! initialize some things + CLFlags%DvrIptFile = .FALSE. + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + ErrMsg = '' + ErrMsgTmp = '' + adskFlag = .FALSE. + FileNameGiven = .FALSE. + FileName = '' + + ! Check how many arguments are passed in + NumInputArgs = COMMAND_ARGUMENT_COUNT() + + ! exit if we don't have enough + IF (NumInputArgs == 0) THEN + CALL SetErrStat(ErrID_Fatal," Insufficient Arguments. Use option "//SwChar//"help for help menu.", & + ErrStat,ErrMsg,'RetrieveArgs') + RETURN + ENDIF + + + ! Loop through all the arguments, and store them + DO i=1,NumInputArgs + ! get the ith argument + CALL get_command_argument(i, Arg) + ArgUC = Arg + + ! convert to uppercase + CALL Conv2UC( ArgUC ) + + ! Check to see if it is a control parameter or the filename + IF ( INDEX( SwChar, ArgUC(1:1) ) > 0 ) THEN + + ! check to see if we asked for help + IF ( ArgUC(2:5) == "HELP" ) THEN + CALL DispHelpText() + CALL ProgExit(0) + ENDIF + + + ! Check the argument and put it where it belongs + ! chop the SwChar off before passing the argument + CALL ParseArg( CLSettings, CLFlags, ArgUC(2:), Arg(2:), adskFlag, ErrStatTmp, ErrMsgTmp ) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'RetrieveArgs') + IF (ErrStat>AbortErrLev) RETURN + + ELSE + + ! since there is no switch character, assume it is the filename, unless we already set one + IF ( FileNameGiven ) THEN + CALL SetErrStat(ErrID_Fatal," Multiple driver input filenames given: "//TRIM(FileName)//", "//TRIM(Arg), & + ErrStat,ErrMsg,'RetrieveArgs') + RETURN + ELSE + FileName = TRIM(Arg) + FileNameGiven = .TRUE. + ENDIF + + ENDIF + END DO + + + ! Was a filename given? + IF ( .NOT. FileNameGiven ) THEN + CALL SetErrStat( ErrID_Fatal, " No filename given.", ErrStat, ErrMsg, 'RetrieveArgs' ) + RETURN + ENDIF + + ! Was the -adsk flag set? If so, the filename is the AeroDisk input file. Otherwise + ! it is the driver input file. + IF ( adskFlag ) THEN + CLSettings%ADskIptFileName = TRIM(FileName) + CLFlags%ADskIptFile = .TRUE. + ELSE + CLSettings%DvrIptFileName = TRIM(FileName) + CLFlags%DvrIptFile = .TRUE. + ENDIF + + + + !------------------------------------------------------------------------------- + !------------------------------------------------------------------------------- + CONTAINS + + + !------------------------------------------------------------------------------- + !> Convert a string to a real number + FUNCTION StringToReal( StringIn, ErrStat ) + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT(IN ) :: StringIn + + REAL(ReKi) :: StringToReal + INTEGER(IntKi) :: ErrStatTmp ! Temporary variable to hold the error status + + read( StringIn, *, iostat=ErrStatTmp) StringToReal + + ! If that isn't a number, only warn since we can continue by skipping this value + IF ( ErrStatTmp .ne. 0 ) ErrStat = ErrID_Warn + + END FUNCTION StringToReal + + + + !------------------------------------------------------------------------------- + SUBROUTINE ParseArg( CLSettings, CLFlags, ThisArgUC, ThisArg, adskFlagSet, ErrStat, ErrMsg ) + !-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-! + ! Parse and store the input argument ! + !-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-! + + USE NWTC_Library + USE AeroDisk_Driver_Types + USE AeroDisk_Types + + IMPLICIT NONE + + ! Storing the arguments + TYPE( ADskDriver_Flags ), INTENT(INOUT) :: CLFlags ! Flags indicating which arguments were specified + TYPE( ADskDriver_Settings ), INTENT(INOUT) :: CLSettings ! Arguments passed in + + CHARACTER(*), INTENT(IN ) :: ThisArgUC ! The current argument (upper case for testing) + CHARACTER(*), INTENT(IN ) :: ThisArg ! The current argument (as passed in for error messages) + LOGICAL, INTENT(INOUT) :: adskFlagSet ! Was the -adsk flag given? + + ! Error Handling + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + + ! local variables + INTEGER(IntKi) :: Delim1 ! where the [ is + INTEGER(IntKi) :: Delim2 ! where the ] is + INTEGER(IntKi) :: DelimSep ! where the : is + REAL(ReKi) :: TempReal ! temp variable to hold a real + + INTEGER(IntKi) :: ErrStatTmp ! Temporary error status for calls + + + + ! Initialize some things + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + ErrMsg = '' + + ! Get the delimiters -- returns 0 if there isn't one + Delim1 = INDEX(ThisArgUC,'[') + Delim2 = INDEX(ThisArgUC,']') + DelimSep = INDEX(ThisArgUC,':') + + + ! check that if there is an opening bracket, then there is a closing one + IF ( (Delim1 > 0_IntKi ) .and. (Delim2 < Delim1) ) THEN + CALL SetErrStat(ErrID_Warn," Syntax error in option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArg') + RETURN + ENDIF + + ! check that if there is a colon, then there are brackets + IF ( (DelimSep > 0_IntKi) .and. (Delim1 == 0_IntKi) ) THEN + CALL SetErrStat(ErrID_Warn," Syntax error in option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArg') + RETURN + ENDIF + + + ! If no delimeters were given, than this option is simply a flag + IF ( Delim1 == 0_IntKi ) THEN + ! check to see if the filename is the name of the ADsk input file + IF ( ThisArgUC(1:4) == "ADSK" ) THEN + adskFlagSet = .TRUE. ! More logic in the routine that calls this one to set things. + RETURN + ELSEIF ( ThisArgUC(1:2) == "VV" ) THEN + CLFlags%VVerbose = .TRUE. + RETURN + ELSEIF ( ThisArgUC(1:1) == "V" ) THEN + CLFlags%Verbose = .TRUE. + RETURN + ELSE + CALL SetErrStat( ErrID_Warn," Unrecognized option '"//SwChar//TRIM(ThisArg)//"'. Ignoring. Use option "//SwChar//"help for list of options.", & + ErrStat,ErrMsg,'ParseArg') + ENDIF + + ENDIF + + + ! "DT[#]" + IF( ThisArgUC(1:Delim1) == "DT[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%Dt = .TRUE. + CLSettings%DT = abs(TempReal) + ELSE + CLFlags%Dt = .FALSE. + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF + + + ! "TSTEPS[#]" + ELSEIF( ThisArgUC(1:Delim1) == "TSTEPS[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%NumTimeSteps = .TRUE. + CLSettings%NumTimeSteps = nint(abs(TempReal)) + ELSE + CLFlags%NumTimeSteps = .FALSE. + CLSettings%NumTimeSteps = 1_IntKi + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF + + + + ! "TSTART[#]" + ELSEIF( ThisArgUC(1:Delim1) == "TSTART[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%TStart = .TRUE. + CLSettings%TStart = abs(TempReal) + ELSE + CLFlags%TStart = .FALSE. + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF +!FIXME: add in the other inputs here. + + ELSE + ErrMsg = " Unrecognized option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring. Use option "//SwChar//"help for list of options." + ErrStat = ErrID_Warn + ENDIF + + END SUBROUTINE ParseArg + !------------------------------------------------------------------------------- + +END SUBROUTINE RetrieveArgs + + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> This subroutine reads the driver input file and sets up the flags and settings +!! for the driver code. Any settings from the command line options will override +!! this. +SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat, ErrMsg ) + + CHARACTER(1024), INTENT(IN ) :: DvrFileName + TYPE(ADskDriver_Flags), INTENT(INOUT) :: DvrFlags + TYPE(ADskDriver_Settings), INTENT(INOUT) :: DvrSettings + TYPE(ProgDesc), INTENT(IN ) :: ProgInfo + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! returns a non-zero value when an error occurs + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + ! Local variables + INTEGER(IntKi) :: UnIn ! Unit number for the driver input file + CHARACTER(1024) :: FileName ! Name of AeroDisk driver input file + + ! Input file echoing + LOGICAL :: EchoFileContents ! Do we echo the driver file out or not? + INTEGER(IntKi) :: UnEchoLocal ! The local unit number for this module's echo file + CHARACTER(1024) :: EchoFileName ! Name of AeroDisk driver echo file + + ! Time steps + CHARACTER(1024) :: InputChr ! Character string for timesteps and input file names (to handle DEFAULT or NONE value) + + ! Local error handling + INTEGER(IntKi) :: ios !< I/O status + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + CHARACTER(1024) :: ErrMsgTmp !< Temporary error messages for calls + + + ! Initialize the echo file unit to -1 which is the default to prevent echoing, we will alter this based on user input + UnEchoLocal = -1 + + FileName = TRIM(DvrFileName) + + CALL GetNewUnit( UnIn ) + CALL OpenFInpFile( UnIn, FileName, ErrStatTmp, ErrMsgTmp ) + IF ( ErrStatTmp /= ErrID_None ) THEN + CALL SetErrStat(ErrID_Fatal,' Failed to open AeroDisk Driver input file: '//FileName, & + ErrStat,ErrMsg,'ReadDvrIptFile') + CLOSE( UnIn ) + RETURN + ENDIF + + + CALL WrScr( 'Opening AeroDisk Driver input file: '//trim(FileName) ) + + + !------------------------------------------------------------------------------------------------- + ! File header + !------------------------------------------------------------------------------------------------- + + CALL ReadCom( UnIn, FileName,' AeroDisk Driver input file header line 1', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'AeroDisk Driver input file header line 2', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'AeroDisk Driver input file seperator line', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + ! Echo Input Files. + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + + ! If we are Echoing the input then we should re-read the first three lines so that we can echo them + ! using the NWTC_Library routines. The echoing is done inside those routines via a global variable + ! which we must store, set, and then replace on error or completion. + + IF ( EchoFileContents ) THEN + + EchoFileName = TRIM(FileName)//'.ech' + CALL GetNewUnit( UnEchoLocal ) + CALL OpenEcho ( UnEchoLocal, EchoFileName, ErrStatTmp, ErrMsgTmp, ProgInfo ) + if (Failed()) return + + REWIND(UnIn) + + ! Reread and echo + CALL ReadCom( UnIn, FileName,' AeroDisk Driver input file header line 1', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'AeroDisk Driver input file header line 2', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'AeroDisk Driver input file seperator line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Echo Input Files. + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ENDIF + + + !------------------------------------------------------------------------------------------------- + ! Driver setup section + !------------------------------------------------------------------------------------------------- + + ! Header + CALL ReadCom( UnIn, FileName,' Driver setup section, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! AeroDisk input file + CALL ReadVar( UnIn, FileName,DvrSettings%ADskIptFileName,'ADskIptFileName',' AeroDisk input filename', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) then + return + else + DvrFlags%ADskIptFile = .TRUE. + endif + + + ! TStart -- start time + CALL ReadVar( UnIn, FileName,DvrSettings%TStart,'TStart',' Time in wind file to start parsing.', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) then + return + else + DvrFlags%TStart = .TRUE. + endif + + + ! DT -- Timestep size for the driver to take (or DEFAULT for what the file contains) + CALL ReadVar( UnIn, FileName,InputChr,'InputChr',' Character string for Timestep size for the driver to take (or DEFAULT for what the file contains).', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Check if we asked for the DEFAULT (use what is in the file) + CALL Conv2UC( InputChr ) + IF ( TRIM(InputChr) == 'DEFAULT' ) THEN ! we asked for the default value + DvrFlags%DT = .TRUE. + DvrFlags%DTDefault = .TRUE. ! This flag tells us to use the inflow wind file values + ELSE + ! We probably have a number if it isn't 'DEFAULT', so do an internal read and check to + ! make sure that it was appropriately interpretted. + READ (InputChr,*,IOSTAT=IOS) DvrSettings%DT + IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. + CALL CheckIOS ( IOS, '', 'DT',NumType, ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ELSE ! Was ok, so set the flags + DvrFlags%DT = .TRUE. + DvrFlags%DTDefault = .FALSE. + ENDIF + ENDIF + + + ! Number of timesteps + CALL ReadVar( UnIn, FileName,InputChr,'InputChr',' Character string for number of timesteps to read.', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Check if we asked for the DEFAULT (use what is in the file) + CALL Conv2UC( InputChr ) + IF ( TRIM(InputChr) == 'DEFAULT' ) THEN ! we asked for the default value + DvrFlags%NumTimeSteps = .FALSE. + DvrFlags%NumTimeStepsDefault = .TRUE. ! This flag tells us to use the inflow wind file values + ELSE + ! We probably have a number if it isn't 'DEFAULT', so do an internal read and check to + ! make sure that it was appropriately interpretted. + READ (InputChr,*,IOSTAT=IOS) DvrSettings%NumTimeSteps + IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. + CALL CheckIOS ( IOS, '', 'NumTimeSteps',NumType, ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ELSE ! Was ok, so set the flags + DvrFlags%NumTimeSteps = .TRUE. + DvrFlags%NumTimeStepsDefault = .FALSE. + ENDIF + ENDIF + + + + !------------------------------------------------------------------------------------------------- + ! AeroDisk time series input -- this is read from a file of 7 columns (time and 6 dof) + !------------------------------------------------------------------------------------------------- + + ! InputDispFile input file + CALL ReadVar( UnIn, FileName,InputChr,'InputDispFile',' AeroDisk input displacements filename', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + DvrSettings%InputDispFile = InputChr + call Conv2UC( InputChr ) + if (trim(InputChr) == 'NONE') then + DvrSettings%InputDispFile = '' + DvrFlags%InputDispFile = .FALSE. + else + DvrFlags%InputDispFile = .TRUE. + endif + + + ! Close the echo and input file + CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) + CLOSE( UnIn ) + + +CONTAINS + + !> Set error status, close stuff, and return + logical function Failed() + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'ReadDvrIptFile') + if (ErrStat >= AbortErrLev) then + CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) + CLOSE( UnIn ) + endif + Failed = ErrStat >= AbortErrLev + end function Failed + + !> Clean up the module echo file + subroutine CleanupEchoFile( EchoFlag, UnEcho) + logical, intent(in ) :: EchoFlag ! local version of echo flag + integer(IntKi), intent(in ) :: UnEcho ! echo unit number + + ! Close this module's echo file + if ( EchoFlag ) then + close(UnEcho) + endif + END SUBROUTINE CleanupEchoFile + +END SUBROUTINE ReadDvrIptFile + + +!> This subroutine copies an command line (CL) settings over to the program settings. Warnings are +!! issued if anything is changed from what the driver input file requested. +SUBROUTINE UpdateSettingsWithCL( DvrFlags, DvrSettings, CLFlags, CLSettings, DVRIPT, ErrStat, ErrMsg ) + + TYPE(ADskDriver_Flags), INTENT(INOUT) :: DvrFlags + TYPE(ADskDriver_Settings), INTENT(INOUT) :: DvrSettings + TYPE(ADskDriver_Flags), INTENT(IN ) :: CLFlags + TYPE(ADskDriver_Settings), INTENT(IN ) :: CLSettings + LOGICAL, INTENT(IN ) :: DVRIPT + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + + ! Local variables + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + CHARACTER(1024) :: ErrMsgTmp !< Temporary error status for calls + LOGICAL :: WindGridModify !< Did we modify any of the WindGrid related settings? + character(*), parameter :: RoutineName = 'UpdateSettingsWithCL' + + ! Initialization + WindGridModify = .FALSE. + + ! Initialize the error handling + ErrStat = ErrID_None + ErrMsg = '' + ErrStatTmp = ErrID_None + ErrMsgTmp = '' + + + !-------------------------------------------- + ! Did we change any time information? + !-------------------------------------------- + + ! Check TStart + IF ( CLFlags%TStart ) THEN + IF ( DvrFlags%TStart .AND. ( .NOT. EqualRealNos(DvrSettings%TStart, CLSettings%TStart) ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for TStart with '//TRIM(Num2LStr(CLSettings%TStart))//'.', & + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%TStart = .TRUE. + ENDIF + DvrSettings%TStart = CLSettings%TStart + ENDIF + + ! Check DT + IF ( CLFlags%DT ) THEN + IF ( DvrFlags%DT .AND. ( .NOT. EqualRealNos(DvrSettings%DT, CLSettings%DT) ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for DT with '//TRIM(Num2LStr(CLSettings%DT))//'.', & + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%DT = .TRUE. + ENDIF + DvrSettings%DT = CLSettings%DT + DvrFlags%DTDefault = .FALSE. + ENDIF + + ! Check NumTimeSteps + IF ( CLFlags%NumTimeSteps ) THEN + IF ( DvrFlags%NumTimeSteps .AND. ( DvrSettings%NumTimeSteps /= CLSettings%NumTimeSteps ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for NumTimeSteps with '// & + TRIM(Num2LStr(CLSettings%NumTimeSteps))//'.',& + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%NumTimeSteps = .TRUE. + ENDIF + DvrSettings%NumTimeSteps = CLSettings%NumTimeSteps + DvrFlags%NumTimeStepsDefault = .FALSE. + ENDIF + + ! Make sure there is at least one timestep + DvrSettings%NumTimeSteps = MAX(DvrSettings%NumTimeSteps,1_IntKi) + + + !-------------------------------------------- + ! If there was no driver input file, we need to set a few things. + !-------------------------------------------- + + IF ( .NOT. DVRIPT ) THEN + + ! Do we need to set the NumTimeStepsDefault flag? + IF ( .NOT. DvrFlags%NumTimeSteps ) THEN + DvrFlags%NumTimeStepsDefault = .TRUE. + CALL SetErrStat( ErrID_Info,' The number of timesteps is not specified. Defaulting to what is in the input series file.', & + ErrStat,ErrMsg,RoutineName) + ENDIF + ENDIF + + +!FIXME: remove this after parsing rest of input file. + ! If no DT value has been set (DEFAULT requested), we need to set a default to pass into ADsk + IF ( .NOT. DvrFlags%DT ) THEN + DvrSettings%DT = 0.025_DbKi ! This value gets passed into the ADsk_Init routine, so something must be set. + ENDIF + + +END SUBROUTINE UpdateSettingsWithCL + + + +SUBROUTINE ReadInputDispFile( InputDispFile, DisplacementList, ErrStat, ErrMsg ) + CHARACTER(1024), INTENT(IN ) :: InputDispFile !< Name of the points file to read + REAL(R8Ki), ALLOCATABLE, INTENT( OUT) :: DisplacementList(:,:) !< The coordinates we read in: idx 1 = timestep, idx 2 = values + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< The error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< The message for the status + + ! Local variables + CHARACTER(1024) :: ErrMsgTmp !< Temporary error message for calls + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + INTEGER(IntKi) :: FiUnitPoints !< Unit number for points file to open + + INTEGER(IntKi) :: NumDataColumns !< Number of data columns + INTEGER(IntKi) :: NumDataPoints !< Number of lines of data (one point per line) + INTEGER(IntKi) :: NumHeaderLines !< Number of header lines to ignore + + INTEGER(IntKi) :: I !< Generic counter + character(*), parameter :: RoutineName = 'ReadInputDispFile' + + ! Initialization of subroutine + ErrMsg = '' + ErrMsgTmp = '' + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + + + ! Now open file + CALL GetNewUnit( FiUnitPoints, ErrStatTmp, ErrMsgTmp ); if (Failed()) return + CALL OpenFInpFile( FiUnitPoints, TRIM(InputDispFile), ErrStatTmp, ErrMsgTmp ) ! Unformatted input file + if (Failed()) return + + ! Find out how long the file is + CALL GetFileLength( FiUnitPoints, InputDispFile, NumDataColumns, NumDataPoints, NumHeaderLines, ErrMsgTmp, ErrStatTmp ) + if (Failed()) return + IF ( NumDataColumns /= 7 ) THEN + ErrStatTmp = ErrID_Fatal + ErrMsgTmp = ' Expecting seven columns in '//TRIM(InputDispFile)//' corresponding to '// & + 'time, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z coordinates. Instead found '//TRIM(Num2LStr(NumDataColumns))//' columns.' + if (Failed()) return + ENDIF + + + ! Allocate the storage for the data + CALL AllocAry( DisplacementList, NumDataPoints, 7, "Array of Points data", ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + + ! Read in the headers and throw them away + DO I=1,NumHeaderLines + CALL ReadCom( FiUnitPoints, InputDispFile,' Points file header line', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ENDDO + + ! Read in the datapoints -- This is arranged with time in first index for speed in later interpolation operations + DO I=1,NumDataPoints + CALL ReadAry ( FiUnitPoints, InputDispFile, DisplacementList(I,:), 7, 'DisplacementList', & + 'Coordinate point from Points file', ErrStatTmp, ErrMsgTmp) + if (Failed()) return + ENDDO + + CLOSE( FiUnitPoints ) + +CONTAINS + !> Set error status, close stuff, and return + logical function Failed() + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev .and. FiUnitPoints >0) close( FiUnitPoints ) + Failed = ErrStat >= AbortErrLev + end function Failed + + + !------------------------------------------------------------------------------------------------------------------------------- + !> This subroutine looks at a file that has been opened and finds out how many header lines there are, how many columns there + !! are, and how many lines of data there are in the file. + !! + !! A few things are assumed about the file: + !! 1. Any header lines are the first thing in the file. + !! 2. No text appears anyplace other than in first part of the file + !! 3. The datalines only contain numbers that can be read in as reals. + !! + !! Limitations: + !! 1. only handles up to 20 words (columns) on a line + !! 2. empty lines are considered text lines + !! 3. All data rows must contain the same number of columns + !! + !! + SUBROUTINE GetFileLength(UnitDataFile, DataFileName, NumDataColumns, NumDataLines, NumHeaderLines, ErrMsg, ErrStat) + + INTEGER(IntKi), INTENT(IN ) :: UnitDataFile !< Unit number of the file we are looking at. + CHARACTER(*), INTENT(IN ) :: DataFileName !< The name of the file we are looking at. + INTEGER(IntKi), INTENT( OUT) :: NumDataColumns !< The number of columns in the data file. + INTEGER(IntKi), INTENT( OUT) :: NumDataLines !< Number of lines containing data + INTEGER(IntKi), INTENT( OUT) :: NumHeaderLines !< Number of header lines at the start of the file + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error Message to return (empty if all good) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Status flag if there were any problems (ErrID_None if all good) + + ! Local Variables + CHARACTER(2048) :: ErrMsgTmp !< Temporary message variable. Used in calls. + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status. Used in calls. + INTEGER(IntKi) :: LclErrStat !< Temporary error status. Used locally to indicate when we have reached the end of the file. + INTEGER(IntKi) :: TmpIOErrStat !< Temporary error status for the internal read of the first word to a real number + LOGICAL :: IsRealNum !< Flag indicating if the first word on the line was a real number + + CHARACTER(1024) :: TextLine !< One line of text read from the file + INTEGER(IntKi) :: LineLen !< The length of the line read in + CHARACTER(1024) :: StrRead !< String containing the first word read in + REAL(R8Ki) :: RealRead !< Returns value of the number (if there was one), or NaN (as set by NWTC_Num) if there wasn't + CHARACTER(24) :: Words(20) !< Array of words we extract from a line. We shouldn't have more than 20. + INTEGER(IntKi) :: i !< simple integer counters + INTEGER(IntKi) :: LineNumber !< the line I am on + LOGICAL :: LineHasText !< Flag indicating if the line I just read has text. If so, it is a header line. + LOGICAL :: HaveReadData !< Flag indicating if I have started reading data. + INTEGER(IntKi) :: NumWords !< Number of words on a line + INTEGER(IntKi) :: FirstDataLineNum !< Line number of the first row of data in the file + + ! Initialize the error handling + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + LclErrStat = ErrID_None + ErrMsg = '' + ErrMsgTmp = '' + + ! Set some of the flags and counters + HaveReadData = .FALSE. + NumDataColumns = 0 + NumHeaderLines = 0 + NumDataLines = 0 + LineNumber = 0 + + ! Just in case we were handed a file that we are part way through reading (should never be true), rewind to the start + + REWIND( UnitDataFile ) + + !------------------------------------ + !> The variable LclErrStat is used to indicate when we have reached the end of the file or had an error from + !! ReadLine. Until that occurs, we read each line, and decide if it contained any non-numeric data. The + !! first group of lines containing non-numeric data is considered the header. The first line of all numeric + !! data is considered the start of the data section. Any non-numeric containing found within the data section + !! will be considered as an invalid file format at which point we will return a fatal error from this routine. + + DO WHILE ( LclErrStat == ErrID_None ) + + !> Reset the indicator flag for the non-numeric content + LineHasText = .FALSE. + + !> Read in a single line from the file + CALL ReadLine( UnitDataFile, '', TextLine, LineLen, LclErrStat ) + + !> If there was an error in reading the file, then exit. + !! Possible causes: reading beyond end of file in which case we are done so don't process it. + IF ( LclErrStat /= ErrID_None ) EXIT + + !> Increment the line counter. + LineNumber = LineNumber + 1 + + !> Read all the words on the line into the array called 'Words'. Only the first words will be encountered + !! will be stored. The others are empty (i.e. only three words on the line, so the remaining 17 are empty). + CALL GetWords( TextLine, Words, 20 ) + + !> Cycle through and count how many are not empty. Once an empty value is encountered, all the rest should + !! be empty if GetWords worked correctly. The index of the last non-empty value is stored. + DO i=1,20 + IF (TRIM(Words(i)) .ne. '') NumWords=i + ENDDO + + + !> Now cycle through the first 'NumWords' of non-empty values stored in 'Words'. Words should contain + !! everything that is one the line. The subroutine ReadRealNumberFromString will set a flag 'IsRealNum' + !! when the value in Words(i) can be read as a real(R8Ki). 'StrRead' will contain the string equivalent. + DO i=1,NumWords + CALL ReadRealNumberFromString( Words(i), RealRead, StrRead, IsRealNum, ErrStatTmp, ErrMsgTmp, TmpIOErrStat ) + IF ( .NOT. IsRealNum) LineHasText = .TRUE. + ENDDO + + !> If all the words on that line had no text in them, then it must have been a line of data. + !! If not, then we have either a header line, which is ok, or a line containing text in the middle of the + !! the data section, which is not good (the flag HaveReadData tells us which case this is). + IF ( LineHasText ) THEN + IF ( HaveReadData ) THEN ! Uh oh, we have already read a line of data before now, so there is a problem + CALL SetErrStat( ErrID_Fatal, ' Found text on line '//TRIM(Num2LStr(LineNumber))//' of '//TRIM(DataFileName)// & + ' when real numbers were expected. There may be a problem with format of the file: '// & + TRIM(DataFileName)//'.', ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ELSE + NumHeaderLines = NumHeaderLines + 1 + ENDIF + ELSE ! No text, must be data line + NumDataLines = NumDataLines + 1 + ! If this is the first row of data, then store the number of words that were on the line + IF ( .NOT. HaveReadData ) THEN + ! If this is the first line of data, keep some relevant info about it and the number of columns in it + HaveReadData = .TRUE. + FirstDataLineNum = LineNumber ! Keep the line number of the first row of data (for error reporting) + NumDataColumns = NumWords + ELSE + ! Make sure that the number columns on the row matches the number of columnns on the first row of data. + IF ( NumWords /= NumDataColumns ) THEN + CALL SetErrStat( ErrID_Fatal, ' Error in file: '//TRIM(DataFileName)//'.'// & + ' The number of data columns on line '//TRIM(Num2LStr(LineNumber))// & + '('//TRIM(Num2LStr(NumWords))//' columns) is different than the number of columns on first row of data '// & + ' (line: '//TRIM(Num2LStr(FirstDataLineNum))//', '//TRIM(Num2LStr(NumDataColumns))//' columns).', & + ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ENDIF + ENDIF + ENDIF + + ENDDO + + REWIND( UnitDataFile ) + + END SUBROUTINE GetFileLength + + !------------------------------------------------------------------------------- + !> This subroutine takes a line of text that is passed in and reads the first + !! word to see if it is a number. An internal read is used to do this. If + !! it is a number, it is started in ValueRead and returned. The flag IsRealNum + !! is set to true. Otherwise, ValueRead is set to NaN (value from the NWTC_Num) + !! and the flag is set to false. + !! + !! The IsRealNum flag is set to indicate if we actually have a real number or + !! not. After calling this routine, a simple if statement can be used: + !! + !! @code + !! IF (IsRealNum) THEN + !! ! do something + !! ELSE + !! ! do something else + !! ENDIF + !! @endcode + !! + !------------------------------------------------------------------------------- + SUBROUTINE ReadRealNumberFromString(StringToParse, ValueRead, StrRead, IsRealNum, ErrStat, ErrMsg, IOErrStat) + CHARACTER(*), INTENT(IN ) :: StringToParse !< The string we were handed. + REAL(R8Ki), INTENT( OUT) :: ValueRead !< The variable being read. Returns as NaN (library defined) if not a Real. + CHARACTER(*), INTENT( OUT) :: StrRead !< A string containing what was read from the ReadNum routine. + LOGICAL, INTENT( OUT) :: IsRealNum !< Flag indicating if we successfully read a Real + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< ErrID level returned from ReadNum + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message including message from ReadNum + INTEGER(IntKi), INTENT( OUT) :: IOErrStat !< Error status from the internal read. Useful for diagnostics. + + ErrStat = ErrID_None + ErrMsg = '' + + ! ReadNum returns a string contained in StrRead. So, we now try to do an internal read to VarRead and then trap errors. + read(StringToParse,*,IOSTAT=IOErrStat) StrRead + read(StringToParse,*,IOSTAT=IOErrStat) ValueRead + + ! If IOErrStat==0, then we have a real number, anything else is a problem. + if (IOErrStat==0) then + IsRealNum = .TRUE. + else + IsRealNum = .FALSE. + ValueRead = NaN ! This is NaN as defined in the NWTC_Num. + ErrMsg = 'Not a real number. '//TRIM(ErrMsgTmp)//NewLine + ErrSTat = ErrID_Severe + endif + + RETURN + END SUBROUTINE ReadRealNumberFromString + + !------------------------------------------------------------------------------- + !> This subroutine works with the ReadNum routine from the library. ReadNum is + !! called to read a word from the input file. An internal read is then done to + !! convert the string to a number that is stored in VarRead and returned. + !! + !! The IsRealNum flag is set to indicate if we actually have a real number or + !! not. After calling this routine, a simple if statement can be used: + !! + !! @code + !! IF (ISRealNum) THEN + !! ! do something + !! ELSE + !! ! do something else + !! ENDIF + !! @endcode + !! + !------------------------------------------------------------------------------- + SUBROUTINE ReadRealNumber(UnitNum, FileName, VarName, VarRead, StrRead, IsRealNum, ErrStat, ErrMsg, IOErrStat) + INTEGER(IntKi), INTENT(IN ) :: UnitNum !< The unit number of the file being read + CHARACTER(*), INTENT(IN ) :: FileName !< The name of the file being read. Used in the ErrMsg from ReadNum (Library routine). + CHARACTER(*), INTENT(IN ) :: VarName !< The variable we are reading. Used in the ErrMsg from ReadNum (Library routine)'. + REAL(R8Ki), INTENT( OUT) :: VarRead !< The variable being read. Returns as NaN (library defined) if not a Real. + CHARACTER(*), INTENT( OUT) :: StrRead !< A string containing what was read from the ReadNum routine. + LOGICAL, INTENT( OUT) :: IsRealNum !< Flag indicating if we successfully read a Real + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< ErrID level returned from ReadNum + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message including message from ReadNum + INTEGER(IntKi), INTENT( OUT) :: IOErrStat !< Error status from the internal read. Useful for diagnostics. + + INTEGER(IntKi) :: ErrStatTmp + CHARACTER(2048) :: ErrMsgTmp + + ErrStat = ErrID_None + ErrMsg = '' + + ! Now call the ReadNum routine to get the number + ! If it is a word that does not start with T or F, then ReadNum won't give any errors. + CALL ReadNum( UnitNum, FileName, StrRead, VarName, ErrStatTmp, ErrMsgTmp) + + ! ReadNum returns a string contained in StrRead. So, we now try to do an internal read to VarRead and then trap errors. + read(StrRead,*,IOSTAT=IOErrStat) VarRead + + ! If IOErrStat==0, then we have a real number, anything else is a problem. + if (IOErrStat==0) then + IsRealNum = .TRUE. + else + IsRealNum = .FALSE. + VarRead = NaN ! This is NaN as defined in the NWTC_Num. + ErrMsg = 'Not a real number. '//TRIM(ErrMsgTmp)//NewLine + ErrStat = ErrStatTmp ! The ErrStatTmp returned by the ReadNum routine is an ErrID level. + endif + RETURN + END SUBROUTINE ReadRealNumber + +END SUBROUTINE ReadInputDispFile + + + + +!> This routine exists only to support the development of the module. It will not be needed after the module is complete. +SUBROUTINE printSettings( DvrFlags, DvrSettings ) + ! The arguments + TYPE( ADskDriver_Flags ), INTENT(IN ) :: DvrFlags !< Flags indicating which settings were set + TYPE( ADskDriver_Settings ), INTENT(IN ) :: DvrSettings !< Stored settings + + CALL WrsCr(TRIM(GetNVD(DvrSettings%ProgInfo))) + CALL WrScr(' DvrIptFile: '//FLAG(DvrFlags%DvrIptFile)// ' '//TRIM(DvrSettings%DvrIptFileName)) + CALL WrScr(' ADskIptFile: '//FLAG(DvrFlags%ADskIptFile)// ' '//TRIM(DvrSettings%ADskIptFileName)) + CALL WrScr(' TStart: '//FLAG(DvrFlags%TStart)// ' '//TRIM(Num2LStr(DvrSettings%TStart))) + IF ( DvrFlags%DTDefault) THEN + CALL WrScr(' DT: '//FLAG(DvrFlags%DT)// ' DEFAULT') + ELSE + CALL WrScr(' DT: '//FLAG(DvrFlags%DT)// ' '//TRIM(Num2LStr(DvrSettings%DT))) + ENDIF + IF ( DvrFlags%NumTimeStepsDefault) THEN + CALL WrScr(' NumTimeSteps: '//FLAG(DvrFlags%NumTimeSteps)// ' DEFAULT') + ELSE + CALL WrScr(' NumTimeSteps: '//FLAG(DvrFlags%NumTimeSteps)// ' '//TRIM(Num2LStr(DvrSettings%NumTimeSteps))) + ENDIF + CALL WrScr(' Verbose: '//FLAG(DvrFlags%Verbose)) + CALL WrScr(' VVerbose: '//FLAG(DvrFlags%VVerbose)) + RETURN +END SUBROUTINE printSettings + + +!> This routine exists only to support the development of the module. It will not be kept after the module is complete. +!! This routine takes a flag setting (LOGICAL) and exports either 'T' or '-' for T/F (respectively) +FUNCTION FLAG(flagval) + LOGICAL, INTENT(IN ) :: flagval !< Value of the flag + CHARACTER(1) :: FLAG !< character interpretation (for prettiness when printing) + IF ( flagval ) THEN + FLAG = 'T' + ELSE + FLAG = '-' + ENDIF + RETURN +END FUNCTION FLAG + + +SUBROUTINE Dvr_InitializeOutputFile(OutUnit,IntOutput,RootName,ErrStat,ErrMsg) + integer(IntKi), intent( out):: OutUnit + type(ADsk_InitOutputType), intent(in ):: IntOutput ! Output for initialization routine + integer(IntKi), intent( out):: ErrStat ! Error status of the operation + character(*), intent( out):: ErrMsg ! Error message if ErrStat /= ErrID_None + character(*), intent(in ):: RootName + integer(IntKi) :: i + integer(IntKi) :: numOuts + integer(IntKi) :: ErrStat2 ! Temporary Error status + character(ErrMsgLen) :: ErrMsg2 ! Temporary Error message + character(*), parameter :: RoutineName = 'Dvr_InitializeOutputFile' + + ErrStat = ErrID_none + ErrMsg = "" + + CALL GetNewUnit(OutUnit,ErrStat2,ErrMsg2) + CALL OpenFOutFile ( OutUnit, trim(RootName)//'.out', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) return + + write (OutUnit,'(/,A)') 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//trim(GetNVD(IntOutput%Ver)) + write (OutUnit,'()' ) !print a blank line + + numOuts = size(IntOutput%WriteOutputHdr) + !...................................................... + ! Write the names of the output parameters on one line: + !...................................................... + + write (OutUnit,'()') + write (OutUnit,'()') + write (OutUnit,'()') + + call WrFileNR ( OutUnit, 'Time' ) + + do i=1,NumOuts + call WrFileNR ( OutUnit, tab//IntOutput%WriteOutputHdr(i) ) + end do ! i + + write (OutUnit,'()') + + !...................................................... + ! Write the units of the output parameters on one line: + !...................................................... + + call WrFileNR ( OutUnit, '(s)' ) + + do i=1,NumOuts + call WrFileNR ( Outunit, tab//trim(IntOutput%WriteOutputUnt(i)) ) + end do ! i + + write (OutUnit,'()') + + +END SUBROUTINE Dvr_InitializeOutputFile + +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE Dvr_WriteOutputLine(t,OutUnit, OutFmt, Output) + real(DbKi) , intent(in ) :: t ! simulation time (s) + integer(IntKi) , intent(in ) :: OutUnit ! Status of error message + character(*) , intent(in ) :: OutFmt + type(ADsk_OutputType), intent(in ) :: Output + integer(IntKi) :: errStat ! Status of error message (we're going to ignore errors in writing to the file) + character(ErrMsgLen) :: errMsg ! Error message if ErrStat /= ErrID_None + character(200) :: frmt ! A string to hold a format specifier + character(15) :: tmpStr ! temporary string to print the time output as text + + frmt = '"'//tab//'"'//trim(OutFmt) ! format for array elements from individual modules + + ! time + write( tmpStr, '(F15.6)' ) t + call WrFileNR( OutUnit, tmpStr ) + call WrNumAryFileNR ( OutUnit, Output%WriteOutput, frmt, errStat, errMsg ) + + ! write a new line (advance to the next line) + write (OutUnit,'()') +end subroutine Dvr_WriteOutputLine + + +END MODULE AeroDisk_Driver_Subs diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 new file mode 100644 index 0000000000..5197f274d9 --- /dev/null +++ b/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 @@ -0,0 +1,69 @@ +!********************************************************************************************************************************** +! +! MODULE: ADsk_Driver_Types - This module contains types used by the AeroDisk Driver program to store arguments passed in +! +! The types listed here are used within the AeroDisk Driver program to store the settings. These settings are read in as +! command line arguments, then stored within these types. +! +!********************************************************************************************************************************** +! +!.................................................................................................................................. +! LICENSING +! Copyright (C) 2015 National Renewable Energy Laboratory +! +! This file is part of AeroDisk. +! +! AeroDisk is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as +! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along with AeroDisk. +! If not, see . +! +!********************************************************************************************************************************** +module AeroDisk_Driver_Types + + use NWTC_Library + use AeroDisk_Types + + implicit none + + !> This contains flags to note if the settings were made. This same data structure is + !! used both during the driver input file and the command line options. + !! + !! NOTE: The WindFileType is only set if it is given as a command line option. Otherwise + !! it is handled internally by InflowWInd. + !! + !! NOTE: The wind direction is specified by the AeroDisk input file. + type :: ADskDriver_Flags + logical :: DvrIptFile = .FALSE. !< Was an input file name given on the command line? + logical :: ADskIptFile = .FALSE. !< Was an AeroDisk input file requested? + logical :: InputDispFile = .FALSE. !< Input displacement time series + logical :: TStart = .FALSE. !< specified a start time + logical :: NumTimeSteps = .FALSE. !< specified a number of timesteps to process + logical :: NumTimeStepsDefault = .FALSE. !< specified a 'DEFAULT' for number of timesteps to process + logical :: DT = .FALSE. !< specified a resolution in time + logical :: DTDefault = .FALSE. !< specified a 'DEFAULT' for the time resolution + logical :: Verbose = .FALSE. !< Verbose error reporting + logical :: VVerbose = .FALSE. !< Very Verbose error reporting + end type ADskDriver_Flags + + + ! This contains all the settings (possible passed in arguments). + type :: ADskDriver_Settings + character(1024) :: DvrIptFileName !< Driver input file name + character(1024) :: ADskIptFileName !< Filename of AeroDisk input file to read (if no driver input file) + character(1024) :: InputDispFile !< Filename of AeroDisk time series displacements + + integer(IntKi) :: NumTimeSteps !< Number of timesteps + real(DbKi) :: DT !< resolution of time + real(DbKi) :: TStart !< Start time + + type(ProgDesc) :: ProgInfo !< Program info + type(ProgDesc) :: ADskProgInfo !< Program info for AeroDisk + end type ADskDriver_Settings + + +end module AeroDisk_Driver_Types From 9bbd523793d099ae3e96566251e25fced7c95113 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 15 Feb 2022 14:07:43 -0700 Subject: [PATCH 020/130] SED: add rough code placeholders and rough driver placeholder It all compiles, but does nothing --- modules/simple-elastodyn/CMakeLists.txt | 15 +- modules/simple-elastodyn/src/SED.f90 | 320 +++++ modules/simple-elastodyn/src/SED_IO.f90 | 52 + .../src/SED_Output_Params.f90 | 5 + modules/simple-elastodyn/src/SED_Registry.txt | 4 +- modules/simple-elastodyn/src/SED_Types.f90 | 7 + .../src/driver/SED_Driver.f90 | 342 +++++ .../src/driver/SED_Driver_Subs.f90 | 1126 +++++++++++++++++ .../src/driver/SED_Driver_Types.f90 | 69 + 9 files changed, 1936 insertions(+), 4 deletions(-) create mode 100644 modules/simple-elastodyn/src/SED.f90 create mode 100644 modules/simple-elastodyn/src/SED_IO.f90 create mode 100644 modules/simple-elastodyn/src/SED_Output_Params.f90 create mode 100644 modules/simple-elastodyn/src/driver/SED_Driver.f90 create mode 100644 modules/simple-elastodyn/src/driver/SED_Driver_Subs.f90 create mode 100644 modules/simple-elastodyn/src/driver/SED_Driver_Types.f90 diff --git a/modules/simple-elastodyn/CMakeLists.txt b/modules/simple-elastodyn/CMakeLists.txt index c77fea1092..0341197593 100644 --- a/modules/simple-elastodyn/CMakeLists.txt +++ b/modules/simple-elastodyn/CMakeLists.txt @@ -20,14 +20,23 @@ endif() set(SED_SOURCES src/SED_Types.f90 + src/SED_Output_Params.f90 + src/SED_IO.f90 + src/SED.f90 ) - #src/SED.f90 - #src/SED_IO.f90 add_library(sedlib ${SED_SOURCES}) target_link_libraries(sedlib nwtclibs) -install(TARGETS sedlib +set(SED_DRIVER_SOURCES + src/driver/SED_Driver_Types.f90 + src/driver/SED_Driver_Subs.f90 + src/driver/SED_Driver.f90 +) +add_executable(sed_driver ${SED_DRIVER_SOURCES}) +target_link_libraries(sed_driver sedlib nwtclibs versioninfolib ${CMAKE_DL_LIBS}) + +install(TARGETS sedlib sed_driver EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/modules/simple-elastodyn/src/SED.f90 b/modules/simple-elastodyn/src/SED.f90 new file mode 100644 index 0000000000..99a108b1c6 --- /dev/null +++ b/modules/simple-elastodyn/src/SED.f90 @@ -0,0 +1,320 @@ +!********************************************************************************************************************************** +!> ## SED +!! The SED module solves a quasi-steady actuator disk representation of the rotor to calculate the 3 forces and 3 moments of +!! the rotor dependent on the tip-speed ratio (TSR), rotor speed (RotSpeed), relative wind velocity vector (VRel), and the rotor- +!! collective blade-pitch (BlPitch). +!! +! .................................................................................................................................. +!! ## LICENSING +!! Copyright (C) 2022 National Renewable Energy Laboratory +!! +!! This file is part of SED. +!! +!! Licensed under the Apache License, Version 2.0 (the "License"); +!! you may not use this file except in compliance with the License. +!! You may obtain a copy of the License at +!! +!! http://www.apache.org/licenses/LICENSE-2.0 +!! +!! Unless required by applicable law or agreed to in writing, software +!! distributed under the License is distributed on an "AS IS" BASIS, +!! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +!! See the License for the specific language governing permissions and +!! limitations under the License. +!********************************************************************************************************************************** +MODULE SED + + USE SED_Types + USE SED_IO + USE NWTC_Library + + implicit none + private + type(ProgDesc), parameter :: SED_Ver = ProgDesc( 'SED', 'v1.00.00', '15-Feb-2022' ) + + public :: SED_Init + public :: SED_End + public :: SED_UpdateStates + public :: SED_CalcOutput + public :: SED_CalcContStateDeriv + + ! Linearization is not supported by this module, so the following routines are omitted + !public :: SED_CalcConstrStateResidual + !public :: SED_UpdateDiscState + !public :: SED_JacobianPInput + !public :: SED_JacobianPContState + !public :: SED_JacobianPDiscState + !public :: SED_JacobianPConstrState + !public :: SED_GetOP + +CONTAINS + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> Initialize the SED module: +!! - load settings (passed or from file) +!! - setup meshes +!! - initialize outputs and other data storage +SUBROUTINE SED_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut, ErrStat, ErrMsg ) + type(SED_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine + type(SED_InputType), intent( out) :: u !< An initial guess for the input; input mesh must be defined + type(SED_ParameterType), intent( out) :: p !< Parameters + type(SED_ContinuousStateType), intent( out) :: x !< Initial continuous states + type(SED_DiscreteStateType), intent( out) :: xd !< Initial discrete states + type(SED_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states + type(SED_OtherStateType), intent( out) :: OtherState !< Initial other states (logical, etc) + type(SED_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated) + type(SED_MiscVarType), intent( out) :: m !< Misc variables for optimization (not copied in glue code) + real(DbKi), intent(inout) :: Interval !< Coupling interval in seconds: the rate that + type(SED_InitOutputType), intent( out) :: InitOut !< Output for initialization routine + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: NumOuts ! number of outputs; would probably be in the parameter type + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'SED_Init' + + ! Initialize variables + ErrStat = ErrID_None + ErrMsg = "" + NumOuts = 2 + + ! Initialize the NWTC Subroutine Library + call NWTC_Init( ) + + ! Display the module information + call DispNVD( SED_Ver ) + + ! Define parameters here: + p%DeltaT = Interval + + ! Define initial system states here: +! x%DummyContState = 0.0_ReKi +! xd%DummyDiscState = 0.0_ReKi +! z%DummyConstrState = 0.0_ReKi +! OtherState%DummyOtherState = 0.0_ReKi + + ! Define optimization variables here: + m%DummyMiscVar = 0.0_ReKi + + ! Define initial guess for the system inputs here: +! u%DummyInput = 0.0_ReKi + +! call SetOutParams() + + ! Define system output initializations (set up mesh) here: + call AllocAry( y%WriteOutput, NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; + y%WriteOutput = 0 + + ! Define initialization-routine output here: + call AllocAry(InitOut%WriteOutputHdr,NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%WriteOutputUnt,NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; + InitOut%WriteOutputHdr = (/ 'Time ', 'Column2' /) + InitOut%WriteOutputUnt = (/ '(s)', '(-)' /) + + +!FIXME: any logic around this? + !Interval = p%DeltaT + + + if (InitInp%Linearize) then + CALL SetErrStat( ErrID_Fatal, 'SED cannot perform linearization analysis.', ErrStat, ErrMsg, RoutineName) + end if + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE SED_Init + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine is called at the end of the simulation. +SUBROUTINE SED_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) + type(SED_InputType), intent(inout) :: u !< System inputs + type(SED_ParameterType), intent(inout) :: p !< Parameters + type(SED_ContinuousStateType), intent(inout) :: x !< Continuous states + type(SED_DiscreteStateType), intent(inout) :: xd !< Discrete states + type(SED_ConstraintStateType), intent(inout) :: z !< Constraint states + type(SED_OtherStateType), intent(inout) :: OtherState !< Other states + type(SED_OutputType), intent(inout) :: y !< System outputs + type(SED_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'SED_End' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + !! Place any last minute operations or calculations here: + + !! Close files here (but because of checkpoint-restart capability, it is not recommended to have files open during the simulation): + + ! Destroy the input data: + call SED_DestroyInput( u, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the parameter data: + call SED_DestroyParam( p, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the state data: + call SED_DestroyContState( x, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call SED_DestroyDiscState( xd, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call SED_DestroyConstrState( z, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call SED_DestroyOtherState( OtherState, ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the output data: + call SED_DestroyOutput( y, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! Destroy the misc data: + call SED_DestroyMisc( m, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) +END SUBROUTINE SED_End + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a loose coupling routine for solving constraint states, integrating continuous states, and updating discrete and other +!! states. Continuous, constraint, discrete, and other states are updated to values at t + Interval. +SUBROUTINE SED_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + integer(IntKi), intent(in ) :: n !< Current step of the simulation: t = n*Interval + type(SED_InputType), intent(inout) :: Inputs(:) !< Inputs at InputTimes (output for mesh connect) + real(DbKi), intent(in ) :: InputTimes(:) !< Times in seconds associated with Inputs + type(SED_ParameterType), intent(in ) :: p !< Parameters + type(SED_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; + type(SED_DiscreteStateType), intent(inout) :: xd !< Input: Discrete states at t; + type(SED_ConstraintStateType), intent(inout) :: z !< Input: Constraint states at t; + type(SED_OtherStateType), intent(inout) :: OtherState !< Other states: Other states at t; + type(SED_MiscVarType), intent(inout) :: m !< Misc variables for optimization + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables + type(SED_ContinuousStateType) :: dxdt ! Continuous state derivatives at t + type(SED_InputType) :: u ! Instantaneous inputs + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'SED_UpdateStates' + + ! Initialize variables + ErrStat = ErrID_None ! no error has occurred + ErrMsg = "" + + ! Get the inputs at time t, based on the array of values sent by the glue code: + ! before calling ExtrapInterp routine, memory in u must be allocated; we can do that with a copy: + call SED_CopyInput( Inputs(1), u, MESH_NEWCOPY, ErrStat2, ErrMsg2 ); if (Failed()) return; + + call SED_Input_ExtrapInterp( Inputs, InputTimes, u, t, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Get first time derivatives of continuous states (dxdt): + call SED_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat2, ErrMsg2 ); if (Failed()) return; + + ! Integrate (update) continuous states (x) here: + !x = function of dxdt and x + + ! Destroy local variables before returning + call cleanup() + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine Cleanup() + ! Destroy data to prevent memory leaks + call SED_DestroyInput( u, ErrStat2, ErrMsg2) + call SED_DestroyContState( dxdt, ErrStat2, ErrMsg2) + end subroutine Cleanup +end subroutine SED_UpdateStates + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a routine for computing outputs, used in both loose and tight coupling. +SUBROUTINE SED_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(SED_InputType), intent(in ) :: u !< Inputs at t + type(SED_ParameterType), intent(in ) :: p !< Parameters + type(SED_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(SED_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(SED_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(SED_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(SED_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(SED_OutputType), intent(inout) :: y !< Outputs computed at t (Input only for mesh) + integer(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'SED_CalcOutput' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + ! Compute outputs here: + !y%DummyOutput = 2.0_ReKi + + y%WriteOutput(1) = REAL(t,ReKi) + y%WriteOutput(2) = 1.0_ReKi + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + !if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE SED_CalcOutput + + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This is a tight coupling routine for computing derivatives of continuous states. +SUBROUTINE SED_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrStat, ErrMsg ) + real(DbKi), intent(in ) :: t !< Current simulation time in seconds + type(SED_InputType), intent(in ) :: u !< Inputs at t + type(SED_ParameterType), intent(in ) :: p !< Parameters + type(SED_ContinuousStateType), intent(in ) :: x !< Continuous states at t + type(SED_DiscreteStateType), intent(in ) :: xd !< Discrete states at t + type(SED_ConstraintStateType), intent(in ) :: z !< Constraint states at t + type(SED_OtherStateType), intent(in ) :: OtherState !< Other states at t + type(SED_MiscVarType), intent(inout) :: m !< Misc variables for optimization (not copied in glue code) + type(SED_ContinuousStateType), intent( out) :: dxdt !< Continuous state derivatives at t + INTEGER(IntKi), intent( out) :: ErrStat !< Error status of the operation + character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + integer(IntKi) :: ErrStat2 ! local error status + character(ErrMsgLen) :: ErrMsg2 ! local error message + character(*), parameter :: RoutineName = 'SED_CalcContStateDeriv' + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + ! Compute the first time derivatives of the continuous states here: + !dxdt%DummyContState = 0.0_ReKi + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + +END SUBROUTINE SED_CalcContStateDeriv + + +END MODULE SED +!********************************************************************************************************************************** diff --git a/modules/simple-elastodyn/src/SED_IO.f90 b/modules/simple-elastodyn/src/SED_IO.f90 new file mode 100644 index 0000000000..bfece4ce68 --- /dev/null +++ b/modules/simple-elastodyn/src/SED_IO.f90 @@ -0,0 +1,52 @@ +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2020 National Renewable Energy Laboratory +! +! This file is part of SED +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +!********************************************************************************************************************************** +MODULE SED_IO + + USE SED_Types + USE SED_Output_Params + USE NWTC_Library + + implicit none + + +contains + +SUBROUTINE SED_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) + type(SED_InitInputType), intent(in ) :: InitInp !< Input data for initialization + type(SED_InputFile), intent(inout) :: InputFileData !< The data for initialization + integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine + character(*), intent( out) :: ErrMsg !< Error message from this subroutine + integer(IntKi) :: ErrStat2 !< Temporary error status for subroutine and function calls + character(ErrMsgLen) :: ErrMsg2 !< Temporary error message for subroutine and function calls + integer(IntKi) :: I !< Generic counter + character(*), parameter :: RoutineName="SED_ValidateInput" + integer(IntKi) :: IOS !< Temporary error status + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + +END SUBROUTINE SED_ValidateInput + + +!FIXME: add SetOutParam here + + +END MODULE SED_IO + diff --git a/modules/simple-elastodyn/src/SED_Output_Params.f90 b/modules/simple-elastodyn/src/SED_Output_Params.f90 new file mode 100644 index 0000000000..638cd224c9 --- /dev/null +++ b/modules/simple-elastodyn/src/SED_Output_Params.f90 @@ -0,0 +1,5 @@ +!> The parameters in this code are from the MATLAB autogeneration scripts. Do not manually edit unless also editing the OutListParamters.xls SED tab. +module SED_Output_Params + use NWTC_Library + +end module SED_Output_Params diff --git a/modules/simple-elastodyn/src/SED_Registry.txt b/modules/simple-elastodyn/src/SED_Registry.txt index 9f2c51de43..413913e6e3 100644 --- a/modules/simple-elastodyn/src/SED_Registry.txt +++ b/modules/simple-elastodyn/src/SED_Registry.txt @@ -43,6 +43,7 @@ typedef ^ SED_InputFile CHARACTER(ChanLen) OutList : - # inputs for initialization: typedef SED/SED InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - typedef ^ InitInputType CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ InitInputType LOGICAL Linearize - .false. - "Linearization not currently enabled" - # outputs from initialization: @@ -72,12 +73,13 @@ typedef ^ InputType ReKi YawRate - - # ..... Outputs ................................................................................................................... -# outputs not meshes: +# outputs on meshes: typedef ^ OutputType MeshType BladeRootMotion {:} - - "For AeroDyn/BeamDyn: motions at the blade roots" - typedef ^ OutputType MeshType HubPtMotion - - - "For AeroDyn and Lidar(InflowWind): motions of the hub" - typedef ^ OutputType MeshType NacelleMotion - - - "For AeroDyn14 & ServoDyn/TMD: motions of the nacelle." - typedef ^ OutputType MeshType TowerLn2Mesh - - - "Tower line2 mesh with positions/orientations/velocities/accelerations" - typedef ^ OutputType MeshType PlatformPtMesh - - - "Platform reference point positions/orientations/velocities/accelerations" - +#TODO: any mesh for visualization of blades/rotor disk? # outputs not on meshes: typedef ^ OutputType ReKi LSSTipPxa - - 2pi "Rotor azimuth angle (position)" radians typedef ^ OutputType ReKi RotSpeed - - - "Rotor azimuth angular speed" rad/s diff --git a/modules/simple-elastodyn/src/SED_Types.f90 b/modules/simple-elastodyn/src/SED_Types.f90 index c7d091f6a9..32281a992c 100644 --- a/modules/simple-elastodyn/src/SED_Types.f90 +++ b/modules/simple-elastodyn/src/SED_Types.f90 @@ -63,6 +63,7 @@ MODULE SED_Types TYPE, PUBLIC :: SED_InitInputType CHARACTER(1024) :: InputFile !< Name of the input file [-] CHARACTER(1024) :: RootName !< RootName for writing output files [-] + LOGICAL :: Linearize = .false. !< Linearization not currently enabled [-] END TYPE SED_InitInputType ! ======================= ! ========= SED_InitOutputType ======= @@ -463,6 +464,7 @@ SUBROUTINE SED_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrS ErrMsg = "" DstInitInputData%InputFile = SrcInitInputData%InputFile DstInitInputData%RootName = SrcInitInputData%RootName + DstInitInputData%Linearize = SrcInitInputData%Linearize END SUBROUTINE SED_CopyInitInput SUBROUTINE SED_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) @@ -513,6 +515,7 @@ SUBROUTINE SED_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_BufSz = 0 Int_BufSz = Int_BufSz + 1*LEN(InData%InputFile) ! InputFile Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Int_BufSz = Int_BufSz + 1 ! Linearize IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -548,6 +551,8 @@ SUBROUTINE SED_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) Int_Xferred = Int_Xferred + 1 END DO ! I + IntKiBuf(Int_Xferred) = TRANSFER(InData%Linearize, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE SED_PackInitInput SUBROUTINE SED_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -584,6 +589,8 @@ SUBROUTINE SED_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 END DO ! I + OutData%Linearize = TRANSFER(IntKiBuf(Int_Xferred), OutData%Linearize) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE SED_UnPackInitInput SUBROUTINE SED_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/simple-elastodyn/src/driver/SED_Driver.f90 b/modules/simple-elastodyn/src/driver/SED_Driver.f90 new file mode 100644 index 0000000000..c4a4fb7501 --- /dev/null +++ b/modules/simple-elastodyn/src/driver/SED_Driver.f90 @@ -0,0 +1,342 @@ +!********************************************************************************************************************************** +!> ## SED_DriverCode: This code tests the SED module +!!.................................................................................................................................. +!! LICENSING +!! Copyright (C) 2012, 2015 National Renewable Energy Laboratory +!! +!! This file is part of SED. +!! +!! Licensed under the Apache License, Version 2.0 (the "License"); +!! you may not use this file except in compliance with the License. +!! You may obtain a copy of the License at +!! +!! http://www.apache.org/licenses/LICENSE-2.0 +!! +!! Unless required by applicable law or agreed to in writing, software +!! distributed under the License is distributed on an "AS IS" BASIS, +!! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +!! See the License for the specific language governing permissions and +!! limitations under the License. +!********************************************************************************************************************************** +PROGRAM SED_Driver + + USE NWTC_Library + USE VersionInfo + USE SED + USE SED_Types + USE SED_Driver_Subs + USE SED_Driver_Types + + IMPLICIT NONE + + TYPE( ProgDesc ), PARAMETER :: ProgInfo = ProgDesc("SED_Driver","","") + INTEGER(IntKi) :: SEDDriver_Verbose = 5 ! Verbose level. 0 = none, 5 = some, 10 = lots + + + + integer(IntKi), parameter :: NumInp = 1 !< Number of inputs sent to SED_UpdateStates + + ! Program variables + real(DbKi) :: Time !< Variable for storing time, in seconds + real(DbKi) :: TimeInterval !< Interval between time steps, in seconds + real(DbKi) :: TStart !< Time to start + real(DbKi) :: TMax !< Maximum time if found by default + integer(IntKi) :: NumTSteps !< number of timesteps + logical :: TimeIntervalFound !< Interval between time steps, in seconds + real(DbKi) :: InputTime(NumInp) !< Variable for storing time associated with inputs, in seconds + real(R8Ki), allocatable :: DisplacementList(:,:) !< List of displacements and times to apply {idx 1 = time step, idx 2 = [T, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z]} + + type(SED_InitInputType) :: InitInData !< Input data for initialization + type(SED_InitOutputType) :: InitOutData !< Output data from initialization + + type(SED_ContinuousStateType) :: x !< Continuous states + type(SED_DiscreteStateType) :: xd !< Discrete states + type(SED_ConstraintStateType) :: z !< Constraint states + type(SED_ConstraintStateType) :: Z_residual !< Residual of the constraint state functions (Z) + type(SED_OtherStateType) :: OtherState !< Other states + type(SED_MiscVarType) :: misc !< Optimization variables + + type(SED_ParameterType) :: p !< Parameters + type(SED_InputType) :: u(NumInp) !< System inputs + type(SED_OutputType) :: y !< System outputs + + ! Local variables for this code + TYPE(SEDDriver_Flags) :: CLSettingsFlags ! Flags indicating which command line arguments were specified + TYPE(SEDDriver_Settings) :: CLSettings ! Command line arguments passed in + TYPE(SEDDriver_Flags) :: SettingsFlags ! Flags indicating which settings were specified (includes CL and ipt file) + TYPE(SEDDriver_Settings) :: Settings ! Driver settings + REAL(DbKi) :: Timer(1:2) ! Keep track of how long this takes to run + + ! Data transfer + real(R8Ki) :: Force(6) + real(R8Ki) :: Displacement(6) + real(R8Ki) :: Theta(3) + + INTEGER(IntKi) :: n !< Loop counter (for time step) + integer(IntKi) :: i !< generic loop counter + integer(IntKi) :: DimIdx !< Index of current dimension + integer(IntKi) :: TmpIdx(6) !< Index of last point accessed by dimension + INTEGER(IntKi) :: ErrStat !< Status of error message + CHARACTER(ErrMsgLen) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + CHARACTER(200) :: git_commit ! String containing the current git commit hash + TYPE(ProgDesc), PARAMETER :: version = ProgDesc( 'SED Driver', '', '' ) ! The version number of this program. + integer(IntKi) :: DvrOut + character(1024) :: OutputFileRootName + + + ! initialize library + call NWTC_Init + call DispNVD(ProgInfo) + DvrOut=-1 ! Set output unit to negative + + ! Display the copyright notice + CALL DispCopyrightLicense( version%Name ) + ! Obtain OpenFAST git commit hash + git_commit = QueryGitVersion() + ! Tell our users what they're running + CALL WrScr( ' Running '//GetNVD( version )//' a part of OpenFAST - '//TRIM(git_Commit)//NewLine//' linked with '//TRIM( GetNVD( NWTC_Ver ))//NewLine ) + + ! Start the timer + call CPU_TIME( Timer(1) ) + + ! Initialize the driver settings to their default values (same as the CL -- command line -- values) + call InitSettingsFlags( ProgInfo, CLSettings, CLSettingsFlags ) + Settings = CLSettings + SettingsFlags = CLSettingsFlags + + ! Parse the input line + call RetrieveArgs( CLSettings, CLSettingsFlags, ErrStat, ErrMsg ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL ProgAbort( ErrMsg ) + ELSEIF ( ErrStat /= 0 ) THEN + CALL WrScr( NewLine//ErrMsg ) + ErrStat = ErrID_None + ENDIF + + ! Check if we are doing verbose error reporting + IF ( CLSettingsFlags%VVerbose ) SEDDriver_Verbose = 10_IntKi + IF ( CLSettingsFlags%Verbose ) SEDDriver_Verbose = 7_IntKi + + ! Verbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr('--- Settings from the command line: ---') + CALL printSettings( CLSettingsFlags, CLSettings ) + CALL WrSCr(NewLine) + ENDIF + + ! Verbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr('--- Driver settings (before reading driver ipt file): ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + + ! Copy the input file information from the CLSettings to the Settings. + ! At this point only one input file type can be set. + IF ( CLSettingsFlags%DvrIptFile ) THEN + SettingsFlags%DvrIptFile = CLSettingsFlags%DvrIptFile + Settings%DvrIptFileName = CLSettings%DvrIptFileName + ELSE + SettingsFlags%SEDIptFile = CLSettingsFlags%SEDIptFile + Settings%SEDIptFileName = CLSettings%SEDIptFileName + ENDIF + + ! If the filename given was not the SED input file (-ifw option), then it is treated + ! as the driver input file (flag should be set correctly by RetrieveArgs). So, we must + ! open this. + IF ( SettingsFlags%DvrIptFile ) THEN + + ! Read the driver input file + CALL ReadDvrIptFile( CLSettings%DvrIptFileName, SettingsFlags, Settings, ProgInfo, ErrStat, ErrMsg ) + call CheckErr('') + + ! VVerbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr(NewLine//'--- Driver settings after reading the driver ipt file: ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + ! VVerbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) CALL WrScr('Updating driver settings with command line arguments') + + ELSE + + ! VVerbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) CALL WrScr('No driver input file used. Updating driver settings with command line arguments') + + ENDIF + + ! Since there were no settings picked up from the driver input file, we need to copy over all + ! the CLSettings into the regular Settings. The SettingsFlags%DvrIptFile is a flag indicating + ! if the driver input file read. + CALL UpdateSettingsWithCL( SettingsFlags, Settings, CLSettingsFlags, CLSettings, SettingsFlags%DvrIptFile, ErrStat, ErrMsg ) + call CheckErr('') + + ! Verbose error reporting + IF ( SEDDriver_Verbose >= 10_IntKi ) THEN + CALL WrScr(NewLine//'--- Driver settings after copying over CL settings: ---') + CALL printSettings( SettingsFlags, Settings ) + CALL WrScr(NewLine) + ENDIF + + + !------------------------------------------ + ! Read DisplacementList from InputDispFile + ! NOTE: DiplacementList is arranged for speed in interpolation + ! -- index 1 = time step + ! -- index 2 = [T, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z] + !------------------------------------------ + if ( SettingsFlags%InputDispFile ) then + call ReadInputDispFile( Settings%InputDispFile, DisplacementList, ErrStat, ErrMsg ) + call CheckErr('') + + if ( SEDDriver_Verbose >= 10_IntKi ) call WrScr('Input Displacements given for '//trim(Num2LStr(size(DisplacementList,1)))// & + ' time steps from T = '//trim(Num2LStr(DisplacementList(1,1)))//' to '//trim(Num2LStr(DisplacementList(size(DisplacementList,1),1)))//' seconds.') + endif + + + !------------------------------------------ + ! Logic for timestep and total time for sim. + !------------------------------------------ + if ( SettingsFlags%TStart ) then + TStart = Settings%TStart + else + TStart = 0.0_DbKi + ! TODO: if using the input file, could start at the initial time given there (set the TStart with a "default" input option) + endif + + + + TimeIntervalFound=.true. ! If specified or default value set + ! DT - timestep. If default was specified, then calculate default level. + if ( SettingsFlags%DTdefault ) then + if ( SettingsFlags%InputDispFile ) then + ! Set a value to start with (something larger than any expected DT). + TimeIntervalFound=.false. + TimeInterval=1000.0_DbKi + ! Step through all lines to get smallest DT + do n=min(2,size(DisplacementList,1)),size(DisplacementList,1) ! Start at 2nd point (min to avoid stepping over end for single line files) + TimeInterval=min(TimeInterval, real(DisplacementList(n,1)-DisplacementList(n-1,1), DbKi)) + TimeIntervalFound=.true. + enddo + if (TimeIntervalFound) then + call WrScr('Using smallest DT from data file: '//trim(Num2LStr(TimeInterval))//' seconds.') + else + call WrScr('No time timesteps found in input displacement file. Using only one timestep.') + endif + else + ! set default level. NOTE: the REDWIN dll does not use any form of timestep, so this is merely for bookkeeping. + TimeInterval = 0.01_DbKi + call WrScr('Setting default timestep to '//trim(Num2LStr(TimeInterval))//' seconds.') + endif + endif + + + ! TMax and NumTSteps from input file or from the value specified (specified overrides) + if ( SettingsFlags%NumTimeStepsDefault ) then + if ( SettingsFlags%InputDispFile ) then + TMax = real(DisplacementList(size(DisplacementList,1),1), DbKi) + NumTSteps = ceiling( TMax / TimeInterval ) + else ! Do one timestep + NumTSteps = 1_IntKi + TMax = TimeInterval * NumTSteps + endif + elseif ( SettingsFlags%NumTimeSteps ) then ! Override with number of timesteps + TMax = TimeInterval * Settings%NumTimeSteps + TStart + NumTSteps = Settings%NumTimeSteps + else + NumTSteps = 1_IntKi + TMax = TimeInterval * NumTSteps + endif + + + + ! Routines called in initialization + !............................................................................................................................... + + InitInData%InputFile = Settings%SEDIptFileName + + ! Initialize the module + CALL SED_Init( InitInData, u(1), p, x, xd, z, OtherState, y, misc, TimeInterval, InitOutData, ErrStat, ErrMsg ) + IF ( ErrStat /= ErrID_None ) THEN ! Check if there was an error and do something about it if necessary + CALL WrScr( 'After Init: '//ErrMsg ) + if ( ErrStat >= AbortErrLev ) call ProgEnd() + END IF + + ! Set the output file + call GetRoot(Settings%SEDIptFileName,OutputFileRootName) + call Dvr_InitializeOutputFile(DvrOut, InitOutData, OutputFileRootName, ErrStat, ErrMsg) + call CheckErr('Setting output file'); + + ! Destroy initialization data + CALL SED_DestroyInitInput( InitInData, ErrStat, ErrMsg ) + CALL SED_DestroyInitOutput( InitOutData, ErrStat, ErrMsg ) + + + + ! Routines called in loose coupling -- the glue code may implement this in various ways + !............................................................................................................................... + + + TmpIdx(1:6) = 0_IntKi + + DO n = 0,NumTSteps + Time = n*TimeInterval+TStart + InputTime(1) = Time + + ! interpolate into the input data to get the displacement. Set this as u then run + if ( SettingsFlags%InputDispFile ) then +! do i=1,u(1)%SoilMesh%NNodes +! ! InterpStpReal( X, Xary, Yary, indx, size) +! do DimIdx=1,3 +! u(1)%SoilMesh%TranslationDisp(DimIdx,i) = InterpStpReal8( real(Time,R8Ki), DisplacementList(:,1), DisplacementList(:,DimIdx+1), TmpIdx(DimIdx), size(DisplacementList,1) ) +! enddo +! do DimIdx=1,3 +! Theta(DimIdx) = InterpStpReal8( real(Time,R8Ki), DisplacementList(:,1), DisplacementList(:,DimIdx+4), TmpIdx(DimIdx), size(DisplacementList,1) ) +! enddo +! u(1)%SoilMesh%Orientation(1:3,1:3,i) = EulerConstruct(Theta) +! enddo + endif + + ! Calculate outputs at n + CALL SED_CalcOutput( Time, u(1), p, x, xd, z, OtherState, y, misc, ErrStat, ErrMsg ); + call CheckErr('After CalcOutput: '); + + ! There are no states to update in SED, but for completeness we add this. + ! Get state variables at next step: INPUT at step n, OUTPUT at step n + 1 + CALL SED_UpdateStates( Time, n, u, InputTime, p, x, xd, z, OtherState, misc, ErrStat, ErrMsg ); + call CheckErr(''); + + !call Dvr_WriteOutputLine(Time,DvrOut,p%OutFmt,y) + call Dvr_WriteOutputLine(Time,DvrOut,"ES20.12E2",y) + END DO + + + + + !............................................................................................................................... + ! Routine to terminate program execution + !............................................................................................................................... + if (DvrOut>0) close(DvrOut) + CALL SED_End( u(1), p, x, xd, z, OtherState, y, misc, ErrStat, ErrMsg ) + + IF ( ErrStat /= ErrID_None ) THEN + CALL WrScr( 'After End: '//ErrMsg ) + END IF + +CONTAINS + subroutine CheckErr(Text) + character(*), intent(in) :: Text + IF ( ErrStat /= ErrID_None ) THEN ! Check if there was an error and do something about it if necessary + CALL WrScr( Text//ErrMsg ) + if ( ErrStat >= AbortErrLev ) call ProgEnd() + END IF + end subroutine CheckErr + subroutine ProgEnd() + ! Placeholder for moment + Call ProgAbort('Fatal error encountered. Ending.') + end subroutine ProgEnd +END PROGRAM SED_Driver diff --git a/modules/simple-elastodyn/src/driver/SED_Driver_Subs.f90 b/modules/simple-elastodyn/src/driver/SED_Driver_Subs.f90 new file mode 100644 index 0000000000..b3f05d0ddb --- /dev/null +++ b/modules/simple-elastodyn/src/driver/SED_Driver_Subs.f90 @@ -0,0 +1,1126 @@ +!********************************************************************************************************************************** +! +! MODULE: SED_Driver_Subs - This module contains subroutines used by the SED Driver program +! +!********************************************************************************************************************************** +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2020 National Renewable Energy Laboratory +! +! This file is part of SED. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +! +!********************************************************************************************************************************** +MODULE SED_Driver_Subs + + USE NWTC_Library + USE SED_Driver_Types + IMPLICIT NONE + +! NOTE: This is loosely based on the InflowWind driver code. + +CONTAINS +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> Print out help information +SUBROUTINE DispHelpText() + ! Statement about usage + CALL WrScr("") + CALL WrScr(" Syntax: SED_Driver [options]") + CALL WrScr("") + CALL WrScr(" where: -- Name of driver input file to use") + CALL WrScr(" options: "//SWChar//"sed -- treat as name of SED input file") + CALL WrScr(" (no driver input file)") + CALL WrScr("") + CALL WrScr(" The following options will overwrite values in the driver input file:") + CALL WrScr(" "//SwChar//"DT[#] -- timestep ") + CALL WrScr(" "//SwChar//"TStart[#] -- start time ") + CALL WrScr(" "//SwChar//"TSteps[#] -- number of timesteps ") + CALL WrScr(" "//SwChar//"v -- verbose output ") + CALL WrScr(" "//SwChar//"vv -- very verbose output ") + CALL WrScr(" "//SwChar//"NonLinear -- only return non-linear portion of reaction force") + CALL WrScr(" "//SwChar//"help -- print this help menu and exit") + CALL WrScr("") + CALL WrScr(" Notes:") + CALL WrScr(" -- Options are not case sensitive.") + CALL WrScr("") +!FIXME: update this +END SUBROUTINE DispHelpText + + +subroutine InitSettingsFlags( ProgInfo, CLSettings, CLFlags ) + implicit none + ! Storing the arguments + type( ProgDesc ), intent(in ) :: ProgInfo + type( SEDDriver_Settings ), intent( out) :: CLSettings !< Command line arguments passed in + type( SEDDriver_Flags ), intent( out) :: CLFlags !< Flags indicating which command line arguments were specified + + ! Set some CLSettings to null/default values + CLSettings%DvrIptFileName = "" ! No input name name until set + CLSettings%SEDIptFileName = "" ! No SED input file name until set + CLSettings%InputDispFile = "" ! No SED input displacement timeseries file name until set + CLSettings%NumTimeSteps = 0_IntKi + CLSettings%DT = 0.0_DbKi + CLSettings%TStart = 0.0_ReKi + CLSettings%ProgInfo = ProgInfo ! Driver info + + ! Set some CLFlags to null/default values + CLFlags%DvrIptFile = .FALSE. ! Driver input filename given as command line argument + CLFlags%SEDIptFile = .FALSE. ! SED input filename given as command line argument + CLFlags%InputDispFile = .FALSE. ! No SED input displacement timeseries file name until set + CLFlags%TStart = .FALSE. ! specified time to start at + CLFlags%NumTimeSteps = .FALSE. ! specified a number of timesteps + CLFlags%NumTimeStepsDefault = .FALSE. ! specified 'DEFAULT' for number of timesteps + CLFlags%DT = .FALSE. ! specified a resolution in time + CLFlags%DTDefault = .FALSE. ! specified 'DEFAULT' for resolution in time + CLFlags%Verbose = .FALSE. ! Turn on verbose error reporting? + CLFlags%VVerbose = .FALSE. ! Turn on very verbose error reporting? + +end subroutine InitSettingsFlags + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> This subroutine retrieves the command line arguments and passes them to the +!! SED_driver_subs::parsearg routine for processing. +SUBROUTINE RetrieveArgs( CLSettings, CLFlags, ErrStat, ErrMsg ) + ! Storing the arguments + type( SEDDriver_Flags ), intent( out) :: CLFlags !< Flags indicating which command line arguments were specified + type( SEDDriver_Settings ), intent( out) :: CLSettings !< Command line arguments passed in + integer(IntKi), intent( out) :: ErrStat + CHARACTER(*), intent( out) :: ErrMsg + + ! Local variable + integer(IntKi) :: i !< Generic counter + character(1024) :: Arg !< argument given + character(1024) :: ArgUC !< Upper case argument to check + integer(IntKi) :: NumInputArgs !< Number of argements passed in from command line + logical :: sedFlag !< The -sed flag was set + character(1024) :: FileName !< Filename from the command line. + logical :: FileNameGiven !< Flag indicating if a filename was given. + integer(IntKi) :: ErrStatTmp !< Temporary error status (for calls) + character(1024) :: ErrMsgTmp !< Temporary error message (for calls) + + ! initialize some things + CLFlags%DvrIptFile = .FALSE. + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + ErrMsg = '' + ErrMsgTmp = '' + sedFlag = .FALSE. + FileNameGiven = .FALSE. + FileName = '' + + ! Check how many arguments are passed in + NumInputArgs = COMMAND_ARGUMENT_COUNT() + + ! exit if we don't have enough + IF (NumInputArgs == 0) THEN + CALL SetErrStat(ErrID_Fatal," Insufficient Arguments. Use option "//SwChar//"help for help menu.", & + ErrStat,ErrMsg,'RetrieveArgs') + RETURN + ENDIF + + + ! Loop through all the arguments, and store them + DO i=1,NumInputArgs + ! get the ith argument + CALL get_command_argument(i, Arg) + ArgUC = Arg + + ! convert to uppercase + CALL Conv2UC( ArgUC ) + + ! Check to see if it is a control parameter or the filename + IF ( INDEX( SwChar, ArgUC(1:1) ) > 0 ) THEN + + ! check to see if we asked for help + IF ( ArgUC(2:5) == "HELP" ) THEN + CALL DispHelpText() + CALL ProgExit(0) + ENDIF + + + ! Check the argument and put it where it belongs + ! chop the SwChar off before passing the argument + CALL ParseArg( CLSettings, CLFlags, ArgUC(2:), Arg(2:), sedFlag, ErrStatTmp, ErrMsgTmp ) + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'RetrieveArgs') + IF (ErrStat>AbortErrLev) RETURN + + ELSE + + ! since there is no switch character, assume it is the filename, unless we already set one + IF ( FileNameGiven ) THEN + CALL SetErrStat(ErrID_Fatal," Multiple driver input filenames given: "//TRIM(FileName)//", "//TRIM(Arg), & + ErrStat,ErrMsg,'RetrieveArgs') + RETURN + ELSE + FileName = TRIM(Arg) + FileNameGiven = .TRUE. + ENDIF + + ENDIF + END DO + + + ! Was a filename given? + IF ( .NOT. FileNameGiven ) THEN + CALL SetErrStat( ErrID_Fatal, " No filename given.", ErrStat, ErrMsg, 'RetrieveArgs' ) + RETURN + ENDIF + + ! Was the -sed flag set? If so, the filename is the SED input file. Otherwise + ! it is the driver input file. + IF ( sedFlag ) THEN + CLSettings%SEDIptFileName = TRIM(FileName) + CLFlags%SEDIptFile = .TRUE. + ELSE + CLSettings%DvrIptFileName = TRIM(FileName) + CLFlags%DvrIptFile = .TRUE. + ENDIF + + + + !------------------------------------------------------------------------------- + !------------------------------------------------------------------------------- + CONTAINS + + + !------------------------------------------------------------------------------- + !> Convert a string to a real number + FUNCTION StringToReal( StringIn, ErrStat ) + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT(IN ) :: StringIn + + REAL(ReKi) :: StringToReal + INTEGER(IntKi) :: ErrStatTmp ! Temporary variable to hold the error status + + read( StringIn, *, iostat=ErrStatTmp) StringToReal + + ! If that isn't a number, only warn since we can continue by skipping this value + IF ( ErrStatTmp .ne. 0 ) ErrStat = ErrID_Warn + + END FUNCTION StringToReal + + + + !------------------------------------------------------------------------------- + SUBROUTINE ParseArg( CLSettings, CLFlags, ThisArgUC, ThisArg, sedFlagSet, ErrStat, ErrMsg ) + !-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-! + ! Parse and store the input argument ! + !-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-! + + USE NWTC_Library + USE SED_Driver_Types + USE SED_Types + + IMPLICIT NONE + + ! Storing the arguments + TYPE( SEDDriver_Flags ), INTENT(INOUT) :: CLFlags ! Flags indicating which arguments were specified + TYPE( SEDDriver_Settings ), INTENT(INOUT) :: CLSettings ! Arguments passed in + + CHARACTER(*), INTENT(IN ) :: ThisArgUC ! The current argument (upper case for testing) + CHARACTER(*), INTENT(IN ) :: ThisArg ! The current argument (as passed in for error messages) + LOGICAL, INTENT(INOUT) :: sedFlagSet ! Was the -sed flag given? + + ! Error Handling + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + + ! local variables + INTEGER(IntKi) :: Delim1 ! where the [ is + INTEGER(IntKi) :: Delim2 ! where the ] is + INTEGER(IntKi) :: DelimSep ! where the : is + REAL(ReKi) :: TempReal ! temp variable to hold a real + + INTEGER(IntKi) :: ErrStatTmp ! Temporary error status for calls + + + + ! Initialize some things + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + ErrMsg = '' + + ! Get the delimiters -- returns 0 if there isn't one + Delim1 = INDEX(ThisArgUC,'[') + Delim2 = INDEX(ThisArgUC,']') + DelimSep = INDEX(ThisArgUC,':') + + + ! check that if there is an opening bracket, then there is a closing one + IF ( (Delim1 > 0_IntKi ) .and. (Delim2 < Delim1) ) THEN + CALL SetErrStat(ErrID_Warn," Syntax error in option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArg') + RETURN + ENDIF + + ! check that if there is a colon, then there are brackets + IF ( (DelimSep > 0_IntKi) .and. (Delim1 == 0_IntKi) ) THEN + CALL SetErrStat(ErrID_Warn," Syntax error in option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArg') + RETURN + ENDIF + + + ! If no delimeters were given, than this option is simply a flag + IF ( Delim1 == 0_IntKi ) THEN + ! check to see if the filename is the name of the SED input file + IF ( ThisArgUC(1:4) == "SED" ) THEN + sedFlagSet = .TRUE. ! More logic in the routine that calls this one to set things. + RETURN + ELSEIF ( ThisArgUC(1:2) == "VV" ) THEN + CLFlags%VVerbose = .TRUE. + RETURN + ELSEIF ( ThisArgUC(1:1) == "V" ) THEN + CLFlags%Verbose = .TRUE. + RETURN + ELSE + CALL SetErrStat( ErrID_Warn," Unrecognized option '"//SwChar//TRIM(ThisArg)//"'. Ignoring. Use option "//SwChar//"help for list of options.", & + ErrStat,ErrMsg,'ParseArg') + ENDIF + + ENDIF + + + ! "DT[#]" + IF( ThisArgUC(1:Delim1) == "DT[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%Dt = .TRUE. + CLSettings%DT = abs(TempReal) + ELSE + CLFlags%Dt = .FALSE. + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF + + + ! "TSTEPS[#]" + ELSEIF( ThisArgUC(1:Delim1) == "TSTEPS[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%NumTimeSteps = .TRUE. + CLSettings%NumTimeSteps = nint(abs(TempReal)) + ELSE + CLFlags%NumTimeSteps = .FALSE. + CLSettings%NumTimeSteps = 1_IntKi + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF + + + + ! "TSTART[#]" + ELSEIF( ThisArgUC(1:Delim1) == "TSTART[" ) THEN + TempReal = StringToReal( ThisArgUC(Delim1+1:Delim2-1), ErrStat ) + IF ( ErrStat == ErrID_None ) THEN + CLFlags%TStart = .TRUE. + CLSettings%TStart = abs(TempReal) + ELSE + CLFlags%TStart = .FALSE. + IF ( ErrStat == ErrID_Warn ) THEN + CALL SetErrStat(ErrStatTmp," Invalid number in option '"//SwChar//TRIM(ThisArg)//"'. Ignoring.", & + ErrStat,ErrMsg,'ParseArgs') + ELSE + CALL SetErrStat( ErrID_Fatal," Something failed in parsing option '"//SwChar//TRIM(ThisArg)//"'.", & + ErrStat, ErrMsg, 'ParseArg') + ENDIF + RETURN + ENDIF +!FIXME: add in the other inputs here. + + ELSE + ErrMsg = " Unrecognized option: '"//SwChar//TRIM(ThisArg)//"'. Ignoring. Use option "//SwChar//"help for list of options." + ErrStat = ErrID_Warn + ENDIF + + END SUBROUTINE ParseArg + !------------------------------------------------------------------------------- + +END SUBROUTINE RetrieveArgs + + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +!> This subroutine reads the driver input file and sets up the flags and settings +!! for the driver code. Any settings from the command line options will override +!! this. +SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat, ErrMsg ) + + CHARACTER(1024), INTENT(IN ) :: DvrFileName + TYPE(SEDDriver_Flags), INTENT(INOUT) :: DvrFlags + TYPE(SEDDriver_Settings), INTENT(INOUT) :: DvrSettings + TYPE(ProgDesc), INTENT(IN ) :: ProgInfo + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! returns a non-zero value when an error occurs + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None + + ! Local variables + INTEGER(IntKi) :: UnIn ! Unit number for the driver input file + CHARACTER(1024) :: FileName ! Name of SED driver input file + + ! Input file echoing + LOGICAL :: EchoFileContents ! Do we echo the driver file out or not? + INTEGER(IntKi) :: UnEchoLocal ! The local unit number for this module's echo file + CHARACTER(1024) :: EchoFileName ! Name of SED driver echo file + + ! Time steps + CHARACTER(1024) :: InputChr ! Character string for timesteps and input file names (to handle DEFAULT or NONE value) + + ! Local error handling + INTEGER(IntKi) :: ios !< I/O status + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + CHARACTER(1024) :: ErrMsgTmp !< Temporary error messages for calls + + + ! Initialize the echo file unit to -1 which is the default to prevent echoing, we will alter this based on user input + UnEchoLocal = -1 + + FileName = TRIM(DvrFileName) + + CALL GetNewUnit( UnIn ) + CALL OpenFInpFile( UnIn, FileName, ErrStatTmp, ErrMsgTmp ) + IF ( ErrStatTmp /= ErrID_None ) THEN + CALL SetErrStat(ErrID_Fatal,' Failed to open SED Driver input file: '//FileName, & + ErrStat,ErrMsg,'ReadDvrIptFile') + CLOSE( UnIn ) + RETURN + ENDIF + + + CALL WrScr( 'Opening SED Driver input file: '//trim(FileName) ) + + + !------------------------------------------------------------------------------------------------- + ! File header + !------------------------------------------------------------------------------------------------- + + CALL ReadCom( UnIn, FileName,' SED Driver input file header line 1', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'SED Driver input file header line 2', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'SED Driver input file seperator line', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + ! Echo Input Files. + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + + ! If we are Echoing the input then we should re-read the first three lines so that we can echo them + ! using the NWTC_Library routines. The echoing is done inside those routines via a global variable + ! which we must store, set, and then replace on error or completion. + + IF ( EchoFileContents ) THEN + + EchoFileName = TRIM(FileName)//'.ech' + CALL GetNewUnit( UnEchoLocal ) + CALL OpenEcho ( UnEchoLocal, EchoFileName, ErrStatTmp, ErrMsgTmp, ProgInfo ) + if (Failed()) return + + REWIND(UnIn) + + ! Reread and echo + CALL ReadCom( UnIn, FileName,' SED Driver input file header line 1', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'SED Driver input file header line 2', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + CALL ReadCom( UnIn, FileName, 'SED Driver input file seperator line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Echo Input Files. + CALL ReadVar ( UnIn, FileName, EchoFileContents, 'Echo', 'Echo Input', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ENDIF + + + !------------------------------------------------------------------------------------------------- + ! Driver setup section + !------------------------------------------------------------------------------------------------- + + ! Header + CALL ReadCom( UnIn, FileName,' Driver setup section, comment line', ErrStatTmp, ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! SED input file + CALL ReadVar( UnIn, FileName,DvrSettings%SEDIptFileName,'SEDIptFileName',' SED input filename', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) then + return + else + DvrFlags%SEDIptFile = .TRUE. + endif + + + ! TStart -- start time + CALL ReadVar( UnIn, FileName,DvrSettings%TStart,'TStart',' Time in wind file to start parsing.', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) then + return + else + DvrFlags%TStart = .TRUE. + endif + + + ! DT -- Timestep size for the driver to take (or DEFAULT for what the file contains) + CALL ReadVar( UnIn, FileName,InputChr,'InputChr',' Character string for Timestep size for the driver to take (or DEFAULT for what the file contains).', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Check if we asked for the DEFAULT (use what is in the file) + CALL Conv2UC( InputChr ) + IF ( TRIM(InputChr) == 'DEFAULT' ) THEN ! we asked for the default value + DvrFlags%DT = .TRUE. + DvrFlags%DTDefault = .TRUE. ! This flag tells us to use the inflow wind file values + ELSE + ! We probably have a number if it isn't 'DEFAULT', so do an internal read and check to + ! make sure that it was appropriately interpretted. + READ (InputChr,*,IOSTAT=IOS) DvrSettings%DT + IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. + CALL CheckIOS ( IOS, '', 'DT',NumType, ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ELSE ! Was ok, so set the flags + DvrFlags%DT = .TRUE. + DvrFlags%DTDefault = .FALSE. + ENDIF + ENDIF + + + ! Number of timesteps + CALL ReadVar( UnIn, FileName,InputChr,'InputChr',' Character string for number of timesteps to read.', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + ! Check if we asked for the DEFAULT (use what is in the file) + CALL Conv2UC( InputChr ) + IF ( TRIM(InputChr) == 'DEFAULT' ) THEN ! we asked for the default value + DvrFlags%NumTimeSteps = .FALSE. + DvrFlags%NumTimeStepsDefault = .TRUE. ! This flag tells us to use the inflow wind file values + ELSE + ! We probably have a number if it isn't 'DEFAULT', so do an internal read and check to + ! make sure that it was appropriately interpretted. + READ (InputChr,*,IOSTAT=IOS) DvrSettings%NumTimeSteps + IF ( IOS /= 0 ) THEN ! problem in the read, so parse the error. + CALL CheckIOS ( IOS, '', 'NumTimeSteps',NumType, ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ELSE ! Was ok, so set the flags + DvrFlags%NumTimeSteps = .TRUE. + DvrFlags%NumTimeStepsDefault = .FALSE. + ENDIF + ENDIF + + + + !------------------------------------------------------------------------------------------------- + ! SED time series input -- this is read from a file of 7 columns (time and 6 dof) + !------------------------------------------------------------------------------------------------- + + ! InputDispFile input file + CALL ReadVar( UnIn, FileName,InputChr,'InputDispFile',' SED input displacements filename', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) return + + DvrSettings%InputDispFile = InputChr + call Conv2UC( InputChr ) + if (trim(InputChr) == 'NONE') then + DvrSettings%InputDispFile = '' + DvrFlags%InputDispFile = .FALSE. + else + DvrFlags%InputDispFile = .TRUE. + endif + + + ! Close the echo and input file + CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) + CLOSE( UnIn ) + + +CONTAINS + + !> Set error status, close stuff, and return + logical function Failed() + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,'ReadDvrIptFile') + if (ErrStat >= AbortErrLev) then + CALL CleanupEchoFile( EchoFileContents, UnEchoLocal ) + CLOSE( UnIn ) + endif + Failed = ErrStat >= AbortErrLev + end function Failed + + !> Clean up the module echo file + subroutine CleanupEchoFile( EchoFlag, UnEcho) + logical, intent(in ) :: EchoFlag ! local version of echo flag + integer(IntKi), intent(in ) :: UnEcho ! echo unit number + + ! Close this module's echo file + if ( EchoFlag ) then + close(UnEcho) + endif + END SUBROUTINE CleanupEchoFile + +END SUBROUTINE ReadDvrIptFile + + +!> This subroutine copies an command line (CL) settings over to the program settings. Warnings are +!! issued if anything is changed from what the driver input file requested. +SUBROUTINE UpdateSettingsWithCL( DvrFlags, DvrSettings, CLFlags, CLSettings, DVRIPT, ErrStat, ErrMsg ) + + TYPE(SEDDriver_Flags), INTENT(INOUT) :: DvrFlags + TYPE(SEDDriver_Settings), INTENT(INOUT) :: DvrSettings + TYPE(SEDDriver_Flags), INTENT(IN ) :: CLFlags + TYPE(SEDDriver_Settings), INTENT(IN ) :: CLSettings + LOGICAL, INTENT(IN ) :: DVRIPT + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + + + ! Local variables + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + CHARACTER(1024) :: ErrMsgTmp !< Temporary error status for calls + LOGICAL :: WindGridModify !< Did we modify any of the WindGrid related settings? + character(*), parameter :: RoutineName = 'UpdateSettingsWithCL' + + ! Initialization + WindGridModify = .FALSE. + + ! Initialize the error handling + ErrStat = ErrID_None + ErrMsg = '' + ErrStatTmp = ErrID_None + ErrMsgTmp = '' + + + !-------------------------------------------- + ! Did we change any time information? + !-------------------------------------------- + + ! Check TStart + IF ( CLFlags%TStart ) THEN + IF ( DvrFlags%TStart .AND. ( .NOT. EqualRealNos(DvrSettings%TStart, CLSettings%TStart) ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for TStart with '//TRIM(Num2LStr(CLSettings%TStart))//'.', & + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%TStart = .TRUE. + ENDIF + DvrSettings%TStart = CLSettings%TStart + ENDIF + + ! Check DT + IF ( CLFlags%DT ) THEN + IF ( DvrFlags%DT .AND. ( .NOT. EqualRealNos(DvrSettings%DT, CLSettings%DT) ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for DT with '//TRIM(Num2LStr(CLSettings%DT))//'.', & + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%DT = .TRUE. + ENDIF + DvrSettings%DT = CLSettings%DT + DvrFlags%DTDefault = .FALSE. + ENDIF + + ! Check NumTimeSteps + IF ( CLFlags%NumTimeSteps ) THEN + IF ( DvrFlags%NumTimeSteps .AND. ( DvrSettings%NumTimeSteps /= CLSettings%NumTimeSteps ) ) THEN + CALL SetErrStat( ErrID_Warn, ' Overriding driver input value for NumTimeSteps with '// & + TRIM(Num2LStr(CLSettings%NumTimeSteps))//'.',& + ErrStat,ErrMsg,RoutineName) + ELSE + DvrFlags%NumTimeSteps = .TRUE. + ENDIF + DvrSettings%NumTimeSteps = CLSettings%NumTimeSteps + DvrFlags%NumTimeStepsDefault = .FALSE. + ENDIF + + ! Make sure there is at least one timestep + DvrSettings%NumTimeSteps = MAX(DvrSettings%NumTimeSteps,1_IntKi) + + + !-------------------------------------------- + ! If there was no driver input file, we need to set a few things. + !-------------------------------------------- + + IF ( .NOT. DVRIPT ) THEN + + ! Do we need to set the NumTimeStepsDefault flag? + IF ( .NOT. DvrFlags%NumTimeSteps ) THEN + DvrFlags%NumTimeStepsDefault = .TRUE. + CALL SetErrStat( ErrID_Info,' The number of timesteps is not specified. Defaulting to what is in the input series file.', & + ErrStat,ErrMsg,RoutineName) + ENDIF + ENDIF + + +!FIXME: remove this after parsing rest of input file. + ! If no DT value has been set (DEFAULT requested), we need to set a default to pass into SED + IF ( .NOT. DvrFlags%DT ) THEN + DvrSettings%DT = 0.025_DbKi ! This value gets passed into the SED_Init routine, so something must be set. + ENDIF + + +END SUBROUTINE UpdateSettingsWithCL + + + +SUBROUTINE ReadInputDispFile( InputDispFile, DisplacementList, ErrStat, ErrMsg ) + CHARACTER(1024), INTENT(IN ) :: InputDispFile !< Name of the points file to read + REAL(R8Ki), ALLOCATABLE, INTENT( OUT) :: DisplacementList(:,:) !< The coordinates we read in: idx 1 = timestep, idx 2 = values + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< The error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< The message for the status + + ! Local variables + CHARACTER(1024) :: ErrMsgTmp !< Temporary error message for calls + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status for calls + INTEGER(IntKi) :: FiUnitPoints !< Unit number for points file to open + + INTEGER(IntKi) :: NumDataColumns !< Number of data columns + INTEGER(IntKi) :: NumDataPoints !< Number of lines of data (one point per line) + INTEGER(IntKi) :: NumHeaderLines !< Number of header lines to ignore + + INTEGER(IntKi) :: I !< Generic counter + character(*), parameter :: RoutineName = 'ReadInputDispFile' + + ! Initialization of subroutine + ErrMsg = '' + ErrMsgTmp = '' + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + + + ! Now open file + CALL GetNewUnit( FiUnitPoints, ErrStatTmp, ErrMsgTmp ); if (Failed()) return + CALL OpenFInpFile( FiUnitPoints, TRIM(InputDispFile), ErrStatTmp, ErrMsgTmp ) ! Unformatted input file + if (Failed()) return + + ! Find out how long the file is + CALL GetFileLength( FiUnitPoints, InputDispFile, NumDataColumns, NumDataPoints, NumHeaderLines, ErrMsgTmp, ErrStatTmp ) + if (Failed()) return + IF ( NumDataColumns /= 7 ) THEN + ErrStatTmp = ErrID_Fatal + ErrMsgTmp = ' Expecting seven columns in '//TRIM(InputDispFile)//' corresponding to '// & + 'time, dX, dY, dZ, dTheta_X, dTheta_Y, dTheta_Z coordinates. Instead found '//TRIM(Num2LStr(NumDataColumns))//' columns.' + if (Failed()) return + ENDIF + + + ! Allocate the storage for the data + CALL AllocAry( DisplacementList, NumDataPoints, 7, "Array of Points data", ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + + + ! Read in the headers and throw them away + DO I=1,NumHeaderLines + CALL ReadCom( FiUnitPoints, InputDispFile,' Points file header line', ErrStatTmp, ErrMsgTmp ) + if (Failed()) return + ENDDO + + ! Read in the datapoints -- This is arranged with time in first index for speed in later interpolation operations + DO I=1,NumDataPoints + CALL ReadAry ( FiUnitPoints, InputDispFile, DisplacementList(I,:), 7, 'DisplacementList', & + 'Coordinate point from Points file', ErrStatTmp, ErrMsgTmp) + if (Failed()) return + ENDDO + + CLOSE( FiUnitPoints ) + +CONTAINS + !> Set error status, close stuff, and return + logical function Failed() + CALL SetErrStat(ErrStatTmp,ErrMsgTmp,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev .and. FiUnitPoints >0) close( FiUnitPoints ) + Failed = ErrStat >= AbortErrLev + end function Failed + + + !------------------------------------------------------------------------------------------------------------------------------- + !> This subroutine looks at a file that has been opened and finds out how many header lines there are, how many columns there + !! are, and how many lines of data there are in the file. + !! + !! A few things are assumed about the file: + !! 1. Any header lines are the first thing in the file. + !! 2. No text appears anyplace other than in first part of the file + !! 3. The datalines only contain numbers that can be read in as reals. + !! + !! Limitations: + !! 1. only handles up to 20 words (columns) on a line + !! 2. empty lines are considered text lines + !! 3. All data rows must contain the same number of columns + !! + !! + SUBROUTINE GetFileLength(UnitDataFile, DataFileName, NumDataColumns, NumDataLines, NumHeaderLines, ErrMsg, ErrStat) + + INTEGER(IntKi), INTENT(IN ) :: UnitDataFile !< Unit number of the file we are looking at. + CHARACTER(*), INTENT(IN ) :: DataFileName !< The name of the file we are looking at. + INTEGER(IntKi), INTENT( OUT) :: NumDataColumns !< The number of columns in the data file. + INTEGER(IntKi), INTENT( OUT) :: NumDataLines !< Number of lines containing data + INTEGER(IntKi), INTENT( OUT) :: NumHeaderLines !< Number of header lines at the start of the file + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error Message to return (empty if all good) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Status flag if there were any problems (ErrID_None if all good) + + ! Local Variables + CHARACTER(2048) :: ErrMsgTmp !< Temporary message variable. Used in calls. + INTEGER(IntKi) :: ErrStatTmp !< Temporary error status. Used in calls. + INTEGER(IntKi) :: LclErrStat !< Temporary error status. Used locally to indicate when we have reached the end of the file. + INTEGER(IntKi) :: TmpIOErrStat !< Temporary error status for the internal read of the first word to a real number + LOGICAL :: IsRealNum !< Flag indicating if the first word on the line was a real number + + CHARACTER(1024) :: TextLine !< One line of text read from the file + INTEGER(IntKi) :: LineLen !< The length of the line read in + CHARACTER(1024) :: StrRead !< String containing the first word read in + REAL(R8Ki) :: RealRead !< Returns value of the number (if there was one), or NaN (as set by NWTC_Num) if there wasn't + CHARACTER(24) :: Words(20) !< Array of words we extract from a line. We shouldn't have more than 20. + INTEGER(IntKi) :: i !< simple integer counters + INTEGER(IntKi) :: LineNumber !< the line I am on + LOGICAL :: LineHasText !< Flag indicating if the line I just read has text. If so, it is a header line. + LOGICAL :: HaveReadData !< Flag indicating if I have started reading data. + INTEGER(IntKi) :: NumWords !< Number of words on a line + INTEGER(IntKi) :: FirstDataLineNum !< Line number of the first row of data in the file + + ! Initialize the error handling + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + LclErrStat = ErrID_None + ErrMsg = '' + ErrMsgTmp = '' + + ! Set some of the flags and counters + HaveReadData = .FALSE. + NumDataColumns = 0 + NumHeaderLines = 0 + NumDataLines = 0 + LineNumber = 0 + + ! Just in case we were handed a file that we are part way through reading (should never be true), rewind to the start + + REWIND( UnitDataFile ) + + !------------------------------------ + !> The variable LclErrStat is used to indicate when we have reached the end of the file or had an error from + !! ReadLine. Until that occurs, we read each line, and decide if it contained any non-numeric data. The + !! first group of lines containing non-numeric data is considered the header. The first line of all numeric + !! data is considered the start of the data section. Any non-numeric containing found within the data section + !! will be considered as an invalid file format at which point we will return a fatal error from this routine. + + DO WHILE ( LclErrStat == ErrID_None ) + + !> Reset the indicator flag for the non-numeric content + LineHasText = .FALSE. + + !> Read in a single line from the file + CALL ReadLine( UnitDataFile, '', TextLine, LineLen, LclErrStat ) + + !> If there was an error in reading the file, then exit. + !! Possible causes: reading beyond end of file in which case we are done so don't process it. + IF ( LclErrStat /= ErrID_None ) EXIT + + !> Increment the line counter. + LineNumber = LineNumber + 1 + + !> Read all the words on the line into the array called 'Words'. Only the first words will be encountered + !! will be stored. The others are empty (i.e. only three words on the line, so the remaining 17 are empty). + CALL GetWords( TextLine, Words, 20 ) + + !> Cycle through and count how many are not empty. Once an empty value is encountered, all the rest should + !! be empty if GetWords worked correctly. The index of the last non-empty value is stored. + DO i=1,20 + IF (TRIM(Words(i)) .ne. '') NumWords=i + ENDDO + + + !> Now cycle through the first 'NumWords' of non-empty values stored in 'Words'. Words should contain + !! everything that is one the line. The subroutine ReadRealNumberFromString will set a flag 'IsRealNum' + !! when the value in Words(i) can be read as a real(R8Ki). 'StrRead' will contain the string equivalent. + DO i=1,NumWords + CALL ReadRealNumberFromString( Words(i), RealRead, StrRead, IsRealNum, ErrStatTmp, ErrMsgTmp, TmpIOErrStat ) + IF ( .NOT. IsRealNum) LineHasText = .TRUE. + ENDDO + + !> If all the words on that line had no text in them, then it must have been a line of data. + !! If not, then we have either a header line, which is ok, or a line containing text in the middle of the + !! the data section, which is not good (the flag HaveReadData tells us which case this is). + IF ( LineHasText ) THEN + IF ( HaveReadData ) THEN ! Uh oh, we have already read a line of data before now, so there is a problem + CALL SetErrStat( ErrID_Fatal, ' Found text on line '//TRIM(Num2LStr(LineNumber))//' of '//TRIM(DataFileName)// & + ' when real numbers were expected. There may be a problem with format of the file: '// & + TRIM(DataFileName)//'.', ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ELSE + NumHeaderLines = NumHeaderLines + 1 + ENDIF + ELSE ! No text, must be data line + NumDataLines = NumDataLines + 1 + ! If this is the first row of data, then store the number of words that were on the line + IF ( .NOT. HaveReadData ) THEN + ! If this is the first line of data, keep some relevant info about it and the number of columns in it + HaveReadData = .TRUE. + FirstDataLineNum = LineNumber ! Keep the line number of the first row of data (for error reporting) + NumDataColumns = NumWords + ELSE + ! Make sure that the number columns on the row matches the number of columnns on the first row of data. + IF ( NumWords /= NumDataColumns ) THEN + CALL SetErrStat( ErrID_Fatal, ' Error in file: '//TRIM(DataFileName)//'.'// & + ' The number of data columns on line '//TRIM(Num2LStr(LineNumber))// & + '('//TRIM(Num2LStr(NumWords))//' columns) is different than the number of columns on first row of data '// & + ' (line: '//TRIM(Num2LStr(FirstDataLineNum))//', '//TRIM(Num2LStr(NumDataColumns))//' columns).', & + ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + ENDIF + ENDIF + ENDIF + + ENDDO + + REWIND( UnitDataFile ) + + END SUBROUTINE GetFileLength + + !------------------------------------------------------------------------------- + !> This subroutine takes a line of text that is passed in and reads the first + !! word to see if it is a number. An internal read is used to do this. If + !! it is a number, it is started in ValueRead and returned. The flag IsRealNum + !! is set to true. Otherwise, ValueRead is set to NaN (value from the NWTC_Num) + !! and the flag is set to false. + !! + !! The IsRealNum flag is set to indicate if we actually have a real number or + !! not. After calling this routine, a simple if statement can be used: + !! + !! @code + !! IF (IsRealNum) THEN + !! ! do something + !! ELSE + !! ! do something else + !! ENDIF + !! @endcode + !! + !------------------------------------------------------------------------------- + SUBROUTINE ReadRealNumberFromString(StringToParse, ValueRead, StrRead, IsRealNum, ErrStat, ErrMsg, IOErrStat) + CHARACTER(*), INTENT(IN ) :: StringToParse !< The string we were handed. + REAL(R8Ki), INTENT( OUT) :: ValueRead !< The variable being read. Returns as NaN (library defined) if not a Real. + CHARACTER(*), INTENT( OUT) :: StrRead !< A string containing what was read from the ReadNum routine. + LOGICAL, INTENT( OUT) :: IsRealNum !< Flag indicating if we successfully read a Real + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< ErrID level returned from ReadNum + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message including message from ReadNum + INTEGER(IntKi), INTENT( OUT) :: IOErrStat !< Error status from the internal read. Useful for diagnostics. + + ErrStat = ErrID_None + ErrMsg = '' + + ! ReadNum returns a string contained in StrRead. So, we now try to do an internal read to VarRead and then trap errors. + read(StringToParse,*,IOSTAT=IOErrStat) StrRead + read(StringToParse,*,IOSTAT=IOErrStat) ValueRead + + ! If IOErrStat==0, then we have a real number, anything else is a problem. + if (IOErrStat==0) then + IsRealNum = .TRUE. + else + IsRealNum = .FALSE. + ValueRead = NaN ! This is NaN as defined in the NWTC_Num. + ErrMsg = 'Not a real number. '//TRIM(ErrMsgTmp)//NewLine + ErrSTat = ErrID_Severe + endif + + RETURN + END SUBROUTINE ReadRealNumberFromString + + !------------------------------------------------------------------------------- + !> This subroutine works with the ReadNum routine from the library. ReadNum is + !! called to read a word from the input file. An internal read is then done to + !! convert the string to a number that is stored in VarRead and returned. + !! + !! The IsRealNum flag is set to indicate if we actually have a real number or + !! not. After calling this routine, a simple if statement can be used: + !! + !! @code + !! IF (ISRealNum) THEN + !! ! do something + !! ELSE + !! ! do something else + !! ENDIF + !! @endcode + !! + !------------------------------------------------------------------------------- + SUBROUTINE ReadRealNumber(UnitNum, FileName, VarName, VarRead, StrRead, IsRealNum, ErrStat, ErrMsg, IOErrStat) + INTEGER(IntKi), INTENT(IN ) :: UnitNum !< The unit number of the file being read + CHARACTER(*), INTENT(IN ) :: FileName !< The name of the file being read. Used in the ErrMsg from ReadNum (Library routine). + CHARACTER(*), INTENT(IN ) :: VarName !< The variable we are reading. Used in the ErrMsg from ReadNum (Library routine)'. + REAL(R8Ki), INTENT( OUT) :: VarRead !< The variable being read. Returns as NaN (library defined) if not a Real. + CHARACTER(*), INTENT( OUT) :: StrRead !< A string containing what was read from the ReadNum routine. + LOGICAL, INTENT( OUT) :: IsRealNum !< Flag indicating if we successfully read a Real + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< ErrID level returned from ReadNum + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message including message from ReadNum + INTEGER(IntKi), INTENT( OUT) :: IOErrStat !< Error status from the internal read. Useful for diagnostics. + + INTEGER(IntKi) :: ErrStatTmp + CHARACTER(2048) :: ErrMsgTmp + + ErrStat = ErrID_None + ErrMsg = '' + + ! Now call the ReadNum routine to get the number + ! If it is a word that does not start with T or F, then ReadNum won't give any errors. + CALL ReadNum( UnitNum, FileName, StrRead, VarName, ErrStatTmp, ErrMsgTmp) + + ! ReadNum returns a string contained in StrRead. So, we now try to do an internal read to VarRead and then trap errors. + read(StrRead,*,IOSTAT=IOErrStat) VarRead + + ! If IOErrStat==0, then we have a real number, anything else is a problem. + if (IOErrStat==0) then + IsRealNum = .TRUE. + else + IsRealNum = .FALSE. + VarRead = NaN ! This is NaN as defined in the NWTC_Num. + ErrMsg = 'Not a real number. '//TRIM(ErrMsgTmp)//NewLine + ErrStat = ErrStatTmp ! The ErrStatTmp returned by the ReadNum routine is an ErrID level. + endif + RETURN + END SUBROUTINE ReadRealNumber + +END SUBROUTINE ReadInputDispFile + + + + +!> This routine exists only to support the development of the module. It will not be needed after the module is complete. +SUBROUTINE printSettings( DvrFlags, DvrSettings ) + ! The arguments + TYPE( SEDDriver_Flags ), INTENT(IN ) :: DvrFlags !< Flags indicating which settings were set + TYPE( SEDDriver_Settings ), INTENT(IN ) :: DvrSettings !< Stored settings + + CALL WrsCr(TRIM(GetNVD(DvrSettings%ProgInfo))) + CALL WrScr(' DvrIptFile: '//FLAG(DvrFlags%DvrIptFile)// ' '//TRIM(DvrSettings%DvrIptFileName)) + CALL WrScr(' SEDIptFile: '//FLAG(DvrFlags%SEDIptFile)// ' '//TRIM(DvrSettings%SEDIptFileName)) + CALL WrScr(' TStart: '//FLAG(DvrFlags%TStart)// ' '//TRIM(Num2LStr(DvrSettings%TStart))) + IF ( DvrFlags%DTDefault) THEN + CALL WrScr(' DT: '//FLAG(DvrFlags%DT)// ' DEFAULT') + ELSE + CALL WrScr(' DT: '//FLAG(DvrFlags%DT)// ' '//TRIM(Num2LStr(DvrSettings%DT))) + ENDIF + IF ( DvrFlags%NumTimeStepsDefault) THEN + CALL WrScr(' NumTimeSteps: '//FLAG(DvrFlags%NumTimeSteps)// ' DEFAULT') + ELSE + CALL WrScr(' NumTimeSteps: '//FLAG(DvrFlags%NumTimeSteps)// ' '//TRIM(Num2LStr(DvrSettings%NumTimeSteps))) + ENDIF + CALL WrScr(' Verbose: '//FLAG(DvrFlags%Verbose)) + CALL WrScr(' VVerbose: '//FLAG(DvrFlags%VVerbose)) + RETURN +END SUBROUTINE printSettings + + +!> This routine exists only to support the development of the module. It will not be kept after the module is complete. +!! This routine takes a flag setting (LOGICAL) and exports either 'T' or '-' for T/F (respectively) +FUNCTION FLAG(flagval) + LOGICAL, INTENT(IN ) :: flagval !< Value of the flag + CHARACTER(1) :: FLAG !< character interpretation (for prettiness when printing) + IF ( flagval ) THEN + FLAG = 'T' + ELSE + FLAG = '-' + ENDIF + RETURN +END FUNCTION FLAG + + +SUBROUTINE Dvr_InitializeOutputFile(OutUnit,IntOutput,RootName,ErrStat,ErrMsg) + integer(IntKi), intent( out):: OutUnit + type(SED_InitOutputType), intent(in ):: IntOutput ! Output for initialization routine + integer(IntKi), intent( out):: ErrStat ! Error status of the operation + character(*), intent( out):: ErrMsg ! Error message if ErrStat /= ErrID_None + character(*), intent(in ):: RootName + integer(IntKi) :: i + integer(IntKi) :: numOuts + integer(IntKi) :: ErrStat2 ! Temporary Error status + character(ErrMsgLen) :: ErrMsg2 ! Temporary Error message + character(*), parameter :: RoutineName = 'Dvr_InitializeOutputFile' + + ErrStat = ErrID_none + ErrMsg = "" + + CALL GetNewUnit(OutUnit,ErrStat2,ErrMsg2) + CALL OpenFOutFile ( OutUnit, trim(RootName)//'.out', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) return + + write (OutUnit,'(/,A)') 'Predictions were generated on '//CurDate()//' at '//CurTime()//' using '//trim(GetNVD(IntOutput%Ver)) + write (OutUnit,'()' ) !print a blank line + + numOuts = size(IntOutput%WriteOutputHdr) + !...................................................... + ! Write the names of the output parameters on one line: + !...................................................... + + write (OutUnit,'()') + write (OutUnit,'()') + write (OutUnit,'()') + + call WrFileNR ( OutUnit, 'Time' ) + + do i=1,NumOuts + call WrFileNR ( OutUnit, tab//IntOutput%WriteOutputHdr(i) ) + end do ! i + + write (OutUnit,'()') + + !...................................................... + ! Write the units of the output parameters on one line: + !...................................................... + + call WrFileNR ( OutUnit, '(s)' ) + + do i=1,NumOuts + call WrFileNR ( Outunit, tab//trim(IntOutput%WriteOutputUnt(i)) ) + end do ! i + + write (OutUnit,'()') + + +END SUBROUTINE Dvr_InitializeOutputFile + +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE Dvr_WriteOutputLine(t,OutUnit, OutFmt, Output) + real(DbKi) , intent(in ) :: t ! simulation time (s) + integer(IntKi) , intent(in ) :: OutUnit ! Status of error message + character(*) , intent(in ) :: OutFmt + type(SED_OutputType), intent(in ) :: Output + integer(IntKi) :: errStat ! Status of error message (we're going to ignore errors in writing to the file) + character(ErrMsgLen) :: errMsg ! Error message if ErrStat /= ErrID_None + character(200) :: frmt ! A string to hold a format specifier + character(15) :: tmpStr ! temporary string to print the time output as text + + frmt = '"'//tab//'"'//trim(OutFmt) ! format for array elements from individual modules + + ! time + write( tmpStr, '(F15.6)' ) t + call WrFileNR( OutUnit, tmpStr ) + call WrNumAryFileNR ( OutUnit, Output%WriteOutput, frmt, errStat, errMsg ) + + ! write a new line (advance to the next line) + write (OutUnit,'()') +end subroutine Dvr_WriteOutputLine + + +END MODULE SED_Driver_Subs diff --git a/modules/simple-elastodyn/src/driver/SED_Driver_Types.f90 b/modules/simple-elastodyn/src/driver/SED_Driver_Types.f90 new file mode 100644 index 0000000000..fef837eb8c --- /dev/null +++ b/modules/simple-elastodyn/src/driver/SED_Driver_Types.f90 @@ -0,0 +1,69 @@ +!********************************************************************************************************************************** +! +! MODULE: SED_Driver_Types - This module contains types used by the SED Driver program to store arguments passed in +! +! The types listed here are used within the SED Driver program to store the settings. These settings are read in as +! command line arguments, then stored within these types. +! +!********************************************************************************************************************************** +! +!.................................................................................................................................. +! LICENSING +! Copyright (C) 2015 National Renewable Energy Laboratory +! +! This file is part of SED. +! +! SED is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as +! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +! of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along with SED. +! If not, see . +! +!********************************************************************************************************************************** +module SED_Driver_Types + + use NWTC_Library + use SED_Types + + implicit none + + !> This contains flags to note if the settings were made. This same data structure is + !! used both during the driver input file and the command line options. + !! + !! NOTE: The WindFileType is only set if it is given as a command line option. Otherwise + !! it is handled internally by InflowWInd. + !! + !! NOTE: The wind direction is specified by the SED input file. + type :: SEDDriver_Flags + logical :: DvrIptFile = .FALSE. !< Was an input file name given on the command line? + logical :: SEDIptFile = .FALSE. !< Was an SED input file requested? + logical :: InputDispFile = .FALSE. !< Input displacement time series + logical :: TStart = .FALSE. !< specified a start time + logical :: NumTimeSteps = .FALSE. !< specified a number of timesteps to process + logical :: NumTimeStepsDefault = .FALSE. !< specified a 'DEFAULT' for number of timesteps to process + logical :: DT = .FALSE. !< specified a resolution in time + logical :: DTDefault = .FALSE. !< specified a 'DEFAULT' for the time resolution + logical :: Verbose = .FALSE. !< Verbose error reporting + logical :: VVerbose = .FALSE. !< Very Verbose error reporting + end type SEDDriver_Flags + + + ! This contains all the settings (possible passed in arguments). + type :: SEDDriver_Settings + character(1024) :: DvrIptFileName !< Driver input file name + character(1024) :: SEDIptFileName !< Filename of SED input file to read (if no driver input file) + character(1024) :: InputDispFile !< Filename of SED time series displacements + + integer(IntKi) :: NumTimeSteps !< Number of timesteps + real(DbKi) :: DT !< resolution of time + real(DbKi) :: TStart !< Start time + + type(ProgDesc) :: ProgInfo !< Program info + type(ProgDesc) :: SEDProgInfo !< Program info for SED + end type SEDDriver_Settings + + +end module SED_Driver_Types From cd0a6c15f5cb9a3926a05c1737fca67389a70b1a Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 21 Feb 2022 12:19:00 -0700 Subject: [PATCH 021/130] NWTC_IO: ParseVarWDefault was putting double entries in echo files if not default value --- modules/nwtc-library/src/NWTC_IO.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index 81d768f82b..eb742ef302 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -4611,7 +4611,7 @@ SUBROUTINE ParseSiVarWDefault ( FileInfo, LineNum, ExpVarName, Var, VarDefault, CALL Conv2UC( defaultStr ) IF ( INDEX(defaultStr, "DEFAULT" ) /= 1 ) THEN ! If it's not "default", read this variable LineNum = LineNum - 1 ! back up a line - CALL ParseVar ( FileInfo, LineNum, ExpVarName, Var, ErrStatLcl, ErrMsg2, UnEc ) + CALL ParseVar ( FileInfo, LineNum, ExpVarName, Var, ErrStatLcl, ErrMsg2 ) CALL SetErrStat( ErrStatLcl, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ELSE Var = VarDefault ! "DEFAULT" value From 524e408c08d02be43f3f69fef89a0d25ff810512 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 21 Feb 2022 18:25:19 -0700 Subject: [PATCH 022/130] ADsk: add input file passing/parsing - Also add a bit to the driver --- docs/source/user/aerodisk/input_files.rst | 5 +- modules/aerodisk/src/AeroDisk.f90 | 72 +- modules/aerodisk/src/AeroDisk_IO.f90 | 773 +++- .../aerodisk/src/AeroDisk_Output_Params.f90 | 66 + modules/aerodisk/src/AeroDisk_Registry.txt | 72 +- modules/aerodisk/src/AeroDisk_Types.f90 | 3276 ++++++++--------- .../aerodisk/src/driver/AeroDisk_Driver.f90 | 1 + .../src/driver/AeroDisk_Driver_Subs.f90 | 11 + .../src/driver/AeroDisk_Driver_Types.f90 | 2 + 9 files changed, 2489 insertions(+), 1789 deletions(-) diff --git a/docs/source/user/aerodisk/input_files.rst b/docs/source/user/aerodisk/input_files.rst index d50cac0983..aaf166b228 100644 --- a/docs/source/user/aerodisk/input_files.rst +++ b/docs/source/user/aerodisk/input_files.rst @@ -19,10 +19,13 @@ Input file --- AERO DISK INPUT FILE ------- Sample actuator disk input file + --- SIMULATION CONTROL --------- + FALSE echo - Echo input data to ".ADsk.ech" (flag) + "default" DT - Integration time step (s) --- ENVIRONMENTAL CONDITIONS --- 1.225 AirDens - Air density (kg/m^3) (or "default") --- ACTUATOR DISK PROPERTIES --- - 63.0 RotRad - Rotor radius (m) (or "default") + 63.0 RotorRad - Rotor radius (m) (or "default") "RtSpd,VRel,Skew,Pitch" InColNames - Input column headers (string) {may include a combination of "TSR, RtSpd, VRel, Pitch, Skew"} (up to 4 columns) [choose TSR or RtSpd,VRel; if Skew is absent, Skew is modeled as (COS(Skew))^2] 9,1,1,1 InColDims - Number of values in each column (-) (must have same number of columns as InColName) [each >=2] RtSpd VRel Skew Pitch C_Fx C_Fy C_Fz C_Mx C_My C_Mz diff --git a/modules/aerodisk/src/AeroDisk.f90 b/modules/aerodisk/src/AeroDisk.f90 index 10eacd6be4..f591611c7b 100644 --- a/modules/aerodisk/src/AeroDisk.f90 +++ b/modules/aerodisk/src/AeroDisk.f90 @@ -48,7 +48,7 @@ MODULE AeroDisk !public :: ADsk_GetOP CONTAINS - + !---------------------------------------------------------------------------------------------------------------------------------- !> Initialize the AeroDisk module: @@ -63,15 +63,17 @@ SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO type(ADsk_DiscreteStateType), intent( out) :: xd !< Initial discrete states type(ADsk_ConstraintStateType), intent( out) :: z !< Initial guess of the constraint states type(ADsk_OtherStateType), intent( out) :: OtherState !< Initial other states (logical, etc) - type(ADsk_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated) + type(ADsk_OutputType), intent( out) :: y !< Initial system outputs (outputs are not calculated) type(ADsk_MiscVarType), intent( out) :: m !< Misc variables for optimization (not copied in glue code) - real(DbKi), intent(inout) :: Interval !< Coupling interval in seconds: the rate that + real(DbKi), intent(inout) :: Interval !< Coupling interval in seconds type(ADsk_InitOutputType), intent( out) :: InitOut !< Output for initialization routine integer(IntKi), intent( out) :: ErrStat !< Error status of the operation character(*), intent( out) :: ErrMsg !< Error message if ErrStat /= ErrID_None ! local variables - integer(IntKi) :: NumOuts ! number of outputs; would probably be in the parameter type + type(ADsk_InputFile) :: InputFileData !< Data from input file as a string array + type(FileInfoType) :: FileInfo_In !< The derived type for holding the full input file for parsing -- we may pass this in the future + integer(IntKi) :: UnEc ! unit number for the echo file (-1 for not in use) integer(IntKi) :: ErrStat2 ! local error status character(ErrMsgLen) :: ErrMsg2 ! local error message character(*), parameter :: RoutineName = 'ADsk_Init' @@ -79,38 +81,66 @@ SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO ! Initialize variables ErrStat = ErrID_None ErrMsg = "" - NumOuts = 2 - ! Initialize the NWTC Subroutine Library + ! Initialize the NWTC Subroutine Library call NWTC_Init( ) - ! Display the module information + ! Display the module information call DispNVD( ADsk_Ver ) + ! set rootname + p%RootName = trim(InitInp%RootName)//".ADsk" + + ! Get primary input file + if ( InitInp%UseInputFile ) then + CALL ProcessComFile( InitInp%InputFile, FileInfo_In, ErrStat2, ErrMsg2 ) + else + CALL NWTC_Library_CopyFileInfoType( InitInp%PassedFileData, FileInfo_In, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) + endif + if (Failed()) return + + ! For diagnostic purposes, the following can be used to display the contents + ! of the FileInfo_In data structure. + !call Print_FileInfo_Struct( CU, FileInfo_In ) ! CU is the screen -- different number on different systems. + + ! Parse all ADsk-related input and populate the InputFileData structure + call ADsk_ParsePrimaryFileData( InitInp, p%RootName, Interval, FileInfo_In, InputFileData, UnEc, ErrStat2, ErrMsg2 ) + if (Failed()) return; + +call SetErrStat(ErrID_Fatal,'Have not set parameters from init or checked primary file data yet',ErrStat,ErrMsg,RoutineName); return + + ! Verify all the necessary initialization and input file data +! CALL ADskInput_ValidateProcessInitData( InitInp, Interval, InputFileData, ErrStat2, ErrMsg2 ) +! if (Failed()) return; + + +!FIXME: see if we requested something different for time ! Define parameters here: - p%DeltaT = Interval + p%DT = Interval + p%numOuts = InputFileData%NumOuts ! Define initial system states here: ! x%DummyContState = 0.0_ReKi ! xd%DummyDiscState = 0.0_ReKi ! z%DummyConstrState = 0.0_ReKi ! OtherState%DummyOtherState = 0.0_ReKi - - ! Define optimization variables here: + + ! Define optimization variables here: m%DummyMiscVar = 0.0_ReKi - + ! Define initial guess for the system inputs here: ! u%DummyInput = 0.0_ReKi + ! call SetOutParams() ! Define system output initializations (set up mesh) here: - call AllocAry( y%WriteOutput, NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; + call AllocAry( y%WriteOutput, p%NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; y%WriteOutput = 0 ! Define initialization-routine output here: - call AllocAry(InitOut%WriteOutputHdr,NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; - call AllocAry(InitOut%WriteOutputUnt,NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%WriteOutputHdr,p%NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%WriteOutputUnt,p%NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; InitOut%WriteOutputHdr = (/ 'Time ', 'Column2' /) InitOut%WriteOutputUnt = (/ '(s)', '(-)' /) @@ -118,14 +148,16 @@ SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO !FIXME: any logic around this? !Interval = p%DeltaT - + if (InitInp%Linearize) then CALL SetErrStat( ErrID_Fatal, 'AeroDisk cannot perform linearization analysis.', ErrStat, ErrMsg, RoutineName) end if +call SetErrStat(ErrID_Fatal, 'Stopping early',ErrStat,ErrMsg,RoutineName); return + contains logical function Failed() - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev !if (Failed) call CleanUp() end function Failed @@ -227,7 +259,7 @@ SUBROUTINE ADsk_UpdateStates( t, n, Inputs, InputTimes, p, x, xd, z, OtherState, contains logical function Failed() - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev if (Failed) call CleanUp() end function Failed @@ -271,7 +303,7 @@ SUBROUTINE ADsk_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg contains logical function Failed() - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev !if (Failed) call CleanUp() end function Failed @@ -308,9 +340,9 @@ SUBROUTINE ADsk_CalcContStateDeriv( t, u, p, x, xd, z, OtherState, m, dxdt, ErrS contains logical function Failed() - call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev - if (Failed) call CleanUp() +! if (Failed) call CleanUp() end function Failed END SUBROUTINE ADsk_CalcContStateDeriv diff --git a/modules/aerodisk/src/AeroDisk_IO.f90 b/modules/aerodisk/src/AeroDisk_IO.f90 index 5ee01c45f3..44694f7cac 100644 --- a/modules/aerodisk/src/AeroDisk_IO.f90 +++ b/modules/aerodisk/src/AeroDisk_IO.f90 @@ -24,10 +24,628 @@ MODULE AeroDisk_IO implicit none + ! data storage for reading/parsing table + type :: TableIndexType + integer(IntKi) :: ColTSR !< Column number for Tip-Speed Ratio + integer(IntKi) :: ColRtSpd !< Column number for Rotor Speed + integer(IntKi) :: ColVRel !< Column number for VRel + integer(IntKi) :: ColSkew !< Column number for Skew + integer(IntKi) :: ColPitch !< Column number for Pitch + end type TableIndexType contains -SUBROUTINE ADsk_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) +!--------------------------------------------------------------- +!> Parse the input in the InFileInfo (FileInfo_Type data structure): +subroutine ADsk_ParsePrimaryFileData( InitInp, RootName, interval, FileInfo_In, InputFileData, UnEc, ErrStat, ErrMsg ) + type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization routine + character(1024), intent(in ) :: RootName !< root name for summary file + real(DBKi), intent(in ) :: interval !< timestep + type(FileInfoType), intent(in ) :: FileInfo_In !< The input file stored in a data structure + type(ADsk_InputFile), intent(inout) :: InputFileData !< The data for initialization + integer(IntKi), intent( out) :: UnEc !< The local unit number for this module's echo file + integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine + character(*), intent( out) :: ErrMsg !< Error message from this subroutine + + ! local vars + integer(IntKi) :: CurLine !< current entry in FileInfo_In%Lines array + integer(IntKi) :: i !< generic counter + type(TableIndexType) :: TabIdx !< indices for table columnns, for simplifying data parsing/passing + real(SiKi) :: TmpRe(10) !< temporary 10 number array for reading values in from table + integer(IntKi) :: ErrStat2 !< Temporary error status for subroutine and function calls + character(ErrMsgLen) :: ErrMsg2 !< Temporary error message for subroutine and function calls + character(*), parameter :: RoutineName="ADsk_ParsePrimaryFileData" + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + UnEc = -1 ! No file + + + CALL AllocAry( InputFileData%OutList, MaxOutPts, "Outlist", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + !====== General ==================================================================================== + CurLine = 4 ! Skip the first three lines as they are known to be header lines and separators + call ParseVar( FileInfo_In, CurLine, 'Echo', InputFileData%Echo, ErrStat2, ErrMsg2 ) + if (Failed()) return; + + if ( InputFileData%Echo ) then + CALL OpenEcho ( UnEc, TRIM(RootName)//'.ech', ErrStat2, ErrMsg2 ) + if (Failed()) return; + WRITE(UnEc, '(A)') 'Echo file for AeroDisk primary input file: '//trim(InitInp%InputFile) + ! Write the first three lines into the echo file + WRITE(UnEc, '(A)') FileInfo_In%Lines(1) + WRITE(UnEc, '(A)') FileInfo_In%Lines(2) + WRITE(UnEc, '(A)') FileInfo_In%Lines(3) + + CurLine = 4 + call ParseVar( FileInfo_In, CurLine, 'Echo', InputFileData%Echo, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + endif + + + ! DeltaT - Time interval for aerodynamic calculations {or default} (s): + call ParseVarWDefault ( FileInfo_In, CurLine, "DT", InputFileData%DT, interval, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + !====== Environmental Conditions =================================================================== + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + ! AirDens - Air density {or default} (kg/m^3) + call ParseVarWDefault( FileInfo_In, CurLine, "AirDens", InputFileData%AirDens, InitInp%defAirDens, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + !====== Actuator Disk Properties =================================================================== + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + ! RotorRad - Rotor radius (m) (or "default") + call ParseVarWDefault( FileInfo_In, CurLine, "RotorRad", InputFileData%RotorRad, InitInp%RotorRad, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + ! InColNames - names for the input columns for the table. + call Get_InColNames( FileInfo_In, CurLine, TabIdx, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + ! InColDims - Number of values in each column (-) (must have same number of columns as InColName) [each >=2] + call Get_InColDims( FileInfo_In, CurLine, TabIdx, InputFileData%AeroTable, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + ! Column headers + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) + CurLine = CurLine + 1 + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) + CurLine = CurLine + 1 + + ! Read table + call Get_RtAeroTableData( FileInfo_In, CurLine, TabIdx, InputFileData%AeroTable, ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return + + + !====== Outputs ==================================================================================== + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 +! ! SumPrint - Generate a summary file listing input options and interpolated properties to ".AD.sum"? (flag) +! call ParseVar( FileInfo_In, CurLine, "SumPrint", InputFileData%SumPrint, ErrStat2, ErrMsg2, UnEc ) +! if (Failed()) return + + if ( InputFileData%Echo ) WRITE(UnEc, '(A)') FileInfo_In%Lines(CurLine) ! Write section break to echo + CurLine = CurLine + 1 + call ReadOutputListFromFileInfo( FileInfo_In, CurLine, InputFileData%OutList, & + InputFileData%NumOuts, 'OutList', "List of user-requested output channels", ErrStat2, ErrMsg2, UnEc ) + if (Failed()) return; + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev +! if (Failed) call CleanUp() + end function Failed + subroutine GetVarNamePos(FileName,LineNo,ChAry,NameToCheck,ColNum,ErrStat3,ErrMsg3) + character(*), intent(in ) :: FileName + integer(IntKi), intent(in ) :: LineNo + character(*), intent(in ) :: ChAry(:) + character(*), intent(in ) :: NameToCheck + integer(IntKi), intent( out) :: ColNum + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + character(len(ChAry(1))) :: TmpNm + character(len=len(NameToCheck)) :: TmpNmCk + integer(IntKi) :: WordNum + logical :: TmpFlag + ErrStat3 = ErrID_None + ErrMsg3 = "" + TmpFlag = .false. + ColNum = 0_IntKi ! if not present + TmpNmCk = NameToCheck; call Conv2UC(TmpNmCk) + do WordNum=1,size(ChAry) + TmpNm = ChAry(WordNum); call Conv2UC(TmpNm) + if (trim(TmpNm) == TmpNmCk) then + if (TmpFlag) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = NewLine//' >> A fatal error occurred when parsing data from '// & + trim(FileName)//'.'//NewLine// & + ' >> The column name '//trim(NameToCheck)//' occurs more than once on line '// & + trim(Num2LStr(LineNo))//'.' + return + endif + TmpFlag = .true. + ColNum = WordNum + endif + enddo + end subroutine GetVarNamePos + subroutine Get_InColNames(Info,LineNo,Idx,ErrStat3,ErrMsg3,UnEc) + ! A custom routine is used here rather than using the ParseChAry as ParseChAry does not + ! handle an unknown number of quoted strings well (i.e: "RtSpd,VRel,Skew,Pitch") + type(FileInfoType), intent(in ) :: Info + integer(IntKi), intent(inout) :: LineNo + type(TableIndexType), intent(inout) :: Idx + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi), intent(in ) :: UnEc + integer(IntKi) :: WordPos + character(1024) :: thisFile ! Simplify some error management + integer(IntKi) :: thisLine ! Simplify some error management + character(20) :: TmpChAry(6) + ErrStat3 = ErrID_None + ErrMsg3 = "" + ! Echo if we have a file + if ( UnEc > 0 ) write (UnEc,'(A)') TRIM( Info%Lines(LineNo) ) + + ! Parse out words from the line + call GetWords( Info%Lines(LineNo), TmpChAry, size(TmpChAry)) + + ! file info for error handling -- note that this could be in a different file than the above!!!! + thisFile =trim(Info%FileList(Info%FileIndx(LineNo))) + thisLine = Info%FileLine(LineNo) + + ! Check that this is the right line in the file and InColNames exists in first 5 words of line + call GetVarNamePos(thisFile, thisLine, TmpChAry, "InColNames", WordPos, ErrStat3, ErrMsg3) ! ignore duplicate entry error here + ! Error handling if wrong row + if (WordPos <= 0_IntKi) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = NewLine//' >> A fatal error occurred when parsing data from '// & + trim(thisFile)//'.'//NewLine// & + ' >> The variable "InColNames" was not found on line '//trim(Num2LStr(thisLine))//'.' + return + endif + + ! Get order of the other columns + call GetVarNamePos(thisFile, thisLine, TmpChAry, "TSR", Idx%ColTSR, ErrStat3,ErrMsg3); if (ErrStat3 >= ErrID_Fatal) return + call GetVarNamePos(thisFile, thisLine, TmpChAry, "RtSpd", Idx%ColRtSpd, ErrStat3,ErrMsg3); if (ErrStat3 >= ErrID_Fatal) return + call GetVarNamePos(thisFile, thisLine, TmpChAry, "VRel", Idx%ColVRel, ErrStat3,ErrMsg3); if (ErrStat3 >= ErrID_Fatal) return + call GetVarNamePos(thisFile, thisLine, TmpChAry, "Skew", Idx%ColSkew, ErrStat3,ErrMsg3); if (ErrStat3 >= ErrID_Fatal) return + call GetVarNamePos(thisFile, thisLine, TmpChAry, "Pitch", Idx%ColPitch, ErrStat3,ErrMsg3); if (ErrStat3 >= ErrID_Fatal) return + + ! make sure have have column names + if ((Idx%ColTSR + Idx%ColRtSpd + Idx%ColVRel + Idx%ColSkew + Idx%ColPitch) <= 0_IntKi) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = NewLine//' >> A fatal error occurred when parsing data from '// & + trim(thisFile)//'.'//NewLine// & + ' >> At least one column of data named "TSR", "RtSpd", "VRel", "Skew", or "Pitch" must exist'// & + ' in the table header, but none were found'//trim(Num2LStr(thisLine))//'.' + return + endif + LineNo = LineNo + 1 ! Picked up column names, so increment to next line and return + return + end subroutine Get_InColNames + subroutine Get_InColDims(Info,LineNo,Idx,AeroTable,ErrStat3,ErrMsg3,UnEc) + ! A custom routine is used here rather than using the ParseChAry as ParseChAry does not + ! handle an unknown number of quoted strings well (i.e: "RtSpd,VRel,Skew,Pitch") + type(FileInfoType), intent(in ) :: Info + integer(IntKi), intent(inout) :: LineNo + type(TableIndexType), intent(in ) :: Idx + type(ADsk_AeroTable), intent(inout) :: AeroTable + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi), intent(in ) :: UnEc + integer(IntKi) :: WordPos + integer(IntKi) :: IOS + character(1024) :: thisFile ! Simplify some error management + integer(IntKi) :: thisLine ! Simplify some error management + character(20) :: TmpChAry(6) ! Assume 5 columns and the name + ErrStat3 = ErrID_None + ErrMsg3 = "" + ! Echo if we have a file + if ( UnEc > 0 ) write (UnEc,'(A)') TRIM( Info%Lines(LineNo) ) + + ! Parse out words from the line + call GetWords( Info%Lines(LineNo), TmpChAry, size(TmpChAry)) + + ! file info for error handling -- note that this could be in a different file than the above!!!! + thisFile =trim(Info%FileList(Info%FileIndx(LineNo))) + thisLine = Info%FileLine(LineNo) + + ! Check that this is the right line in the file and InColDims exists in first 5 words of line + call GetVarNamePos(thisFile, thisLine, TmpChAry, "InColDims", WordPos, ErrStat3, ErrMsg3) ! ignore duplicate entry error here + ! Error handling if wrong row + if (WordPos <= 0_IntKi) then + ErrStat3 = ErrID_Fatal + ErrMsg3 = NewLine//' >> A fatal error occurred when parsing data from '// & + trim(thisFile)//'.'//NewLine// & + ' >> The variable "InColDims" was not found on line '//trim(Num2LStr(thisLine))//'.' + return + endif + + ! set number of indices for each to 0 + AeroTable%N_TSR = 0 + AeroTable%N_RtSpd = 0 + AeroTable%N_VRel = 0 + AeroTable%N_Skew = 0 + AeroTable%N_Pitch = 0 + + ! Read numbers for number of various entries from the tmpChAry + if (Idx%ColTSR > 0_IntKi) then + READ (TmpChAry(Idx%ColTSR ),*,IOSTAT=IOS) AeroTable%N_TSR + if (IOS /= 0) then + call SetErrStat(ErrID_Fatal,'Could not read "N_TSR" from column '// & + trim(Num2LStr(Idx%ColTSR))//' on line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + return + endif + endif + if (Idx%ColRtSpd > 0_IntKi) then + READ (TmpChAry(Idx%ColRtSpd),*,IOSTAT=IOS) AeroTable%N_RtSpd + if (IOS /= 0) then + call SetErrStat(ErrID_Fatal,'Could not read "N_RtSpd" from column '// & + trim(Num2LStr(Idx%ColRtSpd))//' on line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + return + endif + endif + if (Idx%ColVRel > 0_IntKi) then + READ (TmpChAry(Idx%ColVRel ),*,IOSTAT=IOS) AeroTable%N_VRel + if (IOS /= 0) then + call SetErrStat(ErrID_Fatal,'Could not read "N_VRel" from column '// & + trim(Num2LStr(Idx%ColVRel))//' on line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + return + endif + endif + if (Idx%ColSkew > 0_IntKi) then + READ (TmpChAry(Idx%ColSkew ),*,IOSTAT=IOS) AeroTable%N_Skew + if (IOS /= 0) then + call SetErrStat(ErrID_Fatal,'Could not read "N_Skew" from column '// & + trim(Num2LStr(Idx%ColSkew))//' on line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + return + endif + endif + if (Idx%ColPitch > 0_IntKi) then + READ (TmpChAry(Idx%ColPitch),*,IOSTAT=IOS) AeroTable%N_Pitch + if (IOS /= 0) then + call SetErrStat(ErrID_Fatal,'Could not read "N_Pitch" from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + return + endif + endif + ! make sure all values positive + if (AeroTable%N_TSR < 0_IntKi) call SetErrStat(ErrID_Fatal,'Entry for "N_TSR" must be postive valued from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))//' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + if (AeroTable%N_RtSpd < 0_IntKi) call SetErrStat(ErrID_Fatal,'Entry for "N_RtSpd" must be postive valued from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))//' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + if (AeroTable%N_VRel < 0_IntKi) call SetErrStat(ErrID_Fatal,'Entry for "N_VRel" must be postive valued from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))//' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + if (AeroTable%N_Skew < 0_IntKi) call SetErrStat(ErrID_Fatal,'Entry for "N_Skew" must be postive valued from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))//' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + if (AeroTable%N_Pitch < 0_IntKi) call SetErrStat(ErrID_Fatal,'Entry for "N_Pitch" must be postive valued from column '// & + trim(Num2LStr(Idx%ColPitch))//' on line '//trim(Num2LStr(thisLine))//' in file '//trim(thisFile)//'.',ErrStat3,ErrMsg3,'') + ! NOTE: we are storing 0 for the dimensions that don't exist in the table. We will + ! modify this later to make table usage simpler + LineNo = LineNo + 1 ! Picked up column names, so increment to next line and return + return + end subroutine Get_InColDims + +end subroutine ADsk_ParsePrimaryFileData + + +subroutine Get_RtAeroTableData(Info,LineNo,Idx,AeroTable,ErrStat,ErrMsg,UnEc) + ! Table entries may not be in order. So sort while reading in. + ! NOTE: Sparse data files are not currently supported + type(FileInfoType), intent(in ) :: Info + integer(IntKi), intent(inout) :: LineNo + type(TableIndexType), intent(in ) :: Idx + type(ADsk_AeroTable), intent(inout) :: AeroTable + integer(IntKi), intent( out) :: ErrStat + character(ErrMsgLen), intent( out) :: ErrMsg + integer(IntKi), intent(in ) :: UnEc + integer(IntKi) :: WordPos + integer(IntKi) :: IOS + character(1024) :: thisFile ! Simplify some error management + integer(IntKi) :: thisLine ! Simplify some error management + integer(IntKi) :: i,j ! Generic counters + integer(IntKi) :: NumCols ! number of columns expected + integer(IntKi) :: NumRows ! number of rows expected + integer(IntKi) :: Sz(5) ! Array size -- for readability of code + real(SiKi), allocatable :: TmpTab(:,:) ! temporary real array of allocatable size -- will read entire table in, then do the sorting + logical, allocatable :: Mask(:,:,:,:,:) ! to make sure we aren't missing any terms + integer(IntKi) :: ErrStat2 !< Temporary error status for subroutine and function calls + character(ErrMsgLen) :: ErrMsg2 !< Temporary error message for subroutine and function calls + character(*), parameter :: RoutineName='Get_RtAeroTableData' + ErrStat = ErrID_None + ErrMsg = "" + + + ! Number of columns in table + Sz = 0_IntKi + if (AeroTable%N_TSR > 0_IntKi) Sz(1) = 1_IntKi + if (AeroTable%N_RtSpd > 0_IntKi) Sz(2) = 1_IntKi + if (AeroTable%N_VRel > 0_IntKi) Sz(3) = 1_IntKi + if (AeroTable%N_Pitch > 0_IntKi) Sz(4) = 1_IntKi + if (AeroTable%N_Skew > 0_IntKi) Sz(5) = 1_IntKi + NumCols = sum(Sz) + 6_IntKi ! Add DOF columns + + ! temporary array for sizing -- note that min dimension size is 1 so we calculate number of rows correctly + Sz(1) = max(AeroTable%N_TSR, 1_IntKi) + Sz(2) = max(AeroTable%N_RtSpd,1_IntKi) + Sz(3) = max(AeroTable%N_VRel, 1_IntKi) + Sz(4) = max(AeroTable%N_Pitch,1_IntKi) + Sz(5) = max(AeroTable%N_Skew, 1_IntKi) + + ! Total number of rows we expect to find in the table + NumRows= Sz(1) * Sz(2) * Sz(3) * Sz(4) * Sz(5) + + ! Allocate arrays for forces/moments + call AllocAry(AeroTable%C_Fx, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_Fx', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_Fx = 0.0_SiKi + call AllocAry(AeroTable%C_Fy, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_Fy', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_Fy = 0.0_SiKi + call AllocAry(AeroTable%C_Fz, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_Fz', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_Fz = 0.0_SiKi + call AllocAry(AeroTable%C_Mx, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_Mx', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_Mx = 0.0_SiKi + call AllocAry(AeroTable%C_My, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_My', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_My = 0.0_SiKi + call AllocAry(AeroTable%C_Mz, Sz(1), Sz(2), Sz(3), Sz(4), Sz(5), 'AeroTable%C_Mz', ErrStat2, ErrMsg2); if (Failed()) return; AeroTable%C_Mz = 0.0_SiKi + + ! Allocate a mask for data checks + allocate(Mask(Sz(1),Sz(2),Sz(3),Sz(4),Sz(5)),STAT=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal,'Could not allocate array for data mask',ErrStat,ErrMsg,RoutineName) + call Cleanup() + return + endif + Mask = .false. + + ! Slurp the entire table into real array -- order for more efficient searching (bad for reading in) + call AllocAry(TmpTab,NumRows,NumCols,'TemporaryTable',ErrStat2,ErrMsg2); if (Failed()) return + do i=1,NumRows + read (Info%Lines(LineNo),*,iostat=IOS) TmpTab(i,1:NumCols) + if (IOS /= 0_IntKi) then + thisFile =trim(Info%FileList(Info%FileIndx(LineNo))) + thisLine = Info%FileLine(LineNo) + call SetErrStat(ErrID_Fatal,'Could not read "Actuator Disk Properties Table" row '//trim(Num2LStr(i))//' (line '//trim(Num2LStr(thisLine))// & + ' in file '//trim(thisFile)//'). Expecting '//trim(Num2LStr(NumRows))//' rows and '//trim(Num2LStr(NumCols))//' columns in table.',ErrStat,ErrMsg,RoutineName) + call Cleanup() + return + endif + if (UnEc > 0_IntKi) write(UnEc,'(A)') trim(Info%Lines(LineNo)) + LineNo = LineNo + 1 + enddo + + ! Find the unique values in the indexing columns of the table + if (AeroTable%N_TSR > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColTSR ),'TSR' ,AeroTable%N_TSR ,AeroTable%TSR , ErrStat2, ErrMsg2); if (Failed()) return + if (AeroTable%N_RtSpd > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColRtSpd),'RtSpd',AeroTable%N_RtSpd,AeroTable%RtSpd, ErrStat2, ErrMsg2); if (Failed()) return + if (AeroTable%N_VRel > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColVRel ),'VRel' ,AeroTable%N_VRel ,AeroTable%VRel , ErrStat2, ErrMsg2); if (Failed()) return + if (AeroTable%N_Pitch > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColPitch),'Pitch',AeroTable%N_Pitch,AeroTable%Pitch, ErrStat2, ErrMsg2); if (Failed()) return + if (AeroTable%N_Skew > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColSkew ),'Skew' ,AeroTable%N_Skew ,AeroTable%Skew , ErrStat2, ErrMsg2); if (Failed()) return + + ! Now populate matrix -- read each line and put in correct table entry location + call PopulateAeroTabs(AeroTable,Mask,Idx,TmpTab,NumRows,NumCols,ErrStat2,ErrMsg2); if (Failed()) return + call CheckAeroTabs(AeroTable,Mask,ErrStat2,ErrMsg2); if (Failed()) return + + call Cleanup() + +contains + logical function Failed() + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + Failed = ErrStat >= AbortErrLev + if (Failed) call CleanUp() + end function Failed + subroutine Cleanup() + if (allocated(TmpTab)) deallocate(TmpTab) + if (allocated(Mask)) deallocate(Mask) + end subroutine Cleanup + subroutine GetTabIndexVals(TabCol,ColName,NumExpect,UniqueArray,ErrStat3,ErrMsg3) + real(SiKi), intent(in ) :: TabCol(:) + character(*), intent(in ) :: ColName + integer(IntKi), intent(in ) :: NumExpect + real(SiKi), allocatable,intent( out) :: UniqueArray(:) + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: NumFound + call UniqueRealValues( TabCol, UniqueArray, NumFound, ErrStat3, ErrMsg3 ) + if (NumExpect /= NumFound) then + call SetErrStat(ErrID_Fatal,'Expecting '//trim(Num2LStr(NumExpect))//' unique '//ColName// & + ' entries in "Actuator Disk Properties Table", but found '//trim(Num2LStr(NumFound))//' instead.',ErrStat3,ErrMsg3,'') + endif + end subroutine GetTabIndexVals + subroutine PopulateAeroTabs(Aero,DatMask,TabIdx,Dat,nRow,nCol,ErrStat3,ErrMsg3) + type(ADsk_AeroTable), intent(inout) :: Aero + logical, allocatable,intent(inout) :: DatMask(:,:,:,:,:) + type(TableIndexType), intent(in ) :: TabIdx + real(SiKi), allocatable,intent(in ) :: Dat(:,:) + integer(IntKi), intent(in ) :: nCol ! number of columns in Dat + integer(IntKi), intent(in ) :: nRow ! number of rows in Dat + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + real(SiKi) :: TmpR6(6) + integer(IntKi) :: row + integer(IntKi) :: iTSR,iRtSpd,iVRel,iPitch,iSkew + ErrStat3 = ErrID_None + ErrMsg3 = '' + DatMask = .false. ! Make sure data mask is false. Set to true for entries we populate + ! Step through each row of raw data, and find corresponding data location + ! Set index for placement to 1 in the event that the variable isn't actually used + do row=1,nRow + TmpR6(1:6) = Dat(row,nCol-5:nCol) ! DOF values + ! Find TSR entry LocateStp(XVal, XAry, Ind, AryLen) + iTSR = 1_IntKi + iRtSpd = 1_IntKi + iVRel = 1_IntKi + iPitch = 1_IntKi + iSkew = 1_IntKi + ! if no entries, the corresponding array is unallocated, so skip and leave index at 1 + if (Aero%N_TSR > 0_IntKi) call LocateStp( Dat(row,TabIdx%ColTSR ),Aero%TSR ,iTSR ,Aero%N_TSR ) + if (Aero%N_RtSpd > 0_IntKi) call LocateStp( Dat(row,TabIdx%ColRtSpd),Aero%RtSpd,iRtSpd,Aero%N_RtSpd) + if (Aero%N_VRel > 0_IntKi) call LocateStp( Dat(row,TabIdx%ColVRel ),Aero%VRel ,iVRel ,Aero%N_VRel ) + if (Aero%N_Pitch > 0_IntKi) call LocateStp( Dat(row,TabIdx%ColPitch),Aero%Pitch,iPitch,Aero%N_Pitch) + if (Aero%N_Skew > 0_IntKi) call LocateStp( Dat(row,TabIdx%ColSkew ),Aero%Skew ,iSkew ,Aero%N_Skew ) + Aero%C_Fx(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(1) + Aero%C_Fy(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(2) + Aero%C_Fz(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(3) + Aero%C_Mx(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(4) + Aero%C_My(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(5) + Aero%C_Mz(iTSR,iRtSpd,iVRel,iPitch,iSkew) = TmpR6(6) + if (DatMask(iTSR,iRtSpd,iVRel,iPitch,iSkew)) then + call SetErrStat(ErrID_Fatal,'Duplicate data entry in "Actuator Disk Properties Table" row '//trim(Num2LStr(row))//'.',ErrStat3,ErrMsg3,'') + else + DatMask(iTSR,iRtSpd,iVRel,iPitch,iSkew) = .true. + endif + enddo + end subroutine PopulateAeroTabs + subroutine CheckAeroTabs(Aero,DatMask,ErrStat3,ErrMsg3) + type(ADsk_AeroTable), intent(in ) :: Aero + logical, allocatable,intent(in ) :: DatMask(:,:,:,:,:) + integer(IntKi), intent( out) :: ErrStat3 + character(ErrMsgLen), intent( out) :: ErrMsg3 + integer(IntKi) :: iTSR,iRtSpd,iVRel,iPitch,iSkew + logical :: DataMiss + logical :: FirstMiss + character(60) :: TmpChar + real(SiKi) :: TmpR5(5) + ErrStat3 = ErrID_None + ErrMsg3 = '' + DataMiss = .false. + FirstMiss = .false. + do iSkew=1,size(DatMask,DIM=5) + do iPitch=1,size(DatMask,DIM=4) + do iVRel=1,size(DatMask,DIM=3) + do iRtSpd=1,size(DatMask,DIM=2) + do iTSR=1,size(DatMask,DIM=1) + if (.not. DatMask(iTSR,iRtSpd,iVRel,iPitch,iSkew)) then + DataMiss = .true. + if (.not. FirstMiss) then + FirstMiss = .true. + ErrStat3 = ErrID_Fatal + ErrMsg3 = NewLine//'Data missing from table!!! (note order may not be same as file)'//NewLine// & + ' TSR RtSpd VRel Pitch Skew '//NewLine + endif + TmpR5 = NaN_S + if (Aero%N_TSR >0_IntKi) TmpR5(1) = Aero%TSR (iTSR ) + if (Aero%N_RtSpd>0_IntKi) TmpR5(2) = Aero%RtSpd(iRtSpd) + if (Aero%N_VRel >0_IntKi) TmpR5(3) = Aero%VRel (iVRel ) + if (Aero%N_Pitch>0_IntKi) TmpR5(4) = Aero%Pitch(iPitch) + if (Aero%N_Skew >0_IntKi) TmpR5(5) = Aero%Skew (iSkew ) + write(TmpChar,'(6(f10.3))') TmpR5(1), TmpR5(2), TmpR5(3), TmpR5(4), TmpR5(5) + ErrMsg3 = ErrMsg3//TmpChar//NewLine + endif + enddo + enddo + enddo + enddo + enddo + end subroutine CheckAeroTabs +end subroutine Get_RtAeroTableData + + +!> This subroutine counts the number of unique values in an array and returns a sorted array of them. +!! NOTE: this routine is found in the WAMIT2.f90 file as well +SUBROUTINE UniqueRealValues( DataArrayIn, DataArrayOut, NumUnique, ErrStat, ErrMsg ) + IMPLICIT NONE + REAL(SiKi), INTENT(IN ) :: DataArrayIn(:) !< Array to search + REAL(SiKi), ALLOCATABLE, INTENT( OUT) :: DataArrayOut(:) !< Array to return results in + INTEGER(IntKi), INTENT( OUT) :: NumUnique !< Number of unique values found + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error Status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Message about the error + ! Local variables + REAL(SiKi) :: TmpReal !< Temporary real value + INTEGER(IntKi) :: I !< Generic counter + INTEGER(IntKi) :: J !< Generic counter + REAL(SiKi), ALLOCATABLE :: TmpRealArray(:) !< Temporary real array + LOGICAL :: Duplicate !< If there is a duplicate value + ! Error handling + INTEGER(IntKi) :: ErrStatTmp + CHARACTER(2048) :: ErrMsgTmp + CHARACTER(*), PARAMETER :: RoutineName = 'UniqueRealValues' + + ! Initialize things + ErrStat = ErrID_None + ErrStatTmp = ErrID_None + ErrMsg = '' + ErrMsgTmp = '' + + ! Allocate the temporary array + CALL AllocAry( TmpRealArray, SIZE(DataArrayIn,1), 'Temporary array for data sorting', ErrStatTmp, ErrMsgTmp ) + CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL CleanUp + RETURN + ENDIF + + ! Initialize the array with a large negative number. + TmpRealArray = -9.9e9_SiKi + + ! The first point is unique since we haven't compared it to anything yet. + TmpRealArray(1) = DataArrayIn(1) + NumUnique = 1 + + ! Step through the DataArrayIn and put unique values into TmpRealArray. Start at second point + DO I=2,SIZE(DataArrayIn,1) + ! Check the current value against the largest stored value (I-1). If the current value is + ! larger than the last stored one, then it should be stored after it. + IF ( DataArrayIn(I) > TmpRealArray(NumUnique) ) THEN + TmpRealArray(NumUnique + 1) = DataArrayIn(I) + NumUnique = NumUnique + 1 + ELSE + ! Otherwise, if the value should not be put last, then we have to find where it goes. Before + ! searching for the location, first make sure this isn't a duplicate value. + Duplicate = .FALSE. + DO J= NumUnique, 1, -1 + IF ( EqualRealNos( DataArrayIn(I), TmpRealArray(J) )) THEN + Duplicate = .TRUE. + EXIT ! Stop searching + ENDIF + ENDDO + + ! If this is not a duplicate, the location where it goes has to be find. To do this, we will + ! sequentially shift each value one index further as we step backwards through the sorted + ! array. When we find the location between values where this goes, we put the value there. + IF ( .NOT. Duplicate ) THEN + DO J= NumUnique, 1, -1 ! TempRealArray only has NumUnique values. Everything after is junk. + IF ( DataArrayIn(I) < TmpRealArray(J) ) THEN + TmpRealArray(J+1) = TmpRealArray(J) ! Shift this value further along the array + IF ( J == 1 ) THEN ! If we are at the first value, then it goes here. + TmpRealArray(J) = DataArrayIn(I) + NumUnique = NumUnique + 1 + ELSE + IF ( DataArrayIn(I) > TmpRealArray(J-1) ) THEN ! If larger than the preceeding number, it goes here + TmpRealArray(J) = DataArrayIn(I) + NumUnique = NumUnique + 1 + ENDIF + ENDIF + ENDIF + ENDDO + ENDIF + ENDIF + ENDDO + + ! Now that we have the array sorted into unique values, we need to construct an array to return the values in. + CALL AllocAry( DataArrayOut, NumUnique, 'Return array with sorted values', ErrStatTmp, ErrMsgTmp ) + CALL SetErrStat( ErrStatTmp, ErrMsgTmp, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + CALL CleanUp + RETURN + ENDIF + + ! Copy the values over + DataArrayOut = TmpRealArray(1:NumUnique) + call Cleanup() +contains + subroutine Cleanup() + if (allocated(TmpRealArray)) deallocate(TmpRealArray) + end subroutine Cleanup +END SUBROUTINE UniqueRealValues + + +!> validate and process input file data (some was done during parsing of input file) +subroutine ADsk_ValidateProcessInput( InitInp, InputFileData, ErrStat, ErrMsg ) type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization type(ADsk_InputFile), intent(inout) :: InputFileData !< The data for initialization integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine @@ -42,11 +660,158 @@ SUBROUTINE ADsk_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" -END SUBROUTINE ADsk_ValidateInput +end subroutine ADsk_ValidateProcessInput + -!FIXME: add SetOutParam here +!********************************************************************************************************************************** +! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" +! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these +! lines should be modified in the Matlab script and/or Excel worksheet as necessary. +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine checks to see if any requested output channel names (stored in the OutList(:)) are invalid. It returns a +!! warning if any of the channels are not available outputs from the module. +!! It assigns the settings for OutParam(:) (i.e, the index, name, and units of the output channels, WriteOutput(:)). +!! the sign is set to 0 if the channel is invalid. +!! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here. +!! +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 17-Feb-2022 14:08:12. +SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) +!.................................................................................................................................. + IMPLICIT NONE -END MODULE AeroDisk_IO + ! Passed variables + + CHARACTER(ChanLen), INTENT(IN) :: OutList(:) !< The list out user-requested outputs + TYPE(ADsk_ParameterType), INTENT(INOUT) :: p !< The module parameters + INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status code + CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if an error occurred + + ! Local variables + + INTEGER :: ErrStat2 ! temporary (local) error status + INTEGER :: I ! Generic loop-counting index + INTEGER :: J ! Generic loop-counting index + INTEGER :: INDX ! Index for valid arrays + + LOGICAL :: CheckOutListAgain ! Flag used to determine if output parameter starting with "M" is valid (or the negative of another parameter) + LOGICAL :: InvalidOutput(0:MaxOutPts) ! This array determines if the output channel is valid for this configuration + CHARACTER(ChanLen) :: OutListTmp ! A string to temporarily hold OutList(I) + CHARACTER(*), PARAMETER :: RoutineName = "SetOutParam" + + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(34) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "ADCP ","ADCQ ","ADCT ","ADFX ","ADFXI ","ADFY ","ADFYI ","ADFZ ", & + "ADFZI ","ADMX ","ADMXI ","ADMY ","ADMYI ","ADMZ ","ADMZI ","ADPOWER ", & + "ADSKEW ","ADSPEED ","ADSTVX ","ADSTVXI ","ADSTVY ","ADSTVYI ","ADSTVZ ","ADSTVZI ", & + "ADTPITCH ","ADTSR ","ADVREL ","ADVWINDX ","ADVWINDXI","ADVWINDY ","ADVWINDYI","ADVWINDZ ", & + "ADVWINDZI","ADYAWERR "/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(34) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + ADCp , ADCq , ADCt , ADFx , ADFxi , ADFy , ADFyi , ADFz , & + ADFzi , ADMx , ADMxi , ADMy , ADMyi , ADMz , ADMzi , ADPower , & + ADSkew , ADSpeed , ADSTVx , ADSTVxi , ADSTVy , ADSTVyi , ADSTVz , ADSTVzi , & + ADTPitch , ADTSR , ADVRel , ADVWindx , ADVWindxi , ADVWindy , ADVWindyi , ADVWindz , & + ADVWindzi , ADYawErr /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(34) = (/ & ! This lists the units corresponding to the allowed parameters + "(-) ","(-) ","(-) ","(N) ","(N) ","(N) ","(N) ","(N) ", & + "(N) ","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(W) ", & + "(deg)","(rpm)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & + "(deg)","(-) ","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & + "(m/s)","(deg)"/) + + + ! Initialize values + ErrStat = ErrID_None + ErrMsg = "" + InvalidOutput = .FALSE. + + +! ..... Developer must add checking for invalid inputs here: ..... + +! ................. End of validity checking ................. + + !------------------------------------------------------------------------------------------------- + ! Allocate and set index, name, and units for the output channels + ! If a selected output channel is not available in this module, set error flag. + !------------------------------------------------------------------------------------------------- + + ALLOCATE ( p%OutParam(0:p%NumOuts) , STAT=ErrStat2 ) + IF ( ErrStat2 /= 0_IntKi ) THEN + CALL SetErrStat( ErrID_Fatal,"Error allocating memory for the AeroDisk OutParam array.", ErrStat, ErrMsg, RoutineName ) + RETURN + ENDIF + + ! Set index, name, and units for the time output channel: + + p%OutParam(0)%Indx = Time + p%OutParam(0)%Name = "Time" ! OutParam(0) is the time channel by default. + p%OutParam(0)%Units = "(s)" + p%OutParam(0)%SignM = 1 + + + ! Set index, name, and units for all of the output channels. + ! If a selected output channel is not available by this module set ErrStat = ErrID_Warn. + + DO I = 1,p%NumOuts + + p%OutParam(I)%Name = OutList(I) + OutListTmp = OutList(I) + + ! Reverse the sign (+/-) of the output channel if the user prefixed the + ! channel name with a "-", "_", "m", or "M" character indicating "minus". + + + CheckOutListAgain = .FALSE. + + IF ( INDEX( "-_", OutListTmp(1:1) ) > 0 ) THEN + p%OutParam(I)%SignM = -1 ! ex, "-TipDxc1" causes the sign of TipDxc1 to be switched. + OutListTmp = OutListTmp(2:) + ELSE IF ( INDEX( "mM", OutListTmp(1:1) ) > 0 ) THEN ! We'll assume this is a variable name for now, (if not, we will check later if OutListTmp(2:) is also a variable name) + CheckOutListAgain = .TRUE. + p%OutParam(I)%SignM = 1 + ELSE + p%OutParam(I)%SignM = 1 + END IF + + CALL Conv2UC( OutListTmp ) ! Convert OutListTmp to upper case + + + Indx = IndexCharAry( OutListTmp(1:OutStrLenM1), ValidParamAry ) + + + ! If it started with an "M" (CheckOutListAgain) we didn't find the value in our list (Indx < 1) + + IF ( CheckOutListAgain .AND. Indx < 1 ) THEN ! Let's assume that "M" really meant "minus" and then test again + p%OutParam(I)%SignM = -1 ! ex, "MTipDxc1" causes the sign of TipDxc1 to be switched. + OutListTmp = OutListTmp(2:) + + Indx = IndexCharAry( OutListTmp(1:OutStrLenM1), ValidParamAry ) + END IF + + + IF ( Indx > 0 ) THEN ! we found the channel name + IF ( InvalidOutput( ParamIndxAry(Indx) ) ) THEN ! but, it isn't valid for these settings + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) + p%OutParam(I)%Units = "INVALID" + p%OutParam(I)%SignM = 0 + ELSE + p%OutParam(I)%Indx = ParamIndxAry(Indx) + p%OutParam(I)%Units = ParamUnitsAry(Indx) ! it's a valid output + END IF + ELSE ! this channel isn't valid + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) + p%OutParam(I)%Units = "INVALID" + p%OutParam(I)%SignM = 0 ! multiply all results by zero + + CALL SetErrStat(ErrID_Fatal, TRIM(p%OutParam(I)%Name)//" is not an available output channel.",ErrStat,ErrMsg,RoutineName) + END IF + + END DO + + RETURN +END SUBROUTINE SetOutParam +!---------------------------------------------------------------------------------------------------------------------------------- +!End of code generated by Matlab script +!********************************************************************************************************************************** +END MODULE AeroDisk_IO diff --git a/modules/aerodisk/src/AeroDisk_Output_Params.f90 b/modules/aerodisk/src/AeroDisk_Output_Params.f90 index 64f679d7fb..2876f95652 100644 --- a/modules/aerodisk/src/AeroDisk_Output_Params.f90 +++ b/modules/aerodisk/src/AeroDisk_Output_Params.f90 @@ -2,4 +2,70 @@ module AeroDisk_Output_Params use NWTC_Library +! =================================================================================================== +! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" +! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these +! lines should be modified in the Matlab script and/or Excel worksheet as necessary. +! =================================================================================================== +! This code was generated by Write_ChckOutLst.m at 17-Feb-2022 14:08:12. + + + ! Parameters related to output length (number of characters allowed in the output data headers): + + INTEGER(IntKi), PARAMETER :: OutStrLenM1 = ChanLen - 1 + + + ! Indices for computing output channels: + ! NOTES: + ! (1) These parameters are in the order stored in "OutListParameters.xlsx" + ! (2) Array AllOuts() must be dimensioned to the value of the largest output parameter + + ! Time: + + INTEGER(IntKi), PARAMETER :: Time = 0 + + + ! All channels: + + INTEGER(IntKi), PARAMETER :: ADSpeed = 1 + INTEGER(IntKi), PARAMETER :: ADTSR = 2 + INTEGER(IntKi), PARAMETER :: ADTPitch = 3 + INTEGER(IntKi), PARAMETER :: ADVWindx = 4 + INTEGER(IntKi), PARAMETER :: ADVWindy = 5 + INTEGER(IntKi), PARAMETER :: ADVWindz = 6 + INTEGER(IntKi), PARAMETER :: ADVWindxi = 7 + INTEGER(IntKi), PARAMETER :: ADVWindyi = 8 + INTEGER(IntKi), PARAMETER :: ADVWindzi = 9 + INTEGER(IntKi), PARAMETER :: ADSTVx = 10 + INTEGER(IntKi), PARAMETER :: ADSTVy = 11 + INTEGER(IntKi), PARAMETER :: ADSTVz = 12 + INTEGER(IntKi), PARAMETER :: ADSTVxi = 13 + INTEGER(IntKi), PARAMETER :: ADSTVyi = 14 + INTEGER(IntKi), PARAMETER :: ADSTVzi = 15 + INTEGER(IntKi), PARAMETER :: ADVRel = 16 + INTEGER(IntKi), PARAMETER :: ADSkew = 17 + INTEGER(IntKi), PARAMETER :: ADYawErr = 18 + INTEGER(IntKi), PARAMETER :: ADCp = 19 + INTEGER(IntKi), PARAMETER :: ADCt = 20 + INTEGER(IntKi), PARAMETER :: ADCq = 21 + INTEGER(IntKi), PARAMETER :: ADFx = 22 + INTEGER(IntKi), PARAMETER :: ADFy = 23 + INTEGER(IntKi), PARAMETER :: ADFz = 24 + INTEGER(IntKi), PARAMETER :: ADFxi = 25 + INTEGER(IntKi), PARAMETER :: ADFyi = 26 + INTEGER(IntKi), PARAMETER :: ADFzi = 27 + INTEGER(IntKi), PARAMETER :: ADMx = 28 + INTEGER(IntKi), PARAMETER :: ADMy = 29 + INTEGER(IntKi), PARAMETER :: ADMz = 30 + INTEGER(IntKi), PARAMETER :: ADMxi = 31 + INTEGER(IntKi), PARAMETER :: ADMyi = 32 + INTEGER(IntKi), PARAMETER :: ADMzi = 33 + INTEGER(IntKi), PARAMETER :: ADPower = 34 + + + ! The maximum number of output channels which can be output by the code. + INTEGER(IntKi), PARAMETER :: MaxOutPts = 34 + +!End of code generated by Matlab script +! =================================================================================================== end module AeroDisk_Output_Params diff --git a/modules/aerodisk/src/AeroDisk_Registry.txt b/modules/aerodisk/src/AeroDisk_Registry.txt index f58145be4f..196735bc8d 100644 --- a/modules/aerodisk/src/AeroDisk_Registry.txt +++ b/modules/aerodisk/src/AeroDisk_Registry.txt @@ -13,29 +13,35 @@ include Registry_NWTC_Library.txt +# ..... Table storage ............................................................................................................. +typedef AeroDisk/ADsk ADsk_AeroTable IntKi N_TSR - - - "Number of rotor tip-speed ratios in tables" - +typedef ^ ADsk_AeroTable IntKi N_RtSpd - - - "Number of rotor speeds in tables" - +typedef ^ ADsk_AeroTable IntKi N_VRel - - - "Number of rotor inflow wind speeds in tables" - +typedef ^ ADsk_AeroTable IntKi N_Pitch - - - "Number of rotor-collective blade-pitch angles in tables" - +typedef ^ ADsk_AeroTable IntKi N_Skew - - - "Number of rotor inflow-skew angles in tables" - +typedef ^ ADsk_AeroTable SiKi TSR {:} - - "Rotor TSR values in tables" - +typedef ^ ADsk_AeroTable SiKi RtSpd {:} - - "Rotor speed values in tables" rad/s +typedef ^ ADsk_AeroTable SiKi VRel {:} - - "Rotor inflow wind speeds tables" m/s +typedef ^ ADsk_AeroTable SiKi Pitch {:} - - "Rotor-collective blade-pitch anges in tables" rad +typedef ^ ADsk_AeroTable SiKi Skew {:} - - "Rotor inflow-skew values in tables" rad +typedef ^ ADsk_AeroTable SiKi C_Fx {:}{:}{:}{:}{:} - - "Thrust (x/axial) coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_AeroTable SiKi C_Fy {:}{:}{:}{:}{:} - - "Transverse (y) force coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_AeroTable SiKi C_Fz {:}{:}{:}{:}{:} - - "Transverse (z) force coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_AeroTable SiKi C_Mx {:}{:}{:}{:}{:} - - "Torque (x/axial) coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_AeroTable SiKi C_My {:}{:}{:}{:}{:} - - "Transverse (y) moment coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - +typedef ^ ADsk_AeroTable SiKi C_Mz {:}{:}{:}{:}{:} - - "Transverse (z) moment coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew]" - + + # ..... Initialization data ....................................................................................................... # ADsk input file -typedef AeroDisk/ADsk ADsk_InputFile LOGICAL EchoFlag - - - "Echo the input file" - -typedef ^ ADsk_InputFile R8Ki DeltaT - - - "Time step for module time integration" s +typedef AeroDisk/ADsk ADsk_InputFile LOGICAL Echo - - - "Echo the input file" - +typedef ^ ADsk_InputFile R8Ki DT - - - "Time step for module time integration" s +typedef ^ ADsk_InputFile ReKi AirDens - - - "Air density" "kg/m^3" +typedef ^ ADsk_InputFile ReKi RotorRad - - - "Rotor radius" m typedef ^ ADsk_InputFile LOGICAL SumPrint - - - "Print summary data to .sum" - +typedef ^ ADsk_InputFile IntKi NumOuts - - - "Number of outputs" - typedef ^ ADsk_InputFile CHARACTER(ChanLen) OutList : - - "List of user-requested output channels" - -typedef ^ ADsk_InputFile IntKi N_RtSpd - - - "Number of rotor speeds in tables" - -typedef ^ ADsk_InputFile IntKi N_VRel - - - "Number of rotor inflow wind speeds in tables" - -typedef ^ ADsk_InputFile IntKi N_Pitch - - - "Number of rotor-collective blade-pitch angles in tables" - -typedef ^ ADsk_InputFile IntKi N_Skew - - - "Number of rotor inflow-skew angles in tables" - -typedef ^ ADsk_InputFile ReKi TSR {:} - - "Rotor TSR values in tables" - -typedef ^ ADsk_InputFile ReKi RtSpd {:} - - "Rotor speed values in tables" rad/s -typedef ^ ADsk_InputFile ReKi VRel {:} - - "Rotor inflow wind speeds tables" m/s -typedef ^ ADsk_InputFile ReKi Pitch {:} - - "Rotor-collective blade-pitch anges in tables" rad -typedef ^ ADsk_InputFile ReKi Skew {:} - - "Rotor inflow-skew values in tables" rad -typedef ^ ADsk_InputFile ReKi C_fx {:}{:}{:}{:} - - "Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ADsk_InputFile ReKi C_fy {:}{:}{:}{:} - - "Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ADsk_InputFile ReKi C_fz {:}{:}{:}{:} - - "Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ADsk_InputFile ReKi C_mx {:}{:}{:}{:} - - "Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ADsk_InputFile ReKi C_my {:}{:}{:}{:} - - "Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ADsk_InputFile ReKi C_mz {:}{:}{:}{:} - - "Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - - - +typedef ^ ADsk_InputFile ADsk_AeroTable AeroTable - - - "Data table" - # ..... Initialization data ....................................................................................................... # inputs for initialization: @@ -44,8 +50,10 @@ typedef ^ InitInputType CHARACTER(1024) RootName - - typedef ^ InitInputType ReKi RotorRad - - - "Rotor radius" m typedef ^ InitInputType ReKi HubPosition {3} - - "Hub position -- center of rotor" m typedef ^ InitInputType R8Ki HubOrientation {3}{3} - - "Hub orientation" - -typedef ^ InitInputType ReKi defPatm - - - "Default atmospheric pressure from the driver; may be overwritten" Pa +typedef ^ InitInputType ReKi defAirDens - - - "Default atmospheric density from the driver; may be overwritten" "kg/m^3" typedef ^ InitInputType LOGICAL Linearize - .false. - "this module cannot be linearized at present" - +typedef ^ InitInputType LOGICAL UseInputFile - .TRUE. - "Supplied by Driver: .TRUE. if using a input file, .FALSE. if all inputs are being passed in by the caller" - +typedef ^ InitInputType FileInfoType PassedFileData - - - "If we don't use the input file, pass everything through this" - # outputs from initialization: @@ -94,26 +102,14 @@ typedef ^ OtherStateType IntKi DummyOtherState - - # ..... Parameters................................................................................................................. # unchanging parameters: -typedef ^ ParameterType DbKi DeltaT - - - "Time step for module time integration" s +typedef ^ ParameterType CHARACTER(1024) RootName - - - "RootName for writing output files" - +typedef ^ ParameterType DbKi DT - - - "Time step for module time integration" s typedef ^ ParameterType ReKi RotorRad - - - "Rotor radius" m +typedef ^ ParameterType ReKi AirDens - - - "Air density" "kg/m^3" +typedef ^ ParameterType IntKi NumOuts - - - "Number of outputs" - typedef ^ ParameterType ReKi halfRhoA - - - "half air density times rotor swept area" "kg/m" -typedef ^ ParameterType IntKi N_TSR - - - "Number of rotor tip-speed ratios in tables" - -typedef ^ ParameterType IntKi N_RtSpd - - - "Number of rotor speeds in tables" - -typedef ^ ParameterType IntKi N_VRel - - - "Number of rotor inflow wind speeds in tables" - -typedef ^ ParameterType IntKi N_Pitch - - - "Number of rotor-collective blade-pitch angles in tables" - -typedef ^ ParameterType IntKi N_Skew - - - "Number of rotor inflow-skew angles in tables" - -typedef ^ ParameterType ReKi TSR {:} - - "Rotor TSR values in tables" - -typedef ^ ParameterType ReKi RtSpd {:} - - "Rotor speed values in tables" rad/s -typedef ^ ParameterType ReKi VRel {:} - - "Rotor inflow wind speeds tables" m/s -typedef ^ ParameterType ReKi Pitch {:} - - "Rotor-collective blade-pitch anges in tables" rad -typedef ^ ParameterType ReKi Skew {:} - - "Rotor inflow-skew values in tables" rad -typedef ^ ParameterType ReKi C_fx {:}{:}{:}{:} - - "Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ParameterType ReKi C_fy {:}{:}{:}{:} - - "Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ParameterType ReKi C_fz {:}{:}{:}{:} - - "Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ParameterType ReKi C_mx {:}{:}{:}{:} - - "Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ParameterType ReKi C_my {:}{:}{:}{:} - - "Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - -typedef ^ ParameterType ReKi C_mz {:}{:}{:}{:} - - "Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew]" - - +typedef ^ ParameterType ADsk_AeroTable AeroTable - - - "Data table" - +typedef ^ ParameterType OutParmType OutParam {:} - - "Names and units (and other characteristics) of all requested output parameters" - # ..... Misc/Optimization variables................................................................................................. typedef ^ MiscVarType IntKi DummyMiscVar - - - "" - diff --git a/modules/aerodisk/src/AeroDisk_Types.f90 b/modules/aerodisk/src/AeroDisk_Types.f90 index f1ae10d699..e721d09ccc 100644 --- a/modules/aerodisk/src/AeroDisk_Types.f90 +++ b/modules/aerodisk/src/AeroDisk_Types.f90 @@ -33,27 +33,36 @@ MODULE AeroDisk_Types !--------------------------------------------------------------------------------------------------------------------------------- USE NWTC_Library IMPLICIT NONE -! ========= ADsk_InputFile ======= - TYPE, PUBLIC :: ADsk_InputFile - LOGICAL :: EchoFlag !< Echo the input file [-] - REAL(R8Ki) :: DeltaT !< Time step for module time integration [s] - LOGICAL :: SumPrint !< Print summary data to .sum [-] - CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< List of user-requested output channels [-] +! ========= ADsk_AeroTable ======= + TYPE, PUBLIC :: ADsk_AeroTable + INTEGER(IntKi) :: N_TSR !< Number of rotor tip-speed ratios in tables [-] INTEGER(IntKi) :: N_RtSpd !< Number of rotor speeds in tables [-] INTEGER(IntKi) :: N_VRel !< Number of rotor inflow wind speeds in tables [-] INTEGER(IntKi) :: N_Pitch !< Number of rotor-collective blade-pitch angles in tables [-] INTEGER(IntKi) :: N_Skew !< Number of rotor inflow-skew angles in tables [-] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TSR !< Rotor TSR values in tables [-] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RtSpd !< Rotor speed values in tables [rad/s] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: VRel !< Rotor inflow wind speeds tables [m/s] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Rotor-collective blade-pitch anges in tables [rad] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Skew !< Rotor inflow-skew values in tables [rad] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fx !< Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fy !< Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fz !< Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mx !< Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_my !< Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mz !< Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: TSR !< Rotor TSR values in tables [-] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: RtSpd !< Rotor speed values in tables [rad/s] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: VRel !< Rotor inflow wind speeds tables [m/s] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Rotor-collective blade-pitch anges in tables [rad] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: Skew !< Rotor inflow-skew values in tables [rad] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_Fx !< Thrust (x/axial) coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_Fy !< Transverse (y) force coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_Fz !< Transverse (z) force coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_Mx !< Torque (x/axial) coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_My !< Transverse (y) moment coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: C_Mz !< Transverse (z) moment coefficient [N_TSR, N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + END TYPE ADsk_AeroTable +! ======================= +! ========= ADsk_InputFile ======= + TYPE, PUBLIC :: ADsk_InputFile + LOGICAL :: Echo !< Echo the input file [-] + REAL(R8Ki) :: DT !< Time step for module time integration [s] + REAL(ReKi) :: AirDens !< Air density [kg/m^3] + REAL(ReKi) :: RotorRad !< Rotor radius [m] + LOGICAL :: SumPrint !< Print summary data to .sum [-] + INTEGER(IntKi) :: NumOuts !< Number of outputs [-] + CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< List of user-requested output channels [-] + TYPE(ADsk_AeroTable) :: AeroTable !< Data table [-] END TYPE ADsk_InputFile ! ======================= ! ========= ADsk_InitInputType ======= @@ -63,8 +72,10 @@ MODULE AeroDisk_Types REAL(ReKi) :: RotorRad !< Rotor radius [m] REAL(ReKi) , DIMENSION(1:3) :: HubPosition !< Hub position -- center of rotor [m] REAL(R8Ki) , DIMENSION(1:3,1:3) :: HubOrientation !< Hub orientation [-] - REAL(ReKi) :: defPatm !< Default atmospheric pressure from the driver; may be overwritten [Pa] + REAL(ReKi) :: defAirDens !< Default atmospheric density from the driver; may be overwritten [kg/m^3] LOGICAL :: Linearize = .false. !< this module cannot be linearized at present [-] + LOGICAL :: UseInputFile = .TRUE. !< Supplied by Driver: .TRUE. if using a input file, .FALSE. if all inputs are being passed in by the caller [-] + TYPE(FileInfoType) :: PassedFileData !< If we don't use the input file, pass everything through this [-] END TYPE ADsk_InitInputType ! ======================= ! ========= ADsk_InitOutputType ======= @@ -116,25 +127,14 @@ MODULE AeroDisk_Types ! ======================= ! ========= ADsk_ParameterType ======= TYPE, PUBLIC :: ADsk_ParameterType - REAL(DbKi) :: DeltaT !< Time step for module time integration [s] + CHARACTER(1024) :: RootName !< RootName for writing output files [-] + REAL(DbKi) :: DT !< Time step for module time integration [s] REAL(ReKi) :: RotorRad !< Rotor radius [m] + REAL(ReKi) :: AirDens !< Air density [kg/m^3] + INTEGER(IntKi) :: NumOuts !< Number of outputs [-] REAL(ReKi) :: halfRhoA !< half air density times rotor swept area [kg/m] - INTEGER(IntKi) :: N_TSR !< Number of rotor tip-speed ratios in tables [-] - INTEGER(IntKi) :: N_RtSpd !< Number of rotor speeds in tables [-] - INTEGER(IntKi) :: N_VRel !< Number of rotor inflow wind speeds in tables [-] - INTEGER(IntKi) :: N_Pitch !< Number of rotor-collective blade-pitch angles in tables [-] - INTEGER(IntKi) :: N_Skew !< Number of rotor inflow-skew angles in tables [-] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: TSR !< Rotor TSR values in tables [-] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RtSpd !< Rotor speed values in tables [rad/s] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: VRel !< Rotor inflow wind speeds tables [m/s] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< Rotor-collective blade-pitch anges in tables [rad] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Skew !< Rotor inflow-skew values in tables [rad] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fx !< Thrust (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fy !< Transverse (y) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_fz !< Transverse (z) force coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mx !< Torque (x/axial) coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_my !< Transverse (y) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] - REAL(ReKi) , DIMENSION(:,:,:,:), ALLOCATABLE :: C_mz !< Transverse (z) moment coefficient [N_RtSpd, N_VRel, N_Pitch, N_Skew] [-] + TYPE(ADsk_AeroTable) :: AeroTable !< Data table [-] + TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: OutParam !< Names and units (and other characteristics) of all requested output parameters [-] END TYPE ADsk_ParameterType ! ======================= ! ========= ADsk_MiscVarType ======= @@ -143,9 +143,9 @@ MODULE AeroDisk_Types END TYPE ADsk_MiscVarType ! ======================= CONTAINS - SUBROUTINE ADsk_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_InputFile), INTENT(IN) :: SrcInputFileData - TYPE(ADsk_InputFile), INTENT(INOUT) :: DstInputFileData + SUBROUTINE ADsk_CopyAeroTable( SrcAeroTableData, DstAeroTableData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_AeroTable), INTENT(IN) :: SrcAeroTableData + TYPE(ADsk_AeroTable), INTENT(INOUT) :: DstAeroTableData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -155,253 +155,249 @@ SUBROUTINE ADsk_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, Err INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: i5, i5_l, i5_u ! bounds (upper/lower) for an array dimension 5 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInputFile' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyAeroTable' ! ErrStat = ErrID_None ErrMsg = "" - DstInputFileData%EchoFlag = SrcInputFileData%EchoFlag - DstInputFileData%DeltaT = SrcInputFileData%DeltaT - DstInputFileData%SumPrint = SrcInputFileData%SumPrint -IF (ALLOCATED(SrcInputFileData%OutList)) THEN - i1_l = LBOUND(SrcInputFileData%OutList,1) - i1_u = UBOUND(SrcInputFileData%OutList,1) - IF (.NOT. ALLOCATED(DstInputFileData%OutList)) THEN - ALLOCATE(DstInputFileData%OutList(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%OutList.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstInputFileData%OutList = SrcInputFileData%OutList -ENDIF - DstInputFileData%N_RtSpd = SrcInputFileData%N_RtSpd - DstInputFileData%N_VRel = SrcInputFileData%N_VRel - DstInputFileData%N_Pitch = SrcInputFileData%N_Pitch - DstInputFileData%N_Skew = SrcInputFileData%N_Skew -IF (ALLOCATED(SrcInputFileData%TSR)) THEN - i1_l = LBOUND(SrcInputFileData%TSR,1) - i1_u = UBOUND(SrcInputFileData%TSR,1) - IF (.NOT. ALLOCATED(DstInputFileData%TSR)) THEN - ALLOCATE(DstInputFileData%TSR(i1_l:i1_u),STAT=ErrStat2) + DstAeroTableData%N_TSR = SrcAeroTableData%N_TSR + DstAeroTableData%N_RtSpd = SrcAeroTableData%N_RtSpd + DstAeroTableData%N_VRel = SrcAeroTableData%N_VRel + DstAeroTableData%N_Pitch = SrcAeroTableData%N_Pitch + DstAeroTableData%N_Skew = SrcAeroTableData%N_Skew +IF (ALLOCATED(SrcAeroTableData%TSR)) THEN + i1_l = LBOUND(SrcAeroTableData%TSR,1) + i1_u = UBOUND(SrcAeroTableData%TSR,1) + IF (.NOT. ALLOCATED(DstAeroTableData%TSR)) THEN + ALLOCATE(DstAeroTableData%TSR(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%TSR.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%TSR.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%TSR = SrcInputFileData%TSR + DstAeroTableData%TSR = SrcAeroTableData%TSR ENDIF -IF (ALLOCATED(SrcInputFileData%RtSpd)) THEN - i1_l = LBOUND(SrcInputFileData%RtSpd,1) - i1_u = UBOUND(SrcInputFileData%RtSpd,1) - IF (.NOT. ALLOCATED(DstInputFileData%RtSpd)) THEN - ALLOCATE(DstInputFileData%RtSpd(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%RtSpd)) THEN + i1_l = LBOUND(SrcAeroTableData%RtSpd,1) + i1_u = UBOUND(SrcAeroTableData%RtSpd,1) + IF (.NOT. ALLOCATED(DstAeroTableData%RtSpd)) THEN + ALLOCATE(DstAeroTableData%RtSpd(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%RtSpd.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%RtSpd.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%RtSpd = SrcInputFileData%RtSpd + DstAeroTableData%RtSpd = SrcAeroTableData%RtSpd ENDIF -IF (ALLOCATED(SrcInputFileData%VRel)) THEN - i1_l = LBOUND(SrcInputFileData%VRel,1) - i1_u = UBOUND(SrcInputFileData%VRel,1) - IF (.NOT. ALLOCATED(DstInputFileData%VRel)) THEN - ALLOCATE(DstInputFileData%VRel(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%VRel)) THEN + i1_l = LBOUND(SrcAeroTableData%VRel,1) + i1_u = UBOUND(SrcAeroTableData%VRel,1) + IF (.NOT. ALLOCATED(DstAeroTableData%VRel)) THEN + ALLOCATE(DstAeroTableData%VRel(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%VRel.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%VRel.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%VRel = SrcInputFileData%VRel + DstAeroTableData%VRel = SrcAeroTableData%VRel ENDIF -IF (ALLOCATED(SrcInputFileData%Pitch)) THEN - i1_l = LBOUND(SrcInputFileData%Pitch,1) - i1_u = UBOUND(SrcInputFileData%Pitch,1) - IF (.NOT. ALLOCATED(DstInputFileData%Pitch)) THEN - ALLOCATE(DstInputFileData%Pitch(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%Pitch)) THEN + i1_l = LBOUND(SrcAeroTableData%Pitch,1) + i1_u = UBOUND(SrcAeroTableData%Pitch,1) + IF (.NOT. ALLOCATED(DstAeroTableData%Pitch)) THEN + ALLOCATE(DstAeroTableData%Pitch(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%Pitch.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%Pitch.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%Pitch = SrcInputFileData%Pitch + DstAeroTableData%Pitch = SrcAeroTableData%Pitch ENDIF -IF (ALLOCATED(SrcInputFileData%Skew)) THEN - i1_l = LBOUND(SrcInputFileData%Skew,1) - i1_u = UBOUND(SrcInputFileData%Skew,1) - IF (.NOT. ALLOCATED(DstInputFileData%Skew)) THEN - ALLOCATE(DstInputFileData%Skew(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%Skew)) THEN + i1_l = LBOUND(SrcAeroTableData%Skew,1) + i1_u = UBOUND(SrcAeroTableData%Skew,1) + IF (.NOT. ALLOCATED(DstAeroTableData%Skew)) THEN + ALLOCATE(DstAeroTableData%Skew(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%Skew.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%Skew.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%Skew = SrcInputFileData%Skew + DstAeroTableData%Skew = SrcAeroTableData%Skew ENDIF -IF (ALLOCATED(SrcInputFileData%C_fx)) THEN - i1_l = LBOUND(SrcInputFileData%C_fx,1) - i1_u = UBOUND(SrcInputFileData%C_fx,1) - i2_l = LBOUND(SrcInputFileData%C_fx,2) - i2_u = UBOUND(SrcInputFileData%C_fx,2) - i3_l = LBOUND(SrcInputFileData%C_fx,3) - i3_u = UBOUND(SrcInputFileData%C_fx,3) - i4_l = LBOUND(SrcInputFileData%C_fx,4) - i4_u = UBOUND(SrcInputFileData%C_fx,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_fx)) THEN - ALLOCATE(DstInputFileData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_Fx)) THEN + i1_l = LBOUND(SrcAeroTableData%C_Fx,1) + i1_u = UBOUND(SrcAeroTableData%C_Fx,1) + i2_l = LBOUND(SrcAeroTableData%C_Fx,2) + i2_u = UBOUND(SrcAeroTableData%C_Fx,2) + i3_l = LBOUND(SrcAeroTableData%C_Fx,3) + i3_u = UBOUND(SrcAeroTableData%C_Fx,3) + i4_l = LBOUND(SrcAeroTableData%C_Fx,4) + i4_u = UBOUND(SrcAeroTableData%C_Fx,4) + i5_l = LBOUND(SrcAeroTableData%C_Fx,5) + i5_u = UBOUND(SrcAeroTableData%C_Fx,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_Fx)) THEN + ALLOCATE(DstAeroTableData%C_Fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fx.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_Fx.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_fx = SrcInputFileData%C_fx + DstAeroTableData%C_Fx = SrcAeroTableData%C_Fx ENDIF -IF (ALLOCATED(SrcInputFileData%C_fy)) THEN - i1_l = LBOUND(SrcInputFileData%C_fy,1) - i1_u = UBOUND(SrcInputFileData%C_fy,1) - i2_l = LBOUND(SrcInputFileData%C_fy,2) - i2_u = UBOUND(SrcInputFileData%C_fy,2) - i3_l = LBOUND(SrcInputFileData%C_fy,3) - i3_u = UBOUND(SrcInputFileData%C_fy,3) - i4_l = LBOUND(SrcInputFileData%C_fy,4) - i4_u = UBOUND(SrcInputFileData%C_fy,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_fy)) THEN - ALLOCATE(DstInputFileData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_Fy)) THEN + i1_l = LBOUND(SrcAeroTableData%C_Fy,1) + i1_u = UBOUND(SrcAeroTableData%C_Fy,1) + i2_l = LBOUND(SrcAeroTableData%C_Fy,2) + i2_u = UBOUND(SrcAeroTableData%C_Fy,2) + i3_l = LBOUND(SrcAeroTableData%C_Fy,3) + i3_u = UBOUND(SrcAeroTableData%C_Fy,3) + i4_l = LBOUND(SrcAeroTableData%C_Fy,4) + i4_u = UBOUND(SrcAeroTableData%C_Fy,4) + i5_l = LBOUND(SrcAeroTableData%C_Fy,5) + i5_u = UBOUND(SrcAeroTableData%C_Fy,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_Fy)) THEN + ALLOCATE(DstAeroTableData%C_Fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fy.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_Fy.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_fy = SrcInputFileData%C_fy + DstAeroTableData%C_Fy = SrcAeroTableData%C_Fy ENDIF -IF (ALLOCATED(SrcInputFileData%C_fz)) THEN - i1_l = LBOUND(SrcInputFileData%C_fz,1) - i1_u = UBOUND(SrcInputFileData%C_fz,1) - i2_l = LBOUND(SrcInputFileData%C_fz,2) - i2_u = UBOUND(SrcInputFileData%C_fz,2) - i3_l = LBOUND(SrcInputFileData%C_fz,3) - i3_u = UBOUND(SrcInputFileData%C_fz,3) - i4_l = LBOUND(SrcInputFileData%C_fz,4) - i4_u = UBOUND(SrcInputFileData%C_fz,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_fz)) THEN - ALLOCATE(DstInputFileData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_Fz)) THEN + i1_l = LBOUND(SrcAeroTableData%C_Fz,1) + i1_u = UBOUND(SrcAeroTableData%C_Fz,1) + i2_l = LBOUND(SrcAeroTableData%C_Fz,2) + i2_u = UBOUND(SrcAeroTableData%C_Fz,2) + i3_l = LBOUND(SrcAeroTableData%C_Fz,3) + i3_u = UBOUND(SrcAeroTableData%C_Fz,3) + i4_l = LBOUND(SrcAeroTableData%C_Fz,4) + i4_u = UBOUND(SrcAeroTableData%C_Fz,4) + i5_l = LBOUND(SrcAeroTableData%C_Fz,5) + i5_u = UBOUND(SrcAeroTableData%C_Fz,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_Fz)) THEN + ALLOCATE(DstAeroTableData%C_Fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_fz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_Fz.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_fz = SrcInputFileData%C_fz + DstAeroTableData%C_Fz = SrcAeroTableData%C_Fz ENDIF -IF (ALLOCATED(SrcInputFileData%C_mx)) THEN - i1_l = LBOUND(SrcInputFileData%C_mx,1) - i1_u = UBOUND(SrcInputFileData%C_mx,1) - i2_l = LBOUND(SrcInputFileData%C_mx,2) - i2_u = UBOUND(SrcInputFileData%C_mx,2) - i3_l = LBOUND(SrcInputFileData%C_mx,3) - i3_u = UBOUND(SrcInputFileData%C_mx,3) - i4_l = LBOUND(SrcInputFileData%C_mx,4) - i4_u = UBOUND(SrcInputFileData%C_mx,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_mx)) THEN - ALLOCATE(DstInputFileData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_Mx)) THEN + i1_l = LBOUND(SrcAeroTableData%C_Mx,1) + i1_u = UBOUND(SrcAeroTableData%C_Mx,1) + i2_l = LBOUND(SrcAeroTableData%C_Mx,2) + i2_u = UBOUND(SrcAeroTableData%C_Mx,2) + i3_l = LBOUND(SrcAeroTableData%C_Mx,3) + i3_u = UBOUND(SrcAeroTableData%C_Mx,3) + i4_l = LBOUND(SrcAeroTableData%C_Mx,4) + i4_u = UBOUND(SrcAeroTableData%C_Mx,4) + i5_l = LBOUND(SrcAeroTableData%C_Mx,5) + i5_u = UBOUND(SrcAeroTableData%C_Mx,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_Mx)) THEN + ALLOCATE(DstAeroTableData%C_Mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_mx.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_Mx.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_mx = SrcInputFileData%C_mx + DstAeroTableData%C_Mx = SrcAeroTableData%C_Mx ENDIF -IF (ALLOCATED(SrcInputFileData%C_my)) THEN - i1_l = LBOUND(SrcInputFileData%C_my,1) - i1_u = UBOUND(SrcInputFileData%C_my,1) - i2_l = LBOUND(SrcInputFileData%C_my,2) - i2_u = UBOUND(SrcInputFileData%C_my,2) - i3_l = LBOUND(SrcInputFileData%C_my,3) - i3_u = UBOUND(SrcInputFileData%C_my,3) - i4_l = LBOUND(SrcInputFileData%C_my,4) - i4_u = UBOUND(SrcInputFileData%C_my,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_my)) THEN - ALLOCATE(DstInputFileData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_My)) THEN + i1_l = LBOUND(SrcAeroTableData%C_My,1) + i1_u = UBOUND(SrcAeroTableData%C_My,1) + i2_l = LBOUND(SrcAeroTableData%C_My,2) + i2_u = UBOUND(SrcAeroTableData%C_My,2) + i3_l = LBOUND(SrcAeroTableData%C_My,3) + i3_u = UBOUND(SrcAeroTableData%C_My,3) + i4_l = LBOUND(SrcAeroTableData%C_My,4) + i4_u = UBOUND(SrcAeroTableData%C_My,4) + i5_l = LBOUND(SrcAeroTableData%C_My,5) + i5_u = UBOUND(SrcAeroTableData%C_My,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_My)) THEN + ALLOCATE(DstAeroTableData%C_My(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_my.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_My.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_my = SrcInputFileData%C_my + DstAeroTableData%C_My = SrcAeroTableData%C_My ENDIF -IF (ALLOCATED(SrcInputFileData%C_mz)) THEN - i1_l = LBOUND(SrcInputFileData%C_mz,1) - i1_u = UBOUND(SrcInputFileData%C_mz,1) - i2_l = LBOUND(SrcInputFileData%C_mz,2) - i2_u = UBOUND(SrcInputFileData%C_mz,2) - i3_l = LBOUND(SrcInputFileData%C_mz,3) - i3_u = UBOUND(SrcInputFileData%C_mz,3) - i4_l = LBOUND(SrcInputFileData%C_mz,4) - i4_u = UBOUND(SrcInputFileData%C_mz,4) - IF (.NOT. ALLOCATED(DstInputFileData%C_mz)) THEN - ALLOCATE(DstInputFileData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) +IF (ALLOCATED(SrcAeroTableData%C_Mz)) THEN + i1_l = LBOUND(SrcAeroTableData%C_Mz,1) + i1_u = UBOUND(SrcAeroTableData%C_Mz,1) + i2_l = LBOUND(SrcAeroTableData%C_Mz,2) + i2_u = UBOUND(SrcAeroTableData%C_Mz,2) + i3_l = LBOUND(SrcAeroTableData%C_Mz,3) + i3_u = UBOUND(SrcAeroTableData%C_Mz,3) + i4_l = LBOUND(SrcAeroTableData%C_Mz,4) + i4_u = UBOUND(SrcAeroTableData%C_Mz,4) + i5_l = LBOUND(SrcAeroTableData%C_Mz,5) + i5_u = UBOUND(SrcAeroTableData%C_Mz,5) + IF (.NOT. ALLOCATED(DstAeroTableData%C_Mz)) THEN + ALLOCATE(DstAeroTableData%C_Mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%C_mz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstAeroTableData%C_Mz.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputFileData%C_mz = SrcInputFileData%C_mz + DstAeroTableData%C_Mz = SrcAeroTableData%C_Mz ENDIF - END SUBROUTINE ADsk_CopyInputFile + END SUBROUTINE ADsk_CopyAeroTable - SUBROUTINE ADsk_DestroyInputFile( InputFileData, ErrStat, ErrMsg ) - TYPE(ADsk_InputFile), INTENT(INOUT) :: InputFileData + SUBROUTINE ADsk_DestroyAeroTable( AeroTableData, ErrStat, ErrMsg ) + TYPE(ADsk_AeroTable), INTENT(INOUT) :: AeroTableData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInputFile' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyAeroTable' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(InputFileData%OutList)) THEN - DEALLOCATE(InputFileData%OutList) +IF (ALLOCATED(AeroTableData%TSR)) THEN + DEALLOCATE(AeroTableData%TSR) ENDIF -IF (ALLOCATED(InputFileData%TSR)) THEN - DEALLOCATE(InputFileData%TSR) +IF (ALLOCATED(AeroTableData%RtSpd)) THEN + DEALLOCATE(AeroTableData%RtSpd) ENDIF -IF (ALLOCATED(InputFileData%RtSpd)) THEN - DEALLOCATE(InputFileData%RtSpd) +IF (ALLOCATED(AeroTableData%VRel)) THEN + DEALLOCATE(AeroTableData%VRel) ENDIF -IF (ALLOCATED(InputFileData%VRel)) THEN - DEALLOCATE(InputFileData%VRel) +IF (ALLOCATED(AeroTableData%Pitch)) THEN + DEALLOCATE(AeroTableData%Pitch) ENDIF -IF (ALLOCATED(InputFileData%Pitch)) THEN - DEALLOCATE(InputFileData%Pitch) +IF (ALLOCATED(AeroTableData%Skew)) THEN + DEALLOCATE(AeroTableData%Skew) ENDIF -IF (ALLOCATED(InputFileData%Skew)) THEN - DEALLOCATE(InputFileData%Skew) +IF (ALLOCATED(AeroTableData%C_Fx)) THEN + DEALLOCATE(AeroTableData%C_Fx) ENDIF -IF (ALLOCATED(InputFileData%C_fx)) THEN - DEALLOCATE(InputFileData%C_fx) +IF (ALLOCATED(AeroTableData%C_Fy)) THEN + DEALLOCATE(AeroTableData%C_Fy) ENDIF -IF (ALLOCATED(InputFileData%C_fy)) THEN - DEALLOCATE(InputFileData%C_fy) +IF (ALLOCATED(AeroTableData%C_Fz)) THEN + DEALLOCATE(AeroTableData%C_Fz) ENDIF -IF (ALLOCATED(InputFileData%C_fz)) THEN - DEALLOCATE(InputFileData%C_fz) +IF (ALLOCATED(AeroTableData%C_Mx)) THEN + DEALLOCATE(AeroTableData%C_Mx) ENDIF -IF (ALLOCATED(InputFileData%C_mx)) THEN - DEALLOCATE(InputFileData%C_mx) +IF (ALLOCATED(AeroTableData%C_My)) THEN + DEALLOCATE(AeroTableData%C_My) ENDIF -IF (ALLOCATED(InputFileData%C_my)) THEN - DEALLOCATE(InputFileData%C_my) +IF (ALLOCATED(AeroTableData%C_Mz)) THEN + DEALLOCATE(AeroTableData%C_Mz) ENDIF -IF (ALLOCATED(InputFileData%C_mz)) THEN - DEALLOCATE(InputFileData%C_mz) -ENDIF - END SUBROUTINE ADsk_DestroyInputFile + END SUBROUTINE ADsk_DestroyAeroTable - SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackAeroTable( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_InputFile), INTENT(IN) :: InData + TYPE(ADsk_AeroTable), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -416,7 +412,7 @@ SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInputFile' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackAeroTable' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -432,14 +428,7 @@ SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! EchoFlag - Db_BufSz = Db_BufSz + 1 ! DeltaT - Int_BufSz = Int_BufSz + 1 ! SumPrint - Int_BufSz = Int_BufSz + 1 ! OutList allocated yes/no - IF ( ALLOCATED(InData%OutList) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! OutList upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%OutList)*LEN(InData%OutList) ! OutList - END IF + Int_BufSz = Int_BufSz + 1 ! N_TSR Int_BufSz = Int_BufSz + 1 ! N_RtSpd Int_BufSz = Int_BufSz + 1 ! N_VRel Int_BufSz = Int_BufSz + 1 ! N_Pitch @@ -469,35 +458,35 @@ SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Int_BufSz = Int_BufSz + 2*1 ! Skew upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%Skew) ! Skew END IF - Int_BufSz = Int_BufSz + 1 ! C_fx allocated yes/no - IF ( ALLOCATED(InData%C_fx) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fx upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fx) ! C_fx + Int_BufSz = Int_BufSz + 1 ! C_Fx allocated yes/no + IF ( ALLOCATED(InData%C_Fx) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_Fx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_Fx) ! C_Fx END IF - Int_BufSz = Int_BufSz + 1 ! C_fy allocated yes/no - IF ( ALLOCATED(InData%C_fy) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fy upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fy) ! C_fy + Int_BufSz = Int_BufSz + 1 ! C_Fy allocated yes/no + IF ( ALLOCATED(InData%C_Fy) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_Fy upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_Fy) ! C_Fy END IF - Int_BufSz = Int_BufSz + 1 ! C_fz allocated yes/no - IF ( ALLOCATED(InData%C_fz) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fz upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fz) ! C_fz + Int_BufSz = Int_BufSz + 1 ! C_Fz allocated yes/no + IF ( ALLOCATED(InData%C_Fz) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_Fz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_Fz) ! C_Fz END IF - Int_BufSz = Int_BufSz + 1 ! C_mx allocated yes/no - IF ( ALLOCATED(InData%C_mx) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_mx upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_mx) ! C_mx + Int_BufSz = Int_BufSz + 1 ! C_Mx allocated yes/no + IF ( ALLOCATED(InData%C_Mx) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_Mx upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_Mx) ! C_Mx END IF - Int_BufSz = Int_BufSz + 1 ! C_my allocated yes/no - IF ( ALLOCATED(InData%C_my) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_my upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_my) ! C_my + Int_BufSz = Int_BufSz + 1 ! C_My allocated yes/no + IF ( ALLOCATED(InData%C_My) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_My upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_My) ! C_My END IF - Int_BufSz = Int_BufSz + 1 ! C_mz allocated yes/no - IF ( ALLOCATED(InData%C_mz) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_mz upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_mz) ! C_mz + Int_BufSz = Int_BufSz + 1 ! C_Mz allocated yes/no + IF ( ALLOCATED(InData%C_Mz) ) THEN + Int_BufSz = Int_BufSz + 2*5 ! C_Mz upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%C_Mz) ! C_Mz END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) @@ -526,29 +515,8 @@ SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_Xferred = 1 Int_Xferred = 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%EchoFlag, IntKiBuf(1)) - Int_Xferred = Int_Xferred + 1 - DbKiBuf(Db_Xferred) = InData%DeltaT - Db_Xferred = Db_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%SumPrint, IntKiBuf(1)) - Int_Xferred = Int_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%OutList) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 + IntKiBuf(Int_Xferred) = InData%N_TSR Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%OutList,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutList,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%OutList,1), UBOUND(InData%OutList,1) - DO I = 1, LEN(InData%OutList) - IntKiBuf(Int_Xferred) = ICHAR(InData%OutList(i1)(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I - END DO - END IF IntKiBuf(Int_Xferred) = InData%N_RtSpd Int_Xferred = Int_Xferred + 1 IntKiBuf(Int_Xferred) = InData%N_VRel @@ -632,193 +600,223 @@ SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_Xferred = Re_Xferred + 1 END DO END IF - IF ( .NOT. ALLOCATED(InData%C_fx) ) THEN + IF ( .NOT. ALLOCATED(InData%C_Fx) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fx,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fx,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fx,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fx,4) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fx,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fx,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_fx,4), UBOUND(InData%C_fx,4) - DO i3 = LBOUND(InData%C_fx,3), UBOUND(InData%C_fx,3) - DO i2 = LBOUND(InData%C_fx,2), UBOUND(InData%C_fx,2) - DO i1 = LBOUND(InData%C_fx,1), UBOUND(InData%C_fx,1) - ReKiBuf(Re_Xferred) = InData%C_fx(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_Fx,5), UBOUND(InData%C_Fx,5) + DO i4 = LBOUND(InData%C_Fx,4), UBOUND(InData%C_Fx,4) + DO i3 = LBOUND(InData%C_Fx,3), UBOUND(InData%C_Fx,3) + DO i2 = LBOUND(InData%C_Fx,2), UBOUND(InData%C_Fx,2) + DO i1 = LBOUND(InData%C_Fx,1), UBOUND(InData%C_Fx,1) + ReKiBuf(Re_Xferred) = InData%C_Fx(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%C_fy) ) THEN + IF ( .NOT. ALLOCATED(InData%C_Fy) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fy,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fy,1) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fy,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fy,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fy,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fy,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fy,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fy,4) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fy,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fy,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_fy,4), UBOUND(InData%C_fy,4) - DO i3 = LBOUND(InData%C_fy,3), UBOUND(InData%C_fy,3) - DO i2 = LBOUND(InData%C_fy,2), UBOUND(InData%C_fy,2) - DO i1 = LBOUND(InData%C_fy,1), UBOUND(InData%C_fy,1) - ReKiBuf(Re_Xferred) = InData%C_fy(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_Fy,5), UBOUND(InData%C_Fy,5) + DO i4 = LBOUND(InData%C_Fy,4), UBOUND(InData%C_Fy,4) + DO i3 = LBOUND(InData%C_Fy,3), UBOUND(InData%C_Fy,3) + DO i2 = LBOUND(InData%C_Fy,2), UBOUND(InData%C_Fy,2) + DO i1 = LBOUND(InData%C_Fy,1), UBOUND(InData%C_Fy,1) + ReKiBuf(Re_Xferred) = InData%C_Fy(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%C_fz) ) THEN + IF ( .NOT. ALLOCATED(InData%C_Fz) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fz,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fz,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fz,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fz,4) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Fz,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Fz,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_fz,4), UBOUND(InData%C_fz,4) - DO i3 = LBOUND(InData%C_fz,3), UBOUND(InData%C_fz,3) - DO i2 = LBOUND(InData%C_fz,2), UBOUND(InData%C_fz,2) - DO i1 = LBOUND(InData%C_fz,1), UBOUND(InData%C_fz,1) - ReKiBuf(Re_Xferred) = InData%C_fz(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_Fz,5), UBOUND(InData%C_Fz,5) + DO i4 = LBOUND(InData%C_Fz,4), UBOUND(InData%C_Fz,4) + DO i3 = LBOUND(InData%C_Fz,3), UBOUND(InData%C_Fz,3) + DO i2 = LBOUND(InData%C_Fz,2), UBOUND(InData%C_Fz,2) + DO i1 = LBOUND(InData%C_Fz,1), UBOUND(InData%C_Fz,1) + ReKiBuf(Re_Xferred) = InData%C_Fz(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%C_mx) ) THEN + IF ( .NOT. ALLOCATED(InData%C_Mx) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mx,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mx,1) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mx,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mx,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mx,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mx,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mx,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mx,4) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mx,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mx,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_mx,4), UBOUND(InData%C_mx,4) - DO i3 = LBOUND(InData%C_mx,3), UBOUND(InData%C_mx,3) - DO i2 = LBOUND(InData%C_mx,2), UBOUND(InData%C_mx,2) - DO i1 = LBOUND(InData%C_mx,1), UBOUND(InData%C_mx,1) - ReKiBuf(Re_Xferred) = InData%C_mx(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_Mx,5), UBOUND(InData%C_Mx,5) + DO i4 = LBOUND(InData%C_Mx,4), UBOUND(InData%C_Mx,4) + DO i3 = LBOUND(InData%C_Mx,3), UBOUND(InData%C_Mx,3) + DO i2 = LBOUND(InData%C_Mx,2), UBOUND(InData%C_Mx,2) + DO i1 = LBOUND(InData%C_Mx,1), UBOUND(InData%C_Mx,1) + ReKiBuf(Re_Xferred) = InData%C_Mx(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%C_my) ) THEN + IF ( .NOT. ALLOCATED(InData%C_My) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_My,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_My,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_My,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_My,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_My,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_My,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_My,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_My,4) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_My,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_My,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_my,4), UBOUND(InData%C_my,4) - DO i3 = LBOUND(InData%C_my,3), UBOUND(InData%C_my,3) - DO i2 = LBOUND(InData%C_my,2), UBOUND(InData%C_my,2) - DO i1 = LBOUND(InData%C_my,1), UBOUND(InData%C_my,1) - ReKiBuf(Re_Xferred) = InData%C_my(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_My,5), UBOUND(InData%C_My,5) + DO i4 = LBOUND(InData%C_My,4), UBOUND(InData%C_My,4) + DO i3 = LBOUND(InData%C_My,3), UBOUND(InData%C_My,3) + DO i2 = LBOUND(InData%C_My,2), UBOUND(InData%C_My,2) + DO i1 = LBOUND(InData%C_My,1), UBOUND(InData%C_My,1) + ReKiBuf(Re_Xferred) = InData%C_My(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%C_mz) ) THEN + IF ( .NOT. ALLOCATED(InData%C_Mz) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mz,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mz,1) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,2) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mz,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mz,2) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,3) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mz,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mz,3) Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mz,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mz,4) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%C_Mz,5) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_Mz,5) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_mz,4), UBOUND(InData%C_mz,4) - DO i3 = LBOUND(InData%C_mz,3), UBOUND(InData%C_mz,3) - DO i2 = LBOUND(InData%C_mz,2), UBOUND(InData%C_mz,2) - DO i1 = LBOUND(InData%C_mz,1), UBOUND(InData%C_mz,1) - ReKiBuf(Re_Xferred) = InData%C_mz(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(InData%C_Mz,5), UBOUND(InData%C_Mz,5) + DO i4 = LBOUND(InData%C_Mz,4), UBOUND(InData%C_Mz,4) + DO i3 = LBOUND(InData%C_Mz,3), UBOUND(InData%C_Mz,3) + DO i2 = LBOUND(InData%C_Mz,2), UBOUND(InData%C_Mz,2) + DO i1 = LBOUND(InData%C_Mz,1), UBOUND(InData%C_Mz,1) + ReKiBuf(Re_Xferred) = InData%C_Mz(i1,i2,i3,i4,i5) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - END SUBROUTINE ADsk_PackInputFile + END SUBROUTINE ADsk_PackAeroTable - SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackAeroTable( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_InputFile), INTENT(INOUT) :: OutData + TYPE(ADsk_AeroTable), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -831,9 +829,10 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 + INTEGER(IntKi) :: i5, i5_l, i5_u ! bounds (upper/lower) for an array dimension 5 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInputFile' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackAeroTable' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -844,32 +843,8 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%EchoFlag = TRANSFER(IntKiBuf(Int_Xferred), OutData%EchoFlag) - Int_Xferred = Int_Xferred + 1 - OutData%DeltaT = REAL(DbKiBuf(Db_Xferred), R8Ki) - Db_Xferred = Db_Xferred + 1 - OutData%SumPrint = TRANSFER(IntKiBuf(Int_Xferred), OutData%SumPrint) - Int_Xferred = Int_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutList not allocated - Int_Xferred = Int_Xferred + 1 - ELSE + OutData%N_TSR = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%OutList)) DEALLOCATE(OutData%OutList) - ALLOCATE(OutData%OutList(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutList.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%OutList,1), UBOUND(OutData%OutList,1) - DO I = 1, LEN(OutData%OutList) - OutData%OutList(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I - END DO - END IF OutData%N_RtSpd = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 OutData%N_VRel = IntKiBuf(Int_Xferred) @@ -892,7 +867,7 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E RETURN END IF DO i1 = LBOUND(OutData%TSR,1), UBOUND(OutData%TSR,1) - OutData%TSR(i1) = ReKiBuf(Re_Xferred) + OutData%TSR(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -910,7 +885,7 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E RETURN END IF DO i1 = LBOUND(OutData%RtSpd,1), UBOUND(OutData%RtSpd,1) - OutData%RtSpd(i1) = ReKiBuf(Re_Xferred) + OutData%RtSpd(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -928,7 +903,7 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E RETURN END IF DO i1 = LBOUND(OutData%VRel,1), UBOUND(OutData%VRel,1) - OutData%VRel(i1) = ReKiBuf(Re_Xferred) + OutData%VRel(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -946,7 +921,7 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E RETURN END IF DO i1 = LBOUND(OutData%Pitch,1), UBOUND(OutData%Pitch,1) - OutData%Pitch(i1) = ReKiBuf(Re_Xferred) + OutData%Pitch(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -964,11 +939,11 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E RETURN END IF DO i1 = LBOUND(OutData%Skew,1), UBOUND(OutData%Skew,1) - OutData%Skew(i1) = ReKiBuf(Re_Xferred) + OutData%Skew(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fx not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_Fx not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -984,24 +959,29 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fx)) DEALLOCATE(OutData%C_fx) - ALLOCATE(OutData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_Fx)) DEALLOCATE(OutData%C_Fx) + ALLOCATE(OutData%C_Fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fx.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_Fx.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_fx,4), UBOUND(OutData%C_fx,4) - DO i3 = LBOUND(OutData%C_fx,3), UBOUND(OutData%C_fx,3) - DO i2 = LBOUND(OutData%C_fx,2), UBOUND(OutData%C_fx,2) - DO i1 = LBOUND(OutData%C_fx,1), UBOUND(OutData%C_fx,1) - OutData%C_fx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_Fx,5), UBOUND(OutData%C_Fx,5) + DO i4 = LBOUND(OutData%C_Fx,4), UBOUND(OutData%C_Fx,4) + DO i3 = LBOUND(OutData%C_Fx,3), UBOUND(OutData%C_Fx,3) + DO i2 = LBOUND(OutData%C_Fx,2), UBOUND(OutData%C_Fx,2) + DO i1 = LBOUND(OutData%C_Fx,1), UBOUND(OutData%C_Fx,1) + OutData%C_Fx(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fy not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_Fy not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -1017,24 +997,29 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fy)) DEALLOCATE(OutData%C_fy) - ALLOCATE(OutData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_Fy)) DEALLOCATE(OutData%C_Fy) + ALLOCATE(OutData%C_Fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fy.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_Fy.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_fy,4), UBOUND(OutData%C_fy,4) - DO i3 = LBOUND(OutData%C_fy,3), UBOUND(OutData%C_fy,3) - DO i2 = LBOUND(OutData%C_fy,2), UBOUND(OutData%C_fy,2) - DO i1 = LBOUND(OutData%C_fy,1), UBOUND(OutData%C_fy,1) - OutData%C_fy(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_Fy,5), UBOUND(OutData%C_Fy,5) + DO i4 = LBOUND(OutData%C_Fy,4), UBOUND(OutData%C_Fy,4) + DO i3 = LBOUND(OutData%C_Fy,3), UBOUND(OutData%C_Fy,3) + DO i2 = LBOUND(OutData%C_Fy,2), UBOUND(OutData%C_Fy,2) + DO i1 = LBOUND(OutData%C_Fy,1), UBOUND(OutData%C_Fy,1) + OutData%C_Fy(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fz not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_Fz not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -1050,24 +1035,29 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fz)) DEALLOCATE(OutData%C_fz) - ALLOCATE(OutData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_Fz)) DEALLOCATE(OutData%C_Fz) + ALLOCATE(OutData%C_Fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_Fz.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_fz,4), UBOUND(OutData%C_fz,4) - DO i3 = LBOUND(OutData%C_fz,3), UBOUND(OutData%C_fz,3) - DO i2 = LBOUND(OutData%C_fz,2), UBOUND(OutData%C_fz,2) - DO i1 = LBOUND(OutData%C_fz,1), UBOUND(OutData%C_fz,1) - OutData%C_fz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_Fz,5), UBOUND(OutData%C_Fz,5) + DO i4 = LBOUND(OutData%C_Fz,4), UBOUND(OutData%C_Fz,4) + DO i3 = LBOUND(OutData%C_Fz,3), UBOUND(OutData%C_Fz,3) + DO i2 = LBOUND(OutData%C_Fz,2), UBOUND(OutData%C_Fz,2) + DO i1 = LBOUND(OutData%C_Fz,1), UBOUND(OutData%C_Fz,1) + OutData%C_Fz(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mx not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_Mx not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -1083,24 +1073,29 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_mx)) DEALLOCATE(OutData%C_mx) - ALLOCATE(OutData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_Mx)) DEALLOCATE(OutData%C_Mx) + ALLOCATE(OutData%C_Mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mx.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_Mx.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_mx,4), UBOUND(OutData%C_mx,4) - DO i3 = LBOUND(OutData%C_mx,3), UBOUND(OutData%C_mx,3) - DO i2 = LBOUND(OutData%C_mx,2), UBOUND(OutData%C_mx,2) - DO i1 = LBOUND(OutData%C_mx,1), UBOUND(OutData%C_mx,1) - OutData%C_mx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_Mx,5), UBOUND(OutData%C_Mx,5) + DO i4 = LBOUND(OutData%C_Mx,4), UBOUND(OutData%C_Mx,4) + DO i3 = LBOUND(OutData%C_Mx,3), UBOUND(OutData%C_Mx,3) + DO i2 = LBOUND(OutData%C_Mx,2), UBOUND(OutData%C_Mx,2) + DO i1 = LBOUND(OutData%C_Mx,1), UBOUND(OutData%C_Mx,1) + OutData%C_Mx(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_my not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_My not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -1116,24 +1111,29 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_my)) DEALLOCATE(OutData%C_my) - ALLOCATE(OutData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_My)) DEALLOCATE(OutData%C_My) + ALLOCATE(OutData%C_My(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_my.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_My.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_my,4), UBOUND(OutData%C_my,4) - DO i3 = LBOUND(OutData%C_my,3), UBOUND(OutData%C_my,3) - DO i2 = LBOUND(OutData%C_my,2), UBOUND(OutData%C_my,2) - DO i1 = LBOUND(OutData%C_my,1), UBOUND(OutData%C_my,1) - OutData%C_my(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_My,5), UBOUND(OutData%C_My,5) + DO i4 = LBOUND(OutData%C_My,4), UBOUND(OutData%C_My,4) + DO i3 = LBOUND(OutData%C_My,3), UBOUND(OutData%C_My,3) + DO i2 = LBOUND(OutData%C_My,2), UBOUND(OutData%C_My,2) + DO i1 = LBOUND(OutData%C_My,1), UBOUND(OutData%C_My,1) + OutData%C_My(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mz not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_Mz not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 @@ -1149,66 +1149,88 @@ SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E i4_l = IntKiBuf( Int_Xferred ) i4_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_mz)) DEALLOCATE(OutData%C_mz) - ALLOCATE(OutData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + i5_l = IntKiBuf( Int_Xferred ) + i5_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%C_Mz)) DEALLOCATE(OutData%C_Mz) + ALLOCATE(OutData%C_Mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u,i5_l:i5_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_Mz.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_mz,4), UBOUND(OutData%C_mz,4) - DO i3 = LBOUND(OutData%C_mz,3), UBOUND(OutData%C_mz,3) - DO i2 = LBOUND(OutData%C_mz,2), UBOUND(OutData%C_mz,2) - DO i1 = LBOUND(OutData%C_mz,1), UBOUND(OutData%C_mz,1) - OutData%C_mz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + DO i5 = LBOUND(OutData%C_Mz,5), UBOUND(OutData%C_Mz,5) + DO i4 = LBOUND(OutData%C_Mz,4), UBOUND(OutData%C_Mz,4) + DO i3 = LBOUND(OutData%C_Mz,3), UBOUND(OutData%C_Mz,3) + DO i2 = LBOUND(OutData%C_Mz,2), UBOUND(OutData%C_Mz,2) + DO i1 = LBOUND(OutData%C_Mz,1), UBOUND(OutData%C_Mz,1) + OutData%C_Mz(i1,i2,i3,i4,i5) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO END DO END DO END DO END DO END IF - END SUBROUTINE ADsk_UnPackInputFile + END SUBROUTINE ADsk_UnPackAeroTable - SUBROUTINE ADsk_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_InitInputType), INTENT(IN) :: SrcInitInputData - TYPE(ADsk_InitInputType), INTENT(INOUT) :: DstInitInputData + SUBROUTINE ADsk_CopyInputFile( SrcInputFileData, DstInputFileData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InputFile), INTENT(IN) :: SrcInputFileData + TYPE(ADsk_InputFile), INTENT(INOUT) :: DstInputFileData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInputFile' ! ErrStat = ErrID_None ErrMsg = "" - DstInitInputData%InputFile = SrcInitInputData%InputFile - DstInitInputData%RootName = SrcInitInputData%RootName - DstInitInputData%RotorRad = SrcInitInputData%RotorRad - DstInitInputData%HubPosition = SrcInitInputData%HubPosition - DstInitInputData%HubOrientation = SrcInitInputData%HubOrientation - DstInitInputData%defPatm = SrcInitInputData%defPatm - DstInitInputData%Linearize = SrcInitInputData%Linearize - END SUBROUTINE ADsk_CopyInitInput + DstInputFileData%Echo = SrcInputFileData%Echo + DstInputFileData%DT = SrcInputFileData%DT + DstInputFileData%AirDens = SrcInputFileData%AirDens + DstInputFileData%RotorRad = SrcInputFileData%RotorRad + DstInputFileData%SumPrint = SrcInputFileData%SumPrint + DstInputFileData%NumOuts = SrcInputFileData%NumOuts +IF (ALLOCATED(SrcInputFileData%OutList)) THEN + i1_l = LBOUND(SrcInputFileData%OutList,1) + i1_u = UBOUND(SrcInputFileData%OutList,1) + IF (.NOT. ALLOCATED(DstInputFileData%OutList)) THEN + ALLOCATE(DstInputFileData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputFileData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInputFileData%OutList = SrcInputFileData%OutList +ENDIF + CALL ADsk_Copyaerotable( SrcInputFileData%AeroTable, DstInputFileData%AeroTable, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + END SUBROUTINE ADsk_CopyInputFile - SUBROUTINE ADsk_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) - TYPE(ADsk_InitInputType), INTENT(INOUT) :: InitInputData + SUBROUTINE ADsk_DestroyInputFile( InputFileData, ErrStat, ErrMsg ) + TYPE(ADsk_InputFile), INTENT(INOUT) :: InputFileData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInputFile' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE ADsk_DestroyInitInput +IF (ALLOCATED(InputFileData%OutList)) THEN + DEALLOCATE(InputFileData%OutList) +ENDIF + CALL ADsk_Destroyaerotable( InputFileData%AeroTable, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInputFile - SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_InitInputType), INTENT(IN) :: InData + TYPE(ADsk_InputFile), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -1223,7 +1245,7 @@ SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInputFile' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -1239,13 +1261,35 @@ SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1*LEN(InData%InputFile) ! InputFile - Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Int_BufSz = Int_BufSz + 1 ! Echo + Db_BufSz = Db_BufSz + 1 ! DT + Re_BufSz = Re_BufSz + 1 ! AirDens Re_BufSz = Re_BufSz + 1 ! RotorRad - Re_BufSz = Re_BufSz + SIZE(InData%HubPosition) ! HubPosition - Db_BufSz = Db_BufSz + SIZE(InData%HubOrientation) ! HubOrientation - Re_BufSz = Re_BufSz + 1 ! defPatm - Int_BufSz = Int_BufSz + 1 ! Linearize + Int_BufSz = Int_BufSz + 1 ! SumPrint + Int_BufSz = Int_BufSz + 1 ! NumOuts + Int_BufSz = Int_BufSz + 1 ! OutList allocated yes/no + IF ( ALLOCATED(InData%OutList) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! OutList upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%OutList)*LEN(InData%OutList) ! OutList + END IF + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! AeroTable: size of buffers for each call to pack subtype + CALL ADsk_Packaerotable( Re_Buf, Db_Buf, Int_Buf, InData%AeroTable, ErrStat2, ErrMsg2, .TRUE. ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! AeroTable + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! AeroTable + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! AeroTable + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1273,159 +1317,212 @@ SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_Xferred = 1 Int_Xferred = 1 - DO I = 1, LEN(InData%InputFile) - IntKiBuf(Int_Xferred) = ICHAR(InData%InputFile(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I - DO I = 1, LEN(InData%RootName) - IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I - ReKiBuf(Re_Xferred) = InData%RotorRad + IntKiBuf(Int_Xferred) = TRANSFER(InData%Echo, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%DT + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%AirDens Re_Xferred = Re_Xferred + 1 - DO i1 = LBOUND(InData%HubPosition,1), UBOUND(InData%HubPosition,1) - ReKiBuf(Re_Xferred) = InData%HubPosition(i1) - Re_Xferred = Re_Xferred + 1 - END DO - DO i2 = LBOUND(InData%HubOrientation,2), UBOUND(InData%HubOrientation,2) - DO i1 = LBOUND(InData%HubOrientation,1), UBOUND(InData%HubOrientation,1) - DbKiBuf(Db_Xferred) = InData%HubOrientation(i1,i2) - Db_Xferred = Db_Xferred + 1 - END DO - END DO - ReKiBuf(Re_Xferred) = InData%defPatm + ReKiBuf(Re_Xferred) = InData%RotorRad Re_Xferred = Re_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%Linearize, IntKiBuf(1)) + IntKiBuf(Int_Xferred) = TRANSFER(InData%SumPrint, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - END SUBROUTINE ADsk_PackInitInput + IntKiBuf(Int_Xferred) = InData%NumOuts + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%OutList) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutList,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutList,1) + Int_Xferred = Int_Xferred + 2 - SUBROUTINE ADsk_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) - REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_InitInputType), INTENT(INOUT) :: OutData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - ! Local variables - INTEGER(IntKi) :: Buf_size - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitInput' - ! buffers to store meshes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - DO I = 1, LEN(OutData%InputFile) - OutData%InputFile(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I - DO I = 1, LEN(OutData%RootName) - OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I - OutData%RotorRad = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - i1_l = LBOUND(OutData%HubPosition,1) - i1_u = UBOUND(OutData%HubPosition,1) - DO i1 = LBOUND(OutData%HubPosition,1), UBOUND(OutData%HubPosition,1) - OutData%HubPosition(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - i1_l = LBOUND(OutData%HubOrientation,1) - i1_u = UBOUND(OutData%HubOrientation,1) - i2_l = LBOUND(OutData%HubOrientation,2) - i2_u = UBOUND(OutData%HubOrientation,2) - DO i2 = LBOUND(OutData%HubOrientation,2), UBOUND(OutData%HubOrientation,2) - DO i1 = LBOUND(OutData%HubOrientation,1), UBOUND(OutData%HubOrientation,1) - OutData%HubOrientation(i1,i2) = REAL(DbKiBuf(Db_Xferred), R8Ki) - Db_Xferred = Db_Xferred + 1 + DO i1 = LBOUND(InData%OutList,1), UBOUND(InData%OutList,1) + DO I = 1, LEN(InData%OutList) + IntKiBuf(Int_Xferred) = ICHAR(InData%OutList(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I END DO - END DO - OutData%defPatm = ReKiBuf(Re_Xferred) + END IF + CALL ADsk_Packaerotable( Re_Buf, Db_Buf, Int_Buf, InData%AeroTable, ErrStat2, ErrMsg2, OnlySize ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END SUBROUTINE ADsk_PackInputFile + + SUBROUTINE ADsk_UnPackInputFile( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_InputFile), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInputFile' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%Echo = TRANSFER(IntKiBuf(Int_Xferred), OutData%Echo) + Int_Xferred = Int_Xferred + 1 + OutData%DT = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + OutData%AirDens = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - OutData%Linearize = TRANSFER(IntKiBuf(Int_Xferred), OutData%Linearize) + OutData%RotorRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%SumPrint = TRANSFER(IntKiBuf(Int_Xferred), OutData%SumPrint) Int_Xferred = Int_Xferred + 1 - END SUBROUTINE ADsk_UnPackInitInput + OutData%NumOuts = IntKiBuf(Int_Xferred) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutList not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%OutList)) DEALLOCATE(OutData%OutList) + ALLOCATE(OutData%OutList(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutList.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%OutList,1), UBOUND(OutData%OutList,1) + DO I = 1, LEN(OutData%OutList) + OutData%OutList(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL ADsk_Unpackaerotable( Re_Buf, Db_Buf, Int_Buf, OutData%AeroTable, ErrStat2, ErrMsg2 ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - SUBROUTINE ADsk_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_InitOutputType), INTENT(IN) :: SrcInitOutputData - TYPE(ADsk_InitOutputType), INTENT(INOUT) :: DstInitOutputData + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END SUBROUTINE ADsk_UnPackInputFile + + SUBROUTINE ADsk_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InitInputType), INTENT(IN) :: SrcInitInputData + TYPE(ADsk_InitInputType), INTENT(INOUT) :: DstInitInputData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitInput' ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(SrcInitOutputData%WriteOutputHdr)) THEN - i1_l = LBOUND(SrcInitOutputData%WriteOutputHdr,1) - i1_u = UBOUND(SrcInitOutputData%WriteOutputHdr,1) - IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputHdr)) THEN - ALLOCATE(DstInitOutputData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstInitOutputData%WriteOutputHdr = SrcInitOutputData%WriteOutputHdr -ENDIF -IF (ALLOCATED(SrcInitOutputData%WriteOutputUnt)) THEN - i1_l = LBOUND(SrcInitOutputData%WriteOutputUnt,1) - i1_u = UBOUND(SrcInitOutputData%WriteOutputUnt,1) - IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputUnt)) THEN - ALLOCATE(DstInitOutputData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstInitOutputData%WriteOutputUnt = SrcInitOutputData%WriteOutputUnt -ENDIF - CALL NWTC_Library_Copyprogdesc( SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2 ) + DstInitInputData%InputFile = SrcInitInputData%InputFile + DstInitInputData%RootName = SrcInitInputData%RootName + DstInitInputData%RotorRad = SrcInitInputData%RotorRad + DstInitInputData%HubPosition = SrcInitInputData%HubPosition + DstInitInputData%HubOrientation = SrcInitInputData%HubOrientation + DstInitInputData%defAirDens = SrcInitInputData%defAirDens + DstInitInputData%Linearize = SrcInitInputData%Linearize + DstInitInputData%UseInputFile = SrcInitInputData%UseInputFile + CALL NWTC_Library_Copyfileinfotype( SrcInitInputData%PassedFileData, DstInitInputData%PassedFileData, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - END SUBROUTINE ADsk_CopyInitOutput + END SUBROUTINE ADsk_CopyInitInput - SUBROUTINE ADsk_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) - TYPE(ADsk_InitOutputType), INTENT(INOUT) :: InitOutputData + SUBROUTINE ADsk_DestroyInitInput( InitInputData, ErrStat, ErrMsg ) + TYPE(ADsk_InitInputType), INTENT(INOUT) :: InitInputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitInput' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(InitOutputData%WriteOutputHdr)) THEN - DEALLOCATE(InitOutputData%WriteOutputHdr) -ENDIF -IF (ALLOCATED(InitOutputData%WriteOutputUnt)) THEN - DEALLOCATE(InitOutputData%WriteOutputUnt) -ENDIF - CALL NWTC_Library_Destroyprogdesc( InitOutputData%Ver, ErrStat, ErrMsg ) - END SUBROUTINE ADsk_DestroyInitOutput + CALL NWTC_Library_Destroyfileinfotype( InitInputData%PassedFileData, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInitInput - SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_InitOutputType), INTENT(IN) :: InData + TYPE(ADsk_InitInputType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -1440,7 +1537,7 @@ SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitInput' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -1456,31 +1553,29 @@ SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no - IF ( ALLOCATED(InData%WriteOutputHdr) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! WriteOutputHdr upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputHdr)*LEN(InData%WriteOutputHdr) ! WriteOutputHdr - END IF - Int_BufSz = Int_BufSz + 1 ! WriteOutputUnt allocated yes/no - IF ( ALLOCATED(InData%WriteOutputUnt) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! WriteOutputUnt upper/lower bounds for each dimension - Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputUnt)*LEN(InData%WriteOutputUnt) ! WriteOutputUnt - END IF + Int_BufSz = Int_BufSz + 1*LEN(InData%InputFile) ! InputFile + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Re_BufSz = Re_BufSz + 1 ! RotorRad + Re_BufSz = Re_BufSz + SIZE(InData%HubPosition) ! HubPosition + Db_BufSz = Db_BufSz + SIZE(InData%HubOrientation) ! HubOrientation + Re_BufSz = Re_BufSz + 1 ! defAirDens + Int_BufSz = Int_BufSz + 1 ! Linearize + Int_BufSz = Int_BufSz + 1 ! UseInputFile ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! Ver: size of buffers for each call to pack subtype - CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, .TRUE. ) ! Ver + Int_BufSz = Int_BufSz + 3 ! PassedFileData: size of buffers for each call to pack subtype + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, .TRUE. ) ! PassedFileData CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! Ver + IF(ALLOCATED(Re_Buf)) THEN ! PassedFileData Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! Ver + IF(ALLOCATED(Db_Buf)) THEN ! PassedFileData Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! Ver + IF(ALLOCATED(Int_Buf)) THEN ! PassedFileData Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF @@ -1511,41 +1606,33 @@ SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Db_Xferred = 1 Int_Xferred = 1 - IF ( .NOT. ALLOCATED(InData%WriteOutputHdr) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputHdr,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputHdr,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%WriteOutputHdr,1), UBOUND(InData%WriteOutputHdr,1) - DO I = 1, LEN(InData%WriteOutputHdr) - IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputHdr(i1)(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I - END DO - END IF - IF ( .NOT. ALLOCATED(InData%WriteOutputUnt) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputUnt,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputUnt,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%WriteOutputUnt,1), UBOUND(InData%WriteOutputUnt,1) - DO I = 1, LEN(InData%WriteOutputUnt) - IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputUnt(i1)(I:I), IntKi) - Int_Xferred = Int_Xferred + 1 - END DO ! I + DO I = 1, LEN(InData%InputFile) + IntKiBuf(Int_Xferred) = ICHAR(InData%InputFile(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + ReKiBuf(Re_Xferred) = InData%RotorRad + Re_Xferred = Re_Xferred + 1 + DO i1 = LBOUND(InData%HubPosition,1), UBOUND(InData%HubPosition,1) + ReKiBuf(Re_Xferred) = InData%HubPosition(i1) + Re_Xferred = Re_Xferred + 1 + END DO + DO i2 = LBOUND(InData%HubOrientation,2), UBOUND(InData%HubOrientation,2) + DO i1 = LBOUND(InData%HubOrientation,1), UBOUND(InData%HubOrientation,1) + DbKiBuf(Db_Xferred) = InData%HubOrientation(i1,i2) + Db_Xferred = Db_Xferred + 1 END DO - END IF - CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, OnlySize ) ! Ver + END DO + ReKiBuf(Re_Xferred) = InData%defAirDens + Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%Linearize, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%UseInputFile, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + CALL NWTC_Library_Packfileinfotype( Re_Buf, Db_Buf, Int_Buf, InData%PassedFileData, ErrStat2, ErrMsg2, OnlySize ) ! PassedFileData CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -1573,13 +1660,13 @@ SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - END SUBROUTINE ADsk_PackInitOutput + END SUBROUTINE ADsk_PackInitInput - SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_InitOutputType), INTENT(INOUT) :: OutData + TYPE(ADsk_InitInputType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -1589,9 +1676,10 @@ SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, INTEGER(IntKi) :: Int_Xferred INTEGER(IntKi) :: i INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitInput' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -1602,46 +1690,38 @@ SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputHdr not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WriteOutputHdr)) DEALLOCATE(OutData%WriteOutputHdr) - ALLOCATE(OutData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%WriteOutputHdr,1), UBOUND(OutData%WriteOutputHdr,1) - DO I = 1, LEN(OutData%WriteOutputHdr) - OutData%WriteOutputHdr(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I + DO I = 1, LEN(OutData%InputFile) + OutData%InputFile(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%RootName) + OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + OutData%RotorRad = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + i1_l = LBOUND(OutData%HubPosition,1) + i1_u = UBOUND(OutData%HubPosition,1) + DO i1 = LBOUND(OutData%HubPosition,1), UBOUND(OutData%HubPosition,1) + OutData%HubPosition(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + i1_l = LBOUND(OutData%HubOrientation,1) + i1_u = UBOUND(OutData%HubOrientation,1) + i2_l = LBOUND(OutData%HubOrientation,2) + i2_u = UBOUND(OutData%HubOrientation,2) + DO i2 = LBOUND(OutData%HubOrientation,2), UBOUND(OutData%HubOrientation,2) + DO i1 = LBOUND(OutData%HubOrientation,1), UBOUND(OutData%HubOrientation,1) + OutData%HubOrientation(i1,i2) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputUnt not allocated + END DO + OutData%defAirDens = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Linearize = TRANSFER(IntKiBuf(Int_Xferred), OutData%Linearize) Int_Xferred = Int_Xferred + 1 - ELSE + OutData%UseInputFile = TRANSFER(IntKiBuf(Int_Xferred), OutData%UseInputFile) Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WriteOutputUnt)) DEALLOCATE(OutData%WriteOutputUnt) - ALLOCATE(OutData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%WriteOutputUnt,1), UBOUND(OutData%WriteOutputUnt,1) - DO I = 1, LEN(OutData%WriteOutputUnt) - OutData%WriteOutputUnt(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) - Int_Xferred = Int_Xferred + 1 - END DO ! I - END DO - END IF Buf_size=IntKiBuf( Int_Xferred ) Int_Xferred = Int_Xferred + 1 IF(Buf_size > 0) THEN @@ -1675,18 +1755,18 @@ SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL NWTC_Library_Unpackprogdesc( Re_Buf, Db_Buf, Int_Buf, OutData%Ver, ErrStat2, ErrMsg2 ) ! Ver + CALL NWTC_Library_Unpackfileinfotype( Re_Buf, Db_Buf, Int_Buf, OutData%PassedFileData, ErrStat2, ErrMsg2 ) ! PassedFileData CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - END SUBROUTINE ADsk_UnPackInitOutput + END SUBROUTINE ADsk_UnPackInitInput - SUBROUTINE ADsk_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_InputType), INTENT(INOUT) :: SrcInputData - TYPE(ADsk_InputType), INTENT(INOUT) :: DstInputData + SUBROUTINE ADsk_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InitOutputType), INTENT(IN) :: SrcInitOutputData + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: DstInitOutputData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -1695,35 +1775,62 @@ SUBROUTINE ADsk_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInitOutput' ! ErrStat = ErrID_None ErrMsg = "" - CALL MeshCopy( SrcInputData%HubMotion, DstInputData%HubMotion, CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +IF (ALLOCATED(SrcInitOutputData%WriteOutputHdr)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputHdr,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputHdr,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputHdr)) THEN + ALLOCATE(DstInitOutputData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputHdr = SrcInitOutputData%WriteOutputHdr +ENDIF +IF (ALLOCATED(SrcInitOutputData%WriteOutputUnt)) THEN + i1_l = LBOUND(SrcInitOutputData%WriteOutputUnt,1) + i1_u = UBOUND(SrcInitOutputData%WriteOutputUnt,1) + IF (.NOT. ALLOCATED(DstInitOutputData%WriteOutputUnt)) THEN + ALLOCATE(DstInitOutputData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%WriteOutputUnt = SrcInitOutputData%WriteOutputUnt +ENDIF + CALL NWTC_Library_Copyprogdesc( SrcInitOutputData%Ver, DstInitOutputData%Ver, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN - DstInputData%RotSpeed = SrcInputData%RotSpeed - DstInputData%BlPitch = SrcInputData%BlPitch - DstInputData%VWind = SrcInputData%VWind - END SUBROUTINE ADsk_CopyInput + END SUBROUTINE ADsk_CopyInitOutput - SUBROUTINE ADsk_DestroyInput( InputData, ErrStat, ErrMsg ) - TYPE(ADsk_InputType), INTENT(INOUT) :: InputData + SUBROUTINE ADsk_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg ) + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: InitOutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInitOutput' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - CALL MeshDestroy( InputData%HubMotion, ErrStat, ErrMsg ) - END SUBROUTINE ADsk_DestroyInput +IF (ALLOCATED(InitOutputData%WriteOutputHdr)) THEN + DEALLOCATE(InitOutputData%WriteOutputHdr) +ENDIF +IF (ALLOCATED(InitOutputData%WriteOutputUnt)) THEN + DEALLOCATE(InitOutputData%WriteOutputUnt) +ENDIF + CALL NWTC_Library_Destroyprogdesc( InitOutputData%Ver, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInitOutput - SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_InputType), INTENT(IN) :: InData + TYPE(ADsk_InitOutputType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -1738,7 +1845,7 @@ SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInitOutput' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -1754,27 +1861,34 @@ SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no + IF ( ALLOCATED(InData%WriteOutputHdr) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputHdr upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputHdr)*LEN(InData%WriteOutputHdr) ! WriteOutputHdr + END IF + Int_BufSz = Int_BufSz + 1 ! WriteOutputUnt allocated yes/no + IF ( ALLOCATED(InData%WriteOutputUnt) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutputUnt upper/lower bounds for each dimension + Int_BufSz = Int_BufSz + SIZE(InData%WriteOutputUnt)*LEN(InData%WriteOutputUnt) ! WriteOutputUnt + END IF ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! HubMotion: size of buffers for each call to pack subtype - CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! HubMotion + Int_BufSz = Int_BufSz + 3 ! Ver: size of buffers for each call to pack subtype + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, .TRUE. ) ! Ver CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! HubMotion + IF(ALLOCATED(Re_Buf)) THEN ! Ver Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! HubMotion + IF(ALLOCATED(Db_Buf)) THEN ! Ver Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! HubMotion + IF(ALLOCATED(Int_Buf)) THEN ! Ver Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Re_BufSz = Re_BufSz + 1 ! RotSpeed - Re_BufSz = Re_BufSz + 1 ! BlPitch - Re_BufSz = Re_BufSz + SIZE(InData%VWind) ! VWind IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -1802,7 +1916,41 @@ SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Db_Xferred = 1 Int_Xferred = 1 - CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! HubMotion + IF ( .NOT. ALLOCATED(InData%WriteOutputHdr) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputHdr,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputHdr,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputHdr,1), UBOUND(InData%WriteOutputHdr,1) + DO I = 1, LEN(InData%WriteOutputHdr) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputHdr(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( .NOT. ALLOCATED(InData%WriteOutputUnt) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutputUnt,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutputUnt,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%WriteOutputUnt,1), UBOUND(InData%WriteOutputUnt,1) + DO I = 1, LEN(InData%WriteOutputUnt) + IntKiBuf(Int_Xferred) = ICHAR(InData%WriteOutputUnt(i1)(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + CALL NWTC_Library_Packprogdesc( Re_Buf, Db_Buf, Int_Buf, InData%Ver, ErrStat2, ErrMsg2, OnlySize ) ! Ver CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -1830,21 +1978,13 @@ SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - ReKiBuf(Re_Xferred) = InData%RotSpeed - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%BlPitch - Re_Xferred = Re_Xferred + 1 - DO i1 = LBOUND(InData%VWind,1), UBOUND(InData%VWind,1) - ReKiBuf(Re_Xferred) = InData%VWind(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END SUBROUTINE ADsk_PackInput + END SUBROUTINE ADsk_PackInitOutput - SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_InputType), INTENT(INOUT) :: OutData + TYPE(ADsk_InitOutputType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -1856,7 +1996,7 @@ SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInitOutput' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -1867,14 +2007,54 @@ SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - Buf_size=IntKiBuf( Int_Xferred ) - Int_Xferred = Int_Xferred + 1 - IF(Buf_size > 0) THEN - ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputHdr not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputHdr)) DEALLOCATE(OutData%WriteOutputHdr) + ALLOCATE(OutData%WriteOutputHdr(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputHdr.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputHdr,1), UBOUND(OutData%WriteOutputHdr,1) + DO I = 1, LEN(OutData%WriteOutputHdr) + OutData%WriteOutputHdr(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputUnt not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutputUnt)) DEALLOCATE(OutData%WriteOutputUnt) + ALLOCATE(OutData%WriteOutputUnt(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutputUnt.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutputUnt,1), UBOUND(OutData%WriteOutputUnt,1) + DO I = 1, LEN(OutData%WriteOutputUnt) + OutData%WriteOutputUnt(i1)(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + END DO + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) Re_Xferred = Re_Xferred + Buf_size END IF @@ -1900,28 +2080,18 @@ SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL MeshUnpack( OutData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! HubMotion + CALL NWTC_Library_Unpackprogdesc( Re_Buf, Db_Buf, Int_Buf, OutData%Ver, ErrStat2, ErrMsg2 ) ! Ver CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - OutData%RotSpeed = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%BlPitch = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - i1_l = LBOUND(OutData%VWind,1) - i1_u = UBOUND(OutData%VWind,1) - DO i1 = LBOUND(OutData%VWind,1), UBOUND(OutData%VWind,1) - OutData%VWind(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END SUBROUTINE ADsk_UnPackInput + END SUBROUTINE ADsk_UnPackInitOutput - SUBROUTINE ADsk_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_OutputType), INTENT(INOUT) :: SrcOutputData - TYPE(ADsk_OutputType), INTENT(INOUT) :: DstOutputData + SUBROUTINE ADsk_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_InputType), INTENT(INOUT) :: SrcInputData + TYPE(ADsk_InputType), INTENT(INOUT) :: DstInputData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -1930,53 +2100,35 @@ SUBROUTINE ADsk_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, Err INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyInput' ! ErrStat = ErrID_None ErrMsg = "" - CALL MeshCopy( SrcOutputData%AeroLoads, DstOutputData%AeroLoads, CtrlCode, ErrStat2, ErrMsg2 ) + CALL MeshCopy( SrcInputData%HubMotion, DstInputData%HubMotion, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat>=AbortErrLev) RETURN - DstOutputData%YawErr = SrcOutputData%YawErr - DstOutputData%SkewAngle = SrcOutputData%SkewAngle - DstOutputData%ChiSkew = SrcOutputData%ChiSkew - DstOutputData%VRel = SrcOutputData%VRel - DstOutputData%Ct = SrcOutputData%Ct - DstOutputData%Cq = SrcOutputData%Cq -IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN - i1_l = LBOUND(SrcOutputData%WriteOutput,1) - i1_u = UBOUND(SrcOutputData%WriteOutput,1) - IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN - ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstOutputData%WriteOutput = SrcOutputData%WriteOutput -ENDIF - END SUBROUTINE ADsk_CopyOutput + DstInputData%RotSpeed = SrcInputData%RotSpeed + DstInputData%BlPitch = SrcInputData%BlPitch + DstInputData%VWind = SrcInputData%VWind + END SUBROUTINE ADsk_CopyInput - SUBROUTINE ADsk_DestroyOutput( OutputData, ErrStat, ErrMsg ) - TYPE(ADsk_OutputType), INTENT(INOUT) :: OutputData + SUBROUTINE ADsk_DestroyInput( InputData, ErrStat, ErrMsg ) + TYPE(ADsk_InputType), INTENT(INOUT) :: InputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyInput' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - CALL MeshDestroy( OutputData%AeroLoads, ErrStat, ErrMsg ) -IF (ALLOCATED(OutputData%WriteOutput)) THEN - DEALLOCATE(OutputData%WriteOutput) -ENDIF - END SUBROUTINE ADsk_DestroyOutput + CALL MeshDestroy( InputData%HubMotion, ErrStat, ErrMsg ) + END SUBROUTINE ADsk_DestroyInput - SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_OutputType), INTENT(IN) :: InData + TYPE(ADsk_InputType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -1991,7 +2143,7 @@ SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackInput' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2008,34 +2160,26 @@ SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Db_BufSz = 0 Int_BufSz = 0 ! Allocate buffers for subtypes, if any (we'll get sizes from these) - Int_BufSz = Int_BufSz + 3 ! AeroLoads: size of buffers for each call to pack subtype - CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! AeroLoads + Int_BufSz = Int_BufSz + 3 ! HubMotion: size of buffers for each call to pack subtype + CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! HubMotion CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN - IF(ALLOCATED(Re_Buf)) THEN ! AeroLoads + IF(ALLOCATED(Re_Buf)) THEN ! HubMotion Re_BufSz = Re_BufSz + SIZE( Re_Buf ) DEALLOCATE(Re_Buf) END IF - IF(ALLOCATED(Db_Buf)) THEN ! AeroLoads + IF(ALLOCATED(Db_Buf)) THEN ! HubMotion Db_BufSz = Db_BufSz + SIZE( Db_Buf ) DEALLOCATE(Db_Buf) END IF - IF(ALLOCATED(Int_Buf)) THEN ! AeroLoads + IF(ALLOCATED(Int_Buf)) THEN ! HubMotion Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF - Re_BufSz = Re_BufSz + 1 ! YawErr - Re_BufSz = Re_BufSz + 1 ! SkewAngle - Re_BufSz = Re_BufSz + 1 ! ChiSkew - Re_BufSz = Re_BufSz + 1 ! VRel - Re_BufSz = Re_BufSz + 1 ! Ct - Re_BufSz = Re_BufSz + 1 ! Cq - Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no - IF ( ALLOCATED(InData%WriteOutput) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput - END IF + Re_BufSz = Re_BufSz + 1 ! RotSpeed + Re_BufSz = Re_BufSz + 1 ! BlPitch + Re_BufSz = Re_BufSz + SIZE(InData%VWind) ! VWind IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2063,7 +2207,7 @@ SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Db_Xferred = 1 Int_Xferred = 1 - CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! AeroLoads + CALL MeshPack( InData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! HubMotion CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -2091,40 +2235,21 @@ SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF - ReKiBuf(Re_Xferred) = InData%YawErr - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%SkewAngle - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%ChiSkew - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%VRel - Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%Ct + ReKiBuf(Re_Xferred) = InData%RotSpeed Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%Cq + ReKiBuf(Re_Xferred) = InData%BlPitch Re_Xferred = Re_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) - ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - END SUBROUTINE ADsk_PackOutput + DO i1 = LBOUND(InData%VWind,1), UBOUND(InData%VWind,1) + ReKiBuf(Re_Xferred) = InData%VWind(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE ADsk_PackInput - SUBROUTINE ADsk_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_OutputType), INTENT(INOUT) :: OutData + TYPE(ADsk_InputType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -2136,7 +2261,7 @@ SUBROUTINE ADsk_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackOutput' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackInput' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2180,78 +2305,83 @@ SUBROUTINE ADsk_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) Int_Xferred = Int_Xferred + Buf_size END IF - CALL MeshUnpack( OutData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! AeroLoads + CALL MeshUnpack( OutData%HubMotion, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! HubMotion CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat >= AbortErrLev) RETURN IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) - OutData%YawErr = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%SkewAngle = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%ChiSkew = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%VRel = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - OutData%Ct = ReKiBuf(Re_Xferred) + OutData%RotSpeed = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - OutData%Cq = ReKiBuf(Re_Xferred) + OutData%BlPitch = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) - ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) - OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - END SUBROUTINE ADsk_UnPackOutput + i1_l = LBOUND(OutData%VWind,1) + i1_u = UBOUND(OutData%VWind,1) + DO i1 = LBOUND(OutData%VWind,1), UBOUND(OutData%VWind,1) + OutData%VWind(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END SUBROUTINE ADsk_UnPackInput - SUBROUTINE ADsk_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_ContinuousStateType), INTENT(IN) :: SrcContStateData - TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: DstContStateData + SUBROUTINE ADsk_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_OutputType), INTENT(INOUT) :: SrcOutputData + TYPE(ADsk_OutputType), INTENT(INOUT) :: DstOutputData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyOutput' ! ErrStat = ErrID_None ErrMsg = "" - DstContStateData%DummyContState = SrcContStateData%DummyContState - END SUBROUTINE ADsk_CopyContState + CALL MeshCopy( SrcOutputData%AeroLoads, DstOutputData%AeroLoads, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + DstOutputData%YawErr = SrcOutputData%YawErr + DstOutputData%SkewAngle = SrcOutputData%SkewAngle + DstOutputData%ChiSkew = SrcOutputData%ChiSkew + DstOutputData%VRel = SrcOutputData%VRel + DstOutputData%Ct = SrcOutputData%Ct + DstOutputData%Cq = SrcOutputData%Cq +IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN + i1_l = LBOUND(SrcOutputData%WriteOutput,1) + i1_u = UBOUND(SrcOutputData%WriteOutput,1) + IF (.NOT. ALLOCATED(DstOutputData%WriteOutput)) THEN + ALLOCATE(DstOutputData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%WriteOutput = SrcOutputData%WriteOutput +ENDIF + END SUBROUTINE ADsk_CopyOutput - SUBROUTINE ADsk_DestroyContState( ContStateData, ErrStat, ErrMsg ) - TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: ContStateData + SUBROUTINE ADsk_DestroyOutput( OutputData, ErrStat, ErrMsg ) + TYPE(ADsk_OutputType), INTENT(INOUT) :: OutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyContState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyOutput' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE ADsk_DestroyContState + CALL MeshDestroy( OutputData%AeroLoads, ErrStat, ErrMsg ) +IF (ALLOCATED(OutputData%WriteOutput)) THEN + DEALLOCATE(OutputData%WriteOutput) +ENDIF + END SUBROUTINE ADsk_DestroyOutput - SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_ContinuousStateType), INTENT(IN) :: InData + TYPE(ADsk_OutputType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -2266,7 +2396,7 @@ SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackOutput' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2282,7 +2412,35 @@ SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyContState + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! AeroLoads: size of buffers for each call to pack subtype + CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! AeroLoads + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! AeroLoads + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! AeroLoads + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Re_BufSz = Re_BufSz + 1 ! YawErr + Re_BufSz = Re_BufSz + 1 ! SkewAngle + Re_BufSz = Re_BufSz + 1 ! ChiSkew + Re_BufSz = Re_BufSz + 1 ! VRel + Re_BufSz = Re_BufSz + 1 ! Ct + Re_BufSz = Re_BufSz + 1 ! Cq + Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no + IF ( ALLOCATED(InData%WriteOutput) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2310,15 +2468,68 @@ SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyContState + CALL MeshPack( InData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + ReKiBuf(Re_Xferred) = InData%YawErr Re_Xferred = Re_Xferred + 1 - END SUBROUTINE ADsk_PackContState + ReKiBuf(Re_Xferred) = InData%SkewAngle + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%ChiSkew + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%VRel + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Ct + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Cq + Re_Xferred = Re_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%WriteOutput,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%WriteOutput,1) + Int_Xferred = Int_Xferred + 2 - SUBROUTINE ADsk_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + DO i1 = LBOUND(InData%WriteOutput,1), UBOUND(InData%WriteOutput,1) + ReKiBuf(Re_Xferred) = InData%WriteOutput(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE ADsk_PackOutput + + SUBROUTINE ADsk_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: OutData + TYPE(ADsk_OutputType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -2327,9 +2538,10 @@ SUBROUTINE ADsk_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E INTEGER(IntKi) :: Db_Xferred INTEGER(IntKi) :: Int_Xferred INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackContState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackOutput' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2340,13 +2552,81 @@ SUBROUTINE ADsk_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyContState = ReKiBuf(Re_Xferred) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%AeroLoads, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! AeroLoads + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%YawErr = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - END SUBROUTINE ADsk_UnPackContState + OutData%SkewAngle = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%ChiSkew = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%VRel = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Ct = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Cq = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%WriteOutput)) DEALLOCATE(OutData%WriteOutput) + ALLOCATE(OutData%WriteOutput(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%WriteOutput.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%WriteOutput,1), UBOUND(OutData%WriteOutput,1) + OutData%WriteOutput(i1) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE ADsk_UnPackOutput - SUBROUTINE ADsk_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_DiscreteStateType), INTENT(IN) :: SrcDiscStateData - TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData + SUBROUTINE ADsk_CopyContState( SrcContStateData, DstContStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_ContinuousStateType), INTENT(IN) :: SrcContStateData + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: DstContStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -2354,29 +2634,29 @@ SUBROUTINE ADsk_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, Err INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyContState' ! ErrStat = ErrID_None ErrMsg = "" - DstDiscStateData%DummyDiscreteState = SrcDiscStateData%DummyDiscreteState - END SUBROUTINE ADsk_CopyDiscState + DstContStateData%DummyContState = SrcContStateData%DummyContState + END SUBROUTINE ADsk_CopyContState - SUBROUTINE ADsk_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) - TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DiscStateData + SUBROUTINE ADsk_DestroyContState( ContStateData, ErrStat, ErrMsg ) + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: ContStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyContState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE ADsk_DestroyDiscState + END SUBROUTINE ADsk_DestroyContState - SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackContState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_DiscreteStateType), INTENT(IN) :: InData + TYPE(ADsk_ContinuousStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -2391,7 +2671,7 @@ SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackContState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2407,7 +2687,7 @@ SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyDiscreteState + Re_BufSz = Re_BufSz + 1 ! DummyContState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2435,15 +2715,15 @@ SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyDiscreteState + ReKiBuf(Re_Xferred) = InData%DummyContState Re_Xferred = Re_Xferred + 1 - END SUBROUTINE ADsk_PackDiscState + END SUBROUTINE ADsk_PackContState - SUBROUTINE ADsk_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackContState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: OutData + TYPE(ADsk_ContinuousStateType), INTENT(INOUT) :: OutData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg ! Local variables @@ -2454,7 +2734,7 @@ SUBROUTINE ADsk_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E INTEGER(IntKi) :: i INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackDiscState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackContState' ! buffers to store meshes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2465,13 +2745,13 @@ SUBROUTINE ADsk_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DummyDiscreteState = ReKiBuf(Re_Xferred) + OutData%DummyContState = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - END SUBROUTINE ADsk_UnPackDiscState + END SUBROUTINE ADsk_UnPackContState - SUBROUTINE ADsk_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) - TYPE(ADsk_ConstraintStateType), INTENT(IN) :: SrcConstrStateData - TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + SUBROUTINE ADsk_CopyDiscState( SrcDiscStateData, DstDiscStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_DiscreteStateType), INTENT(IN) :: SrcDiscStateData + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DstDiscStateData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg @@ -2479,29 +2759,29 @@ SUBROUTINE ADsk_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCod INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyDiscState' ! ErrStat = ErrID_None ErrMsg = "" - DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState - END SUBROUTINE ADsk_CopyConstrState + DstDiscStateData%DummyDiscreteState = SrcDiscStateData%DummyDiscreteState + END SUBROUTINE ADsk_CopyDiscState - SUBROUTINE ADsk_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) - TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + SUBROUTINE ADsk_DestroyDiscState( DiscStateData, ErrStat, ErrMsg ) + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: DiscStateData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyDiscState' INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 ! ErrStat = ErrID_None ErrMsg = "" - END SUBROUTINE ADsk_DestroyConstrState + END SUBROUTINE ADsk_DestroyDiscState - SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + SUBROUTINE ADsk_PackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) - TYPE(ADsk_ConstraintStateType), INTENT(IN) :: InData + TYPE(ADsk_DiscreteStateType), INTENT(IN) :: InData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly @@ -2516,7 +2796,7 @@ SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackConstrState' + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackDiscState' ! buffers to store subtypes, if any REAL(ReKi), ALLOCATABLE :: Re_Buf(:) REAL(DbKi), ALLOCATABLE :: Db_Buf(:) @@ -2532,7 +2812,7 @@ SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Re_BufSz = Re_BufSz + 1 ! DummyConstrState + Re_BufSz = Re_BufSz + 1 ! DummyDiscreteState IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2560,11 +2840,136 @@ SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Er Db_Xferred = 1 Int_Xferred = 1 - ReKiBuf(Re_Xferred) = InData%DummyConstrState + ReKiBuf(Re_Xferred) = InData%DummyDiscreteState Re_Xferred = Re_Xferred + 1 - END SUBROUTINE ADsk_PackConstrState + END SUBROUTINE ADsk_PackDiscState - SUBROUTINE ADsk_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + SUBROUTINE ADsk_UnPackDiscState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(ADsk_DiscreteStateType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackDiscState' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + OutData%DummyDiscreteState = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_UnPackDiscState + + SUBROUTINE ADsk_CopyConstrState( SrcConstrStateData, DstConstrStateData, CtrlCode, ErrStat, ErrMsg ) + TYPE(ADsk_ConstraintStateType), INTENT(IN) :: SrcConstrStateData + TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: DstConstrStateData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyConstrState' +! + ErrStat = ErrID_None + ErrMsg = "" + DstConstrStateData%DummyConstrState = SrcConstrStateData%DummyConstrState + END SUBROUTINE ADsk_CopyConstrState + + SUBROUTINE ADsk_DestroyConstrState( ConstrStateData, ErrStat, ErrMsg ) + TYPE(ADsk_ConstraintStateType), INTENT(INOUT) :: ConstrStateData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_DestroyConstrState' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE ADsk_DestroyConstrState + + SUBROUTINE ADsk_PackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(ADsk_ConstraintStateType), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_PackConstrState' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Re_BufSz = Re_BufSz + 1 ! DummyConstrState + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + ReKiBuf(Re_Xferred) = InData%DummyConstrState + Re_Xferred = Re_Xferred + 1 + END SUBROUTINE ADsk_PackConstrState + + SUBROUTINE ADsk_UnPackConstrState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) @@ -2728,190 +3133,36 @@ SUBROUTINE ADsk_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ! Local INTEGER(IntKi) :: i,j,k INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 - INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 - INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_CopyParam' ! ErrStat = ErrID_None ErrMsg = "" - DstParamData%DeltaT = SrcParamData%DeltaT + DstParamData%RootName = SrcParamData%RootName + DstParamData%DT = SrcParamData%DT DstParamData%RotorRad = SrcParamData%RotorRad + DstParamData%AirDens = SrcParamData%AirDens + DstParamData%NumOuts = SrcParamData%NumOuts DstParamData%halfRhoA = SrcParamData%halfRhoA - DstParamData%N_TSR = SrcParamData%N_TSR - DstParamData%N_RtSpd = SrcParamData%N_RtSpd - DstParamData%N_VRel = SrcParamData%N_VRel - DstParamData%N_Pitch = SrcParamData%N_Pitch - DstParamData%N_Skew = SrcParamData%N_Skew -IF (ALLOCATED(SrcParamData%TSR)) THEN - i1_l = LBOUND(SrcParamData%TSR,1) - i1_u = UBOUND(SrcParamData%TSR,1) - IF (.NOT. ALLOCATED(DstParamData%TSR)) THEN - ALLOCATE(DstParamData%TSR(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%TSR.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%TSR = SrcParamData%TSR -ENDIF -IF (ALLOCATED(SrcParamData%RtSpd)) THEN - i1_l = LBOUND(SrcParamData%RtSpd,1) - i1_u = UBOUND(SrcParamData%RtSpd,1) - IF (.NOT. ALLOCATED(DstParamData%RtSpd)) THEN - ALLOCATE(DstParamData%RtSpd(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%RtSpd.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%RtSpd = SrcParamData%RtSpd -ENDIF -IF (ALLOCATED(SrcParamData%VRel)) THEN - i1_l = LBOUND(SrcParamData%VRel,1) - i1_u = UBOUND(SrcParamData%VRel,1) - IF (.NOT. ALLOCATED(DstParamData%VRel)) THEN - ALLOCATE(DstParamData%VRel(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%VRel.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%VRel = SrcParamData%VRel -ENDIF -IF (ALLOCATED(SrcParamData%Pitch)) THEN - i1_l = LBOUND(SrcParamData%Pitch,1) - i1_u = UBOUND(SrcParamData%Pitch,1) - IF (.NOT. ALLOCATED(DstParamData%Pitch)) THEN - ALLOCATE(DstParamData%Pitch(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Pitch.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%Pitch = SrcParamData%Pitch -ENDIF -IF (ALLOCATED(SrcParamData%Skew)) THEN - i1_l = LBOUND(SrcParamData%Skew,1) - i1_u = UBOUND(SrcParamData%Skew,1) - IF (.NOT. ALLOCATED(DstParamData%Skew)) THEN - ALLOCATE(DstParamData%Skew(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Skew.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%Skew = SrcParamData%Skew -ENDIF -IF (ALLOCATED(SrcParamData%C_fx)) THEN - i1_l = LBOUND(SrcParamData%C_fx,1) - i1_u = UBOUND(SrcParamData%C_fx,1) - i2_l = LBOUND(SrcParamData%C_fx,2) - i2_u = UBOUND(SrcParamData%C_fx,2) - i3_l = LBOUND(SrcParamData%C_fx,3) - i3_u = UBOUND(SrcParamData%C_fx,3) - i4_l = LBOUND(SrcParamData%C_fx,4) - i4_u = UBOUND(SrcParamData%C_fx,4) - IF (.NOT. ALLOCATED(DstParamData%C_fx)) THEN - ALLOCATE(DstParamData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fx.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%C_fx = SrcParamData%C_fx -ENDIF -IF (ALLOCATED(SrcParamData%C_fy)) THEN - i1_l = LBOUND(SrcParamData%C_fy,1) - i1_u = UBOUND(SrcParamData%C_fy,1) - i2_l = LBOUND(SrcParamData%C_fy,2) - i2_u = UBOUND(SrcParamData%C_fy,2) - i3_l = LBOUND(SrcParamData%C_fy,3) - i3_u = UBOUND(SrcParamData%C_fy,3) - i4_l = LBOUND(SrcParamData%C_fy,4) - i4_u = UBOUND(SrcParamData%C_fy,4) - IF (.NOT. ALLOCATED(DstParamData%C_fy)) THEN - ALLOCATE(DstParamData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fy.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%C_fy = SrcParamData%C_fy -ENDIF -IF (ALLOCATED(SrcParamData%C_fz)) THEN - i1_l = LBOUND(SrcParamData%C_fz,1) - i1_u = UBOUND(SrcParamData%C_fz,1) - i2_l = LBOUND(SrcParamData%C_fz,2) - i2_u = UBOUND(SrcParamData%C_fz,2) - i3_l = LBOUND(SrcParamData%C_fz,3) - i3_u = UBOUND(SrcParamData%C_fz,3) - i4_l = LBOUND(SrcParamData%C_fz,4) - i4_u = UBOUND(SrcParamData%C_fz,4) - IF (.NOT. ALLOCATED(DstParamData%C_fz)) THEN - ALLOCATE(DstParamData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_fz.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%C_fz = SrcParamData%C_fz -ENDIF -IF (ALLOCATED(SrcParamData%C_mx)) THEN - i1_l = LBOUND(SrcParamData%C_mx,1) - i1_u = UBOUND(SrcParamData%C_mx,1) - i2_l = LBOUND(SrcParamData%C_mx,2) - i2_u = UBOUND(SrcParamData%C_mx,2) - i3_l = LBOUND(SrcParamData%C_mx,3) - i3_u = UBOUND(SrcParamData%C_mx,3) - i4_l = LBOUND(SrcParamData%C_mx,4) - i4_u = UBOUND(SrcParamData%C_mx,4) - IF (.NOT. ALLOCATED(DstParamData%C_mx)) THEN - ALLOCATE(DstParamData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_mx.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%C_mx = SrcParamData%C_mx -ENDIF -IF (ALLOCATED(SrcParamData%C_my)) THEN - i1_l = LBOUND(SrcParamData%C_my,1) - i1_u = UBOUND(SrcParamData%C_my,1) - i2_l = LBOUND(SrcParamData%C_my,2) - i2_u = UBOUND(SrcParamData%C_my,2) - i3_l = LBOUND(SrcParamData%C_my,3) - i3_u = UBOUND(SrcParamData%C_my,3) - i4_l = LBOUND(SrcParamData%C_my,4) - i4_u = UBOUND(SrcParamData%C_my,4) - IF (.NOT. ALLOCATED(DstParamData%C_my)) THEN - ALLOCATE(DstParamData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_my.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstParamData%C_my = SrcParamData%C_my -ENDIF -IF (ALLOCATED(SrcParamData%C_mz)) THEN - i1_l = LBOUND(SrcParamData%C_mz,1) - i1_u = UBOUND(SrcParamData%C_mz,1) - i2_l = LBOUND(SrcParamData%C_mz,2) - i2_u = UBOUND(SrcParamData%C_mz,2) - i3_l = LBOUND(SrcParamData%C_mz,3) - i3_u = UBOUND(SrcParamData%C_mz,3) - i4_l = LBOUND(SrcParamData%C_mz,4) - i4_u = UBOUND(SrcParamData%C_mz,4) - IF (.NOT. ALLOCATED(DstParamData%C_mz)) THEN - ALLOCATE(DstParamData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + CALL ADsk_Copyaerotable( SrcParamData%AeroTable, DstParamData%AeroTable, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN +IF (ALLOCATED(SrcParamData%OutParam)) THEN + i1_l = LBOUND(SrcParamData%OutParam,1) + i1_u = UBOUND(SrcParamData%OutParam,1) + IF (.NOT. ALLOCATED(DstParamData%OutParam)) THEN + ALLOCATE(DstParamData%OutParam(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%C_mz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%OutParam.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstParamData%C_mz = SrcParamData%C_mz + DO i1 = LBOUND(SrcParamData%OutParam,1), UBOUND(SrcParamData%OutParam,1) + CALL NWTC_Library_Copyoutparmtype( SrcParamData%OutParam(i1), DstParamData%OutParam(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO ENDIF END SUBROUTINE ADsk_CopyParam @@ -2924,38 +3175,12 @@ SUBROUTINE ADsk_DestroyParam( ParamData, ErrStat, ErrMsg ) ! ErrStat = ErrID_None ErrMsg = "" -IF (ALLOCATED(ParamData%TSR)) THEN - DEALLOCATE(ParamData%TSR) -ENDIF -IF (ALLOCATED(ParamData%RtSpd)) THEN - DEALLOCATE(ParamData%RtSpd) -ENDIF -IF (ALLOCATED(ParamData%VRel)) THEN - DEALLOCATE(ParamData%VRel) -ENDIF -IF (ALLOCATED(ParamData%Pitch)) THEN - DEALLOCATE(ParamData%Pitch) -ENDIF -IF (ALLOCATED(ParamData%Skew)) THEN - DEALLOCATE(ParamData%Skew) -ENDIF -IF (ALLOCATED(ParamData%C_fx)) THEN - DEALLOCATE(ParamData%C_fx) -ENDIF -IF (ALLOCATED(ParamData%C_fy)) THEN - DEALLOCATE(ParamData%C_fy) -ENDIF -IF (ALLOCATED(ParamData%C_fz)) THEN - DEALLOCATE(ParamData%C_fz) -ENDIF -IF (ALLOCATED(ParamData%C_mx)) THEN - DEALLOCATE(ParamData%C_mx) -ENDIF -IF (ALLOCATED(ParamData%C_my)) THEN - DEALLOCATE(ParamData%C_my) -ENDIF -IF (ALLOCATED(ParamData%C_mz)) THEN - DEALLOCATE(ParamData%C_mz) + CALL ADsk_Destroyaerotable( ParamData%AeroTable, ErrStat, ErrMsg ) +IF (ALLOCATED(ParamData%OutParam)) THEN +DO i1 = LBOUND(ParamData%OutParam,1), UBOUND(ParamData%OutParam,1) + CALL NWTC_Library_Destroyoutparmtype( ParamData%OutParam(i1), ErrStat, ErrMsg ) +ENDDO + DEALLOCATE(ParamData%OutParam) ENDIF END SUBROUTINE ADsk_DestroyParam @@ -2994,68 +3219,52 @@ SUBROUTINE ADsk_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 - Db_BufSz = Db_BufSz + 1 ! DeltaT + Int_BufSz = Int_BufSz + 1*LEN(InData%RootName) ! RootName + Db_BufSz = Db_BufSz + 1 ! DT Re_BufSz = Re_BufSz + 1 ! RotorRad + Re_BufSz = Re_BufSz + 1 ! AirDens + Int_BufSz = Int_BufSz + 1 ! NumOuts Re_BufSz = Re_BufSz + 1 ! halfRhoA - Int_BufSz = Int_BufSz + 1 ! N_TSR - Int_BufSz = Int_BufSz + 1 ! N_RtSpd - Int_BufSz = Int_BufSz + 1 ! N_VRel - Int_BufSz = Int_BufSz + 1 ! N_Pitch - Int_BufSz = Int_BufSz + 1 ! N_Skew - Int_BufSz = Int_BufSz + 1 ! TSR allocated yes/no - IF ( ALLOCATED(InData%TSR) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! TSR upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%TSR) ! TSR - END IF - Int_BufSz = Int_BufSz + 1 ! RtSpd allocated yes/no - IF ( ALLOCATED(InData%RtSpd) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! RtSpd upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%RtSpd) ! RtSpd - END IF - Int_BufSz = Int_BufSz + 1 ! VRel allocated yes/no - IF ( ALLOCATED(InData%VRel) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! VRel upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%VRel) ! VRel - END IF - Int_BufSz = Int_BufSz + 1 ! Pitch allocated yes/no - IF ( ALLOCATED(InData%Pitch) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! Pitch upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%Pitch) ! Pitch - END IF - Int_BufSz = Int_BufSz + 1 ! Skew allocated yes/no - IF ( ALLOCATED(InData%Skew) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! Skew upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%Skew) ! Skew - END IF - Int_BufSz = Int_BufSz + 1 ! C_fx allocated yes/no - IF ( ALLOCATED(InData%C_fx) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fx upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fx) ! C_fx - END IF - Int_BufSz = Int_BufSz + 1 ! C_fy allocated yes/no - IF ( ALLOCATED(InData%C_fy) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fy upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fy) ! C_fy - END IF - Int_BufSz = Int_BufSz + 1 ! C_fz allocated yes/no - IF ( ALLOCATED(InData%C_fz) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_fz upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_fz) ! C_fz - END IF - Int_BufSz = Int_BufSz + 1 ! C_mx allocated yes/no - IF ( ALLOCATED(InData%C_mx) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_mx upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_mx) ! C_mx - END IF - Int_BufSz = Int_BufSz + 1 ! C_my allocated yes/no - IF ( ALLOCATED(InData%C_my) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_my upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_my) ! C_my - END IF - Int_BufSz = Int_BufSz + 1 ! C_mz allocated yes/no - IF ( ALLOCATED(InData%C_mz) ) THEN - Int_BufSz = Int_BufSz + 2*4 ! C_mz upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%C_mz) ! C_mz + ! Allocate buffers for subtypes, if any (we'll get sizes from these) + Int_BufSz = Int_BufSz + 3 ! AeroTable: size of buffers for each call to pack subtype + CALL ADsk_Packaerotable( Re_Buf, Db_Buf, Int_Buf, InData%AeroTable, ErrStat2, ErrMsg2, .TRUE. ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! AeroTable + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! AeroTable + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! AeroTable + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + Int_BufSz = Int_BufSz + 1 ! OutParam allocated yes/no + IF ( ALLOCATED(InData%OutParam) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! OutParam upper/lower bounds for each dimension + DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) + Int_BufSz = Int_BufSz + 3 ! OutParam: size of buffers for each call to pack subtype + CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, .TRUE. ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! OutParam + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! OutParam + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! OutParam + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) @@ -3084,276 +3293,88 @@ SUBROUTINE ADsk_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Db_Xferred = 1 Int_Xferred = 1 - DbKiBuf(Db_Xferred) = InData%DeltaT - Db_Xferred = Db_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%RotorRad + DO I = 1, LEN(InData%RootName) + IntKiBuf(Int_Xferred) = ICHAR(InData%RootName(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DbKiBuf(Db_Xferred) = InData%DT + Db_Xferred = Db_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%RotorRad Re_Xferred = Re_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%halfRhoA + ReKiBuf(Re_Xferred) = InData%AirDens Re_Xferred = Re_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%N_TSR - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%N_RtSpd - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%N_VRel - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%N_Pitch - Int_Xferred = Int_Xferred + 1 - IntKiBuf(Int_Xferred) = InData%N_Skew - Int_Xferred = Int_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%TSR) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%TSR,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%TSR,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%TSR,1), UBOUND(InData%TSR,1) - ReKiBuf(Re_Xferred) = InData%TSR(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( .NOT. ALLOCATED(InData%RtSpd) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%RtSpd,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%RtSpd,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%RtSpd,1), UBOUND(InData%RtSpd,1) - ReKiBuf(Re_Xferred) = InData%RtSpd(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( .NOT. ALLOCATED(InData%VRel) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%VRel,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VRel,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%VRel,1), UBOUND(InData%VRel,1) - ReKiBuf(Re_Xferred) = InData%VRel(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( .NOT. ALLOCATED(InData%Pitch) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%Pitch,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Pitch,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%Pitch,1), UBOUND(InData%Pitch,1) - ReKiBuf(Re_Xferred) = InData%Pitch(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( .NOT. ALLOCATED(InData%Skew) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%Skew,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Skew,1) - Int_Xferred = Int_Xferred + 2 - - DO i1 = LBOUND(InData%Skew,1), UBOUND(InData%Skew,1) - ReKiBuf(Re_Xferred) = InData%Skew(i1) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_fx) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fx,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fx,4) - Int_Xferred = Int_Xferred + 2 - - DO i4 = LBOUND(InData%C_fx,4), UBOUND(InData%C_fx,4) - DO i3 = LBOUND(InData%C_fx,3), UBOUND(InData%C_fx,3) - DO i2 = LBOUND(InData%C_fx,2), UBOUND(InData%C_fx,2) - DO i1 = LBOUND(InData%C_fx,1), UBOUND(InData%C_fx,1) - ReKiBuf(Re_Xferred) = InData%C_fx(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_fy) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fy,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fy,4) - Int_Xferred = Int_Xferred + 2 - - DO i4 = LBOUND(InData%C_fy,4), UBOUND(InData%C_fy,4) - DO i3 = LBOUND(InData%C_fy,3), UBOUND(InData%C_fy,3) - DO i2 = LBOUND(InData%C_fy,2), UBOUND(InData%C_fy,2) - DO i1 = LBOUND(InData%C_fy,1), UBOUND(InData%C_fy,1) - ReKiBuf(Re_Xferred) = InData%C_fy(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_fz) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_fz,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_fz,4) - Int_Xferred = Int_Xferred + 2 - - DO i4 = LBOUND(InData%C_fz,4), UBOUND(InData%C_fz,4) - DO i3 = LBOUND(InData%C_fz,3), UBOUND(InData%C_fz,3) - DO i2 = LBOUND(InData%C_fz,2), UBOUND(InData%C_fz,2) - DO i1 = LBOUND(InData%C_fz,1), UBOUND(InData%C_fz,1) - ReKiBuf(Re_Xferred) = InData%C_fz(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_mx) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 + IntKiBuf(Int_Xferred) = InData%NumOuts Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mx,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mx,4) - Int_Xferred = Int_Xferred + 2 + ReKiBuf(Re_Xferred) = InData%halfRhoA + Re_Xferred = Re_Xferred + 1 + CALL ADsk_Packaerotable( Re_Buf, Db_Buf, Int_Buf, InData%AeroTable, ErrStat2, ErrMsg2, OnlySize ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - DO i4 = LBOUND(InData%C_mx,4), UBOUND(InData%C_mx,4) - DO i3 = LBOUND(InData%C_mx,3), UBOUND(InData%C_mx,3) - DO i2 = LBOUND(InData%C_mx,2), UBOUND(InData%C_mx,2) - DO i1 = LBOUND(InData%C_mx,1), UBOUND(InData%C_mx,1) - ReKiBuf(Re_Xferred) = InData%C_mx(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_my) ) THEN + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF ( .NOT. ALLOCATED(InData%OutParam) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_my,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_my,4) + IntKiBuf( Int_Xferred ) = LBOUND(InData%OutParam,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%OutParam,1) Int_Xferred = Int_Xferred + 2 - DO i4 = LBOUND(InData%C_my,4), UBOUND(InData%C_my,4) - DO i3 = LBOUND(InData%C_my,3), UBOUND(InData%C_my,3) - DO i2 = LBOUND(InData%C_my,2), UBOUND(InData%C_my,2) - DO i1 = LBOUND(InData%C_my,1), UBOUND(InData%C_my,1) - ReKiBuf(Re_Xferred) = InData%C_my(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%C_mz) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,3) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%C_mz,4) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%C_mz,4) - Int_Xferred = Int_Xferred + 2 + DO i1 = LBOUND(InData%OutParam,1), UBOUND(InData%OutParam,1) + CALL NWTC_Library_Packoutparmtype( Re_Buf, Db_Buf, Int_Buf, InData%OutParam(i1), ErrStat2, ErrMsg2, OnlySize ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN - DO i4 = LBOUND(InData%C_mz,4), UBOUND(InData%C_mz,4) - DO i3 = LBOUND(InData%C_mz,3), UBOUND(InData%C_mz,3) - DO i2 = LBOUND(InData%C_mz,2), UBOUND(InData%C_mz,2) - DO i1 = LBOUND(InData%C_mz,1), UBOUND(InData%C_mz,1) - ReKiBuf(Re_Xferred) = InData%C_mz(i1,i2,i3,i4) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO END IF END SUBROUTINE ADsk_PackParam @@ -3371,9 +3392,6 @@ SUBROUTINE ADsk_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs INTEGER(IntKi) :: Int_Xferred INTEGER(IntKi) :: i INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: i2, i2_l, i2_u ! bounds (upper/lower) for an array dimension 2 - INTEGER(IntKi) :: i3, i3_l, i3_u ! bounds (upper/lower) for an array dimension 3 - INTEGER(IntKi) :: i4, i4_l, i4_u ! bounds (upper/lower) for an array dimension 4 INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ADsk_UnPackParam' @@ -3387,309 +3405,115 @@ SUBROUTINE ADsk_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 - OutData%DeltaT = DbKiBuf(Db_Xferred) + DO I = 1, LEN(OutData%RootName) + OutData%RootName(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + OutData%DT = DbKiBuf(Db_Xferred) Db_Xferred = Db_Xferred + 1 OutData%RotorRad = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - OutData%halfRhoA = ReKiBuf(Re_Xferred) + OutData%AirDens = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - OutData%N_TSR = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%N_RtSpd = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%N_VRel = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%N_Pitch = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - OutData%N_Skew = IntKiBuf(Int_Xferred) - Int_Xferred = Int_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TSR not allocated - Int_Xferred = Int_Xferred + 1 - ELSE + OutData%NumOuts = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%TSR)) DEALLOCATE(OutData%TSR) - ALLOCATE(OutData%TSR(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%TSR.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%TSR,1), UBOUND(OutData%TSR,1) - OutData%TSR(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! RtSpd not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%RtSpd)) DEALLOCATE(OutData%RtSpd) - ALLOCATE(OutData%RtSpd(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%RtSpd.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%RtSpd,1), UBOUND(OutData%RtSpd,1) - OutData%RtSpd(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VRel not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%VRel)) DEALLOCATE(OutData%VRel) - ALLOCATE(OutData%VRel(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VRel.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%VRel,1), UBOUND(OutData%VRel,1) - OutData%VRel(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Pitch not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%Pitch)) DEALLOCATE(OutData%Pitch) - ALLOCATE(OutData%Pitch(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Pitch.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%Pitch,1), UBOUND(OutData%Pitch,1) - OutData%Pitch(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Skew not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%Skew)) DEALLOCATE(OutData%Skew) - ALLOCATE(OutData%Skew(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Skew.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%Skew,1), UBOUND(OutData%Skew,1) - OutData%Skew(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fx not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fx)) DEALLOCATE(OutData%C_fx) - ALLOCATE(OutData%C_fx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fx.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i4 = LBOUND(OutData%C_fx,4), UBOUND(OutData%C_fx,4) - DO i3 = LBOUND(OutData%C_fx,3), UBOUND(OutData%C_fx,3) - DO i2 = LBOUND(OutData%C_fx,2), UBOUND(OutData%C_fx,2) - DO i1 = LBOUND(OutData%C_fx,1), UBOUND(OutData%C_fx,1) - OutData%C_fx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fy not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fy)) DEALLOCATE(OutData%C_fy) - ALLOCATE(OutData%C_fy(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fy.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i4 = LBOUND(OutData%C_fy,4), UBOUND(OutData%C_fy,4) - DO i3 = LBOUND(OutData%C_fy,3), UBOUND(OutData%C_fy,3) - DO i2 = LBOUND(OutData%C_fy,2), UBOUND(OutData%C_fy,2) - DO i1 = LBOUND(OutData%C_fy,1), UBOUND(OutData%C_fy,1) - OutData%C_fy(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_fz not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_fz)) DEALLOCATE(OutData%C_fz) - ALLOCATE(OutData%C_fz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_fz.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i4 = LBOUND(OutData%C_fz,4), UBOUND(OutData%C_fz,4) - DO i3 = LBOUND(OutData%C_fz,3), UBOUND(OutData%C_fz,3) - DO i2 = LBOUND(OutData%C_fz,2), UBOUND(OutData%C_fz,2) - DO i1 = LBOUND(OutData%C_fz,1), UBOUND(OutData%C_fz,1) - OutData%C_fz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mx not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_mx)) DEALLOCATE(OutData%C_mx) - ALLOCATE(OutData%C_mx(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mx.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i4 = LBOUND(OutData%C_mx,4), UBOUND(OutData%C_mx,4) - DO i3 = LBOUND(OutData%C_mx,3), UBOUND(OutData%C_mx,3) - DO i2 = LBOUND(OutData%C_mx,2), UBOUND(OutData%C_mx,2) - DO i1 = LBOUND(OutData%C_mx,1), UBOUND(OutData%C_mx,1) - OutData%C_mx(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_my not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_my)) DEALLOCATE(OutData%C_my) - ALLOCATE(OutData%C_my(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_my.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i4 = LBOUND(OutData%C_my,4), UBOUND(OutData%C_my,4) - DO i3 = LBOUND(OutData%C_my,3), UBOUND(OutData%C_my,3) - DO i2 = LBOUND(OutData%C_my,2), UBOUND(OutData%C_my,2) - DO i1 = LBOUND(OutData%C_my,1), UBOUND(OutData%C_my,1) - OutData%C_my(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! C_mz not allocated + OutData%halfRhoA = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL ADsk_Unpackaerotable( Re_Buf, Db_Buf, Int_Buf, OutData%AeroTable, ErrStat2, ErrMsg2 ) ! AeroTable + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParam not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 i1_l = IntKiBuf( Int_Xferred ) i1_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i4_l = IntKiBuf( Int_Xferred ) - i4_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%C_mz)) DEALLOCATE(OutData%C_mz) - ALLOCATE(OutData%C_mz(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%OutParam)) DEALLOCATE(OutData%OutParam) + ALLOCATE(OutData%OutParam(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%C_mz.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%OutParam.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i4 = LBOUND(OutData%C_mz,4), UBOUND(OutData%C_mz,4) - DO i3 = LBOUND(OutData%C_mz,3), UBOUND(OutData%C_mz,3) - DO i2 = LBOUND(OutData%C_mz,2), UBOUND(OutData%C_mz,2) - DO i1 = LBOUND(OutData%C_mz,1), UBOUND(OutData%C_mz,1) - OutData%C_mz(i1,i2,i3,i4) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END DO + DO i1 = LBOUND(OutData%OutParam,1), UBOUND(OutData%OutParam,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackoutparmtype( Re_Buf, Db_Buf, Int_Buf, OutData%OutParam(i1), ErrStat2, ErrMsg2 ) ! OutParam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO END IF END SUBROUTINE ADsk_UnPackParam diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver.f90 index 71d4365864..152357f54e 100644 --- a/modules/aerodisk/src/driver/AeroDisk_Driver.f90 +++ b/modules/aerodisk/src/driver/AeroDisk_Driver.f90 @@ -258,6 +258,7 @@ PROGRAM AeroDisk_Driver !............................................................................................................................... InitInData%InputFile = Settings%ADskIptFileName + InitInData%RootName = Settings%OutRootName ! Initialize the module CALL ADsk_Init( InitInData, u(1), p, x, xd, z, OtherState, y, misc, TimeInterval, InitOutData, ErrStat, ErrMsg ) diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 index a955eebec6..46bd886c8b 100644 --- a/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 +++ b/modules/aerodisk/src/driver/AeroDisk_Driver_Subs.f90 @@ -182,6 +182,8 @@ SUBROUTINE RetrieveArgs( CLSettings, CLFlags, ErrStat, ErrMsg ) IF ( adskFlag ) THEN CLSettings%ADskIptFileName = TRIM(FileName) CLFlags%ADskIptFile = .TRUE. + call GetRoot( CLSettings%ADskIptFileName, CLSettings%OutRootName ) + CLFlags%OutRootName = .TRUE. ELSE CLSettings%DvrIptFileName = TRIM(FileName) CLFlags%DvrIptFile = .TRUE. @@ -478,6 +480,15 @@ SUBROUTINE ReadDvrIptFile( DvrFileName, DvrFlags, DvrSettings, ProgInfo, ErrStat DvrFlags%ADskIptFile = .TRUE. endif + ! AeroDisk output root name + CALL ReadVar( UnIn, FileName,DvrSettings%OutRootName,'OutRootName',' AeroDisk output rootname', & + ErrStatTmp,ErrMsgTmp, UnEchoLocal ) + if (Failed()) then + return + else + DvrFlags%OutRootName = .TRUE. + endif + ! TStart -- start time CALL ReadVar( UnIn, FileName,DvrSettings%TStart,'TStart',' Time in wind file to start parsing.', & diff --git a/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 b/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 index 5197f274d9..08013966ed 100644 --- a/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 +++ b/modules/aerodisk/src/driver/AeroDisk_Driver_Types.f90 @@ -40,6 +40,7 @@ module AeroDisk_Driver_Types type :: ADskDriver_Flags logical :: DvrIptFile = .FALSE. !< Was an input file name given on the command line? logical :: ADskIptFile = .FALSE. !< Was an AeroDisk input file requested? + logical :: OutRootName = .FALSE. !< Was an AeroDisk output rootname logical :: InputDispFile = .FALSE. !< Input displacement time series logical :: TStart = .FALSE. !< specified a start time logical :: NumTimeSteps = .FALSE. !< specified a number of timesteps to process @@ -55,6 +56,7 @@ module AeroDisk_Driver_Types type :: ADskDriver_Settings character(1024) :: DvrIptFileName !< Driver input file name character(1024) :: ADskIptFileName !< Filename of AeroDisk input file to read (if no driver input file) + character(1024) :: OutRootName !< Output root name character(1024) :: InputDispFile !< Filename of AeroDisk time series displacements integer(IntKi) :: NumTimeSteps !< Number of timesteps From cd0fa1df60ecf9d827c7f7e01da304e0ca9ea700 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Mon, 21 Feb 2022 18:33:19 -0700 Subject: [PATCH 023/130] ADsk: add simple test case for AeroDisk driver --- reg_tests/CMakeLists.txt | 3 + reg_tests/CTestList.cmake | 13 ++ reg_tests/executeAerodiskRegressionCase.py | 141 +++++++++++++++++++++ reg_tests/lib/openfastDrivers.py | 5 + reg_tests/r-test | 2 +- 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 reg_tests/executeAerodiskRegressionCase.py diff --git a/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 114b3d8771..854dc32425 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -63,6 +63,9 @@ set(CTEST_SUBDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/subdyn/subdyn_driver" C # Set the InflowWind executable configuration option and default set(CTEST_INFLOWWIND_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/inflowwind/inflowwind_driver" CACHE FILEPATH "Specify the InflowWind driver executable to use in testing.") +# Set the AeroDisk executable configuration option and default +set(CTEST_AERODISK_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/aerodisk/aerodisk_driver" CACHE FILEPATH "Specify the AeroDisk driver executable to use in testing.") + # Set the python executable configuration option and default if(NOT EXISTS ${PYTHON_EXECUTABLE}) find_program(PYTHON_EXECUTABLE NAMES python3 python py) diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index caa9a352ac..9cc6ffd35d 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -162,6 +162,15 @@ function(ifw_py_regression TESTNAME LABEL) regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(ifw_py_regression) +# aerodisk +function(adsk_regression TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeAerodiskRegressionCase.py") + set(AERODISK_EXECUTABLE "${CTEST_AERODISK_EXECUTABLE}") + set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") + set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/aerodisk") + regression(${TEST_SCRIPT} ${AERODISK_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") +endfunction(adsk_regression) + #=============================================================================== # Regression tests #=============================================================================== @@ -264,3 +273,7 @@ sd_regression("SD_AnsysComp3_PinBeamCable" "subdyn;offshore") # InflowWind regression tests ifw_regression("ifw_turbsimff" "inflowwind") ifw_py_regression("ifw_py_turbsimff" "inflowwind;python") + +# AeroDisk regression tests +adsk_regression("adsk_test1" "aerodisk") + diff --git a/reg_tests/executeAerodiskRegressionCase.py b/reg_tests/executeAerodiskRegressionCase.py new file mode 100644 index 0000000000..d7fc41d69a --- /dev/null +++ b/reg_tests/executeAerodiskRegressionCase.py @@ -0,0 +1,141 @@ +# +# Copyright 2017 National Renewable Energy Laboratory +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +""" + This program executes AeroDisk and a regression test for a single test case. + The test data is contained in a git submodule, r-test, which must be initialized + prior to running. See the r-test README or OpenFAST documentation for more info. + + Get usage with: `executeAeroDiskRegressionCase.py -h` +""" + +import os +import sys +basepath = os.path.sep.join(sys.argv[0].split(os.path.sep)[:-1]) if os.path.sep in sys.argv[0] else "." +sys.path.insert(0, os.path.sep.join([basepath, "lib"])) +import argparse +import shutil +import glob +import subprocess +import rtestlib as rtl +import openfastDrivers +import pass_fail +from errorPlotting import exportCaseSummary + +##### Main program + +### Store the python executable for future python calls +pythonCommand = sys.executable + +### Verify input arguments +parser = argparse.ArgumentParser(description="Executes OpenFAST and a regression test for a single test case.") +parser.add_argument("caseName", metavar="Case-Name", type=str, nargs=1, help="The name of the test case.") +parser.add_argument("executable", metavar="AeroDisk-Driver", type=str, nargs=1, help="The path to the AeroDisk driver executable.") +parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") +parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") +parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") +parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") +parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") +parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") +parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") + +args = parser.parse_args() + +caseName = args.caseName[0] +executable = args.executable[0] +sourceDirectory = args.sourceDirectory[0] +buildDirectory = args.buildDirectory[0] +tolerance = args.tolerance[0] +plotError = args.plot if args.plot is False else True +noExec = args.noExec if args.noExec is False else True +verbose = args.verbose if args.verbose is False else True + +# validate inputs +rtl.validateExeOrExit(executable) +rtl.validateDirOrExit(sourceDirectory) +if not os.path.isdir(buildDirectory): + os.makedirs(buildDirectory) + +### Build the filesystem navigation variables for running the test case +regtests = os.path.join(sourceDirectory, "reg_tests") +lib = os.path.join(regtests, "lib") +rtest = os.path.join(regtests, "r-test") +moduleDirectory = os.path.join(rtest, "modules", "aerodisk") +inputsDirectory = os.path.join(moduleDirectory, caseName) +targetOutputDirectory = os.path.join(inputsDirectory) +testBuildDirectory = os.path.join(buildDirectory, caseName) + +# verify all the required directories exist +if not os.path.isdir(rtest): + rtl.exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) +if not os.path.isdir(targetOutputDirectory): + rtl.exitWithError("The test data outputs directory, {}, does not exist. Try running `git submodule update`".format(targetOutputDirectory)) +if not os.path.isdir(inputsDirectory): + rtl.exitWithError("The test data inputs directory, {}, does not exist. Verify your local repository is up to date.".format(inputsDirectory)) + +# create the local output directory if it does not already exist +# and initialize it with input files for all test cases +if not os.path.isdir(testBuildDirectory): + os.makedirs(testBuildDirectory) + for file in glob.glob(os.path.join(inputsDirectory,"*inp")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + for file in glob.glob(os.path.join(inputsDirectory,"*dat")): + filename = file.split(os.path.sep)[-1] + shutil.copy(os.path.join(inputsDirectory,filename), os.path.join(testBuildDirectory,filename)) + +### Run aerodisk on the test case +if not noExec: + caseInputFile = os.path.join(testBuildDirectory, "adsk_driver.inp") + returnCode = openfastDrivers.runAerodiskDriverCase(caseInputFile, executable) + if returnCode != 0: + rtl.exitWithError("") + +### Build the filesystem navigation variables for running the regression test +localOutFile = os.path.join(testBuildDirectory, "adsk_driver.out") +baselineOutFile = os.path.join(targetOutputDirectory, "adsk_driver.out") +rtl.validateFileOrExit(localOutFile) +rtl.validateFileOrExit(baselineOutFile) + +testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) +performance = pass_fail.calculateNorms(testData, baselineData) +normalizedNorm = performance[:, 1] + +# export all case summaries +results = list(zip(testInfo["attribute_names"], [*performance])) +results_max = performance.max(axis=0) +exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) + +# failing case +if not pass_fail.passRegressionTest(normalizedNorm, tolerance): + if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] + failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] + failResults = [res for i, res in enumerate(results) if i in ixFailChannels] + for channel in failChannels: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error.msg)) + finalizePlotDirectory(localOutFile, failChannels, caseName) + sys.exit(1) + +# passing case +sys.exit(0) diff --git a/reg_tests/lib/openfastDrivers.py b/reg_tests/lib/openfastDrivers.py index 751c6c492a..02b89dbb35 100644 --- a/reg_tests/lib/openfastDrivers.py +++ b/reg_tests/lib/openfastDrivers.py @@ -80,3 +80,8 @@ def runInflowwindDriverCase(inputFile, executable, verbose=False): caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) os.chdir(caseDirectory) return _runGenericCase(inputFile, executable, verbose) + +def runAerodiskDriverCase(inputFile, executable, verbose=False): + caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) + os.chdir(caseDirectory) + return _runGenericCase(inputFile, executable, verbose) diff --git a/reg_tests/r-test b/reg_tests/r-test index 04cd1d2754..8dd82fbc6c 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 04cd1d27544bea9c6b515b2baf5be7952fdc0f3e +Subproject commit 8dd82fbc6cc2f615677987f942527ba2b6d5e7c0 From 61e4326ed0c3f294b5fdfc7a4d45387d58bcd8e6 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 24 Feb 2022 18:22:00 -0700 Subject: [PATCH 024/130] aerodisk: set outparams and add some table handling at init - also added a generic table writer that will write to whatever unit specified --- modules/aerodisk/src/AeroDisk.f90 | 32 ++- modules/aerodisk/src/AeroDisk_IO.f90 | 210 ++++++++++++++++-- .../aerodisk/src/AeroDisk_Output_Params.f90 | 5 +- 3 files changed, 206 insertions(+), 41 deletions(-) diff --git a/modules/aerodisk/src/AeroDisk.f90 b/modules/aerodisk/src/AeroDisk.f90 index f591611c7b..18d675ca01 100644 --- a/modules/aerodisk/src/AeroDisk.f90 +++ b/modules/aerodisk/src/AeroDisk.f90 @@ -107,33 +107,29 @@ SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO call ADsk_ParsePrimaryFileData( InitInp, p%RootName, Interval, FileInfo_In, InputFileData, UnEc, ErrStat2, ErrMsg2 ) if (Failed()) return; -call SetErrStat(ErrID_Fatal,'Have not set parameters from init or checked primary file data yet',ErrStat,ErrMsg,RoutineName); return - ! Verify all the necessary initialization and input file data -! CALL ADskInput_ValidateProcessInitData( InitInp, Interval, InputFileData, ErrStat2, ErrMsg2 ) -! if (Failed()) return; + CALL ADskInput_ValidateInput( InitInp, InputFileData, ErrStat2, ErrMsg2 ) + if (Failed()) return; + + ! Set parameters + CALL ADskInput_SetParameters( InitInp, Interval, InputFileData, p, ErrStat2, ErrMsg2 ) + if (Failed()) return; + ! For testing: + !call WriteAeroTab(p%AeroTable,Cu) -!FIXME: see if we requested something different for time - ! Define parameters here: - p%DT = Interval - p%numOuts = InputFileData%NumOuts + ! Placeholder empty vars for things we don't use, but the framework requires + xd%DummyDiscreteState = 0.0_ReKi + z%DummyConstrState = 0.0_ReKi + OtherState%DummyOtherState = 0.0_IntKi + m%DummyMiscVar = 0.0_IntKi - ! Define initial system states here: -! x%DummyContState = 0.0_ReKi -! xd%DummyDiscState = 0.0_ReKi -! z%DummyConstrState = 0.0_ReKi -! OtherState%DummyOtherState = 0.0_ReKi - ! Define optimization variables here: - m%DummyMiscVar = 0.0_ReKi +call SetErrStat(ErrID_Fatal,'Need to set inputs and outputs',ErrStat,ErrMsg,RoutineName); return ! Define initial guess for the system inputs here: ! u%DummyInput = 0.0_ReKi - -! call SetOutParams() - ! Define system output initializations (set up mesh) here: call AllocAry( y%WriteOutput, p%NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; y%WriteOutput = 0 diff --git a/modules/aerodisk/src/AeroDisk_IO.f90 b/modules/aerodisk/src/AeroDisk_IO.f90 index 44694f7cac..4d4e5872fb 100644 --- a/modules/aerodisk/src/AeroDisk_IO.f90 +++ b/modules/aerodisk/src/AeroDisk_IO.f90 @@ -425,11 +425,16 @@ subroutine Get_RtAeroTableData(Info,LineNo,Idx,AeroTable,ErrStat,ErrMsg,UnEc) if (AeroTable%N_VRel > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColVRel ),'VRel' ,AeroTable%N_VRel ,AeroTable%VRel , ErrStat2, ErrMsg2); if (Failed()) return if (AeroTable%N_Pitch > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColPitch),'Pitch',AeroTable%N_Pitch,AeroTable%Pitch, ErrStat2, ErrMsg2); if (Failed()) return if (AeroTable%N_Skew > 0_IntKi) call GetTabIndexVals( TmpTab(:,Idx%ColSkew ),'Skew' ,AeroTable%N_Skew ,AeroTable%Skew , ErrStat2, ErrMsg2); if (Failed()) return - + ! Now populate matrix -- read each line and put in correct table entry location call PopulateAeroTabs(AeroTable,Mask,Idx,TmpTab,NumRows,NumCols,ErrStat2,ErrMsg2); if (Failed()) return call CheckAeroTabs(AeroTable,Mask,ErrStat2,ErrMsg2); if (Failed()) return + ! Now convert RtSpd from rpm to rad/s, and Pitch and Skew from deg to rad + if (AeroTable%N_RtSpd > 0_IntKi) AeroTable%RtSpd = (AeroTable%RtSpd * Pi_S)/30.0_SiKi + if (AeroTable%N_Pitch > 0_IntKi) AeroTable%Pitch = (AeroTable%Pitch * Pi_S)/180.0_SiKi + if (AeroTable%N_Skew > 0_IntKi) AeroTable%Skew = (AeroTable%Skew * Pi_S)/180.0_SiKi + call Cleanup() contains @@ -644,38 +649,201 @@ end subroutine Cleanup END SUBROUTINE UniqueRealValues +!> Check inputdata +subroutine ADskInput_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) + type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization + type(ADsk_InputFile), intent(in ) :: InputFileData !< The data for initialization + integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine + character(*), intent( out) :: ErrMsg !< Error message from this subroutine + character(*), parameter :: RoutineName="ADskInput_ValidateInput" + + ! Initialize ErrStat + ErrStat = ErrID_None + ErrMsg = "" + + if (InputFileData%DT <= 0.0_DbKi) call SetErrStat(ErrID_Fatal,'DT must not be negative.', ErrStat,ErrMsg,RoutineName) + if (InputFileData%AirDens <= 0.0_ReKi) call SetErrStat(ErrID_Fatal,'AirDens must not be negative.',ErrStat,ErrMsg,RoutineName) + if (InputFileData%RotorRad <= 0.0_ReKi) call SetErrStat(ErrID_Fatal,'RotorRad must not be negative.',ErrStat,ErrMsg,RoutineName) + + ! Some sanity checks AeroTable + if (InputFileData%AeroTable%N_TSR > 0_IntKi) then + if (minval(InputFileData%AeroTable%TSR) <= 0.0_SiKi) then + call SetErrStat(ErrID_Fatal,'All TSR values in table must be postive.',ErrStat,ErrMsg,RoutineName) + endif + endif + if (InputFileData%AeroTable%N_RtSpd > 0_IntKi) then + if (minval(InputFileData%AeroTable%RtSpd) <= 0.0_SiKi) then + call SetErrStat(ErrID_Fatal,'All RtSpd values in table must be postive.',ErrStat,ErrMsg,RoutineName) + endif + endif + if (InputFileData%AeroTable%N_VRel > 0_IntKi) then + if (minval(InputFileData%AeroTable%VRel) < 0.0_SiKi ) then + call SetErrStat(ErrID_Fatal,'All VRel values in table must be postive.',ErrStat,ErrMsg,RoutineName) + endif + endif + if (InputFileData%AeroTable%N_Pitch > 0_IntKi) then ! input table as deg, already converted to rad + if (minval(InputFileData%AeroTable%Pitch) <= -Pi_S .or. maxval(InputFileData%AeroTable%Pitch) >= Pi_S) then + call SetErrStat(ErrID_Fatal,'All Pitch values in table must be between -180 and 180 degrees.',ErrStat,ErrMsg,RoutineName) + endif + endif + if (InputFileData%AeroTable%N_Skew > 0_IntKi) then ! input table as deg, already converted to rad + if (minval(InputFileData%AeroTable%Skew) <= 0.0_SiKi .or. maxval(InputFileData%AeroTable%Skew) >= Pi_S) then + call SetErrStat(ErrID_Fatal,'All Skew values in table must be between 0 and 180 degrees.',ErrStat,ErrMsg,RoutineName) + endif + endif + +end subroutine ADskInput_ValidateInput + + !> validate and process input file data (some was done during parsing of input file) -subroutine ADsk_ValidateProcessInput( InitInp, InputFileData, ErrStat, ErrMsg ) +subroutine ADskInput_SetParameters( InitInp, Interval, InputFileData, p, ErrStat, ErrMsg ) type(ADsk_InitInputType), intent(in ) :: InitInp !< Input data for initialization + real(DbKi), intent(inout) :: Interval !< Coupling interval in seconds type(ADsk_InputFile), intent(inout) :: InputFileData !< The data for initialization + type(ADsk_ParameterType), intent(inout) :: p !< integer(IntKi), intent( out) :: ErrStat !< Error status from this subroutine character(*), intent( out) :: ErrMsg !< Error message from this subroutine integer(IntKi) :: ErrStat2 !< Temporary error status for subroutine and function calls character(ErrMsgLen) :: ErrMsg2 !< Temporary error message for subroutine and function calls - integer(IntKi) :: I !< Generic counter - character(*), parameter :: RoutineName="ADsk_ValidateInput" - integer(IntKi) :: IOS !< Temporary error status + character(*), parameter :: RoutineName="ADskInput_SetParameters" ! Initialize ErrStat ErrStat = ErrID_None ErrMsg = "" -end subroutine ADsk_ValidateProcessInput - + ! Set parameters + p%DT = InputFileData%DT + Interval = p%DT ! Tell glue code what we want for DT + p%numOuts = InputFileData%NumOuts + p%RootName = InitInp%RootName + p%RotorRad = InputFileData%RotorRad + p%AirDens = InputFileData%AirDens + + ! Derived parameter + p%halfRhoA = 0.5_ReKi * p%AirDens * Pi * p%RotorRad*p%RotorRad + + ! Table of values + p%AeroTable%N_TSR = InputFileData%AeroTable%N_TSR + p%AeroTable%N_RtSpd = InputFileData%AeroTable%N_RtSpd + p%AeroTable%N_VRel = InputFileData%AeroTable%N_VRel + p%AeroTable%N_Pitch = InputFileData%AeroTable%N_Pitch + p%AeroTable%N_Skew = InputFileData%AeroTable%N_Skew + if (allocated( InputFileData%AeroTable%TSR )) call move_alloc( InputFileData%AeroTable%TSR, p%AeroTable%TSR ) + if (allocated( InputFileData%AeroTable%RtSpd)) call move_alloc( InputFileData%AeroTable%RtSpd, p%AeroTable%RtSpd ) + if (allocated( InputFileData%AeroTable%VRel )) call move_alloc( InputFileData%AeroTable%VRel, p%AeroTable%VRel ) + if (allocated( InputFileData%AeroTable%Pitch)) call move_alloc( InputFileData%AeroTable%Pitch, p%AeroTable%Pitch ) + if (allocated( InputFileData%AeroTable%Skew )) call move_alloc( InputFileData%AeroTable%Skew, p%AeroTable%Skew ) + if (allocated( InputFileData%AeroTable%C_Fx )) call move_alloc( InputFileData%AeroTable%C_Fx, p%AeroTable%C_Fx ) + if (allocated( InputFileData%AeroTable%C_Fy )) call move_alloc( InputFileData%AeroTable%C_Fy, p%AeroTable%C_Fy ) + if (allocated( InputFileData%AeroTable%C_Fz )) call move_alloc( InputFileData%AeroTable%C_Fz, p%AeroTable%C_Fz ) + if (allocated( InputFileData%AeroTable%C_Mx )) call move_alloc( InputFileData%AeroTable%C_Mx, p%AeroTable%C_Mx ) + if (allocated( InputFileData%AeroTable%C_My )) call move_alloc( InputFileData%AeroTable%C_My, p%AeroTable%C_My ) + if (allocated( InputFileData%AeroTable%C_Mz )) call move_alloc( InputFileData%AeroTable%C_Mz, p%AeroTable%C_Mz ) + + ! Set the outputs + call SetOutParam(InputFileData%OutList, p, ErrStat, ErrMsg ) +end subroutine ADskInput_SetParameters + + +!> Write the table out to a whatever UnOut is (as long as > 0). +subroutine WriteAeroTab(Aero, UnOut) + type(ADsk_AeroTable), intent(in ) :: Aero + integer(IntKi), intent(in ) :: UnOut + integer(IntKi) :: i1,i2,i3,i4,i5 !< loop counters + character(*), parameter :: RoutineName="ADskInput_SetParameters" + if (UnOut <= 0_IntKi) return + ! Write header info + write(UnOut,'(A)') '=======================================' + write(UnOut,'(A)') 'AeroDisk Actuator Disk Properties table' + write(UnOut,'(A)') ' NOTE: the units correspond to units used internally within code, not units of input' + if (Aero%N_TSR > 0_IntKi) then + write(UnOut,'(A12,I5,A7)') ' TSR ',Aero%N_TSR,' values' + else + write(UnOut,'(A)') ' TSR ---- unused ----' + endif + if (Aero%N_RtSpd > 0_IntKi) then + write(UnOut,'(A12,I5,A7)') ' RtSpd ',Aero%N_RtSpd,' values' + else + write(UnOut,'(A)') ' RtSpd ---- unused ----' + endif + if (Aero%N_VRel > 0_IntKi) then + write(UnOut,'(A12,I5,A7)') ' VRel ',Aero%N_VRel,' values' + else + write(UnOut,'(A)') ' VRel ---- unused ----' + endif + if (Aero%N_Pitch > 0_IntKi) then + write(UnOut,'(A12,I5,A7)') ' Pitch ',Aero%N_Pitch,' values' + else + write(UnOut,'(A)') ' Pitch ---- unused ----' + endif + if (Aero%N_Skew > 0_IntKi) then + write(UnOut,'(A12,I5,A7)') ' Skew ',Aero%N_Skew,' values' + else + write(UnOut,'(A)') ' Skew ---- unused ----' + endif + ! Table header + if (Aero%N_TSR > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' TSR ' + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' RtSpd ' + if (Aero%N_VRel > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' VRel ' + if (Aero%N_Pitch > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' Pitch ' + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' Skew ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_fx ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_fy ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_fz ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_mx ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_my ' + write(UnOut,'(A15)',ADVANCE='NO') ' C_mz ' + write(UnOut,'(A)') '' + if (Aero%N_TSR > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' (rad/s) ' + if (Aero%N_VRel > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' (m/s) ' + if (Aero%N_Pitch > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' (rad) ' + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(A15)',ADVANCE='NO') ' (rad) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A15)',ADVANCE='NO') ' (-) ' + write(UnOut,'(A)') '' + ! Table itself + do i1=1,max(1,Aero%N_TSR ) + do i2=1,max(1,Aero%N_Skew ) + do i3=1,max(1,Aero%N_VRel ) + do i4=1,max(1,Aero%N_Pitch) + do i5=1,max(1,Aero%N_Skew ) + if (Aero%N_TSR > 0_IntKi) write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%TSR (i1) + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%Skew (i2) + if (Aero%N_VRel > 0_IntKi) write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%VRel (i3) + if (Aero%N_Pitch> 0_IntKi) write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%Pitch(i4) + if (Aero%N_Skew > 0_IntKi) write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%Skew (i5) + write(UnOut, '(f13.6)',ADVANCE='NO') Aero%C_Fx(i1,i2,i3,i4,i5) + write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%C_Fy(i1,i2,i3,i4,i5) + write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%C_Fz(i1,i2,i3,i4,i5) + write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%C_Mx(i1,i2,i3,i4,i5) + write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%C_My(i1,i2,i3,i4,i5) + write(UnOut,'(2x,f13.6)',ADVANCE='NO') Aero%C_Mz(i1,i2,i3,i4,i5) + write(UnOut,'(A)') '' + enddo + enddo + enddo + enddo + enddo +end subroutine WriteAeroTab !********************************************************************************************************************************** ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" -! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these -! lines should be modified in the Matlab script and/or Excel worksheet as necessary. +! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these +! lines should be modified in the Matlab script and/or Excel worksheet as necessary. !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine checks to see if any requested output channel names (stored in the OutList(:)) are invalid. It returns a +!> This routine checks to see if any requested output channel names (stored in the OutList(:)) are invalid. It returns a !! warning if any of the channels are not available outputs from the module. !! It assigns the settings for OutParam(:) (i.e, the index, name, and units of the output channels, WriteOutput(:)). !! the sign is set to 0 if the channel is invalid. !! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here. -!! -!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 17-Feb-2022 14:08:12. +!! +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 24-Feb-2022 16:52:56. SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) !.................................................................................................................................. @@ -702,21 +870,21 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(34) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically "ADCP ","ADCQ ","ADCT ","ADFX ","ADFXI ","ADFY ","ADFYI ","ADFZ ", & - "ADFZI ","ADMX ","ADMXI ","ADMY ","ADMYI ","ADMZ ","ADMZI ","ADPOWER ", & - "ADSKEW ","ADSPEED ","ADSTVX ","ADSTVXI ","ADSTVY ","ADSTVYI ","ADSTVZ ","ADSTVZI ", & - "ADTPITCH ","ADTSR ","ADVREL ","ADVWINDX ","ADVWINDXI","ADVWINDY ","ADVWINDYI","ADVWINDZ ", & + "ADFZI ","ADMX ","ADMXI ","ADMY ","ADMYI ","ADMZ ","ADMZI ","ADPITCH ", & + "ADPOWER ","ADSKEW ","ADSPEED ","ADSTVX ","ADSTVXI ","ADSTVY ","ADSTVYI ","ADSTVZ ", & + "ADSTVZI ","ADTSR ","ADVREL ","ADVWINDX ","ADVWINDXI","ADVWINDY ","ADVWINDYI","ADVWINDZ ", & "ADVWINDZI","ADYAWERR "/) INTEGER(IntKi), PARAMETER :: ParamIndxAry(34) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) ADCp , ADCq , ADCt , ADFx , ADFxi , ADFy , ADFyi , ADFz , & - ADFzi , ADMx , ADMxi , ADMy , ADMyi , ADMz , ADMzi , ADPower , & - ADSkew , ADSpeed , ADSTVx , ADSTVxi , ADSTVy , ADSTVyi , ADSTVz , ADSTVzi , & - ADTPitch , ADTSR , ADVRel , ADVWindx , ADVWindxi , ADVWindy , ADVWindyi , ADVWindz , & + ADFzi , ADMx , ADMxi , ADMy , ADMyi , ADMz , ADMzi , ADPitch , & + ADPower , ADSkew , ADSpeed , ADSTVx , ADSTVxi , ADSTVy , ADSTVyi , ADSTVz , & + ADSTVzi , ADTSR , ADVRel , ADVWindx , ADVWindxi , ADVWindy , ADVWindyi , ADVWindz , & ADVWindzi , ADYawErr /) CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(34) = (/ & ! This lists the units corresponding to the allowed parameters "(-) ","(-) ","(-) ","(N) ","(N) ","(N) ","(N) ","(N) ", & - "(N) ","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(W) ", & - "(deg)","(rpm)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & - "(deg)","(-) ","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & + "(N) ","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(N-m)","(deg)", & + "(W) ","(deg)","(rpm)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & + "(m/s)","(-) ","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)","(m/s)", & "(m/s)","(deg)"/) diff --git a/modules/aerodisk/src/AeroDisk_Output_Params.f90 b/modules/aerodisk/src/AeroDisk_Output_Params.f90 index 2876f95652..8015c94d00 100644 --- a/modules/aerodisk/src/AeroDisk_Output_Params.f90 +++ b/modules/aerodisk/src/AeroDisk_Output_Params.f90 @@ -2,12 +2,13 @@ module AeroDisk_Output_Params use NWTC_Library + ! =================================================================================================== ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" ! using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these ! lines should be modified in the Matlab script and/or Excel worksheet as necessary. ! =================================================================================================== -! This code was generated by Write_ChckOutLst.m at 17-Feb-2022 14:08:12. +! This code was generated by Write_ChckOutLst.m at 24-Feb-2022 18:19:57. ! Parameters related to output length (number of characters allowed in the output data headers): @@ -29,7 +30,7 @@ module AeroDisk_Output_Params INTEGER(IntKi), PARAMETER :: ADSpeed = 1 INTEGER(IntKi), PARAMETER :: ADTSR = 2 - INTEGER(IntKi), PARAMETER :: ADTPitch = 3 + INTEGER(IntKi), PARAMETER :: ADPitch = 3 INTEGER(IntKi), PARAMETER :: ADVWindx = 4 INTEGER(IntKi), PARAMETER :: ADVWindy = 5 INTEGER(IntKi), PARAMETER :: ADVWindz = 6 From 38ee0703219daff01ceb0fe661211a525ac43e7e Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 25 Feb 2022 10:02:32 -0700 Subject: [PATCH 025/130] aerodisk: add error handling for {TSR || RtSpd&&VRel} columns --- modules/aerodisk/src/AeroDisk_IO.f90 | 30 ++++++++++++++++++++-- modules/aerodisk/src/AeroDisk_Registry.txt | 1 + modules/aerodisk/src/AeroDisk_Types.f90 | 7 +++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/modules/aerodisk/src/AeroDisk_IO.f90 b/modules/aerodisk/src/AeroDisk_IO.f90 index 4d4e5872fb..16d3d2285d 100644 --- a/modules/aerodisk/src/AeroDisk_IO.f90 +++ b/modules/aerodisk/src/AeroDisk_IO.f90 @@ -139,8 +139,12 @@ subroutine ADsk_ParsePrimaryFileData( InitInp, RootName, interval, FileInfo_In, logical function Failed() call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev -! if (Failed) call CleanUp() + if (Failed) call CleanUp() end function Failed + subroutine Cleanup() + ! Only do this on a fault. Leave open for calling routine in case we want to write anything else. + if (UnEc > 0_IntKi) close(UnEc) + end subroutine Cleanup subroutine GetVarNamePos(FileName,LineNo,ChAry,NameToCheck,ColNum,ErrStat3,ErrMsg3) character(*), intent(in ) :: FileName integer(IntKi), intent(in ) :: LineNo @@ -661,9 +665,11 @@ subroutine ADskInput_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) ErrStat = ErrID_None ErrMsg = "" + ! InitInput checks if (InputFileData%DT <= 0.0_DbKi) call SetErrStat(ErrID_Fatal,'DT must not be negative.', ErrStat,ErrMsg,RoutineName) if (InputFileData%AirDens <= 0.0_ReKi) call SetErrStat(ErrID_Fatal,'AirDens must not be negative.',ErrStat,ErrMsg,RoutineName) if (InputFileData%RotorRad <= 0.0_ReKi) call SetErrStat(ErrID_Fatal,'RotorRad must not be negative.',ErrStat,ErrMsg,RoutineName) + if (InitInp%Linearize) call SetErrStat(ErrID_Fatal,'AeroDisk cannot perform linearization analysis.',ErrStat,ErrMsg,RoutineName) ! Some sanity checks AeroTable if (InputFileData%AeroTable%N_TSR > 0_IntKi) then @@ -692,6 +698,22 @@ subroutine ADskInput_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) endif endif + ! Either TSR or RtSpd+VRel columns must be provided + if (InputFileData%AeroTable%N_TSR > 1_IntKi) then + if (InputFileData%AeroTable%N_RtSpd > 1_IntKi .or. InputFileData%AeroTable%N_VRel > 1_IntKi) then + call SetErrStat(ErrID_Fatal,'TSR values present in table along with RtSpd or VRel values. '//NewLine// & + ' --> Either RtSpd and VRel values must be in the table, or TSR values may be present.'//NewLine// & + ' To skip columns, you may enter "0" for the column index and leave the table values.',ErrStat,ErrMsg,RoutineName) + return + endif + else + if (InputFileData%AeroTable%N_RtSpd < 2_IntKi .and. InputFileData%AeroTable%N_VRel < 2_IntKi) then + call SetErrStat(ErrID_Fatal,'TSR values NOT present in table, but RtSpd and VRel values are not both present. '//NewLine// & + ' --> Either RtSpd and VRel values must be in the table, or TSR values may be present.'//NewLine// & + ' To skip columns, you may enter "0" for the column index and leave the table values.',ErrStat,ErrMsg,RoutineName) + return + endif + endif end subroutine ADskInput_ValidateInput @@ -718,6 +740,7 @@ subroutine ADskInput_SetParameters( InitInp, Interval, InputFileData, p, ErrStat p%RootName = InitInp%RootName p%RotorRad = InputFileData%RotorRad p%AirDens = InputFileData%AirDens + p%UseTSR = .false. ! Reset below if N_TSR>1 ! Derived parameter p%halfRhoA = 0.5_ReKi * p%AirDens * Pi * p%RotorRad*p%RotorRad @@ -740,6 +763,9 @@ subroutine ADskInput_SetParameters( InitInp, Interval, InputFileData, p, ErrStat if (allocated( InputFileData%AeroTable%C_My )) call move_alloc( InputFileData%AeroTable%C_My, p%AeroTable%C_My ) if (allocated( InputFileData%AeroTable%C_Mz )) call move_alloc( InputFileData%AeroTable%C_Mz, p%AeroTable%C_Mz ) + ! Use the TSR values + if (p%AeroTable%N_TSR > 1_IntKi) p%UseTSR = .true. + ! Set the outputs call SetOutParam(InputFileData%OutList, p, ErrStat, ErrMsg ) end subroutine ADskInput_SetParameters @@ -852,7 +878,7 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) ! Passed variables CHARACTER(ChanLen), INTENT(IN) :: OutList(:) !< The list out user-requested outputs - TYPE(ADsk_ParameterType), INTENT(INOUT) :: p !< The module parameters + TYPE(ADsk_ParameterType), INTENT(INOUT) :: p !< The module parameters INTEGER(IntKi), INTENT(OUT) :: ErrStat !< The error status code CHARACTER(*), INTENT(OUT) :: ErrMsg !< The error message, if an error occurred diff --git a/modules/aerodisk/src/AeroDisk_Registry.txt b/modules/aerodisk/src/AeroDisk_Registry.txt index 196735bc8d..7b0a0cb16b 100644 --- a/modules/aerodisk/src/AeroDisk_Registry.txt +++ b/modules/aerodisk/src/AeroDisk_Registry.txt @@ -109,6 +109,7 @@ typedef ^ ParameterType ReKi AirDens - - typedef ^ ParameterType IntKi NumOuts - - - "Number of outputs" - typedef ^ ParameterType ReKi halfRhoA - - - "half air density times rotor swept area" "kg/m" typedef ^ ParameterType ADsk_AeroTable AeroTable - - - "Data table" - +typedef ^ ParameterType LOGICAL UseTSR - .false. - "Use TSR values from table instead of VRel + RtSpd" - typedef ^ ParameterType OutParmType OutParam {:} - - "Names and units (and other characteristics) of all requested output parameters" - # ..... Misc/Optimization variables................................................................................................. diff --git a/modules/aerodisk/src/AeroDisk_Types.f90 b/modules/aerodisk/src/AeroDisk_Types.f90 index e721d09ccc..98a0eb1946 100644 --- a/modules/aerodisk/src/AeroDisk_Types.f90 +++ b/modules/aerodisk/src/AeroDisk_Types.f90 @@ -134,6 +134,7 @@ MODULE AeroDisk_Types INTEGER(IntKi) :: NumOuts !< Number of outputs [-] REAL(ReKi) :: halfRhoA !< half air density times rotor swept area [kg/m] TYPE(ADsk_AeroTable) :: AeroTable !< Data table [-] + LOGICAL :: UseTSR = .false. !< Use TSR values from table instead of VRel + RtSpd [-] TYPE(OutParmType) , DIMENSION(:), ALLOCATABLE :: OutParam !< Names and units (and other characteristics) of all requested output parameters [-] END TYPE ADsk_ParameterType ! ======================= @@ -3148,6 +3149,7 @@ SUBROUTINE ADsk_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg CALL ADsk_Copyaerotable( SrcParamData%AeroTable, DstParamData%AeroTable, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ErrStat>=AbortErrLev) RETURN + DstParamData%UseTSR = SrcParamData%UseTSR IF (ALLOCATED(SrcParamData%OutParam)) THEN i1_l = LBOUND(SrcParamData%OutParam,1) i1_u = UBOUND(SrcParamData%OutParam,1) @@ -3243,6 +3245,7 @@ SUBROUTINE ADsk_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 1 ! UseTSR Int_BufSz = Int_BufSz + 1 ! OutParam allocated yes/no IF ( ALLOCATED(InData%OutParam) ) THEN Int_BufSz = Int_BufSz + 2*1 ! OutParam upper/lower bounds for each dimension @@ -3335,6 +3338,8 @@ SUBROUTINE ADsk_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + IntKiBuf(Int_Xferred) = TRANSFER(InData%UseTSR, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 IF ( .NOT. ALLOCATED(InData%OutParam) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -3459,6 +3464,8 @@ SUBROUTINE ADsk_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + OutData%UseTSR = TRANSFER(IntKiBuf(Int_Xferred), OutData%UseTSR) + Int_Xferred = Int_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! OutParam not allocated Int_Xferred = Int_Xferred + 1 ELSE From 8a1be4d29b59f62f0c09093e0695ac93d2699f05 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 25 Feb 2022 10:03:37 -0700 Subject: [PATCH 026/130] aerodisk: complete Init routine and setting meshes --- modules/aerodisk/src/AeroDisk.f90 | 117 ++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 30 deletions(-) diff --git a/modules/aerodisk/src/AeroDisk.f90 b/modules/aerodisk/src/AeroDisk.f90 index 18d675ca01..b89f3ca2d3 100644 --- a/modules/aerodisk/src/AeroDisk.f90 +++ b/modules/aerodisk/src/AeroDisk.f90 @@ -115,49 +115,106 @@ SUBROUTINE ADsk_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitO CALL ADskInput_SetParameters( InitInp, Interval, InputFileData, p, ErrStat2, ErrMsg2 ) if (Failed()) return; - ! For testing: + ! For diagnostic purposes. If we add a summary file, use this to write table !call WriteAeroTab(p%AeroTable,Cu) - ! Placeholder empty vars for things we don't use, but the framework requires - xd%DummyDiscreteState = 0.0_ReKi - z%DummyConstrState = 0.0_ReKi - OtherState%DummyOtherState = 0.0_IntKi - m%DummyMiscVar = 0.0_IntKi + ! Set inputs + call Init_U(ErrStat2,ErrMsg2); if (Failed()) return -call SetErrStat(ErrID_Fatal,'Need to set inputs and outputs',ErrStat,ErrMsg,RoutineName); return + ! Set outputs + call Init_Y(ErrStat2,ErrMsg2); if (Failed()) return - ! Define initial guess for the system inputs here: -! u%DummyInput = 0.0_ReKi + ! Set InitOutputs + call Init_InitY(ErrStat2,ErrMsg2); if (Failed()) return - ! Define system output initializations (set up mesh) here: - call AllocAry( y%WriteOutput, p%NumOuts, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; - y%WriteOutput = 0 - - ! Define initialization-routine output here: - call AllocAry(InitOut%WriteOutputHdr,p%NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; - call AllocAry(InitOut%WriteOutputUnt,p%NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; - InitOut%WriteOutputHdr = (/ 'Time ', 'Column2' /) - InitOut%WriteOutputUnt = (/ '(s)', '(-)' /) - - -!FIXME: any logic around this? - !Interval = p%DeltaT - - - if (InitInp%Linearize) then - CALL SetErrStat( ErrID_Fatal, 'AeroDisk cannot perform linearization analysis.', ErrStat, ErrMsg, RoutineName) - end if - -call SetErrStat(ErrID_Fatal, 'Stopping early',ErrStat,ErrMsg,RoutineName); return + ! Set some other stuff that the framework requires + call Init_OtherStuff() contains logical function Failed() call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) Failed = ErrStat >= AbortErrLev - !if (Failed) call CleanUp() + if (Failed) call CleanUp() end function Failed + subroutine Cleanup() + if (UnEc > 0_IntKi) close (UnEc) + end subroutine Cleanup + + !> Initialize the inputs in u + subroutine Init_U(ErrStat3,ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 + character(*), intent( out) :: ErrMsg3 + ! HubMotion mesh + call MeshCreate ( BlankMesh = u%HubMotion & + ,IOS = COMPONENT_INPUT & + ,Nnodes = 1 & + ,ErrStat = ErrStat3 & + ,ErrMess = ErrMsg3 & + ,Orientation = .true. & + ,TranslationDisp = .true. & + ,RotationVel = .true. & + ) + if (errStat3 >= AbortErrLev) return + call MeshPositionNode(u%HubMotion, 1, InitInp%HubPosition, errStat3, errMsg3, InitInp%HubOrientation); if (errStat3 >= AbortErrLev) return + call MeshConstructElement( u%HubMotion, ELEMENT_POINT, errStat3, errMsg3, p1=1 ); if (errStat3 >= AbortErrLev) return + call MeshCommit(u%HubMotion, errStat3, errMsg3 ); if (errStat3 >= AbortErrLev) return + u%HubMotion%Orientation = u%HubMotion%RefOrientation + u%HubMotion%TranslationDisp = 0.0_R8Ki + u%HubMotion%RotationVel = 0.0_ReKi + return + end subroutine Init_U + + !> Initialize the outputs in Y + subroutine Init_Y(ErrStat3,ErrMSg3) + integer(IntKi), intent( out) :: ErrStat3 + character(*), intent( out) :: ErrMsg3 + ! Set output loads mesh + call MeshCopy ( SrcMesh = u%HubMotion & + , DestMesh = y%AeroLoads & + , CtrlCode = MESH_SIBLING & + , IOS = COMPONENT_OUTPUT & + , force = .TRUE. & + , moment = .TRUE. & + , ErrStat = ErrStat3 & + , ErrMess = ErrMsg3 ) + if (ErrStat3 >= AbortErrLev) return + + ! Initialize all outputs to zero (will be set by CalcOutput) + y%YawErr = 0.0_ReKi + y%SkewAngle = 0.0_ReKi + y%ChiSkew = 0.0_ReKi + y%VRel = 0.0_ReKi + y%Ct = 0.0_ReKi + y%Cq = 0.0_ReKi + call AllocAry(y%WriteOutput,p%NumOuts,'WriteOutput',Errstat3,ErrMsg3); if (ErrStat3 >= AbortErrLev) return + y%WriteOutput = 0.0_ReKi + end subroutine Init_Y + + !> Initialize other stuff that the framework requires, but isn't used here + subroutine Init_OtherStuff() + ! Placeholder empty vars for things we don't use, but the framework requires + xd%DummyDiscreteState = 0.0_ReKi + z%DummyConstrState = 0.0_ReKi + OtherState%DummyOtherState = 0.0_IntKi + m%DummyMiscVar = 0.0_IntKi + end subroutine Init_OtherStuff + + !> Initialize the InitOutput + subroutine Init_InitY(ErrStat3,ErrMsg3) + integer(IntKi), intent( out) :: ErrStat3 + character(*), intent( out) :: ErrMsg3 + integer(IntKi) :: i + call AllocAry(InitOut%WriteOutputHdr,p%NumOuts,'WriteOutputHdr',ErrStat2,ErrMsg2); if (Failed()) return; + call AllocAry(InitOut%WriteOutputUnt,p%NumOuts,'WriteOutputUnt',ErrStat2,ErrMsg2); if (Failed()) return; + do i=1,p%NumOuts + InitOut%WriteOutputHdr(i) = p%OutParam(i)%Name + InitOut%WriteOutputUnt(i) = p%OutParam(i)%Units + end do + ! Version + InitOut%Ver = ADsk_Ver + end subroutine Init_InitY END SUBROUTINE ADsk_Init From ea3bad8b58d96fe646625e621eb889c6c2344245 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Fri, 25 Feb 2022 10:05:37 -0700 Subject: [PATCH 027/130] aerodisk: update OutlistParameters.xslx to match IO This goes with commit 61e4326ed, but got missed somehow --- docs/OtherSupporting/OutListParameters.xlsx | Bin 566317 -> 568061 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index aeb7f5289c550def616c9b501c5bec5ba2c302f9..e561d3b0a808b008904a018ff767e64c69d7569c 100644 GIT binary patch literal 568061 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
}{ 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 Yg$wt(*Ycy0`9e%^nX55xh~mc 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 z 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