diff --git a/.gitignore b/.gitignore index 02caa69e64..f0568ed816 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,5 @@ # CMake specific files build/**/* -# Visual Studio specific files vs-build -build +build \ No newline at end of file diff --git a/glue-codes/fast/src/FAST_Prog.f90 b/glue-codes/fast/src/FAST_Prog.f90 index 7fd432c8fd..0faba44b58 100644 --- a/glue-codes/fast/src/FAST_Prog.f90 +++ b/glue-codes/fast/src/FAST_Prog.f90 @@ -56,7 +56,7 @@ PROGRAM FAST CHARACTER(1024) :: CheckpointRoot ! Rootname of the checkpoint file CHARACTER(20) :: FlagArg ! flag argument from command line INTEGER(IntKi) :: Restart_step ! step to start on (for restart) - +INTEGER(IntKi) :: UnErrLog ! File unit for error log file !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! determine if this is a restart from checkpoint @@ -64,6 +64,19 @@ PROGRAM FAST CALL NWTC_Init() ! open console for writing ProgName = 'FAST' CheckpointRoot = "" + +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +! BEGIN: Draft Code for generating parsable error reporting for automated testing +! + ! Open error report log file + UnErrLog = -1 + CALL GetNewUnit( UnErrLog, ErrStat, ErrMsg ) + CALL OpenFOutfile ( UnErrLog, 'OpenFastErr.log', ErrStat, ErrMsg ) + WRITE (UnErrLog,'(A)') '' +! +! END : Draft Code for generating parsable error reporting for automated testing +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + CALL CheckArgs( CheckpointRoot, ErrStat, Flag=FlagArg ) ! if ErrStat /= ErrID_None, we'll ignore and deal with the problem when we try to read the input file IF ( TRIM(FlagArg) == 'RESTART' ) THEN ! Restart from checkpoint file @@ -144,6 +157,7 @@ PROGRAM FAST END DO ! n_t_global + IF (UnErrLog > 0) CLOSE(UnErrLog) !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! Write simulation times and stop @@ -171,8 +185,12 @@ SUBROUTINE CheckError(ErrID,Msg,ErrLocMsg) IF ( ErrID /= ErrID_None ) THEN CALL WrScr( NewLine//TRIM(Msg)//NewLine ) + IF (UnErrLog > 0) THEN + WRITE (UnErrLog,'(/,A)') TRIM(Num2LStr(ErrID))//': '//Msg + END IF + IF ( ErrID >= AbortErrLev ) THEN - + IF (UnErrLog > 0) CLOSE(UnErrLog) IF (PRESENT(ErrLocMsg)) THEN SimMsg = ErrLocMsg ELSE diff --git a/modules-local/aerodyn/src/AeroDyn.f90 b/modules-local/aerodyn/src/AeroDyn.f90 index 4f882841fb..7a285095ae 100644 --- a/modules-local/aerodyn/src/AeroDyn.f90 +++ b/modules-local/aerodyn/src/AeroDyn.f90 @@ -1372,6 +1372,8 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%AllOuts( BPitch( k) ) = -theta(3)*R2D ! save this value of pitch for potential output #endif theta(3) = 0.0_ReKi + m%hub_theta_x_root(k) = theta(1) ! save this value for FAST.Farm + orientation = EulerConstruct( theta ) orientation_nopitch = matmul( orientation, u%HubMotion%Orientation(:,:,1) ) ! withoutPitch_theta_Root(k) @@ -2114,7 +2116,7 @@ SUBROUTINE getLocalTowerProps(p, u, BladeNodePosition, theta_tower_trans, W_towe TwrClrnc = TwoNorm(r_TowerBlade) - 0.5_ReKi*TwrDiam if ( TwrClrnc <= 0.0_ReKi ) then - call SetErrStat(ErrID_Severe, "Tower strike.", ErrStat, ErrMsg, RoutineName) + call SetErrStat(ErrID_Fatal, "Tower strike.", ErrStat, ErrMsg, RoutineName) end if diff --git a/modules-local/aerodyn/src/AeroDyn_Registry.txt b/modules-local/aerodyn/src/AeroDyn_Registry.txt index 05a0c5c0c8..79510a1cca 100644 --- a/modules-local/aerodyn/src/AeroDyn_Registry.txt +++ b/modules-local/aerodyn/src/AeroDyn_Registry.txt @@ -138,6 +138,7 @@ typedef ^ MiscVarType ReKi X {:}{:} - - "normal force per unit length (normal to typedef ^ MiscVarType ReKi Y {:}{:} - - "tangential force per unit length (tangential to the plane, not chord) of the jth node in the kth blade" N/m typedef ^ MiscVarType ReKi M {:}{:} - - "pitching moment per unit length of the jth node in the kth blade" Nm/m typedef ^ MiscVarType ReKi V_DiskAvg {3} - - "disk-average relative wind speed" m/s +typedef ^ MiscVarType ReKi hub_theta_x_root {3} - - "angles saved for FAST.Farm" rad typedef ^ MiscVarType ReKi V_dot_x - - - typedef ^ MiscVarType MeshType HubLoad - - - "mesh at hub; used to compute an integral for mapping the output blade loads to a single point (for writing to file only)" - typedef ^ MiscVarType MeshMapType B_L_2_H_P {:} - - "mapping data structure to map each bladeLoad output mesh to the MiscVar%HubLoad mesh" diff --git a/modules-local/aerodyn14/src/DWM.f90 b/modules-local/aerodyn14/src/DWM.f90 index 248f2571c5..d5ba83a0a0 100644 --- a/modules-local/aerodyn14/src/DWM.f90 +++ b/modules-local/aerodyn14/src/DWM.f90 @@ -79,6 +79,7 @@ SUBROUTINE DWM_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOu InitInp%IfW%UseInputFile = .TRUE. InitInp%IfW%NumWindPoints = 1 InitInp%IfW%lidar%SensorType = SensorType_None + InitInp%IfW%Use4Dext = .false. CALL InflowWind_Init( InitInp%IfW, u%IfW, p%IfW, x%IfW, xd%IfW, z%IfW, OtherState%IfW, y%IfW, m%IfW, & Interval, InitOut%IfW, ErrStat, ErrMess ) diff --git a/modules-local/beamdyn/src/BeamDyn.f90 b/modules-local/beamdyn/src/BeamDyn.f90 index 773efaaa2c..130a42bd89 100644 --- a/modules-local/beamdyn/src/BeamDyn.f90 +++ b/modules-local/beamdyn/src/BeamDyn.f90 @@ -440,6 +440,9 @@ subroutine InitializeNodalLocations(InputFileData,p,SP_Coef,GLL_nodes,ErrStat, E character(ErrMsgLen) :: ErrMsg2 ! temporary Error message character(*), parameter :: RoutineName = 'InitGaussPoints' + ErrStat = ErrID_None + ErrMsg = "" + !------------------------------------------------- ! p%uuN0 contains the initial (physical) positions and orientations of the (output) GLL nodes !------------------------------------------------- @@ -711,7 +714,7 @@ subroutine SetParameters(InitInp, InputFileData, SP_Coef, p, ErrStat, ErrMsg) p%ngp = p%node_elem !- 1 ELSEIF(p%quadrature .EQ. TRAP_QUADRATURE) THEN p%refine = InputFileData%refine - p%ngp = (InputFileData%kp_member(1) - 1)*p%refine + 1 + p%ngp = (InputFileData%InpBl%station_total - 1)*p%refine + 1 ENDIF ! Degree-of-freedom (DoF) per node diff --git a/modules-local/beamdyn/src/BeamDyn_Subs.f90 b/modules-local/beamdyn/src/BeamDyn_Subs.f90 index 02a86fb740..d9c030968d 100644 --- a/modules-local/beamdyn/src/BeamDyn_Subs.f90 +++ b/modules-local/beamdyn/src/BeamDyn_Subs.f90 @@ -443,7 +443,7 @@ SUBROUTINE BD_TrapezoidalPointWeight(p, InputFileData) ! compute the trapezoidal quadrature weights, p%GLw: - id1 = InputFileData%kp_member(1) !adp: Why is this only checking the first member (size(kp_member) will be number of GL points)???? + id1 = InputFileData%InpBl%station_total temp_id0 = (id0 - 1)*p%refine + 1 ! Starting index in GL --> always going to be 1 temp_id1 = (id1 - 1)*p%refine + 1 ! ending index in GL --> will be size(p%GL) denom = p%GL(temp_id1) - p%GL(temp_id0) ! This is the range of GL --> for single member, is always == 2 diff --git a/modules-local/elastodyn/src/ElastoDyn.f90 b/modules-local/elastodyn/src/ElastoDyn.f90 index eecfe3708f..25565ea441 100644 --- a/modules-local/elastodyn/src/ElastoDyn.f90 +++ b/modules-local/elastodyn/src/ElastoDyn.f90 @@ -3510,8 +3510,14 @@ SUBROUTINE SetPrimaryParameters( p, InputFileData, ErrStat, ErrMsg ) p%CosPreC = COS( InputFileData%Precone(1:p%NumBl) ) p%SinPreC = SIN( InputFileData%Precone(1:p%NumBl) ) - p%CosDel3 = COS( InputFileData%Delta3 ) - p%SinDel3 = SIN( InputFileData%Delta3 ) + + IF ( p%NumBl == 2 ) THEN + p%CosDel3 = COS( InputFileData%Delta3 ) + p%SinDel3 = SIN( InputFileData%Delta3 ) + ELSE + p%CosDel3 = 1.0_ReKi + p%SinDel3 = 0.0_ReKi + END IF !............................................................................................................................... @@ -8706,7 +8712,7 @@ SUBROUTINE ED_AllocOutput( p, m, u, y, ErrStat, ErrMsg ) !....................................................... CALL MeshCreate( BlankMesh = y%TowerLn2Mesh & - , IOS = COMPONENT_OUTPUT & + , IOS = COMPONENT_OUTPUT & , NNodes = p%TwrNodes + 2 & , TranslationDisp = .TRUE. & , Orientation = .TRUE. & diff --git a/modules-local/fast-library/src/FAST_Registry.txt b/modules-local/fast-library/src/FAST_Registry.txt index eede5384ee..ca0ca7f214 100644 --- a/modules-local/fast-library/src/FAST_Registry.txt +++ b/modules-local/fast-library/src/FAST_Registry.txt @@ -112,6 +112,7 @@ typedef ^ FAST_ParameterType CHARACTER(1024) IceFile - - - "Name of file contain #typedef ^ FAST_ParameterType DbKi SttsTime - - - "Amount of time between screen status messages" s typedef ^ FAST_ParameterType DbKi TStart - - - "Time to begin tabular output" s typedef ^ FAST_ParameterType DbKi DT_Out - - - "Time step for tabular output" s +typedef ^ FAST_ParameterType LOGICAL WrSttsTime - - - "Whether we should write the status times to the screen" - typedef ^ FAST_ParameterType INTEGER n_SttsTime - - - "Number of time steps between screen status messages" - typedef ^ FAST_ParameterType INTEGER n_ChkptTime - - - "Number of time steps between writing checkpoint files" - typedef ^ FAST_ParameterType INTEGER n_VTKTime - - - "Number of time steps between writing VTK files" - @@ -140,6 +141,7 @@ typedef ^ FAST_ParameterType IntKi SizeLin {NumModules+1}{3} - - "dimension 1 is typedef ^ FAST_ParameterType IntKi LinStartIndx {NumModules}{3} - - "dimension 1 is the module ID: dimension 2 is the starting index in combined matrices of (1) the module's inputs, (2) the module's linearized outputs, and (3) the module's continuous states" - typedef ^ FAST_ParameterType IntKi Lin_NumMods - - - "number of modules in the linearization" typedef ^ FAST_ParameterType Integer Lin_ModOrder {NumModules} - - "indices that determine which order the modules are in the glue-code linearization matrix" +typedef ^ FAST_ParameterType CHARACTER(4) Tdesc - - - "description of turbine ID (for FAST.Farm) screen printing" # ..... FAST_LinType data ....................................................................................................... typedef FAST FAST_LinType CHARACTER(LinChanLen) Names_u {:} - - "Names of the linearized inputs" @@ -477,10 +479,15 @@ typedef ^ FAST_MiscVarType INTEGER NextLinTimeIndx - - - "index for next time in typedef ^ FAST_ExternInitType DbKi Tmax - -1 - "External code specified Tmax" s typedef ^ FAST_ExternInitType IntKi SensorType - SensorType_None - "lidar sensor type, which should not be pulsed at the moment; this input should be replaced with a section in the InflowWind input file" - typedef ^ FAST_ExternInitType LOGICAL LidRadialVel - - - "TRUE => return radial component, FALSE => return 'x' direction estimate" - -typedef ^ FAST_ExternInitType IntKi TurbineID - - - "ID number for turbine (used to create output file naming convention)" - +typedef ^ FAST_ExternInitType IntKi TurbineID - 0 - "ID number for turbine (used to create output file naming convention)" - typedef ^ FAST_ExternInitType ReKi TurbinePos {3} - - "Initial position of turbine base (origin used in future for graphics)" m typedef ^ FAST_ExternInitType IntKi NumSC2Ctrl - - - "number of controller inputs [from supercontroller]" - typedef ^ FAST_ExternInitType IntKi NumCtrl2SC - - - "number of controller outputs [to supercontroller]" - +typedef ^ FAST_ExternInitType logical FarmIntegration - .false. - "whether this is called from FAST.Farm (or another program that doesn't want FAST to call all of the init stuff first)" - +typedef ^ FAST_ExternInitType IntKi windGrid_n 4 - - "number of grid points in the x, y, z, and t directions for IfW" - +typedef ^ FAST_ExternInitType ReKi windGrid_delta 4 - - "size between 2 consecutive grid points in each grid direction for IfW" "m,m,m,s" +typedef ^ FAST_ExternInitType ReKi windGrid_pZero 3 - - "fixed position of the XYZ grid (i.e., XYZ coordinates of IfW m%V(:,1,1,1,:))" m +typedef ^ FAST_ExternInitType CHARACTER(1024) RootName - - - "Root name of FAST output files (overrides normal operation)" - typedef ^ FAST_ExternInitType IntKi NumActForcePtsBlade - - - "number of actuator line force points in blade" - typedef ^ FAST_ExternInitType IntKi NumActForcePtsTower - - - "number of actuator line force points in tower" - diff --git a/modules-local/fast-library/src/FAST_Solver.f90 b/modules-local/fast-library/src/FAST_Solver.f90 index f3ba97e0e4..dd1b648bc0 100644 --- a/modules-local/fast-library/src/FAST_Solver.f90 +++ b/modules-local/fast-library/src/FAST_Solver.f90 @@ -63,7 +63,7 @@ SUBROUTINE BD_InputSolve( p_FAST, BD, y_AD, u_AD, MeshMapData, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BD Inputs at t TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs - TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-BD load transfer) + TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD inputs (for AD-BD load transfer) TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status @@ -123,7 +123,7 @@ SUBROUTINE ED_InputSolve( p_FAST, u_ED, y_ED, p_AD14, y_AD14, y_AD, y_SrvD, u_AD TYPE(AD14_ParameterType), INTENT(IN ) :: p_AD14 !< AeroDyn14 parameters (a hack because the AD14 meshes aren't set up properly) TYPE(AD14_OutputType), INTENT(IN ) :: y_AD14 !< AeroDyn14 outputs TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs - TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load transfer) + TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD inputs (for AD-ED load transfer) TYPE(SrvD_OutputType), INTENT(IN ) :: y_SrvD !< ServoDyn outputs TYPE(SrvD_InputType), INTENT(IN ) :: u_SrvD !< ServoDyn inputs diff --git a/modules-local/fast-library/src/FAST_Subs.f90 b/modules-local/fast-library/src/FAST_Subs.f90 index 1323c025e4..d9f14c1f33 100644 --- a/modules-local/fast-library/src/FAST_Subs.f90 +++ b/modules-local/fast-library/src/FAST_Subs.f90 @@ -168,6 +168,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, INTEGER(IntKi) :: IceDim ! dimension we're pre-allocating for number of IceDyn legs/instances INTEGER(IntKi) :: I ! generic loop counter INTEGER(IntKi) :: k ! blade loop counter + logical :: CallStart CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -196,16 +197,29 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, m_FAST%UsrTime1 = MAX( 0.0_ReKi, m_FAST%UsrTime1 ) ! CPU_TIME: If a meaningful time cannot be returned, a processor-dependent negative value is returned - AbortErrLev = ErrID_Fatal ! Until we read otherwise from the FAST input file, we abort only on FATAL errors m_FAST%t_global = t_initial - 20. ! initialize this to a number < t_initial for error message in ProgAbort m_FAST%calcJacobian = .TRUE. ! we need to calculate the Jacobian m_FAST%NextJacCalcTime = m_FAST%t_global ! We want to calculate the Jacobian on the first step - + p_FAST%TDesc = '' + + if (present(ExternInitData)) then + CallStart = .not. ExternInitData%FarmIntegration ! .and. ExternInitData%TurbineID == 1 + if (ExternInitData%TurbineID > 0) p_FAST%TDesc = 'T'//trim(num2lstr(ExternInitData%TurbineID)) + else + CallStart = .true. + end if + ! Init NWTC_Library, display copyright and version information: - CALL FAST_ProgStart( FAST_Ver ) - !call DispNVD( FAST_Ver ) - + if (CallStart) then + AbortErrLev = ErrID_Fatal ! Until we read otherwise from the FAST input file, we abort only on FATAL errors + CALL FAST_ProgStart( FAST_Ver ) + p_FAST%WrSttsTime = .TRUE. + else + ! if we don't call the start data (e.g., from FAST.Farm), we won't override AbortErrLev either + CALL DispNVD( FAST_Ver ) + p_FAST%WrSttsTime = .FALSE. + end if IF (PRESENT(InFile)) THEN p_FAST%UseDWM = .FALSE. @@ -223,7 +237,13 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! also, set turbine reference position for graphics output if (PRESENT(ExternInitData)) then p_FAST%TurbinePos = ExternInitData%TurbinePos - CALL FAST_Init( p_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, ExternInitData%TurbineID ) ! We have the name of the input file and the simulation length from somewhere else (e.g. Simulink) + + if (ExternInitData%FarmIntegration) then ! we're integrating with FAST.Farm + CALL FAST_Init( p_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, OverrideAbortLev=.false., RootName=ExternInitData%RootName ) + else + CALL FAST_Init( p_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2, ExternInitData%TMax, ExternInitData%TurbineID ) ! We have the name of the input file and the simulation length from somewhere else (e.g. Simulink) + end if + else p_FAST%TurbinePos = 0.0_ReKi CALL FAST_Init( p_FAST, y_FAST, t_initial, InputFile, ErrStat2, ErrMsg2 ) ! We have the name of the input file from somewhere else (e.g. Simulink) @@ -386,7 +406,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, CALL Cleanup() RETURN END IF - + ALLOCATE( AD%Input( p_FAST%InterpOrder+1 ), AD%InputTimes( p_FAST%InterpOrder+1 ), STAT = ErrStat2 ) IF (ErrStat2 /= 0) THEN CALL SetErrStat(ErrID_Fatal,"Error allocating AD%Input and AD%InputTimes.",ErrStat,ErrMsg,RoutineName) @@ -505,14 +525,23 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! lidar InitInData_IfW%lidar%Tmax = p_FAST%TMax InitInData_IfW%lidar%HubPosition = ED%Output(1)%HubPtMotion%Position(:,1) - ! bjj: these should come from an InflowWind input file; I'm hard coding them here for now IF ( PRESENT(ExternInitData) ) THEN + InitInData_IfW%Use4Dext = ExternInitData%FarmIntegration + + if (InitInData_IfW%Use4Dext) then + InitInData_IfW%FDext%n = ExternInitData%windGrid_n + InitInData_IfW%FDext%delta = ExternInitData%windGrid_delta + InitInData_IfW%FDext%pZero = ExternInitData%windGrid_pZero + end if + + ! bjj: these lidar inputs should come from an InflowWind input file; I'm hard coding them here for now InitInData_IfW%lidar%SensorType = ExternInitData%SensorType InitInData_IfW%lidar%LidRadialVel = ExternInitData%LidRadialVel InitInData_IfW%lidar%RotorApexOffsetPos = 0.0 InitInData_IfW%lidar%NumPulseGate = 0 ELSE InitInData_IfW%lidar%SensorType = SensorType_None + InitInData_IfW%Use4Dext = .false. END IF CALL InflowWind_Init( InitInData_IfW, IfW%Input(1), IfW%p, IfW%x(STATE_CURR), IfW%xd(STATE_CURR), IfW%z(STATE_CURR), & @@ -1339,7 +1368,7 @@ END SUBROUTINE GetInputFileName !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine checks for command-line arguments, gets the root name of the input files !! (including full path name), and creates the names of the output files. -SUBROUTINE FAST_Init( p, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, TMax, TurbID ) +SUBROUTINE FAST_Init( p, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, TMax, TurbID, OverrideAbortLev, RootName ) IMPLICIT NONE @@ -1351,14 +1380,17 @@ SUBROUTINE FAST_Init( p, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, TMax, Tu INTEGER(IntKi), INTENT(OUT) :: ErrStat !< Error status CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message CHARACTER(*), INTENT(IN) :: InputFile !< A CHARACTER string containing the name of the primary FAST input file (if not present, we'll get it from the command line) - REAL(DbKi), INTENT(IN), OPTIONAL :: TMax !< the length of the simulation (from Simulink) + REAL(DbKi), INTENT(IN), OPTIONAL :: TMax !< the length of the simulation (from Simulink or FAST.Farm) INTEGER(IntKi), INTENT(IN), OPTIONAL :: TurbID !< an ID for naming the tubine output file + LOGICAL, INTENT(IN), OPTIONAL :: OverrideAbortLev !< whether or not we should override the abort error level (e.g., FAST.Farm) + CHARACTER(*), INTENT(IN), OPTIONAL :: RootName !< A CHARACTER string containing the root name of FAST output files, overriding normal naming convention ! Local variables INTEGER :: i ! loop counter !CHARACTER(1024) :: DirName ! A CHARACTER string containing the path of the current working directory + LOGICAL :: OverrideAbortErrLev CHARACTER(*), PARAMETER :: RoutineName = "FAST_Init" INTEGER(IntKi) :: ErrStat2 @@ -1367,22 +1399,33 @@ SUBROUTINE FAST_Init( p, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, TMax, Tu ! Initialize some variables ErrStat = ErrID_None ErrMsg = '' + + IF (PRESENT(OverrideAbortLev)) THEN + OverrideAbortErrLev = OverrideAbortLev + ELSE + OverrideAbortErrLev = .true. + END IF + !............................................................................................................................... ! Set the root name of the output files based on the input file name !............................................................................................................................... - - ! Determine the root name of the primary file (will be used for output files) - CALL GetRoot( InputFile, p%OutFileRoot ) - IF ( Cmpl4SFun ) p%OutFileRoot = TRIM( p%OutFileRoot )//'.SFunc' - IF ( PRESENT(TurbID) ) THEN - IF ( TurbID > 0 ) THEN - p%OutFileRoot = TRIM( p%OutFileRoot )//'.T'//TRIM(Num2LStr(TurbID)) + + if (present(RootName)) then + p%OutFileRoot = RootName + else + ! Determine the root name of the primary file (will be used for output files) + CALL GetRoot( InputFile, p%OutFileRoot ) + IF ( Cmpl4SFun ) p%OutFileRoot = TRIM( p%OutFileRoot )//'.SFunc' + IF ( PRESENT(TurbID) ) THEN + IF ( TurbID > 0 ) THEN + p%OutFileRoot = TRIM( p%OutFileRoot )//'.T'//TRIM(Num2LStr(TurbID)) + END IF END IF - END IF - + end if + !............................................................................................................................... ! Initialize the module name/date/version info: @@ -1431,12 +1474,13 @@ SUBROUTINE FAST_Init( p, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, TMax, Tu !............................................................................................................................... ! Read the primary file for the glue code: !............................................................................................................................... - CALL FAST_ReadPrimaryFile( InputFile, p, ErrStat2, ErrMsg2 ) + CALL FAST_ReadPrimaryFile( InputFile, p, OverrideAbortErrLev, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! overwrite TMax if necessary) IF (PRESENT(TMax)) THEN - p%TMax = MAX( TMax, p%TMax ) + p%TMax = TMax + !p%TMax = MAX( TMax, p%TMax ) END IF IF ( ErrStat >= AbortErrLev ) RETURN @@ -1991,13 +2035,14 @@ END SUBROUTINE FAST_InitOutput !---------------------------------------------------------------------------------------------------------------------------------- !> This routine reads in the primary FAST input file, does some validation, and places the values it reads in the !! parameter structure (p). It prints to an echo file if requested. -SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, ErrStat, ErrMsg ) +SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, OverrideAbortErrLev, ErrStat, ErrMsg ) IMPLICIT NONE ! Passed variables TYPE(FAST_ParameterType), INTENT(INOUT) :: p !< The parameter data for the FAST (glue-code) simulation CHARACTER(*), INTENT(IN) :: InputFile !< Name of the file containing the primary input data + LOGICAL, INTENT(IN) :: OverrideAbortErrLev !< Determines if we should override AbortErrLev INTEGER(IntKi), INTENT(OUT) :: ErrStat !< Error status CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message @@ -2124,22 +2169,24 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, ErrStat, ErrMsg ) RETURN end if + IF (OverrideAbortErrLev) THEN ! Let's set the abort level here.... knowing that everything before this aborted only on FATAL errors! - CALL Conv2UC( AbortLevel ) !convert to upper case - SELECT CASE( TRIM(AbortLevel) ) - CASE ( "WARNING" ) - AbortErrLev = ErrID_Warn - CASE ( "SEVERE" ) - AbortErrLev = ErrID_Severe - CASE ( "FATAL" ) - AbortErrLev = ErrID_Fatal - CASE DEFAULT - CALL SetErrStat( ErrID_Fatal, 'Invalid AbortLevel specified in FAST input file. '// & - 'Valid entries are "WARNING", "SEVERE", or "FATAL".',ErrStat,ErrMsg,RoutineName) - call cleanup() - RETURN - END SELECT - + CALL Conv2UC( AbortLevel ) !convert to upper case + SELECT CASE( TRIM(AbortLevel) ) + CASE ( "WARNING" ) + AbortErrLev = ErrID_Warn + CASE ( "SEVERE" ) + AbortErrLev = ErrID_Severe + CASE ( "FATAL" ) + AbortErrLev = ErrID_Fatal + CASE DEFAULT + CALL SetErrStat( ErrID_Fatal, 'Invalid AbortLevel specified in FAST input file. '// & + 'Valid entries are "WARNING", "SEVERE", or "FATAL".',ErrStat,ErrMsg,RoutineName) + call cleanup() + RETURN + END SELECT + END IF + ! TMax - Total run time (s): CALL ReadVar( UnIn, InputFile, p%TMax, "TMax", "Total run time (s)", ErrStat2, ErrMsg2, UnEc) @@ -3119,7 +3166,7 @@ SUBROUTINE WrVTK_Ground ( RefPoint, HalfLengths, FileRootName, ErrStat, ErrMsg ) ! write the data that potentially changes each time step: !................................................................. - ! PolyData (.vtp) � Serial vtkPolyData (unstructured) file + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) file FileName = TRIM(FileRootName)//'.vtp' call WrVTK_header( FileName, NumberOfPoints, NumberOfLines, NumberOfPolys, Un, ErrStat2, ErrMsg2 ) @@ -3243,7 +3290,7 @@ SUBROUTINE AD_SetInitInput(InitInData_AD14, InitOutData_ED, y_ED, p_FAST, ErrSta RETURN END SUBROUTINE AD_SetInitInput !---------------------------------------------------------------------------------------------------------------------------------- -!> This module sets the number of subcycles (substeps) for modules at initialization, checking to make sure that their requested +!> This routine sets the number of subcycles (substeps) for modules at initialization, checking to make sure that their requested !! time step is valid. SUBROUTINE SetModuleSubstepTime(ModuleID, p_FAST, y_FAST, ErrStat, ErrMsg) INTEGER(IntKi), INTENT(IN ) :: ModuleID !< ID of the module to check time step and set @@ -3579,8 +3626,10 @@ SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, O ErrStat = ErrID_None ErrMsg = "" + IF (p_FAST%WrSttsTime) then + CALL SimStatus_FirstTime( m_FAST%TiLstPrn, m_FAST%PrevClockTime, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global, p_FAST%TMax, p_FAST%TDesc ) + END IF - CALL SimStatus_FirstTime( m_FAST%TiLstPrn, m_FAST%PrevClockTime, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global, p_FAST%TMax ) ! Solve input-output relations; this section of code corresponds to Eq. (35) in Gasmi et al. (2013) ! This code will be specific to the underlying modules @@ -4450,13 +4499,15 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, !! Display simulation status every SttsTime-seconds (i.e., n_SttsTime steps): !---------------------------------------------------------------------------------------- - IF ( MOD( n_t_global + 1, p_FAST%n_SttsTime ) == 0 ) THEN + IF (p_FAST%WrSttsTime) then + IF ( MOD( n_t_global + 1, p_FAST%n_SttsTime ) == 0 ) THEN - if (.not. Cmpl4SFun) then - CALL SimStatus( m_FAST%TiLstPrn, m_FAST%PrevClockTime, m_FAST%t_global, p_FAST%TMax ) - end if + if (.not. Cmpl4SFun) then + CALL SimStatus( m_FAST%TiLstPrn, m_FAST%PrevClockTime, m_FAST%t_global, p_FAST%TMax, p_FAST%TDesc ) + end if - ENDIF + ENDIF + ENDIF END SUBROUTINE FAST_Solution !---------------------------------------------------------------------------------------------------------------------------------- @@ -4611,7 +4662,9 @@ SUBROUTINE WrOutputLine( t, p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, ADO ! Write data to array for binary output file IF ( y_FAST%n_Out == y_FAST%NOutSteps ) THEN - CALL ProgWarn( 'Not all data could be written to the binary output file.' ) + ErrStat = ErrID_Warn + ErrMsg = 'Not all data could be written to the binary output file.' + !CALL ProgWarn( 'Not all data could be written to the binary output file.' ) !this really would only happen if we have an error somewhere else, right? !otherwise, we could allocate a new, larger array and move existing data ELSE @@ -4799,11 +4852,12 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD14, AD, IfW, O CHARACTER(ErrMsgLen) :: ErrMSg2 CHARACTER(*), PARAMETER :: RoutineName = 'WrVTK_AllMeshes' + NumBl = 0 if (allocated(ED%Output)) then if (allocated(ED%Output(1)%BladeRootMotion)) then NumBl = SIZE(ED%Output(1)%BladeRootMotion) - end if + end if end if @@ -5226,7 +5280,7 @@ SUBROUTINE WrVTK_WaveElev(t_global, p_FAST, y_FAST, HD) ! write the data that potentially changes each time step: !................................................................. - ! PolyData (.vtp) � Serial vtkPolyData (unstructured) file + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) file FileName = TRIM(p_FAST%OutFileRoot)//'.WaveSurface.t'//TRIM(Num2LStr(y_FAST%VTK_count))//'.vtp' call WrVTK_header( FileName, NumberOfPoints, NumberOfLines, NumberOfPolys, Un, ErrStat2, ErrMsg2 ) @@ -5725,7 +5779,10 @@ SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ! Write simulation times and stop !............................................................................................................................ - CALL RunTimes( m_FAST%StrtTime, m_FAST%UsrTime1, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global ) + IF (p_FAST%WrSttsTime) THEN + CALL RunTimes( m_FAST%StrtTime, m_FAST%UsrTime1, m_FAST%SimStrtTime, m_FAST%UsrTime2, m_FAST%t_global, DescStrIn=p_FAST%TDesc ) + END IF + if (StopTheProgram) then #if (defined COMPILE_SIMULINK || defined COMPILE_LABVIEW) diff --git a/modules-local/fast-library/src/RegistryEntries.xlsx b/modules-local/fast-library/src/RegistryEntries.xlsx index f5af12c819..814810aff7 100644 Binary files a/modules-local/fast-library/src/RegistryEntries.xlsx and b/modules-local/fast-library/src/RegistryEntries.xlsx differ diff --git a/modules-local/fast-registry/src/gen_module_files.c b/modules-local/fast-registry/src/gen_module_files.c index 540b26949d..29a10ffc02 100644 --- a/modules-local/fast-registry/src/gen_module_files.c +++ b/modules-local/fast-registry/src/gen_module_files.c @@ -605,7 +605,6 @@ gen_unpack( FILE * fp, const node_t * ModName, char * inout, char * inoutlong ) fprintf(fp," LOGICAL, ALLOCATABLE :: mask3(:,:,:)\n") ; fprintf(fp," LOGICAL, ALLOCATABLE :: mask4(:,:,:,:)\n") ; fprintf(fp," LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:)\n") ; - fprintf(fp," LOGICAL, ALLOCATABLE :: mask6(:,:,:,:,:,:)\n"); for (d = 1; d <= q->max_ndims; d++){ fprintf(fp," INTEGER(IntKi) :: i%d, i%d_l, i%d_u ! bounds (upper/lower) for an array dimension %d\n", d, d, d, d); } diff --git a/modules-local/hydrodyn/src/HydroDyn.f90 b/modules-local/hydrodyn/src/HydroDyn.f90 index 517643d4ac..61c60f819b 100644 --- a/modules-local/hydrodyn/src/HydroDyn.f90 +++ b/modules-local/hydrodyn/src/HydroDyn.f90 @@ -544,6 +544,7 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I END IF WaveElevSt = Waves_InitOut%WaveElev + ! We need to reset the wave elevation arrays DEALLOCATE(InitLocal%Waves%WaveElevxi) DEALLOCATE(InitLocal%Waves%WaveElevyi) diff --git a/modules-local/inflowwind/src/IfW_UserWind.f90 b/modules-local/inflowwind/src/IfW_UserWind.f90 index c2f4e9aeba..406b957c8d 100644 --- a/modules-local/inflowwind/src/IfW_UserWind.f90 +++ b/modules-local/inflowwind/src/IfW_UserWind.f90 @@ -102,7 +102,7 @@ SUBROUTINE IfW_UserWind_Init(InitData, ParamData, MiscVars, Interval, InitOutDat ! Copy things from the InitData to the ParamData. If you need to store it for later calculations, ! copy it over now. !------------------------------------------------------------------------------------------------- - + ParamData%dummy = 0 ! ParamData%RefHt = InitData%ReferenceHeight ! ParamData%RefLength = InitData%RefLength diff --git a/modules-local/inflowwind/src/InflowWind.f90 b/modules-local/inflowwind/src/InflowWind.f90 index 6a187670ef..1befc90772 100644 --- a/modules-local/inflowwind/src/InflowWind.f90 +++ b/modules-local/inflowwind/src/InflowWind.f90 @@ -43,26 +43,12 @@ MODULE InflowWind USE InflowWind_Types USE NWTC_Library USE InflowWind_Subs - - !------------------------------------------------------------------------------------------------- - ! The included wind modules (TYPES modules are inherited from InflowWind_Types, so not specified here again.) - !------------------------------------------------------------------------------------------------- - USE Lidar ! module for obtaining sensor data - - USE IfW_UniformWind ! uniform wind files (text files) - USE IfW_TSFFWind ! TurbSim style full-field binary wind files - USE IfW_BladedFFWind ! Bladed style full-field binary wind files - USE IfW_UserWind ! User-defined wind module - USE IfW_HAWCWind ! full-field binary wind files in HAWC format - -!!! USE FDWind ! 4-D binary wind files -!!! USE CTWind ! coherent turbulence from KH billow - binary file superimposed on another wind type - + USE Lidar IMPLICIT NONE PRIVATE - TYPE(ProgDesc), PARAMETER :: IfW_Ver = ProgDesc( 'InflowWind', 'v3.03.00', '26-Jul-2016' ) + TYPE(ProgDesc), PARAMETER :: IfW_Ver = ProgDesc( 'InflowWind', 'v3.04.00', '31-Dec-2016' ) @@ -151,6 +137,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, TYPE(IfW_UserWind_InitInputType) :: User_InitData !< initialization info TYPE(IfW_UserWind_InitOutputType) :: User_InitOutData !< initialization info + TYPE(IfW_4Dext_InitOutputType) :: FDext_InitOutData !< initialization info !!! TYPE(CTBladed_Backgr) :: BackGrndValues @@ -214,13 +201,18 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ELSE - !bjj: this is basically all it would take, no? CALL InflowWind_CopyInputFile( InitInp%PassedFileData, InputFileData, MESH_NEWCOPY, TmpErrStat, TmpErrMsg ) CALL SetErrStat(TmpErrStat,TmpErrMsg,ErrStat,ErrMsg,RoutineName) ENDIF - + ! let's tell InflowWind if an external module (e.g., FAST.Farm) is going to set the velocity grids. + IF ( InitInp%Use4Dext) then + InputFileData%WindType = FDext_WindNumber + InputFileData%PropagationDir = 0.0_ReKi ! wind is in XYZ coordinates (already rotated if necessary), so don't rotate it again + END IF + + ! initialize sensor data: CALL Lidar_Init( InitInp, InputGuess, p, ContStates, DiscStates, ConstrStateGuess, OtherStates, & y, m, TimeInterval, InitOutData, TmpErrStat, TmpErrMsg ) @@ -287,6 +279,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, InitOutData%WindFileInfo%MWS = HUGE(InitOutData%WindFileInfo%MWS) + InitOutData%WindFileInfo%WindType = p%WindType SELECT CASE ( p%WindType ) @@ -352,7 +345,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ! Store wind file metadata InitOutData%WindFileInfo%FileName = "" - InitOutData%WindFileInfo%WindType = Steady_WindNumber InitOutData%WindFileInfo%RefHt = InputFileData%Steady_RefHt InitOutData%WindFileInfo%RefHt_Set = .FALSE. ! The wind file does not set this InitOutData%WindFileInfo%DT = 0.0_ReKi @@ -405,7 +397,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ! Store wind file metadata InitOutData%WindFileInfo%FileName = InputFileData%Uniform_FileName - InitOutData%WindFileInfo%WindType = Uniform_WindNumber InitOutData%WindFileInfo%RefHt = p%UniformWind%RefHt InitOutData%WindFileInfo%RefHt_Set = .FALSE. ! The wind file does not set this InitOutData%WindFileInfo%DT = Uniform_InitOutData%WindFileDT @@ -462,7 +453,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ! Store wind file metadata InitOutData%WindFileInfo%FileName = InputFileData%TSFF_FileName - InitOutData%WindFileInfo%WindType = TSFF_WindNumber InitOutData%WindFileInfo%RefHt = p%TSFFWind%RefHt InitOutData%WindFileInfo%RefHt_Set = .TRUE. InitOutData%WindFileInfo%DT = p%TSFFWind%FFDTime @@ -509,7 +499,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ! Store wind file metadata InitOutData%WindFileInfo%FileName = InputFileData%BladedFF_FileName - InitOutData%WindFileInfo%WindType = BladedFF_WindNumber InitOutData%WindFileInfo%RefHt = p%BladedFFWind%RefHt InitOutData%WindFileInfo%RefHt_Set = .TRUE. InitOutData%WindFileInfo%DT = p%BladedFFWind%FFDTime @@ -579,7 +568,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, ! Store wind file metadata InitOutData%WindFileInfo%FileName = InputFileData%HAWC_FileName_u - InitOutData%WindFileInfo%WindType = HAWC_WindNumber InitOutData%WindFileInfo%RefHt = p%HAWCWind%RefHt InitOutData%WindFileInfo%RefHt_Set = .TRUE. InitOutData%WindFileInfo%DT = p%HAWCWind%deltaXInv / p%HAWCWind%URef @@ -608,8 +596,14 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) IF ( ErrStat >= AbortErrLev ) RETURN - - + CASE (FDext_WindNumber) + + ! Initialize the UserWind module + CALL IfW_4Dext_Init(InitInp%FDext, p%FDext, m%FDext, TimeInterval, FDext_InitOutData, TmpErrStat, TmpErrMsg) + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + CASE DEFAULT ! keep this check to make sure that all new wind types have been accounted for CALL SetErrStat(ErrID_Fatal,' Undefined wind type.',ErrStat,ErrMsg,'InflowWind_Init()') @@ -655,32 +649,9 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, !!! !!! END IF !!! -!!! !---------------------------------------------------------------------------------------------- -!!! ! Initialize based on the wind type -!!! !---------------------------------------------------------------------------------------------- -!!! -!!! SELECT CASE ( p%WindType ) -!!! -!!! CASE (Uniform_WindNumber) -!!!NOTE: is the CTTS used on uniform wind? -!!!! IF (CTTS_Flag) CALL CTTS_SetRefVal(FileInfo%ReferenceHeight, 0.5*FileInfo%Width, ErrStat) !FIXME: check if this was originally used -!!!! IF (ErrStat == ErrID_None .AND. p%CTTS_Flag) & -!!!! CALL CTTS_SetRefVal(InitInp%ReferenceHeight, REAL(0.0, ReKi), ErrStat, ErrMsg) !FIXME: will need to put this routine in the Init of CT -!!! -!!! -!!! -!!! CASE (HAWC_WindNumber) -!!! -!!! !FIXME: remove this error message when we add HAWC_Wind in -!!! CALL SetErrStat( ErrID_Fatal, ' InflowWind cannot currently handle the HAWC_Wind type.', ErrStat, ErrMsg, ' IfW_Init' ) -!!! RETURN -!!! -!!!! CALL HW_Init( UnWind, p%WindFileName, ErrStat ) -!!! - ! Allocate arrays for the WriteOutput @@ -938,6 +909,9 @@ SUBROUTINE InflowWind_End( InputData, p, ContStates, DiscStates, ConstrStateGues CASE (User_WindNumber) CALL IfW_UserWind_End( p%UserWind, m%UserWind, ErrStat, ErrMsg ) + CASE (FDext_WindNumber) + CALL IfW_4Dext_End( p%FDext, m%FDext, ErrStat, ErrMsg ) + CASE ( Undef_WindNumber ) ! Do nothing diff --git a/modules-local/inflowwind/src/InflowWind.txt b/modules-local/inflowwind/src/InflowWind.txt index edc458e0bc..938720b6f3 100644 --- a/modules-local/inflowwind/src/InflowWind.txt +++ b/modules-local/inflowwind/src/InflowWind.txt @@ -12,6 +12,7 @@ usefrom IfW_TSFFWind.txt usefrom IfW_BladedFFWind.txt usefrom IfW_HAWCWind.txt usefrom IfW_UserWind.txt +usefrom IfW_4Dext.txt usefrom Lidar.txt include Registry_NWTC_Library.txt @@ -24,7 +25,8 @@ param ^ - IntKi TSFF_WindNu param ^ - IntKi BladedFF_WindNumber - 4 - "Bladed style binary full-field file. Includes native bladed format" - param ^ - IntKi HAWC_WindNumber - 5 - "HAWC wind file." - param ^ - IntKi User_WindNumber - 6 - "User defined wind." - -param ^ - IntKi Highest_WindNumber - 6 - "Highest wind number supported." - +param ^ - IntKi FDext_WindNumber - 7 - "4D wind from external souce (i.e., FAST.Farm)." - +param ^ - IntKi Highest_WindNumber - 7 - "Highest wind number supported." - ######################### @@ -109,13 +111,13 @@ typedef ^ ^ LOGICAL LidRadialVe typedef ^ InitInputType CHARACTER(1024) InputFileName - - - "Name of the InflowWind input file to use" - typedef ^ ^ LOGICAL Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - -#Is TurbineHeight needed? Possibly as a check on the wind data. -#typedef ^ ^ ReKi TurbineHeight - - - "Hub height of the turbine" meters +typedef ^ ^ LOGICAL Use4Dext - .FALSE. - "Flag that tells this module if an external module will pass it 4-D velocity grids." - typedef ^ ^ IntKi NumWindPoints - - - "Number of wind velocity points expected" - -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 ^ ^ InflowWind_InputFile PassedFileData - - - "If we don't use the input file, pass everything through this" - -typedef ^ ^ Lidar_InitInputType lidar - - - "InitInput for lidar data" - +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 ^ ^ InflowWind_InputFile PassedFileData - - - "If we don't use the input file, pass everything through this" - +typedef ^ ^ Lidar_InitInputType lidar - - - "InitInput for lidar data" - +typedef ^ ^ IfW_4Dext_InitInputType FDext - - - "InitInput for lidar data" - # Init Output @@ -138,6 +140,7 @@ typedef ^ ^ IfW_TSFFWind_MiscVarType 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 @@ -163,6 +166,7 @@ typedef ^ ^ IfW_TSFFWind_ParameterType TSFFWind typedef ^ ^ IfW_BladedFFWind_ParameterType BladedFFWind - - - "Parameters from BladedFFWind -- Bladed-style full-field format" - typedef ^ ^ IfW_HAWCWind_ParameterType HAWCWind - - - "Parameters from HAWCWind" - typedef ^ ^ IfW_UserWind_ParameterType UserWind - - - "Parameters from UserWind" - +typedef ^ ^ IfW_4Dext_ParameterType FDext - - - "Parameters from FDext" - #typedef ^ ^ IfW_CTWind_ParameterType CTWind - - - "Parameters from CTWind" - typedef ^ ^ IntKi NumOuts - 0 - "Number of parameters in the output list (number of outputs requested)" - typedef ^ ^ OutParmType OutParam {:} - - "Names and units (and other characteristics) of all requested output parameters" - @@ -188,4 +192,4 @@ typedef ^ ^ lidar_OutputType lidar typedef ^ ContinuousStateType ReKi DummyContState - - - "Remove this variable if you have continuous states" - 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 DummyConstrState - - - "Remove this variable if you have constraint states" - +typedef ^ OtherStateType ReKi DummyOtherState - - - "Remove this variable if you have other states" - diff --git a/modules-local/inflowwind/src/InflowWind_Subs.f90 b/modules-local/inflowwind/src/InflowWind_Subs.f90 index 30ac627535..b3e3f9f3b4 100644 --- a/modules-local/inflowwind/src/InflowWind_Subs.f90 +++ b/modules-local/inflowwind/src/InflowWind_Subs.f90 @@ -30,26 +30,15 @@ MODULE InflowWind_Subs USE IfW_BladedFFWind ! Bladed style full-field binary wind files USE IfW_UserWind ! User-defined wind module USE IfW_HAWCWind ! full-field binary wind files in HAWC format + USE IfW_4Dext ! 4D wind field from external source (e.g., FAST.Farm) !!! USE FDWind ! 4-D binary wind files !!! USE CTWind ! coherent turbulence from KH billow - binary file superimposed on another wind type IMPLICIT NONE - PRIVATE - ! ..... Public Subroutines ................................................................................................... - - PUBLIC :: InflowWind_ReadInput ! Read IfW input file - PUBLIC :: InflowWind_ValidateInput ! Check data read from file - PUBLIC :: InflowWind_SetParameters ! Store input file data in Parameters - PUBLIC :: SetOutParam ! Set the output parameters - PUBLIC :: SetAllOuts ! Set the full list of AllOut values during CalcOutput calls - PUBLIC :: InflowWind_OpenSumFile ! Open a summary file and start writing it - PUBLIC :: InflowWind_CloseSumFile ! Close the summary file - PUBLIC :: CalculateOutput - PUBLIC :: InflowWind_GetMean ! =================================================================================================== ! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m" @@ -976,7 +965,9 @@ SUBROUTINE InflowWind_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) CASE ( User_WindNumber ) CALL User_ValidateInput() - + + CASE (FDext_WindNumber) + IF ( .not. InitInp%Use4Dext) call SetErrStat(ErrID_Fatal,'4D external wind file is valid only with FAST.Farm',ErrStat,ErrMsg,RoutineName) CASE DEFAULT ! keep this check to make sure that all new wind types have been accounted for CALL SetErrStat(ErrID_Fatal,' Undefined wind type.',ErrStat,ErrMsg,RoutineName) @@ -1967,6 +1958,29 @@ SUBROUTINE CalculateOutput( Time, InputData, p, x, xd, z, OtherStates, y, m, Fil ENDIF + CASE (FDext_WindNumber) + + CALL IfW_4Dext_CalcOutput(Time, PositionXYZprime, p%FDext, y%VelocityUVW, m%FDext, TmpErrStat, TmpErrMsg) + DiskVel = 0.0_ReKi ! this is only for AD15, which we frankly don't care about in 4Dext wind + + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + + + ! Call IfW_4Dext_CalcOutput again in order to get the values needed for the OutList + IF ( p%NWindVel >= 1_IntKi .AND. FillWrOut ) THEN + ! Move the arrays for the Velocity information + CALL IfW_4Dext_CalcOutput(Time, p%WindViXYZprime, p%FDext, m%WindViUVW, m%FDext, TmpErrStat, TmpErrMsg) + + ! Out of bounds errors will be ErrID_Severe, not ErrID_Fatal + IF ( TmpErrStat >= ErrID_Fatal ) THEN + CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName ) + RETURN + ENDIF + + ENDIF + + ! If it isn't one of the above cases, we have a problem and won't be able to continue CASE DEFAULT diff --git a/modules-local/nwtc-library/src/ModMesh.f90 b/modules-local/nwtc-library/src/ModMesh.f90 index c2758f40e8..da06a8907e 100644 --- a/modules-local/nwtc-library/src/ModMesh.f90 +++ b/modules-local/nwtc-library/src/ModMesh.f90 @@ -230,7 +230,7 @@ SUBROUTINE MeshWrVTKreference (RefPoint, M, FileRootName, ErrStat, ErrMsg ) ErrMsg = "" - ! PolyData (.vtp) — Serial vtkPolyData (unstructured) + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) call WrVTK_header( TRIM(FileRootName)//'_Reference.vtp', M%Nnodes, M%ElemTable(ELEMENT_LINE2)%nelem, 0, Un, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >= AbortErrLev) return @@ -318,7 +318,7 @@ SUBROUTINE MeshWrVTK ( RefPoint, M, FileRootName, VTKcount, OutputFieldData, Err ! write the data that potentially changes each time step: !................................................................. - ! PolyData (.vtp) — Serial vtkPolyData (unstructured) file + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) file FileName = TRIM(FileRootName)//'.t'//TRIM(Num2LStr(VTKcount))//'.vtp' call WrVTK_header( trim(FileName), M%Nnodes, M%ElemTable(ELEMENT_LINE2)%nelem, 0, Un, ErrStat2, ErrMsg2 ) @@ -567,7 +567,7 @@ SUBROUTINE MeshWrVTK_Ln2Surface ( RefPoint, M, FileRootName, VTKcount, OutputFie ! write the data that potentially changes each time step: !................................................................. - ! PolyData (.vtp) — Serial vtkPolyData (unstructured) file + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) file FileName = TRIM(FileRootName)//'.t'//TRIM(Num2LStr(VTKcount))//'.vtp' ! Write a VTP mesh file (Polygonal VTK file) with positions and polygons (surfaces) @@ -758,7 +758,7 @@ SUBROUTINE MeshWrVTK_PointSurface ( RefPoint, M, FileRootName, VTKcount, OutputF ! write the data that potentially changes each time step: !................................................................. - ! PolyData (.vtp) — Serial vtkPolyData (unstructured) file + ! PolyData (.vtp) - Serial vtkPolyData (unstructured) file FileName = TRIM(FileRootName)//'.t'//TRIM(Num2LStr(VTKcount))//'.vtp' ! Write a VTP mesh file (Polygonal VTK file) with positions and polygons (surfaces) diff --git a/modules-local/nwtc-library/src/ModMesh_Mapping.f90 b/modules-local/nwtc-library/src/ModMesh_Mapping.f90 index afd311b9dc..402b577eae 100644 --- a/modules-local/nwtc-library/src/ModMesh_Mapping.f90 +++ b/modules-local/nwtc-library/src/ModMesh_Mapping.f90 @@ -457,8 +457,8 @@ SUBROUTINE Transfer_Line2_to_Point( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDisp TYPE(MeshType), INTENT(IN ) :: Src !< source mesh TYPE(MeshType), INTENT(INOUT) :: Dest !< destination mesh - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh required for loads transfer; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh required for loads transfer; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh required for loads transfer; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh required for loads transfer; Dest contains loads and DestDisp contains TranslationDisp and Orientation TYPE(MeshMapType), INTENT(INOUT) :: MeshMap !< mapping data structure @@ -596,8 +596,8 @@ SUBROUTINE Linearize_Line2_to_Point( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDis TYPE(MeshType), INTENT(IN ) :: Src ! source mesh TYPE(MeshType), INTENT(IN ) :: Dest ! destination mesh - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp ! a "functional" sibling of the source mesh required for loads transfer; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp ! a "functional" sibling of the destination mesh required for loads transfer; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp ! a "functional" sibling of the source mesh required for loads transfer; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp ! a "functional" sibling of the destination mesh required for loads transfer; Dest contains loads and DestDisp contains TranslationDisp and Orientation TYPE(MeshMapType), INTENT(INOUT) :: MeshMap ! mapping data structure @@ -1241,7 +1241,6 @@ SUBROUTINE Transfer_Motions_Line2_to_Point( Src, Dest, MeshMap, ErrStat, ErrMsg REAL(DbKi) :: FieldValue(3,2) ! Temporary variable to store values for DCM interpolation REAL(DbKi) :: RotationMatrixD(3,3) REAL(DbKi) :: tensor_interp(3) - REAL(DbKi) :: theta(1) ErrStat = ErrID_None @@ -1795,7 +1794,9 @@ SUBROUTINE CreateMapping_ProjectToLine2(Mesh1, Mesh2, NodeMap, Mesh1_TYPE, ErrSt ! INTEGER(IntKi) :: ErrStat2 ! Error status of the operation ! CHARACTER(ErrMsgLen) :: ErrMsg2 ! Error message if ErrStat2 /= ErrID_None +#ifdef DEBUG_MESHMAPPING CHARACTER(200) :: DebugFileName ! File name for debugging file +#endif CHARACTER(*), PARAMETER :: RoutineName = 'CreateMapping_ProjectToLine2' @@ -1820,8 +1821,8 @@ SUBROUTINE CreateMapping_ProjectToLine2(Mesh1, Mesh2, NodeMap, Mesh1_TYPE, ErrSt LOGICAL :: found LOGICAL :: on_element - INTEGER(IntKi) :: Un ! unit number for debugging #ifdef DEBUG_MESHMAPPING + INTEGER(IntKi) :: Un ! unit number for debugging REAL(ReKi) :: closest_elem_position INTEGER(IntKi) :: closest_elem #endif @@ -2104,8 +2105,8 @@ SUBROUTINE Transfer_Point_to_Line2( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDisp INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh for load mapping; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh for load mapping; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh for load mapping; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh for load mapping; Dest contains loads and DestDisp contains TranslationDisp and Orientation ! local variables @@ -2211,8 +2212,8 @@ SUBROUTINE Linearize_Point_to_Line2( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDis INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None - TYPE(MeshType),OPTIONAL, INTENT(IN ) :: SrcDisp ! a "functional" sibling of the source mesh for load mapping; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL, INTENT(IN ) :: DestDisp ! a "functional" sibling of the destination mesh for load mapping; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL, INTENT(IN ) :: SrcDisp ! a "functional" sibling of the source mesh for load mapping; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL, INTENT(IN ) :: DestDisp ! a "functional" sibling of the destination mesh for load mapping; Dest contains loads and DestDisp contains TranslationDisp and Orientation ! local variables @@ -3312,8 +3313,8 @@ SUBROUTINE Transfer_Line2_to_Line2( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDisp TYPE(MeshType), INTENT(IN ) :: Src !< source Line2 mesh TYPE(MeshType), INTENT(INOUT) :: Dest !< destination Line2 mesh - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh; Dest contains loads and DestDisp contains TranslationDisp and Orientation TYPE(MeshMapType), INTENT(INOUT) :: MeshMap !< mapping between Src and Dest meshes @@ -3486,8 +3487,8 @@ SUBROUTINE Linearize_Line2_to_Line2( Src, Dest, MeshMap, ErrStat, ErrMsg, SrcDis TYPE(MeshType), INTENT(IN ) :: Src !< source Line2 mesh TYPE(MeshType), INTENT(IN ) :: Dest !< destination mesh - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh; Src contains loads and SrcDisp contains TranslationDisp and Orientaiton - TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh; Dest contains loads and DestDisp contains TranslationDisp and Orientaiton + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: SrcDisp !< a "functional" sibling of the source mesh; Src contains loads and SrcDisp contains TranslationDisp and Orientation + TYPE(MeshType),OPTIONAL,INTENT(IN ) :: DestDisp !< a "functional" sibling of the destination mesh; Dest contains loads and DestDisp contains TranslationDisp and Orientation TYPE(MeshMapType), INTENT(INOUT) :: MeshMap !< mapping between Src and Dest meshes @@ -3756,16 +3757,16 @@ END SUBROUTINE Transfer_Loads_Point_to_Line2 !! \begin{bmatrix} M_{mi} & M_{f_{\times p}} & 0 & 0 \\ !! 0 & M_{mi} & 0 & 0 \\ !! 0 & 0 & M_{li} & 0 \\ -!! M_{um} & M_{tm} & M_{fm} & M_{li} \\ \end{bmatrix} +!! M_{um} & M_{tm} & M_{fm} & M_{li} \\ \end{bmatrix} !! \left\{ \begin{matrix} \Delta\vec{u}^S \\ \Delta\vec{\theta}^S \\ \Delta\vec{F}^S \\ \Delta\vec{M}^S \end{matrix} \right\} \\ & = !! \begin{bmatrix} I & 0 & 0 & 0 \\ !! 0 & I & 0 & 0 \\ !! 0 & 0 & \begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1} & 0 \\ -!! -\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1}M_{um}^{DL} & 0 & -\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1}M_{fm}^{DL}\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1} & \begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1} \\ \end{bmatrix} +!! -\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1}M_{um}^{DL} & 0 & -\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1}M_{fm}^{DL}\begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1} & \begin{bmatrix} M_{li}^{DL} \end{bmatrix}^{-1} \\ \end{bmatrix} !! \begin{bmatrix} M_{mi} & M_{f_{\times p}} & 0 & 0 \\ !! 0 & M_{mi} & 0 & 0 \\ !! 0 & 0 & M_{li}^D & 0 \\ -!! 0 & M_{tm}^D & M_{fm}^D & M_{li}^D \\ \end{bmatrix} +!! 0 & M_{tm}^D & M_{fm}^D & M_{li}^D \\ \end{bmatrix} !! \left\{ \begin{matrix} \Delta\vec{u}^S \\ \Delta\vec{\theta}^S \\ \Delta\vec{F}^S \\ \Delta\vec{M}^S \end{matrix} \right\} !! \end{aligned} !! \f} @@ -4298,14 +4299,12 @@ SUBROUTINE Create_Augmented_Ln2_Src_Mesh(Src, Dest, MeshMap, Dest_TYPE, ErrStat, Aug_Nnodes = Src%nnodes ! number of nodes in the augmented mesh Aug_NElem = Temp_Ln2_Src%ElemTable(ELEMENT_LINE2)%nelem - ! loop through the destination elements: + ! loop through the destination elements (NOTE: for point elements, this is the same as looping over nodes): DO jElem = 1,dest%ElemTable(Dest_TYPE)%nelem IF ( Dest_TYPE == ELEMENT_LINE2 ) THEN p_eD = dest%Position(:, dest%ElemTable(Dest_TYPE)%Elements(jElem)%ElemNodes(2)) & - dest%Position(:, dest%ElemTable(Dest_TYPE)%Elements(jElem)%ElemNodes(1)) - ELSE - p_eD = dest%Position(:, dest%ElemTable(Dest_TYPE)%Elements(jElem)%ElemNodes(1)) END IF @@ -4318,6 +4317,7 @@ SUBROUTINE Create_Augmented_Ln2_Src_Mesh(Src, Dest, MeshMap, Dest_TYPE, ErrStat, p_eS = Temp_Ln2_Src%Position(:, Temp_Ln2_Src%ElemTable(ELEMENT_LINE2)%Elements(iElem)%ElemNodes(2)) & - Temp_Ln2_Src%Position(:, Temp_Ln2_Src%ElemTable(ELEMENT_LINE2)%Elements(iElem)%ElemNodes(1)) + IF ( Dest_TYPE == ELEMENT_POINT ) p_eD = p_eS denom = DOT_PRODUCT( p_eD , p_eS ) @@ -4344,6 +4344,7 @@ SUBROUTINE Create_Augmented_Ln2_Src_Mesh(Src, Dest, MeshMap, Dest_TYPE, ErrStat, p_eS = Src%Position(:, n2) - Src%Position(:, n1) + IF ( Dest_TYPE == ELEMENT_POINT ) p_eD = p_eS denom = DOT_PRODUCT( p_eD , p_eS ) ! we don't need to check that this is zero because it's just a shorter version of the temp Temp_Ln2_Src element n1S_nD_vector = dest%Position(:, dest%ElemTable(Dest_TYPE)%Elements(jElem)%ElemNodes(jNode)) & - Src%Position(:, n1 ) diff --git a/modules-local/nwtc-library/src/NWTC_Base.f90 b/modules-local/nwtc-library/src/NWTC_Base.f90 index b264235de3..f715e29e7b 100644 --- a/modules-local/nwtc-library/src/NWTC_Base.f90 +++ b/modules-local/nwtc-library/src/NWTC_Base.f90 @@ -40,6 +40,7 @@ MODULE NWTC_Base INTEGER, PARAMETER :: ErrMsgLen = 1024 !< The maximum number of characters in an error message in the FAST framework INTEGER(IntKi), PARAMETER :: ChanLen = 10 !< The allowable length of channel names (i.e., width of output columns) in the FAST framework + INTEGER(IntKi), PARAMETER :: ChanLenFF = 14 !< The allowable length of channel names (i.e., width of output columns) in the FAST.Farm software INTEGER(IntKi), PARAMETER :: LinChanLen = 200 !< The allowable length of row/column names in linearization files INTEGER(IntKi), PARAMETER :: NWTC_Verbose = 10 !< The maximum level of verbosity diff --git a/modules-local/nwtc-library/src/NWTC_IO.f90 b/modules-local/nwtc-library/src/NWTC_IO.f90 index ed599c972a..3b5bda1e6f 100644 --- a/modules-local/nwtc-library/src/NWTC_IO.f90 +++ b/modules-local/nwtc-library/src/NWTC_IO.f90 @@ -33,7 +33,7 @@ MODULE NWTC_IO !======================================================================= TYPE(ProgDesc), PARAMETER :: NWTC_Ver = & - ProgDesc( 'NWTC Subroutine Library', 'v2.11.00', '12-Nov-2016') !< The name, version, and date of the NWTC Subroutine Library + ProgDesc( 'NWTC Subroutine Library', 'v2.11.02', '13-Mar-2017') !< The name, version, and date of the NWTC Subroutine Library !> This type stores a linked list of file names, used in MLB-style input file parsing (currently used in AirfoilInfo) TYPE, PUBLIC :: FNlist_Type @@ -6743,7 +6743,7 @@ SUBROUTINE WrBinFAST(FileName, FileID, DescStr, ChanName, ChanUnit, TimeData, Al DO IC=1,NumOutChans ! Loop through the output channels IF ( ColMax(IC) == ColMin(IC) ) THEN - ColScl(IC) = 1 + ColScl(IC) = IntRng/SQRT(EPSILON(1.0_SiKi)) ELSE ColScl(IC) = IntRng/REAL( ColMax(IC) - ColMin(IC), SiKi ) ENDIF @@ -7679,6 +7679,245 @@ SUBROUTINE WrVTK_footer( Un ) RETURN END SUBROUTINE WrVTK_footer + !======================================================================= - +!> This routine reads the header for a vtk, ascii, structured_points dataset file, +!! including all the information about the structured points. It tries to open a +!! text file for reading and returns the Unit number of the opened file. +!! The caller is responsible for closing the file unit unless caller set Un = -1! + SUBROUTINE ReadVTK_SP_info( FileName, descr, dims, origin, gridSpacing, vecLabel, Un, ErrStat, ErrMsg ) + + CHARACTER(*) , INTENT(IN ) :: FileName !< Name of output file + CHARACTER(1024) , INTENT( OUT) :: descr !< Line describing the contents of the file + INTEGER(IntKi) , INTENT( OUT) :: dims(3) !< dimension of the 3D grid (nX,nY,nZ) + REAL(ReKi) , INTENT( OUT) :: origin(3) !< the lower-left corner of the 3D grid (X0,Y0,Z0) + REAL(ReKi) , INTENT( OUT) :: gridSpacing(3) !< spacing between grid points in each of the 3 directions (dX,dY,dZ) + CHARACTER(1024) , INTENT( OUT) :: vecLabel + INTEGER(IntKi) , INTENT(INOUT) :: Un !< unit number of opened file + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs + + INTEGER(IntKi) :: ErrStat2 ! local error level/status of OpenFOutFile operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local message when error occurs + CHARACTER(1024) :: Line, Line2 ! one line of the file + CHARACTER(1024) :: formatLbl + CHARACTER(*), PARAMETER :: RoutineName = 'ReadVTK_SP_info' + INTEGER(IntKi) :: sz, nPts + LOGICAL :: closeOnReturn + + ErrStat = ErrID_None + ErrMsg = '' + + IF (Un == -1 ) THEN + closeOnReturn = .TRUE. + ELSE + closeOnReturn = .FALSE. + END IF + + CALL GetNewUnit( Un, ErrStat, ErrMsg ) + CALL OpenFInpFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) return + + CALL ReadCom( Un, FileName, 'File header: Module Version (line 1)', ErrStat2, ErrMsg2, 0 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + CALL ReadStr( Un, FileName, descr, 'descr', 'File Description line', ErrStat2, ErrMsg2, 0 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + formatLbl = "" + CALL ReadStr( Un, FileName, formatLbl, 'formatLbl', 'ASCII label', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + call Conv2UC(formatLbl) + if (INDEX(formatLbl, "ASCII" ) /= 1 ) THEN ! If this line doesn't contain the word ASCII, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find ASCII label', ErrStat, ErrMsg, RoutineName ) + end if + Line = "" + CALL ReadStr( Un, FileName, Line, "dataset", "DATASET STRUCTURED_POINTS", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + CALL Conv2UC( Line ) + IF ( INDEX(Line, "DATASET" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find DATASET label', ErrStat, ErrMsg, RoutineName ) + END IF + IF ( INDEX(Line, "STRUCTURED_POINTS" ) == 0 ) THEN ! If this line doesn't also contain the word structured_points, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find STRUCTURED_POINTS label', ErrStat, ErrMsg, RoutineName ) + end if + + ! Dimensions + Line = "" + CALL ReadStr( Un, FileName, Line, "Dimensions", "DIMENSIONS data", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Line = trim(Line) + CALL Conv2UC( Line ) + IF ( INDEX(Line, "DIMENSIONS" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find DIMENSIONS label', ErrStat, ErrMsg, RoutineName ) + ELSE + sz = len(Line) + Line = Line(12:sz) + READ(Line,*) dims + END IF + + ! Origin + Line = "" + CALL ReadStr( Un, FileName, Line, "Origin", "ORIGIN data", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Line = trim(Line) + CALL Conv2UC( Line ) + IF ( INDEX(Line, "ORIGIN" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find ORIGIN label', ErrStat, ErrMsg, RoutineName ) + ELSE + sz = len(Line) + Line = Line(8:sz) + READ(Line,*) origin + END IF + + ! Spacing + Line = "" + CALL ReadStr( Un, FileName, Line, "gridSpacing", "SPACING data", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Line = trim(Line) + CALL Conv2UC( Line ) + IF ( INDEX(Line, "SPACING" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find SPACING label', ErrStat, ErrMsg, RoutineName ) + ELSE + sz = len(Line) + Line = Line(9:sz) + READ(Line,*) gridSpacing + END IF + + ! Point Data + Line = "" + CALL ReadStr( Un, FileName, Line, "Point_Data", "POINT_DATA", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Line = trim(Line) + CALL Conv2UC( Line ) + IF ( INDEX(Line, "POINT_DATA" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find POINT_DATA label', ErrStat, ErrMsg, RoutineName ) + ELSE + sz = len(Line) + Line = Line(12:sz) + READ(Line,*) nPts + END IF + + ! Vector Label + Line = "" + CALL ReadStr( Un, FileName, Line, "Vectors", "VECTORS label", ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + Line = trim(Line) + Line2 = Line + CALL Conv2UC( Line2 ) + IF ( INDEX(Line2, "VECTORS" ) /= 1 ) THEN ! If this line doesn't contain the word dataset, we have a bad file header + CALL SetErrStat( ErrID_Fatal, 'Invalid vtk structured_points file: did not find VECTORS label', ErrStat, ErrMsg, RoutineName ) + ELSE + sz = INDEX(Line2, "FLOAT" ) + IF ( sz == 0 ) THEN + CALL SetErrStat( ErrID_Fatal, 'Invalid VECTORS datatype. Must be set to float.', ErrStat, ErrMsg, RoutineName ) + ELSE + vecLabel = Line(9:sz-2) + END IF + END IF + + IF ( (ErrStat >= AbortErrLev) .or. closeOnReturn ) THEN + close(Un) + Un = -1 + RETURN + END IF + + RETURN + END SUBROUTINE ReadVTK_SP_info + +!======================================================================= +!> This routine reads the vector data for a vtk, ascii, structured_points dataset file, +!! The Unit number of the file is already assumed to be valid via a previous call to +!! ReadVTK_SP_info. + SUBROUTINE ReadVTK_SP_vectors( FileName, Un, dims, gridVals, ErrStat, ErrMsg ) + + CHARACTER(*) , INTENT(IN ) :: FileName !< Name of output file + INTEGER(IntKi) , INTENT(IN ) :: Un !< unit number of opened file + INTEGER(IntKi) , INTENT(IN ) :: dims(3) !< dimension of the 3D grid (nX,nY,nZ) + REAL(ReKi) , INTENT( OUT) :: gridVals(:,:,:,:) !< 3D array of data, size (nX,nY,nZ), must be pre-allocated + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs + + INTEGER(IntKi) :: ErrStat2 ! local error level/status of OpenFOutFile operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local message when error occurs + CHARACTER(1024) :: Line, Line2 ! one line of the file + CHARACTER(1024) :: formatLbl + CHARACTER(*), PARAMETER :: RoutineName = 'ReadVTK_SP_vectors' + INTEGER(IntKi) :: sz, nPts,i,j,k + + ErrStat = ErrID_None + ErrMsg = '' + + READ(Un,*) gridVals(1:3,1:dims(1),1:dims(2),1:dims(3)) + + close(Un) + + END SUBROUTINE ReadVTK_SP_vectors + +!======================================================================= +!> This routine writes out the heading for an vtk, ascii, structured_points dataset file . +!! It tries to open a text file for writing and returns the Unit number of the opened file. + SUBROUTINE WrVTK_SP_header( FileName, descr, Un, ErrStat, ErrMsg ) + + CHARACTER(*) , INTENT(IN ) :: FileName !< Name of output file + CHARACTER(*) , INTENT(IN ) :: descr !< Line describing the contents of the file + INTEGER(IntKi) , INTENT( OUT) :: Un !< unit number of opened file + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs + + CALL GetNewUnit( Un, ErrStat, ErrMsg ) + CALL OpenFOutFile ( Un, TRIM(FileName), ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) return + + WRITE(Un,'(A)') '# vtk DataFile Version 3.0' + WRITE(Un,'(A)') trim(descr) + WRITE(Un,'(A)') 'ASCII' + WRITE(Un,'(A)') 'DATASET STRUCTURED_POINTS' + + RETURN + END SUBROUTINE WrVTK_SP_header + + + + SUBROUTINE WrVTK_SP_vectors3D( Un, dataDescr, dims, origin, gridSpacing, gridVals, ErrStat, ErrMsg ) + + INTEGER(IntKi) , INTENT(IN ) :: Un !< unit number of previously opened file (via call to WrVTK_SP_header) + CHARACTER(*) , INTENT(IN ) :: dataDescr !< Short label describing the vector data + INTEGER(IntKi) , INTENT(IN ) :: dims(3) !< dimension of the 3D grid (nX,nY,nZ) + REAL(ReKi) , INTENT(IN ) :: origin(3) !< the lower-left corner of the 3D grid (X0,Y0,Z0) + REAL(ReKi) , INTENT(IN ) :: gridSpacing(3) !< spacing between grid points in each of the 3 directions (dX,dY,dZ) + REAL(ReKi) , INTENT(IN ) :: gridVals(:,:,:,:) !< 3D array of data, size (nX,nY,nZ) + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< error level/status of OpenFOutFile operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< message when error occurs + + INTEGER(IntKi) :: nPts ! Total number of grid points + + if ( .not. (Un > 0) ) then + ErrStat = ErrID_Fatal + ErrMsg = 'WrVTK_SP_points: Invalid file unit, be sure to call WrVTK_SP_header prior to calling WrVTK_SP_points.' + return + end if + + ErrStat = ErrID_None + ErrMsg = '' + nPts = dims(1)*dims(2)*dims(3) + + ! Note: gridVals must be stored such that the left-most dimension is X and the right-most dimension is Z + WRITE(Un,'(A,3(i5,1X))') 'DIMENSIONS ', dims + WRITE(Un,'(A,3(f10.2,1X))') 'ORIGIN ' , origin + WRITE(Un,'(A,3(f10.2,1X))') 'SPACING ' , gridSpacing + WRITE(Un,'(A,i15)') 'POINT_DATA ', nPts + WRITE(Un,'(A)') 'VECTORS '//trim(dataDescr)//' float' + WRITE(Un,'(3(f10.2,1X))') gridVals + close(Un) + RETURN + + END SUBROUTINE WrVTK_SP_vectors3D + END MODULE NWTC_IO diff --git a/modules-local/nwtc-library/src/NWTC_Library_Types.f90 b/modules-local/nwtc-library/src/NWTC_Library_Types.f90 index 40d804a728..08a5716885 100644 --- a/modules-local/nwtc-library/src/NWTC_Library_Types.f90 +++ b/modules-local/nwtc-library/src/NWTC_Library_Types.f90 @@ -60,6 +60,14 @@ MODULE NWTC_Library_Types INTEGER(IntKi) :: SignM !< Multiplier for output channel; usually -1 (minus) or 0 (invalid channel) [-] END TYPE OutParmType ! ======================= +! ========= OutParmFFType ======= + TYPE, PUBLIC :: OutParmFFType + INTEGER(IntKi) :: Indx !< An index into AllOuts array where this channel is computed/stored [-] + CHARACTER(ChanLenFF) :: Name !< Name of the output channel [-] + CHARACTER(ChanLenFF) :: Units !< Units this channel is specified in [-] + INTEGER(IntKi) :: SignM !< Multiplier for output channel; usually -1 (minus) or 0 (invalid channel) [-] + END TYPE OutParmFFType +! ======================= ! ========= FileInfoType ======= TYPE, PUBLIC :: FileInfoType INTEGER(IntKi) :: NumLines @@ -784,6 +792,163 @@ SUBROUTINE NWTC_Library_UnPackOutParmType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, Int_Xferred = Int_Xferred + 1 END SUBROUTINE NWTC_Library_UnPackOutParmType + SUBROUTINE NWTC_Library_CopyOutParmFFType( SrcOutParmTypeData, DstOutParmTypeData, CtrlCode, ErrStat, ErrMsg ) + TYPE(OutParmFFType), INTENT(IN) :: SrcOutParmTypeData + TYPE(OutParmFFType), INTENT(INOUT) :: DstOutParmTypeData + 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 = 'NWTC_Library_CopyOutParmFFType' +! + ErrStat = ErrID_None + ErrMsg = "" + DstOutParmTypeData%Indx = SrcOutParmTypeData%Indx + DstOutParmTypeData%Name = SrcOutParmTypeData%Name + DstOutParmTypeData%Units = SrcOutParmTypeData%Units + DstOutParmTypeData%SignM = SrcOutParmTypeData%SignM + END SUBROUTINE NWTC_Library_CopyOutParmFFType + + SUBROUTINE NWTC_Library_DestroyOutParmFFType( OutParmTypeData, ErrStat, ErrMsg ) + TYPE(OutParmFFType), INTENT(INOUT) :: OutParmTypeData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + CHARACTER(*), PARAMETER :: RoutineName = 'NWTC_Library_DestroyOutParmFFType' + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 +! + ErrStat = ErrID_None + ErrMsg = "" + END SUBROUTINE NWTC_Library_DestroyOutParmFFType + + SUBROUTINE NWTC_Library_PackOutParmFFType( 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(OutParmFFType), 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 = 'NWTC_Library_PackOutParmFFType' + ! 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 ! Indx + Int_BufSz = Int_BufSz + 1*LEN(InData%Name) ! Name + Int_BufSz = Int_BufSz + 1*LEN(InData%Units) ! Units + Int_BufSz = Int_BufSz + 1 ! SignM + 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:Int_Xferred+(1)-1 ) = InData%Indx + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(InData%Name) + IntKiBuf(Int_Xferred) = ICHAR(InData%Name(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(InData%Units) + IntKiBuf(Int_Xferred) = ICHAR(InData%Units(I:I), IntKi) + Int_Xferred = Int_Xferred + 1 + END DO ! I + IntKiBuf ( Int_Xferred:Int_Xferred+(1)-1 ) = InData%SignM + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE NWTC_Library_PackOutParmFFType + + SUBROUTINE NWTC_Library_UnPackOutParmFFType( 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(OutParmFFType), 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 + LOGICAL :: mask0 + LOGICAL, ALLOCATABLE :: mask1(:) + LOGICAL, ALLOCATABLE :: mask2(:,:) + LOGICAL, ALLOCATABLE :: mask3(:,:,:) + LOGICAL, ALLOCATABLE :: mask4(:,:,:,:) + LOGICAL, ALLOCATABLE :: mask5(:,:,:,:,:) + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'NWTC_Library_UnPackOutParmFFType' + ! 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%Indx = IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + DO I = 1, LEN(OutData%Name) + OutData%Name(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + DO I = 1, LEN(OutData%Units) + OutData%Units(I:I) = CHAR(IntKiBuf(Int_Xferred)) + Int_Xferred = Int_Xferred + 1 + END DO ! I + OutData%SignM = IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + END SUBROUTINE NWTC_Library_UnPackOutParmFFType + SUBROUTINE NWTC_Library_CopyFileInfoType( SrcFileInfoTypeData, DstFileInfoTypeData, CtrlCode, ErrStat, ErrMsg ) TYPE(FileInfoType), INTENT(IN) :: SrcFileInfoTypeData TYPE(FileInfoType), INTENT(INOUT) :: DstFileInfoTypeData diff --git a/modules-local/nwtc-library/src/NWTC_Num.f90 b/modules-local/nwtc-library/src/NWTC_Num.f90 index 46982f8f12..26e0977e7c 100644 --- a/modules-local/nwtc-library/src/NWTC_Num.f90 +++ b/modules-local/nwtc-library/src/NWTC_Num.f90 @@ -4863,7 +4863,7 @@ END SUBROUTINE RombergInt !======================================================================= !> This routine displays a message that gives that status of the simulation and the predicted end time of day. !! It is intended to be used with SimStatus (nwtc_num::simstatus) and SimStatus_FirstTime (nwtc_num::simstatus_firsttime). - SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UsrTime_out ) + SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UsrTime_out, DescStrIn ) IMPLICIT NONE @@ -4876,6 +4876,8 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UsrTime_o REAL(DbKi),INTENT(IN) :: ZTime !< The final simulation time (not necessarially TMax) REAL(ReKi),INTENT(OUT),OPTIONAL:: UsrTime_out !< User CPU time for entire run - optional value returned to calling routine + CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus + ! Local variables REAL(ReKi) :: ClckTime ! Elapsed clock time for the entire run. @@ -4890,6 +4892,14 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UsrTime_o CHARACTER( 8) :: TimePer CHARACTER(MaxWrScrLen) :: BlankLine + CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + + + if (present(DescStrIn)) then + DescStr = DescStrIn + else + DescStr = "" + end if ! Get the end times to compare with start times. @@ -4930,7 +4940,8 @@ SUBROUTINE RunTimes( StrtTime, UsrTime1, SimStrtTime, UsrTime2, ZTime, UsrTime_o BlankLine = "" CALL WrOver( BlankLine ) ! BlankLine contains MaxWrScrLen spaces - CALL WrScr1( ' Total Real Time: '//TRIM( Num2LStr( Factor*ClckTime ) )//TRIM( TimePer ) ) + CALL WrScr ( DescStr ) + CALL WrScr ( ' Total Real Time: '//TRIM( Num2LStr( Factor*ClckTime ) )//TRIM( TimePer ) ) CALL WrScr ( ' Total CPU Time: '//TRIM( Num2LStr( Factor*UsrTime ) )//TRIM( TimePer ) ) ! CALL WrScr ( ' ') ! CALL WrScr ( ' Simulation Real Time: '//TRIM( Num2LStr( Factor*ClckTimeSim ) )//TRIM( TimePer ) ) @@ -5037,7 +5048,7 @@ END SUBROUTINE SetConstants !======================================================================= !> This routine displays a message that gives that status of the simulation. !! It is intended to be used with RunTimes (nwtc_num::runtimes) and SimStatus (nwtc_num::simstatus). - SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTimeSim, ZTime, TMax ) + SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTimeSim, ZTime, TMax, DescStrIn ) IMPLICIT NONE @@ -5048,12 +5059,22 @@ SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTime REAL(ReKi), INTENT( OUT) :: PrevClockTime !< Previous clock time in seconds past midnight INTEGER, INTENT( OUT) :: SimStrtTime (8) !< An array containing the elements of the start time. REAL(ReKi), INTENT( OUT) :: UsrTimeSim !< User CPU time for simulation (without intialization) - + + CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus + ! Local variables. REAL(ReKi) :: CurrClockTime ! Current time in seconds past midnight. + CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus + if (present(DescStrIn)) then + DescStr = DescStrIn + else + DescStr = "" + end if + + ! How many seconds past midnight? CALL DATE_AND_TIME ( Values=SimStrtTime ) @@ -5063,7 +5084,7 @@ SUBROUTINE SimStatus_FirstTime( PrevSimTime, PrevClockTime, SimStrtTime, UsrTime CurrClockTime = TimeValues2Seconds( SimStrtTime ) - CALL WrScr ( ' Timestep: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )//' seconds.') + CALL WrScr ( trim(DescStr)//' Timestep: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )//' seconds.') ! Let's save this time as the previous time for the next call to the routine @@ -5075,7 +5096,7 @@ END SUBROUTINE SimStatus_FirstTime !======================================================================= !> This routine displays a message that gives that status of the simulation and the predicted end time of day. !! It is intended to be used with RunTimes (nwtc_num::runtimes) and SimStatus_FirstTime (nwtc_num::simstatus_firsttime). - SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax ) + SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax, DescStrIn ) IMPLICIT NONE @@ -5086,6 +5107,7 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax ) REAL(DbKi), INTENT(INOUT) :: PrevSimTime !< Previous time message was written to screen (s > 0) REAL(ReKi), INTENT(INOUT) :: PrevClockTime !< Previous clock time in seconds past midnight + CHARACTER(*), INTENT(IN), OPTIONAL :: DescStrIn !< optional additional string to print for SimStatus ! Local variables. @@ -5105,11 +5127,18 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax ) CHARACTER(MaxWrScrLen) :: BlankLine CHARACTER( 8) :: ETimeStr ! String containing the end time. + CHARACTER(10) :: DescStr !< optional additional string to print for SimStatus IF ( ZTime <= PrevSimTime ) RETURN - + + if (present(DescStrIn)) then + DescStr = DescStrIn + else + DescStr = "" + end if + ! How many seconds past midnight? CALL DATE_AND_TIME ( Values=TimeAry ) @@ -5140,7 +5169,7 @@ SUBROUTINE SimStatus( PrevSimTime, PrevClockTime, ZTime, TMax ) BlankLine = "" CALL WrOver( BlankLine ) ! BlankLine contains MaxWrScrLen spaces - CALL WrOver ( ' Timestep: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )// & + CALL WrOver ( trim(DescStr)//' Timestep: '//TRIM( Num2LStr( NINT( ZTime ) ) )//' of '//TRIM( Num2LStr( TMax ) )// & ' seconds. Estimated final completion at '//ETimeStr//'.' ) ! Let's save this time as the previous time for the next call to the routine @@ -5762,6 +5791,7 @@ FUNCTION traceR16(A) end do END FUNCTION traceR16 + !======================================================================= !> This function returns the \f$l_2\f$ (Euclidian) norm of a vector, !! \f$v = \left(v_1, v_2, \ldots ,v_n\right)\f$. The \f$l_2\f$-norm is defined as diff --git a/modules-local/nwtc-library/src/Registry_NWTC_Library.txt b/modules-local/nwtc-library/src/Registry_NWTC_Library.txt index 26fe595ce1..e3416e31ca 100644 --- a/modules-local/nwtc-library/src/Registry_NWTC_Library.txt +++ b/modules-local/nwtc-library/src/Registry_NWTC_Library.txt @@ -28,6 +28,11 @@ usefrom ^ ^ CHARACTER(ChanLen) Name usefrom ^ ^ CHARACTER(ChanLen) Units usefrom ^ ^ IntKi SignM +usefrom NWTC_Library OutParmFFType IntKi Indx +usefrom ^ ^ CHARACTER(ChanLenFF) Name +usefrom ^ ^ CHARACTER(ChanLenFF) Units +usefrom ^ ^ IntKi SignM + usefrom NWTC_Library FileInfoType IntKi NumLines usefrom ^ ^ IntKi NumFiles usefrom ^ ^ IntKi FileLine {:} diff --git a/modules-local/servodyn/src/BladedInterface.f90 b/modules-local/servodyn/src/BladedInterface.f90 index d8ea33c45c..878520c450 100644 --- a/modules-local/servodyn/src/BladedInterface.f90 +++ b/modules-local/servodyn/src/BladedInterface.f90 @@ -357,12 +357,14 @@ SUBROUTINE BladedInterface_End(u, p, m, ErrStat, ErrMsg) CHARACTER(ErrMsgLen) :: ErrMsg2 ! The error message, if an error occurred ! call DLL final time, but skip if we've never called it - IF ( .NOT. EqualRealNos( m%dll_data%avrSWAP( 1), 0.0_SiKi ) ) THEN - m%dll_data%avrSWAP( 1) = -1.0 ! Status flag set as follows: 0 if this is the first call, 1 for all subsequent time steps, -1 if this is the final call at the end of the simulation (-) - !CALL Fill_avrSWAP( -1_IntKi, -10.0_DbKi, u, p, LEN(ErrMsg), m%dll_data ) + if (allocated(m%dll_data%avrSWAP)) then + IF ( .NOT. EqualRealNos( m%dll_data%avrSWAP( 1), 0.0_SiKi ) ) THEN + m%dll_data%avrSWAP( 1) = -1.0 ! Status flag set as follows: 0 if this is the first call, 1 for all subsequent time steps, -1 if this is the final call at the end of the simulation (-) + !CALL Fill_avrSWAP( -1_IntKi, -10.0_DbKi, u, p, LEN(ErrMsg), m%dll_data ) - CALL CallBladedDLL(u, p%DLL_Trgt, m%dll_data, p, ErrStat, ErrMsg) - END IF + CALL CallBladedDLL(u, p%DLL_Trgt, m%dll_data, p, ErrStat, ErrMsg) + END IF + end if CALL FreeDynamicLib( p%DLL_Trgt, ErrStat2, ErrMsg2 ) ! this doesn't do anything #ifdef STATIC_DLL_LOAD because p%DLL_Trgt is 0 (NULL) IF (ErrStat2 /= ErrID_None) THEN