From b879d65471ce7099515e82777f475aff53eadac6 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:17:48 -0700 Subject: [PATCH 01/10] BeamDyn: return DTBeam from BD_Init; sub-step BeamDyn in the driver BD_Init used its Interval argument only as the default for DTBeam and never returned the time step it used. With a numeric DTBeam the BeamDyn driver kept stepping inputs and outputs at its own dt while the integrator advanced by DTBeam, giving wrong results with no message (issue #3516, item 1). - BD_Init now returns p%dt through Interval. - beamdyn_driver sub-steps BeamDyn when DTBeam is an integer divisor of the driver dt and writes output every driver dt. It stops with an error if DTBeam is larger than dt or does not divide it. - OpenFAST: BeamDyn is tightly coupled and cannot be sub-stepped, so FAST_InitializeAll now stops with an error if DTBeam differs from DT. - Docs: describe the DTBeam requirements for OpenFAST and the driver. Co-Authored-By: Claude Opus 5.5 --- docs/source/user/beamdyn/input_files.rst | 6 ++ modules/beamdyn/src/BeamDyn.f90 | 3 + modules/beamdyn/src/Driver_Beam.f90 | 80 ++++++++++++++++------ modules/openfast-library/src/FAST_Subs.f90 | 9 +++ 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/docs/source/user/beamdyn/input_files.rst b/docs/source/user/beamdyn/input_files.rst index 412e921555..f924f7c8ad 100644 --- a/docs/source/user/beamdyn/input_files.rst +++ b/docs/source/user/beamdyn/input_files.rst @@ -266,6 +266,12 @@ keyword “DEFAULT” sets ``N_Fact = 5``. time-integration in seconds. The keyword “DEFAULT” may be used to indicate that the module should employ the time increment prescribed by the driver code (FAST/stand-alone driver program). +In OpenFAST, BeamDyn is tightly coupled to the other structural modules +and cannot be sub-stepped, so ``DTBeam`` must be “DEFAULT” or equal to +``DT``. In the stand-alone BeamDyn driver, ``DTBeam`` may be smaller than +the driver time step ``DT`` if it is an integer divisor of ``DT``; the +driver then takes ``DT``/``DTBeam`` BeamDyn steps per driver step and +writes output every ``DT``. ``load_retries`` specifies the maximum number of load retries allowed. This option currently works only for static analysis. For every load retry, the applied load is diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index 1b510e8a82..e07bdc987e 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -127,6 +127,9 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I ! this routine sets *some* of the parameters (basically the "easy" ones) call SetParameters(InitInp, InputFileData, p, OtherState, ErrStat2, ErrMsg2); if (Failed()) return + ! Return the time step BeamDyn uses (DTBeam) so the caller can step (or sub-step) consistently + Interval = p%dt + ! Temporary GLL point intrinsic coordinates array CALL BD_GenerateGLL(p%nodes_per_elem,GLL_nodes,ErrStat2,ErrMsg2); if (Failed()) return diff --git a/modules/beamdyn/src/Driver_Beam.f90 b/modules/beamdyn/src/Driver_Beam.f90 index 8b218beeab..e1afcd230f 100644 --- a/modules/beamdyn/src/Driver_Beam.f90 +++ b/modules/beamdyn/src/Driver_Beam.f90 @@ -32,6 +32,11 @@ PROGRAM BeamDyn_Driver_Program CHARACTER(1024) :: ErrMsg ! Error message if ErrStat /= ErrID_None REAL(DbKi) :: dt_global ! fixed/constant global time step REAL(DbKi) :: t_global ! global-loop time marker + REAL(DbKi) :: dt_BD ! BeamDyn time step (DTBeam, returned from BD_Init) + REAL(DbKi) :: t_BD ! BeamDyn sub-step time marker + INTEGER(IntKi) :: n_substeps ! number of BeamDyn time steps per driver time step + INTEGER(IntKi) :: j_ss ! BeamDyn sub-step counter + INTEGER(IntKi) :: n_t_BD ! BeamDyn time step counter INTEGER(IntKi) :: n_t_final ! total number of time steps INTEGER(IntKi) :: n_t_global ! global-loop time counter INTEGER(IntKi) :: n_t_vtk ! global vtk step counter @@ -112,6 +117,9 @@ PROGRAM BeamDyn_Driver_Program ALLOCATE(BD_Input(BD_interp_order + 1)) ALLOCATE(BD_InputTimes(BD_interp_order + 1)) + ! Suggested BeamDyn time step. BD_Init returns the time step BeamDyn actually uses (DTBeam) + dt_BD = dt_global + CALL BD_Init(BD_InitInput & , BD_Input(1) & , BD_Parameter & @@ -121,11 +129,15 @@ PROGRAM BeamDyn_Driver_Program , BD_OtherState & , BD_Output & , BD_MiscVar & - , dt_global & + , dt_BD & , BD_InitOutput & , ErrStat & , ErrMsg ) CALL CheckError() + + ! BeamDyn may use a smaller time step (DTBeam) than the driver. Sub-step BeamDyn in that case. + call SetBDSubSteps() + CALL CheckError() ! If the Quasi-Static solve is in use, rerun the initialization with loads at t=0 ! (HACK: set in the driver only because computing Jacobians with this option [as in FAST glue code] is problematic) @@ -155,7 +167,7 @@ PROGRAM BeamDyn_Driver_Program CALL CheckError() ! solve for inputs at previous time steps - BD_InputTimes(j) = DvrData%t_initial - (j - 1) * dt_global + BD_InputTimes(j) = DvrData%t_initial - (j - 1) * dt_BD CALL BD_InputSolve( BD_InputTimes(j), BD_Input(j), DvrData, ErrStat, ErrMsg) CALL CheckError() END DO @@ -194,27 +206,30 @@ PROGRAM BeamDyn_Driver_Program DO n_t_global = 0, n_t_final - ! Shift "window" of BD_Input - DO j = BD_interp_order, 1, -1 - CALL BD_CopyInput (BD_Input(j), BD_Input(j+1), MESH_UPDATECOPY, Errstat, ErrMsg) + IF(BD_Parameter%analysis_type .EQ. BD_STATIC_ANALYSIS .AND. n_t_global > max_ld_step) EXIT + + ! update states from n_t_global to n_t_global + 1, sub-stepping BeamDyn at its own time step + DO j_ss = 1, n_substeps + n_t_BD = n_t_global*n_substeps + j_ss - 1 + t_BD = n_t_BD * dt_BD + DvrData%t_initial + + ! Shift "window" of BD_Input + DO j = BD_interp_order, 1, -1 + CALL BD_CopyInput (BD_Input(j), BD_Input(j+1), MESH_UPDATECOPY, Errstat, ErrMsg) + CALL CheckError() + BD_InputTimes(j+1) = BD_InputTimes(j) + END DO + + BD_InputTimes(1) = t_BD + dt_BD + CALL BD_InputSolve( BD_InputTimes(1), BD_Input(1), DvrData, ErrStat, ErrMsg) CALL CheckError() - BD_InputTimes(j+1) = BD_InputTimes(j) - END DO - - BD_InputTimes(1) = t_global + dt_global - CALL BD_InputSolve( BD_InputTimes(1), BD_Input(1), DvrData, ErrStat, ErrMsg) - CALL CheckError() - - - IF(BD_Parameter%analysis_type .EQ. BD_STATIC_ANALYSIS .AND. n_t_global > max_ld_step) EXIT - - ! update states from n_t_global to n_t_global + 1 - CALL BD_UpdateStates( t_global, n_t_global, BD_Input, BD_InputTimes, BD_Parameter, & - BD_ContinuousState, & - BD_DiscreteState, BD_ConstraintState, & - BD_OtherState, BD_MiscVar, ErrStat, ErrMsg ) - CALL CheckError() + CALL BD_UpdateStates( t_BD, n_t_BD, BD_Input, BD_InputTimes, BD_Parameter, & + BD_ContinuousState, & + BD_DiscreteState, BD_ConstraintState, & + BD_OtherState, BD_MiscVar, ErrStat, ErrMsg ) + CALL CheckError() + END DO ! advance time t_global = (n_t_global+1) * dt_global + DvrData%t_initial @@ -247,6 +262,29 @@ PROGRAM BeamDyn_Driver_Program CALL Dvr_End() CONTAINS +!---------------------------------------------------------------------------------------------------------------------------------- + !> Set the number of BeamDyn sub-steps per driver time step. The BeamDyn time step (DTBeam) must be + !! equal to or an integer divisor of the driver time step. + SUBROUTINE SetBDSubSteps() + if (EqualRealNos(dt_BD, dt_global)) then + n_substeps = 1 + dt_BD = dt_global + elseif (dt_BD > dt_global) then + ErrStat = ErrID_Fatal + ErrMsg = 'BeamDyn time step DTBeam ('//trim(Num2LStr(dt_BD))//' s) cannot be larger than the driver time step DT ('// & + trim(Num2LStr(dt_global))//' s).' + else + n_substeps = nint(dt_global / dt_BD) + if (.not. EqualRealNos(dt_global, dt_BD*n_substeps)) then + ErrStat = ErrID_Fatal + ErrMsg = 'BeamDyn time step DTBeam ('//trim(Num2LStr(dt_BD))//' s) must be an integer divisor of the driver time step DT ('// & + trim(Num2LStr(dt_global))//' s).' + else + call WrScr(' BeamDyn time step DTBeam ('//trim(Num2LStr(dt_BD))//' s) is smaller than the driver time step DT ('// & + trim(Num2LStr(dt_global))//' s). Using '//trim(Num2LStr(n_substeps))//' BeamDyn sub-steps per driver step.') + endif + endif + END SUBROUTINE SetBDSubSteps !---------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE Dvr_End() diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 77c93e5a2a..5f92dbb640 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -459,6 +459,15 @@ SUBROUTINE FAST_InitializeAll( t_initial, m_Glue, p_FAST, y_FAST, m_FAST, ED, SE BD%OtherSt(j,STATE_CURR), BD%y(j), BD%m(j), dt_module, Init%OutData_BD(j), ErrStat2, ErrMsg2) if (Failed()) return + ! BeamDyn is tightly coupled in the glue code, so it cannot be sub-stepped: DTBeam must match DT + if (.not. EqualRealNos(dt_module, p_FAST%DT)) then + call SetErrStat(ErrID_Fatal, "BeamDyn time step DTBeam ("//trim(Num2LStr(dt_module))//" s) must equal the "// & + "OpenFAST time step DT ("//trim(Num2LStr(p_FAST%DT))//" s). Set DTBeam to DEFAULT or to DT.", & + ErrStat, ErrMsg, RoutineName) + call Cleanup() + return + end if + ! We're going to do fewer computations if the BD input and output meshes that couple to AD are siblings (but it needs to be true for all instances): if (BD%p(j)%BldMotionNodeLoc /= BD_MESH_QP) p_FAST%BD_OutputSibling = .false. if (p_FAST%CompAeroMaps .and. BD%p(j)%BldMotionNodeLoc /= BD_MESH_FE) call SetErrStat(ErrID_Fatal, "BeamDyn aero maps must have outputs at FE nodes.", ErrStat, ErrMsg, RoutineName) From 6f77541a44d3fa820e21ab69a7a28a701fa095da Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:17:48 -0700 Subject: [PATCH 02/10] ModReg: check iostat on registry pack/unpack reads and writes The generated read(RF%Unit) and write(RF%Unit) statements in ModReg.f90 had no iostat, so a truncated or unreadable checkpoint stopped the program with a Fortran runtime error instead of setting RF%ErrStat. That ends the calling process when OpenFAST is used as a library (issue #3516, item 2). ModRegGen.py now generates iostat checks on the data-number and data reads/writes, setting RF%ErrStat and RF%ErrMsg on failure. ModReg.f90 is regenerated. Co-Authored-By: Claude Opus 5.5 --- modules/nwtc-library/ModRegGen.py | 34 +- modules/nwtc-library/src/ModReg.f90 | 839 +++++++++++++++++++++++----- 2 files changed, 721 insertions(+), 152 deletions(-) diff --git a/modules/nwtc-library/ModRegGen.py b/modules/nwtc-library/ModRegGen.py index 01981f6b2e..b7c7815e5e 100644 --- a/modules/nwtc-library/ModRegGen.py +++ b/modules/nwtc-library/ModRegGen.py @@ -303,12 +303,19 @@ type(RegFile), intent(inout) :: RF logical :: match integer(B8Ki) :: DataNum + integer(IntKi) :: stat ! Increment the data number to be read RF%NumData = RF%NumData + 1 - ! Read the data number from the file - read(RF%Unit) DataNum + ! Read the data number from the file, return if error + read(RF%Unit, iostat=stat) DataNum + if (stat /= 0) then + match = .false. + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Error reading data number", RF%NumData, "from file, iostat =", stat + return + end if ! If data number from file does not match expected number, set match false ! and create error message; otherwise, set match to true @@ -329,16 +336,26 @@ def gen_pack(w, dt, decl, rank): w.write(f'\n\n subroutine {name}(RF, Data)') w.write(f'\n type(RegFile), intent(inout) :: RF') w.write(f'\n {decl+", intent(in)":<35s} :: Data{dims}') + w.write(f'\n integer(IntKi) :: stat') w.write(f'\n') w.write(f'\n ! If error, return') w.write(f'\n if (RF%ErrStat /= ErrID_None) return') w.write(f'\n') w.write(f'\n ! Increment data number and write to file') w.write(f'\n RF%NumData = RF%NumData + 1') - w.write(f'\n write(RF%Unit) RF%NumData') + w.write(f'\n write(RF%Unit, iostat=stat) RF%NumData') + w.write(f'\n if (stat /= 0) then') + w.write(f'\n RF%ErrStat = ErrID_Fatal') + w.write(f'\n write(RF%ErrMsg, *) "{name}: error writing data number", RF%NumData, "to file, iostat =", stat') + w.write(f'\n return') + w.write(f'\n end if') w.write(f'\n') w.write(f'\n ! Write data to file') - w.write(f'\n write(RF%Unit) Data') + w.write(f'\n write(RF%Unit, iostat=stat) Data') + w.write(f'\n if (stat /= 0) then') + w.write(f'\n RF%ErrStat = ErrID_Fatal') + w.write(f'\n write(RF%ErrMsg, *) "{name}: error writing data", RF%NumData, "to file, iostat =", stat') + w.write(f'\n end if') w.write(f'\n end subroutine') @@ -349,6 +366,7 @@ def gen_unpack(w, dt, decl, rank): w.write(f'\n subroutine {name}(RF, Data)') w.write(f'\n type(RegFile), intent(inout) :: RF') w.write(f'\n {decl+", intent(out)":<35s} :: Data{dims}') + w.write(f'\n integer(IntKi) :: stat') w.write(f'\n') w.write(f'\n ! If error, return') w.write(f'\n if (RF%ErrStat /= ErrID_None) return') @@ -356,8 +374,12 @@ def gen_unpack(w, dt, decl, rank): w.write(f'\n ! Read data number, return if invalid') w.write(f'\n if (.not. DataNumValid(RF)) return') w.write(f'\n') - w.write(f'\n ! Read data from file') - w.write(f'\n read(RF%Unit) Data') + w.write(f'\n ! Read data from file, return if error') + w.write(f'\n read(RF%Unit, iostat=stat) Data') + w.write(f'\n if (stat /= 0) then') + w.write(f'\n RF%ErrStat = ErrID_Fatal') + w.write(f'\n write(RF%ErrMsg, *) "{name}: error reading data", RF%NumData, "from file, iostat =", stat') + w.write(f'\n end if') w.write(f'\n end subroutine') def gen_pack_alloc(w, dt, decl, rank): diff --git a/modules/nwtc-library/src/ModReg.f90 b/modules/nwtc-library/src/ModReg.f90 index 1cc99dca2e..e1bf41175d 100644 --- a/modules/nwtc-library/src/ModReg.f90 +++ b/modules/nwtc-library/src/ModReg.f90 @@ -370,12 +370,19 @@ function DataNumValid(RF) result(match) type(RegFile), intent(inout) :: RF logical :: match integer(B8Ki) :: DataNum + integer(IntKi) :: stat ! Increment the data number to be read RF%NumData = RF%NumData + 1 - ! Read the data number from the file - read(RF%Unit) DataNum + ! Read the data number from the file, return if error + read(RF%Unit, iostat=stat) DataNum + if (stat /= 0) then + match = .false. + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Error reading data number", RF%NumData, "from file, iostat =", stat + return + end if ! If data number from file does not match expected number, set match false ! and create error message; otherwise, set match to true @@ -392,21 +399,32 @@ function DataNumValid(RF) result(match) subroutine Pack_C1(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -414,8 +432,12 @@ subroutine Unpack_C1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1(RF, Data) @@ -538,21 +560,32 @@ subroutine UnpackPtr_C1(RF, Data) subroutine Pack_C1_Rank1(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1_Rank1(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -560,8 +593,12 @@ subroutine Unpack_C1_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1_Rank1(RF, Data) @@ -699,21 +736,32 @@ subroutine UnpackPtr_C1_Rank1(RF, Data, LB, UB) subroutine Pack_C1_Rank2(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1_Rank2(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -721,8 +769,12 @@ subroutine Unpack_C1_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1_Rank2(RF, Data) @@ -860,21 +912,32 @@ subroutine UnpackPtr_C1_Rank2(RF, Data, LB, UB) subroutine Pack_C1_Rank3(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1_Rank3(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -882,8 +945,12 @@ subroutine Unpack_C1_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1_Rank3(RF, Data) @@ -1021,21 +1088,32 @@ subroutine UnpackPtr_C1_Rank3(RF, Data, LB, UB) subroutine Pack_C1_Rank4(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1_Rank4(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1043,8 +1121,12 @@ subroutine Unpack_C1_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1_Rank4(RF, Data) @@ -1182,21 +1264,32 @@ subroutine UnpackPtr_C1_Rank4(RF, Data, LB, UB) subroutine Pack_C1_Rank5(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_C1_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_C1_Rank5(RF, Data) type(RegFile), intent(inout) :: RF character(*), intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1204,8 +1297,12 @@ subroutine Unpack_C1_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_C1_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_C1_Rank5(RF, Data) @@ -1343,21 +1440,32 @@ subroutine UnpackPtr_C1_Rank5(RF, Data, LB, UB) subroutine Pack_L1(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1365,8 +1473,12 @@ subroutine Unpack_L1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1(RF, Data) @@ -1489,21 +1601,32 @@ subroutine UnpackPtr_L1(RF, Data) subroutine Pack_L1_Rank1(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1_Rank1(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1511,8 +1634,12 @@ subroutine Unpack_L1_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1_Rank1(RF, Data) @@ -1650,21 +1777,32 @@ subroutine UnpackPtr_L1_Rank1(RF, Data, LB, UB) subroutine Pack_L1_Rank2(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1_Rank2(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1672,8 +1810,12 @@ subroutine Unpack_L1_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1_Rank2(RF, Data) @@ -1811,21 +1953,32 @@ subroutine UnpackPtr_L1_Rank2(RF, Data, LB, UB) subroutine Pack_L1_Rank3(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1_Rank3(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1833,8 +1986,12 @@ subroutine Unpack_L1_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1_Rank3(RF, Data) @@ -1972,21 +2129,32 @@ subroutine UnpackPtr_L1_Rank3(RF, Data, LB, UB) subroutine Pack_L1_Rank4(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1_Rank4(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -1994,8 +2162,12 @@ subroutine Unpack_L1_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1_Rank4(RF, Data) @@ -2133,21 +2305,32 @@ subroutine UnpackPtr_L1_Rank4(RF, Data, LB, UB) subroutine Pack_L1_Rank5(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_L1_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_L1_Rank5(RF, Data) type(RegFile), intent(inout) :: RF logical, intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2155,8 +2338,12 @@ subroutine Unpack_L1_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_L1_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_L1_Rank5(RF, Data) @@ -2294,21 +2481,32 @@ subroutine UnpackPtr_L1_Rank5(RF, Data, LB, UB) subroutine Pack_I4(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2316,8 +2514,12 @@ subroutine Unpack_I4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4(RF, Data) @@ -2440,21 +2642,32 @@ subroutine UnpackPtr_I4(RF, Data) subroutine Pack_I4_Rank1(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4_Rank1(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2462,8 +2675,12 @@ subroutine Unpack_I4_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4_Rank1(RF, Data) @@ -2601,21 +2818,32 @@ subroutine UnpackPtr_I4_Rank1(RF, Data, LB, UB) subroutine Pack_I4_Rank2(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4_Rank2(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2623,8 +2851,12 @@ subroutine Unpack_I4_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4_Rank2(RF, Data) @@ -2762,21 +2994,32 @@ subroutine UnpackPtr_I4_Rank2(RF, Data, LB, UB) subroutine Pack_I4_Rank3(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4_Rank3(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2784,8 +3027,12 @@ subroutine Unpack_I4_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4_Rank3(RF, Data) @@ -2923,21 +3170,32 @@ subroutine UnpackPtr_I4_Rank3(RF, Data, LB, UB) subroutine Pack_I4_Rank4(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4_Rank4(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -2945,8 +3203,12 @@ subroutine Unpack_I4_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4_Rank4(RF, Data) @@ -3084,21 +3346,32 @@ subroutine UnpackPtr_I4_Rank4(RF, Data, LB, UB) subroutine Pack_I4_Rank5(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I4_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I4_Rank5(RF, Data) type(RegFile), intent(inout) :: RF integer(B4Ki), intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3106,8 +3379,12 @@ subroutine Unpack_I4_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I4_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I4_Rank5(RF, Data) @@ -3245,21 +3522,32 @@ subroutine UnpackPtr_I4_Rank5(RF, Data, LB, UB) subroutine Pack_I8(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3267,8 +3555,12 @@ subroutine Unpack_I8(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8(RF, Data) @@ -3391,21 +3683,32 @@ subroutine UnpackPtr_I8(RF, Data) subroutine Pack_I8_Rank1(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8_Rank1(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3413,8 +3716,12 @@ subroutine Unpack_I8_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8_Rank1(RF, Data) @@ -3552,21 +3859,32 @@ subroutine UnpackPtr_I8_Rank1(RF, Data, LB, UB) subroutine Pack_I8_Rank2(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8_Rank2(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3574,8 +3892,12 @@ subroutine Unpack_I8_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8_Rank2(RF, Data) @@ -3713,21 +4035,32 @@ subroutine UnpackPtr_I8_Rank2(RF, Data, LB, UB) subroutine Pack_I8_Rank3(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8_Rank3(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3735,8 +4068,12 @@ subroutine Unpack_I8_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8_Rank3(RF, Data) @@ -3874,21 +4211,32 @@ subroutine UnpackPtr_I8_Rank3(RF, Data, LB, UB) subroutine Pack_I8_Rank4(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8_Rank4(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -3896,8 +4244,12 @@ subroutine Unpack_I8_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8_Rank4(RF, Data) @@ -4035,21 +4387,32 @@ subroutine UnpackPtr_I8_Rank4(RF, Data, LB, UB) subroutine Pack_I8_Rank5(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_I8_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_I8_Rank5(RF, Data) type(RegFile), intent(inout) :: RF integer(B8Ki), intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4057,8 +4420,12 @@ subroutine Unpack_I8_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_I8_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_I8_Rank5(RF, Data) @@ -4196,21 +4563,32 @@ subroutine UnpackPtr_I8_Rank5(RF, Data, LB, UB) subroutine Pack_R4(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4218,8 +4596,12 @@ subroutine Unpack_R4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4(RF, Data) @@ -4342,21 +4724,32 @@ subroutine UnpackPtr_R4(RF, Data) subroutine Pack_R4_Rank1(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4_Rank1(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4364,8 +4757,12 @@ subroutine Unpack_R4_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4_Rank1(RF, Data) @@ -4503,21 +4900,32 @@ subroutine UnpackPtr_R4_Rank1(RF, Data, LB, UB) subroutine Pack_R4_Rank2(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4_Rank2(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4525,8 +4933,12 @@ subroutine Unpack_R4_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4_Rank2(RF, Data) @@ -4664,21 +5076,32 @@ subroutine UnpackPtr_R4_Rank2(RF, Data, LB, UB) subroutine Pack_R4_Rank3(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4_Rank3(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4686,8 +5109,12 @@ subroutine Unpack_R4_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4_Rank3(RF, Data) @@ -4825,21 +5252,32 @@ subroutine UnpackPtr_R4_Rank3(RF, Data, LB, UB) subroutine Pack_R4_Rank4(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4_Rank4(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -4847,8 +5285,12 @@ subroutine Unpack_R4_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4_Rank4(RF, Data) @@ -4986,21 +5428,32 @@ subroutine UnpackPtr_R4_Rank4(RF, Data, LB, UB) subroutine Pack_R4_Rank5(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R4_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R4_Rank5(RF, Data) type(RegFile), intent(inout) :: RF real(R4Ki), intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5008,8 +5461,12 @@ subroutine Unpack_R4_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R4_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R4_Rank5(RF, Data) @@ -5147,21 +5604,32 @@ subroutine UnpackPtr_R4_Rank5(RF, Data, LB, UB) subroutine Pack_R8(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5169,8 +5637,12 @@ subroutine Unpack_R8(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8(RF, Data) @@ -5293,21 +5765,32 @@ subroutine UnpackPtr_R8(RF, Data) subroutine Pack_R8_Rank1(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank1: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank1: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8_Rank1(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data(:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5315,8 +5798,12 @@ subroutine Unpack_R8_Rank1(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8_Rank1: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8_Rank1(RF, Data) @@ -5454,21 +5941,32 @@ subroutine UnpackPtr_R8_Rank1(RF, Data, LB, UB) subroutine Pack_R8_Rank2(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank2: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank2: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8_Rank2(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data(:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5476,8 +5974,12 @@ subroutine Unpack_R8_Rank2(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8_Rank2: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8_Rank2(RF, Data) @@ -5615,21 +6117,32 @@ subroutine UnpackPtr_R8_Rank2(RF, Data, LB, UB) subroutine Pack_R8_Rank3(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank3: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank3: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8_Rank3(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data(:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5637,8 +6150,12 @@ subroutine Unpack_R8_Rank3(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8_Rank3: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8_Rank3(RF, Data) @@ -5776,21 +6293,32 @@ subroutine UnpackPtr_R8_Rank3(RF, Data, LB, UB) subroutine Pack_R8_Rank4(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank4: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank4: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8_Rank4(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data(:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5798,8 +6326,12 @@ subroutine Unpack_R8_Rank4(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8_Rank4: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8_Rank4(RF, Data) @@ -5937,21 +6469,32 @@ subroutine UnpackPtr_R8_Rank4(RF, Data, LB, UB) subroutine Pack_R8_Rank5(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(in) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return ! Increment data number and write to file RF%NumData = RF%NumData + 1 - write(RF%Unit) RF%NumData + write(RF%Unit, iostat=stat) RF%NumData + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank5: error writing data number", RF%NumData, "to file, iostat =", stat + return + end if ! Write data to file - write(RF%Unit) Data + write(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Pack_R8_Rank5: error writing data", RF%NumData, "to file, iostat =", stat + end if end subroutine subroutine Unpack_R8_Rank5(RF, Data) type(RegFile), intent(inout) :: RF real(R8Ki), intent(out) :: Data(:,:,:,:,:) + integer(IntKi) :: stat ! If error, return if (RF%ErrStat /= ErrID_None) return @@ -5959,8 +6502,12 @@ subroutine Unpack_R8_Rank5(RF, Data) ! Read data number, return if invalid if (.not. DataNumValid(RF)) return - ! Read data from file - read(RF%Unit) Data + ! Read data from file, return if error + read(RF%Unit, iostat=stat) Data + if (stat /= 0) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "Unpack_R8_Rank5: error reading data", RF%NumData, "from file, iostat =", stat + end if end subroutine subroutine PackAlloc_R8_Rank5(RF, Data) From 6ecfad718c69f36868bebcb5ba426e9c3bee5ea2 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:17:48 -0700 Subject: [PATCH 03/10] BeamDyn: reset summary file unit in BD_End after closing it BD_End closed m%Un_Sum but left the unit number unchanged. If BD_End ran before the first dynamic step (which normally resets it) and the same misc variables were reused, the stale unit could be closed again, possibly belonging to another file (issue #3516, item 3). Co-Authored-By: Claude Opus 5.5 --- modules/beamdyn/src/BeamDyn.f90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index e07bdc987e..fa54e19b4f 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -2013,7 +2013,10 @@ SUBROUTINE BD_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) ! Place any last minute operations or calculations here: ! Close files here: - if (m%Un_Sum > 0) CLOSE(m%Un_Sum) + if (m%Un_Sum > 0) then + CLOSE(m%Un_Sum) + m%Un_Sum = -1 + endif ! Destroy the input data: From 5ec44bd1a5eefb51f0fe3ee2cfcc625f9df11c2f Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:18:17 -0700 Subject: [PATCH 04/10] FAST_Solver: index tight-coupling module check through p%iModTC The loop that reports sub-stepping being disabled for tightly coupled modules indexed GlueModData with the loop counter instead of p%iModTC(i), so it checked and named the wrong modules (the first size(p%iModTC) entries of GlueModData rather than the tight-coupling ones). All other category loops already use p%iModTC(i). Co-Authored-By: Claude Opus 5.5 --- modules/openfast-library/src/FAST_Solver.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 37ab4de784..f25ecfc1ef 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -211,9 +211,9 @@ subroutine FAST_SolverInit(p_FAST, p, m, GlueModData, GlueModMaps, Turbine, ErrS ! Loop through tight-coupling modules do i = 1, size(p%iModTC) - if (GlueModData(i)%SubSteps > 1) then - call WrScr('Info: tightly coupled module "'//trim(GlueModData(i)%Abbr)//'" requested '// & - 'time step of '//trim(Num2Lstr(GlueModData(i)%DT))//', which is different than '// & + if (GlueModData(p%iModTC(i))%SubSteps > 1) then + call WrScr('Info: tightly coupled module "'//trim(GlueModData(p%iModTC(i))%Abbr)//'" requested '// & + 'time step of '//trim(Num2Lstr(GlueModData(p%iModTC(i))%DT))//', which is different than '// & 'glue-code time step of '//trim(Num2Lstr(p%h))//'. Sub-stepping disabled for this module.') end if end do From fd1b6cc5cc09245a26566ab97200842f6cab9a7d Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:30:12 -0700 Subject: [PATCH 05/10] OpenFAST: allow BeamDyn sub-stepping; remove DTBeam == DT check The check added in b879d6547 stopped OpenFAST whenever DTBeam differed from DT. That is not needed now that BD_Init returns DTBeam: - Loose coupling: FAST_UpdateStates already sub-steps BeamDyn at its own time step, and MV_AddModule rejects a DTBeam that is larger than DT or not an integer divisor of it. - Tight coupling: the glue code integrates the BeamDyn states at DT and BD_UpdateStates is not called, so DTBeam is not used. The solver already prints an info message that sub-stepping is disabled. Update the DTBeam documentation to match. Co-Authored-By: Claude Opus 5.5 --- docs/source/user/beamdyn/input_files.rst | 12 ++++++------ modules/openfast-library/src/FAST_Subs.f90 | 9 --------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/docs/source/user/beamdyn/input_files.rst b/docs/source/user/beamdyn/input_files.rst index f924f7c8ad..915e6ac0b2 100644 --- a/docs/source/user/beamdyn/input_files.rst +++ b/docs/source/user/beamdyn/input_files.rst @@ -266,12 +266,12 @@ keyword “DEFAULT” sets ``N_Fact = 5``. time-integration in seconds. The keyword “DEFAULT” may be used to indicate that the module should employ the time increment prescribed by the driver code (FAST/stand-alone driver program). -In OpenFAST, BeamDyn is tightly coupled to the other structural modules -and cannot be sub-stepped, so ``DTBeam`` must be “DEFAULT” or equal to -``DT``. In the stand-alone BeamDyn driver, ``DTBeam`` may be smaller than -the driver time step ``DT`` if it is an integer divisor of ``DT``; the -driver then takes ``DT``/``DTBeam`` BeamDyn steps per driver step and -writes output every ``DT``. +``DTBeam`` must be equal to or an integer divisor of the glue-code or +driver time step ``DT``. When it is smaller, BeamDyn takes +``DT``/``DTBeam`` steps per glue-code or driver step, and output is +written every ``DT``. In OpenFAST with tight coupling (``ModCoupling`` = +2 or 3), the glue code integrates the BeamDyn states at ``DT`` and +``DTBeam`` is not used. ``load_retries`` specifies the maximum number of load retries allowed. This option currently works only for static analysis. For every load retry, the applied load is diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 5f92dbb640..77c93e5a2a 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -459,15 +459,6 @@ SUBROUTINE FAST_InitializeAll( t_initial, m_Glue, p_FAST, y_FAST, m_FAST, ED, SE BD%OtherSt(j,STATE_CURR), BD%y(j), BD%m(j), dt_module, Init%OutData_BD(j), ErrStat2, ErrMsg2) if (Failed()) return - ! BeamDyn is tightly coupled in the glue code, so it cannot be sub-stepped: DTBeam must match DT - if (.not. EqualRealNos(dt_module, p_FAST%DT)) then - call SetErrStat(ErrID_Fatal, "BeamDyn time step DTBeam ("//trim(Num2LStr(dt_module))//" s) must equal the "// & - "OpenFAST time step DT ("//trim(Num2LStr(p_FAST%DT))//" s). Set DTBeam to DEFAULT or to DT.", & - ErrStat, ErrMsg, RoutineName) - call Cleanup() - return - end if - ! We're going to do fewer computations if the BD input and output meshes that couple to AD are siblings (but it needs to be true for all instances): if (BD%p(j)%BldMotionNodeLoc /= BD_MESH_QP) p_FAST%BD_OutputSibling = .false. if (p_FAST%CompAeroMaps .and. BD%p(j)%BldMotionNodeLoc /= BD_MESH_FE) call SetErrStat(ErrID_Fatal, "BeamDyn aero maps must have outputs at FE nodes.", ErrStat, ErrMsg, RoutineName) From 145e182defaf5d18dd39bbf0adc72aa7a54b6706 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:34:48 -0700 Subject: [PATCH 06/10] BeamDyn: reject nonpositive DTBeam A zero or negative numeric DTBeam was not rejected. In the driver, zero divided by zero when computing sub-steps, and a negative value gave a nonpositive sub-step count, so the beam states were never updated while output time advanced. - BD_ValidateInputData: DTBeam must be > 0 for dynamic solves (DTBeam is not used in static solves, where the driver dt may be 0). - Driver SetBDSubSteps: also reject dt_BD <= 0 before computing the number of sub-steps. Addresses Copilot review on #3517. Co-Authored-By: Claude Opus 5.5 --- modules/beamdyn/src/BeamDyn_IO.f90 | 4 ++++ modules/beamdyn/src/Driver_Beam.f90 | 3 +++ 2 files changed, 7 insertions(+) diff --git a/modules/beamdyn/src/BeamDyn_IO.f90 b/modules/beamdyn/src/BeamDyn_IO.f90 index 3bebee9578..2429033ed5 100644 --- a/modules/beamdyn/src/BeamDyn_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_IO.f90 @@ -1534,6 +1534,10 @@ SUBROUTINE BD_ValidateInputData( InitInp, InputFileData, ErrStat, ErrMsg ) IF(InputFileData%QuasiStaticInit .AND. (.NOT. InitInp%DynamicSolve)) & CALL SetErrStat ( ErrID_Warn, 'QuasiStaticInit option only valid with dynamic solve. Ignoring.', ErrStat, ErrMsg, RoutineName ) + ! Time step must be positive for dynamic solves (not used in static solves) + IF(InitInp%DynamicSolve .AND. InputFileData%DTBeam <= 0.0_DbKi) & + CALL SetErrStat ( ErrID_Fatal, 'DTBeam must be greater than 0.', ErrStat, ErrMsg, RoutineName ) + IF(InputFileData%rhoinf .LT. 0.0_BDKi .OR. InputFileData%rhoinf .GT. 1.0_BDKi) & CALL SetErrStat ( ErrID_Fatal, 'Numerical damping parameter \rho_{inf} must be in the range of [0.0,1.0]', ErrStat, ErrMsg, RoutineName ) IF(InputFileData%quadrature .NE. GAUSS_QUADRATURE .AND. InputFileData%quadrature .NE. TRAP_QUADRATURE) & diff --git a/modules/beamdyn/src/Driver_Beam.f90 b/modules/beamdyn/src/Driver_Beam.f90 index e1afcd230f..e1e6a1ef75 100644 --- a/modules/beamdyn/src/Driver_Beam.f90 +++ b/modules/beamdyn/src/Driver_Beam.f90 @@ -269,6 +269,9 @@ SUBROUTINE SetBDSubSteps() if (EqualRealNos(dt_BD, dt_global)) then n_substeps = 1 dt_BD = dt_global + elseif (dt_BD <= 0.0_DbKi) then + ErrStat = ErrID_Fatal + ErrMsg = 'BeamDyn time step DTBeam ('//trim(Num2LStr(dt_BD))//' s) must be greater than 0.' elseif (dt_BD > dt_global) then ErrStat = ErrID_Fatal ErrMsg = 'BeamDyn time step DTBeam ('//trim(Num2LStr(dt_BD))//' s) cannot be larger than the driver time step DT ('// & From 343117d223b5fec68ab77ec685e03ba03badbf9e Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:34:48 -0700 Subject: [PATCH 07/10] ModReg: check for errors in RegUnpackPointer before using the index RegUnpackPointer used Idx to index RF%Pointers without checking whether reading it failed. With the new iostat checks (or an existing data number mismatch), Idx is undefined at that point, and a corrupt index was never range checked, so a bad checkpoint could still crash the calling process with an invalid memory access. RegUnpackPointer now initializes Ptr and Idx, returns if the read set an error, and sets an error if Idx is outside RF%Pointers. ModReg.f90 is regenerated. Addresses Copilot review on #3517. Co-Authored-By: Claude Opus 5.5 --- modules/nwtc-library/ModRegGen.py | 15 ++++++++++++++- modules/nwtc-library/src/ModReg.f90 | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/modules/nwtc-library/ModRegGen.py b/modules/nwtc-library/ModRegGen.py index b7c7815e5e..1840b783a8 100644 --- a/modules/nwtc-library/ModRegGen.py +++ b/modules/nwtc-library/ModRegGen.py @@ -261,11 +261,24 @@ type(c_ptr), intent(out) :: Ptr integer(B8Ki), intent(out) :: Idx + ! Initialize outputs + Ptr = c_null_ptr + Idx = 0 + ! If error, return if (RF%ErrStat /= ErrID_None) return - ! Unpack pointer index + ! Unpack pointer index, return if error call RegUnpack(RF, Idx) + if (RegCheckErr(RF, "RegUnpackPointer")) return + + ! Check that index is within pointer index bounds + if (Idx < 1 .or. Idx > size(RF%Pointers, kind=B8Ki)) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "RegUnpackPointer: pointer index", Idx, "out of range 1 to", size(RF%Pointers, kind=B8Ki) + Idx = 0 + return + end if ! Get pointer from index Ptr = RF%Pointers(Idx) diff --git a/modules/nwtc-library/src/ModReg.f90 b/modules/nwtc-library/src/ModReg.f90 index e1bf41175d..cccda0ccfd 100644 --- a/modules/nwtc-library/src/ModReg.f90 +++ b/modules/nwtc-library/src/ModReg.f90 @@ -328,11 +328,24 @@ subroutine RegUnpackPointer(RF, Ptr, Idx) type(c_ptr), intent(out) :: Ptr integer(B8Ki), intent(out) :: Idx + ! Initialize outputs + Ptr = c_null_ptr + Idx = 0 + ! If error, return if (RF%ErrStat /= ErrID_None) return - ! Unpack pointer index + ! Unpack pointer index, return if error call RegUnpack(RF, Idx) + if (RegCheckErr(RF, "RegUnpackPointer")) return + + ! Check that index is within pointer index bounds + if (Idx < 1 .or. Idx > size(RF%Pointers, kind=B8Ki)) then + RF%ErrStat = ErrID_Fatal + write(RF%ErrMsg, *) "RegUnpackPointer: pointer index", Idx, "out of range 1 to", size(RF%Pointers, kind=B8Ki) + Idx = 0 + return + end if ! Get pointer from index Ptr = RF%Pointers(Idx) From 8fa7a2aa07c5ffabbfedabe763f391fa4d980f10 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 14:59:24 -0700 Subject: [PATCH 08/10] BeamDyn driver: do not sub-step static analysis Static analysis does not use DTBeam: each driver step is a load step. Sub-stepping only repeated the static solve at intermediate load levels, and the DTBeam checks could reject inputs the static solve never uses. SetBDSubSteps now uses one step per driver step for static analysis, without checking DTBeam. Addresses Copilot review on #3517. Co-Authored-By: Claude Opus 5.5 --- modules/beamdyn/src/Driver_Beam.f90 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/beamdyn/src/Driver_Beam.f90 b/modules/beamdyn/src/Driver_Beam.f90 index e1e6a1ef75..8b36c60194 100644 --- a/modules/beamdyn/src/Driver_Beam.f90 +++ b/modules/beamdyn/src/Driver_Beam.f90 @@ -264,9 +264,13 @@ PROGRAM BeamDyn_Driver_Program CONTAINS !---------------------------------------------------------------------------------------------------------------------------------- !> Set the number of BeamDyn sub-steps per driver time step. The BeamDyn time step (DTBeam) must be - !! equal to or an integer divisor of the driver time step. + !! equal to or an integer divisor of the driver time step. Static analysis does not use DTBeam (each + !! driver step is a load step), so it is not sub-stepped. SUBROUTINE SetBDSubSteps() - if (EqualRealNos(dt_BD, dt_global)) then + if (BD_Parameter%analysis_type == BD_STATIC_ANALYSIS) then + n_substeps = 1 + dt_BD = dt_global + elseif (EqualRealNos(dt_BD, dt_global)) then n_substeps = 1 dt_BD = dt_global elseif (dt_BD <= 0.0_DbKi) then From 6db3610c4bbb6e7a8fad2d1db7749579364735d0 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 15:28:48 -0700 Subject: [PATCH 09/10] BeamDyn: use inputs interpolated to t+dt for the reference frame update when sub-stepping BD_UpdateStates passed u(1) to BD_UpdateGlobalRef. When the caller sub-steps BeamDyn (OpenFAST loose coupling with DTBeam < DT), u(1) is at the end of the caller's step, not at t+dt, so intermediate sub-steps moved the reference frame and set the root node motion from future root motion. BD_GA2 already interpolates the inputs to t+dt. When utimes(1) differs from t+dt, the inputs are now interpolated to t+dt for BD_UpdateGlobalRef. When they are equal, u(1) is used as before, so results without sub-stepping do not change. Addresses Copilot review on #3517. Co-Authored-By: Claude Fable 5.2 --- modules/beamdyn/src/BeamDyn.f90 | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index fa54e19b4f..fbdba0d808 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -2066,6 +2066,7 @@ SUBROUTINE BD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + TYPE(BD_InputType) :: u_interp ! Inputs interpolated to t+dt (used only when sub-stepping) INTEGER(IntKi) :: ErrStat2 ! Temporary Error status CHARACTER(ErrMsgLen) :: ErrMsg2 ! Temporary Error message @@ -2077,9 +2078,26 @@ SUBROUTINE BD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat CALL BD_GA2( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,''); if (ErrStat >= AbortErrLev) return - ! change reference frame to root motion at t=T+DT (u(1)%RootMotionMesh) - call BD_UpdateGlobalRef(u(1),p,x,OtherState,ErrStat2,ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'') + ! change reference frame to root motion at t+dt + if (EqualRealNos(utimes(1), t + p%dt)) then + ! u(1) is at t+dt (BeamDyn time step is the same as the caller's) + call BD_UpdateGlobalRef(u(1),p,x,OtherState,ErrStat2,ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'') + else + ! BeamDyn is being sub-stepped, so u(1) is at the end of the caller's step, not at t+dt. + ! Interpolate the (global frame) inputs to t+dt so the root motion matches the states. + call BD_CopyInput(u(1), u_interp, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'') + if (ErrStat < AbortErrLev) then + call BD_Input_ExtrapInterp(u, utimes, u_interp, t + p%dt, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'') + end if + if (ErrStat < AbortErrLev) then + call BD_UpdateGlobalRef(u_interp,p,x,OtherState,ErrStat2,ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,'') + end if + call BD_DestroyInput(u_interp, ErrStat2, ErrMsg2) + end if ELSE !IF(p%analysis_type == BD_STATIC_ANALYSIS) THEN CALL BD_Static( t, u, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) ENDIF From 24fe391d3757a43f054bbb624068da91f8b41cab Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 10 Nov 2026 15:55:28 -0700 Subject: [PATCH 10/10] BeamDyn: add bd_5MW_dynamic_substep regression test Adds a driver regression case with DTBeam = 0.001 and driver dt = 0.002 so the sub-step loop in beamdyn_driver is covered. The existing BeamDyn driver cases all use DTBeam = DEFAULT and only take one BeamDyn step per driver step. Updates the r-test pointer for the new case. Addresses Copilot review on #3517. Co-Authored-By: Claude Fable 5.2 --- reg_tests/CTestList.cmake | 1 + reg_tests/r-test | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 787967f6dc..1cfa15cea0 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -472,6 +472,7 @@ ua_regression("ua_redfreq" "unsteadyaero") # BeamDyn regression tests bd_regression("bd_5MW_dynamic" "beamdyn;dynamic") +bd_regression("bd_5MW_dynamic_substep" "beamdyn;dynamic") bd_regression("bd_5MW_dynamic_gravity_Az00" "beamdyn;dynamic") bd_regression("bd_5MW_dynamic_gravity_Az90" "beamdyn;dynamic") bd_regression("bd_5MW_dynamic_modal_damping" "beamdyn;dynamic") diff --git a/reg_tests/r-test b/reg_tests/r-test index 2aa1664832..fd31c2b88e 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 2aa1664832f47d6c1286583b33c36bf4dfe1b80b +Subproject commit fd31c2b88e4731a791d9efe14a765a2a8a6fc837