From 8c802349381bd05e1c30860abe03c06af758ae70 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 29 Apr 2026 12:27:23 -0600 Subject: [PATCH 1/9] WD: fix minor index logic on wake planes getting dropped --- modules/wakedynamics/src/WakeDynamics.f90 | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index 6664c6e44f..e3c032417c 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -972,8 +972,9 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg if ( xd%x_plane(i) > p%x_Buff ) then - xd%NumPlanes = max( xd%NumPlanes - 1.0, 2.0 ) + xd%NumPlanes = max( xd%NumPlanes - 1.0, 2.0 ) ! Plane indexing includes 0, hence the -1.0 + ! If a plane overtakes another plane, drop the plane that is doing the overtaking and shift all remaining planes forward. We skip checking the last plane since it can't overtake anything. else if ( i+1 < NINT(xd%NumPlanes) .and. xd%x_plane(i) >= xd%x_plane(i+1) ) then call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))//' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))//' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))//'). Offending wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) @@ -982,14 +983,9 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg return end if - ! Remove offending plane and shift everything behind up - - xd%NumPlanes = xd%NumPlanes - 1.0 - - ! Didn't check xd%NumPlanes >= 2 here. The first wake plane is unlikely to move upwind of the rotor. - + ! Overwrite the i plane that is passing with the i+1 plane, and shift all following planes back by one plane. + ! Didn't check xd%NumPlanes >= 2 here. The first wake plane is unlikely to pass the second plane. do j = i+1,NINT(xd%NumPlanes)-1 - xd%Vx_wind_disk_filt(j-1) = xd%Vx_wind_disk_filt(j) xd%x_plane ( j-1) = xd%x_plane ( j) xd%TI_amb_filt ( j-1) = xd%TI_amb_filt ( j) @@ -1003,9 +999,11 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg xd%Vx_wake2 (:,:,j-1) = xd%Vx_wake2 (:,:,j) xd%Vy_wake2 (:,:,j-1) = xd%Vy_wake2 (:,:,j) xd%Vz_wake2 (:,:,j-1) = xd%Vz_wake2 (:,:,j) - end do + ! Now that we shifted the planes up, remove the last one + xd%NumPlanes = xd%NumPlanes - 1.0 + end if end do From 674bd007fdc0c1c3bde1a280e9778305f22d94d0 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 29 Apr 2026 13:50:24 -0600 Subject: [PATCH 2/9] WD: change NumDBuff and NumDFull to reals --- glue-codes/fast-farm/src/FAST_Farm_IO.f90 | 4 ++-- glue-codes/fast-farm/src/FAST_Farm_Subs.f90 | 2 +- modules/wakedynamics/src/WakeDynamics_Registry.txt | 4 ++-- modules/wakedynamics/src/WakeDynamics_Types.f90 | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/glue-codes/fast-farm/src/FAST_Farm_IO.f90 b/glue-codes/fast-farm/src/FAST_Farm_IO.f90 index 86e3f58cb3..32fce6d53c 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_IO.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_IO.f90 @@ -775,11 +775,11 @@ SUBROUTINE Farm_ReadPrimaryFile( InputFile, p, WD_InitInp, AWAE_InitInp, OutList CALL ReadVarWDefault( UnIn, InputFile, WD_InitInp%NumDFull, "NumDFull", & "Distance of full wake propagation, expressed as a multiple of RotorDiamRef [>0.0] or DEFAULT [DEFAULT=15]", & - 15_IntKi, ErrStat2, ErrMsg2, UnEc); if (Failed()) return + 15.0_ReKi, ErrStat2, ErrMsg2, UnEc); if (Failed()) return CALL ReadVarWDefault( UnIn, InputFile, WD_InitInp%NumDBuff, "NumDBuff", & "Length of wake propagation buffer region, expressed as a multiple of RotorDiamRef [>=0.0] or DEFAULT [DEFAULT=5]", & - 5_IntKi, ErrStat2, ErrMsg2, UnEc); if (Failed()) return + 5.0_ReKi, ErrStat2, ErrMsg2, UnEc); if (Failed()) return WD_InitInp%RotorDiamRef = p%RotorDiamRef diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 30a7160478..5a2eabde5c 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -211,7 +211,7 @@ SUBROUTINE Farm_Initialize( farm, InputFile, ErrStat, ErrMsg ) call AllocAry( farm%p%MaxNumPlanes, farm%p%NumTurbines, 'farm%p%MaxNumPlanes', ErrStat2, ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName); if (Failed()) return do i=1,farm%p%NumTurbines ! Eventually, we will have different settings for different rotors - farm%p%MaxNumPlanes(i) = ceiling( 15.0 * Real( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff , ReKi ) / AWAE_InitInput%InputFileData%C_Meander ) + farm%p%MaxNumPlanes(i) = ceiling( 15.0 * ( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff ) / AWAE_InitInput%InputFileData%C_Meander ) farm%p%MaxNumPlanes(i) = max( 2, min( farm%p%MaxNumPlanes(i) , farm%p%n_TMax + 2 ) ) end do diff --git a/modules/wakedynamics/src/WakeDynamics_Registry.txt b/modules/wakedynamics/src/WakeDynamics_Registry.txt index 56ae0024ef..692d06973b 100644 --- a/modules/wakedynamics/src/WakeDynamics_Registry.txt +++ b/modules/wakedynamics/src/WakeDynamics_Registry.txt @@ -25,8 +25,8 @@ param ^ - INTEGER Mod_Wake_Cartesian # ..... InputFile Data ....................................................................................................... typedef ^ WD_InputFileType ReKi dr - - - "Radial increment of radial finite-difference grid [>0.0]" m typedef ^ WD_InputFileType IntKi NumRadii - - - "Number of radii in the radial finite-difference grid [>=2]" - -typedef ^ WD_InputFileType IntKi NumDFull - - - "Distance of full wake propagation as a multiple of RotorDiamRef" - -typedef ^ WD_InputFileType IntKi NumDBuff - - - "Length of wake propagation buffer region as a multiple of RotorDiamRef" - +typedef ^ WD_InputFileType ReKi NumDFull - - - "Distance of full wake propagation as a multiple of RotorDiamRef" - +typedef ^ WD_InputFileType ReKi NumDBuff - - - "Length of wake propagation buffer region as a multiple of RotorDiamRef" - typedef ^ WD_InputFileType IntKi Mod_Wake - - - "Switch between wake formulations 1=Polar, 2=Cartesian, 3=Curl" - typedef ^ WD_InputFileType ReKi f_c - - - "Cut-off frequency of the low-pass time-filter for the wake advection, deflection, and meandering model [>0.0]" Hz typedef ^ WD_InputFileType ReKi C_HWkDfl_O - - - "Calibrated parameter in the correction for wake deflection defining the horizontal offset at the rotor" m diff --git a/modules/wakedynamics/src/WakeDynamics_Types.f90 b/modules/wakedynamics/src/WakeDynamics_Types.f90 index 23368a4d45..faec69b17a 100644 --- a/modules/wakedynamics/src/WakeDynamics_Types.f90 +++ b/modules/wakedynamics/src/WakeDynamics_Types.f90 @@ -44,8 +44,8 @@ MODULE WakeDynamics_Types TYPE, PUBLIC :: WD_InputFileType REAL(ReKi) :: dr = 0.0_ReKi !< Radial increment of radial finite-difference grid [>0.0] [m] INTEGER(IntKi) :: NumRadii = 0_IntKi !< Number of radii in the radial finite-difference grid [>=2] [-] - INTEGER(IntKi) :: NumDFull = 0_IntKi !< Distance of full wake propagation as a multiple of RotorDiamRef [-] - INTEGER(IntKi) :: NumDBuff = 0_IntKi !< Length of wake propagation buffer region as a multiple of RotorDiamRef [-] + REAL(ReKi) :: NumDFull = 0.0_ReKi !< Distance of full wake propagation as a multiple of RotorDiamRef [-] + REAL(ReKi) :: NumDBuff = 0.0_ReKi !< Length of wake propagation buffer region as a multiple of RotorDiamRef [-] INTEGER(IntKi) :: Mod_Wake = 0_IntKi !< Switch between wake formulations 1=Polar, 2=Cartesian, 3=Curl [-] REAL(ReKi) :: f_c = 0.0_ReKi !< Cut-off frequency of the low-pass time-filter for the wake advection, deflection, and meandering model [>0.0] [Hz] REAL(ReKi) :: C_HWkDfl_O = 0.0_ReKi !< Calibrated parameter in the correction for wake deflection defining the horizontal offset at the rotor [m] From 01104dcd3c1e36c266c618ebe8b59d873565d4a0 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 29 Apr 2026 14:05:57 -0600 Subject: [PATCH 3/9] FF: change max number of planes calculation Increase factor from 15 to 30 --- glue-codes/fast-farm/src/FAST_Farm_Subs.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 5a2eabde5c..cdd6489f62 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -211,7 +211,7 @@ SUBROUTINE Farm_Initialize( farm, InputFile, ErrStat, ErrMsg ) call AllocAry( farm%p%MaxNumPlanes, farm%p%NumTurbines, 'farm%p%MaxNumPlanes', ErrStat2, ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName); if (Failed()) return do i=1,farm%p%NumTurbines ! Eventually, we will have different settings for different rotors - farm%p%MaxNumPlanes(i) = ceiling( 15.0 * ( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff ) / AWAE_InitInput%InputFileData%C_Meander ) + farm%p%MaxNumPlanes(i) = ceiling( 30.0 * ( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff ) / AWAE_InitInput%InputFileData%C_Meander ) farm%p%MaxNumPlanes(i) = max( 2, min( farm%p%MaxNumPlanes(i) , farm%p%n_TMax + 2 ) ) end do From 344cf7102d120b6f1fe74e7953b69329aba71ebf Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Wed, 29 Apr 2026 15:05:11 -0600 Subject: [PATCH 4/9] WD: revise logic on wake overtake A segfault could occur in evaluating the plane index -- compiler dependent --- modules/wakedynamics/src/WakeDynamics.f90 | 57 ++++++++++++----------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index e3c032417c..4fb87d9da0 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -971,39 +971,42 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg do i=maxPln,0,-1 if ( xd%x_plane(i) > p%x_Buff ) then - xd%NumPlanes = max( xd%NumPlanes - 1.0, 2.0 ) ! Plane indexing includes 0, hence the -1.0 + cycle + endif ! If a plane overtakes another plane, drop the plane that is doing the overtaking and shift all remaining planes forward. We skip checking the last plane since it can't overtake anything. - else if ( i+1 < NINT(xd%NumPlanes) .and. xd%x_plane(i) >= xd%x_plane(i+1) ) then - - call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))//' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))//' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))//'). Offending wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) - if (errStat >= AbortErrLev) then - call Cleanup() - return - end if + if ( i+1 < NINT(xd%NumPlanes)) then + if (xd%x_plane(i) >= xd%x_plane(i+1) ) then - ! Overwrite the i plane that is passing with the i+1 plane, and shift all following planes back by one plane. - ! Didn't check xd%NumPlanes >= 2 here. The first wake plane is unlikely to pass the second plane. - do j = i+1,NINT(xd%NumPlanes)-1 - xd%Vx_wind_disk_filt(j-1) = xd%Vx_wind_disk_filt(j) - xd%x_plane ( j-1) = xd%x_plane ( j) - xd%TI_amb_filt ( j-1) = xd%TI_amb_filt ( j) - xd%D_rotor_filt ( j-1) = xd%D_rotor_filt ( j) - xd%YawErr_filt ( j-1) = xd%YawErr_filt ( j) - xd%p_plane ( :,j-1) = xd%p_plane ( :,j) - xd%xhat_plane ( :,j-1) = xd%xhat_plane ( :,j) - xd%V_plane_filt ( :,j-1) = xd%V_plane_filt ( :,j) - xd%Vx_wake ( :,j-1) = xd%Vx_wake ( :,j) - xd%Vr_wake ( :,j-1) = xd%Vr_wake ( :,j) - xd%Vx_wake2 (:,:,j-1) = xd%Vx_wake2 (:,:,j) - xd%Vy_wake2 (:,:,j-1) = xd%Vy_wake2 (:,:,j) - xd%Vz_wake2 (:,:,j-1) = xd%Vz_wake2 (:,:,j) - end do + call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))//' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))//' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))//'). Offending wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) + if (errStat >= AbortErrLev) then + call Cleanup() + return + end if - ! Now that we shifted the planes up, remove the last one - xd%NumPlanes = xd%NumPlanes - 1.0 + ! Overwrite the i plane that is passing with the i+1 plane, and shift all following planes back by one plane. + ! Didn't check xd%NumPlanes >= 2 here. The first wake plane is unlikely to pass the second plane. + do j = i+1,NINT(xd%NumPlanes)-1 + xd%Vx_wind_disk_filt(j-1) = xd%Vx_wind_disk_filt(j) + xd%x_plane ( j-1) = xd%x_plane ( j) + xd%TI_amb_filt ( j-1) = xd%TI_amb_filt ( j) + xd%D_rotor_filt ( j-1) = xd%D_rotor_filt ( j) + xd%YawErr_filt ( j-1) = xd%YawErr_filt ( j) + xd%p_plane ( :,j-1) = xd%p_plane ( :,j) + xd%xhat_plane ( :,j-1) = xd%xhat_plane ( :,j) + xd%V_plane_filt ( :,j-1) = xd%V_plane_filt ( :,j) + xd%Vx_wake ( :,j-1) = xd%Vx_wake ( :,j) + xd%Vr_wake ( :,j-1) = xd%Vr_wake ( :,j) + xd%Vx_wake2 (:,:,j-1) = xd%Vx_wake2 (:,:,j) + xd%Vy_wake2 (:,:,j-1) = xd%Vy_wake2 (:,:,j) + xd%Vz_wake2 (:,:,j-1) = xd%Vz_wake2 (:,:,j) + end do + + ! Now that we shifted the planes up, remove the last one + xd%NumPlanes = xd%NumPlanes - 1.0 + end if end if end do From ffb6a98aada3092c02be32a90604ce909ffe885c Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 30 Apr 2026 07:18:18 -0600 Subject: [PATCH 5/9] WD: adjust wake plane overtaking message --- modules/wakedynamics/src/WakeDynamics.f90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index 4fb87d9da0..36306a6a4d 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -979,7 +979,10 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg if ( i+1 < NINT(xd%NumPlanes)) then if (xd%x_plane(i) >= xd%x_plane(i+1) ) then - call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))//' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))//' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))//'). Offending wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) + call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))// & + ' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))// & + ' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))// & + '). Overtaking wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) if (errStat >= AbortErrLev) then call Cleanup() return From 8eb9db11e4e36a2969cb783a24f0487ff4dd3b1a Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Thu, 30 Apr 2026 15:20:09 -0600 Subject: [PATCH 6/9] FF: revert 01104dcd3 to keep original safety factor on max planes --- glue-codes/fast-farm/src/FAST_Farm_Subs.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index cdd6489f62..5a2eabde5c 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -211,7 +211,7 @@ SUBROUTINE Farm_Initialize( farm, InputFile, ErrStat, ErrMsg ) call AllocAry( farm%p%MaxNumPlanes, farm%p%NumTurbines, 'farm%p%MaxNumPlanes', ErrStat2, ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName); if (Failed()) return do i=1,farm%p%NumTurbines ! Eventually, we will have different settings for different rotors - farm%p%MaxNumPlanes(i) = ceiling( 30.0 * ( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff ) / AWAE_InitInput%InputFileData%C_Meander ) + farm%p%MaxNumPlanes(i) = ceiling( 15.0 * ( WD_InitInput%InputFileData%NumDFull + WD_InitInput%InputFileData%NumDBuff ) / AWAE_InitInput%InputFileData%C_Meander ) farm%p%MaxNumPlanes(i) = max( 2, min( farm%p%MaxNumPlanes(i) , farm%p%n_TMax + 2 ) ) end do From a6eca4625d6697a539c9fd4a0a4f7a06b43f52c9 Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 5 May 2026 13:10:08 -0600 Subject: [PATCH 7/9] WD: merge passing wake planes instead of simply dropping Merging fast plane and slow plane it is passing by simple averaging. --- modules/wakedynamics/src/WakeDynamics.f90 | 53 +++++++++++++++-------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index 36306a6a4d..b0b107b4b1 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -970,40 +970,55 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg do i=maxPln,0,-1 + ! if a plane is beyond the buffer, simply drop it and all following planes (it should only be the last plane that gets dropped) if ( xd%x_plane(i) > p%x_Buff ) then xd%NumPlanes = max( xd%NumPlanes - 1.0, 2.0 ) ! Plane indexing includes 0, hence the -1.0 cycle endif - ! If a plane overtakes another plane, drop the plane that is doing the overtaking and shift all remaining planes forward. We skip checking the last plane since it can't overtake anything. - if ( i+1 < NINT(xd%NumPlanes)) then + ! If a plane overtakes another plane, merge the planes by averaging, then shift all remaining planes forward. + if ( i+1 < NINT(xd%NumPlanes)) then ! don't overstep bounds with i+1 indexing if (xd%x_plane(i) >= xd%x_plane(i+1) ) then call SetErrStat(ErrID_Warn, ' Turbine '//trim(num2lstr(p%TurbNum))//' wake plane '//trim(num2lstr(i))// & ' (x_plane='//trim(num2lstr(xd%x_plane(i)))//') has overtaken wake plane '//trim(num2lstr(i+1))// & ' (x_plane='//trim(num2lstr(xd%x_plane(i+1)))// & - '). Overtaking wake plane removed. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) + '). Merging planes by averaging. Reduce f_c to prevent planes from passing each other. ', errStat, errMsg, RoutineName) if (errStat >= AbortErrLev) then call Cleanup() return end if - ! Overwrite the i plane that is passing with the i+1 plane, and shift all following planes back by one plane. - ! Didn't check xd%NumPlanes >= 2 here. The first wake plane is unlikely to pass the second plane. - do j = i+1,NINT(xd%NumPlanes)-1 - xd%Vx_wind_disk_filt(j-1) = xd%Vx_wind_disk_filt(j) - xd%x_plane ( j-1) = xd%x_plane ( j) - xd%TI_amb_filt ( j-1) = xd%TI_amb_filt ( j) - xd%D_rotor_filt ( j-1) = xd%D_rotor_filt ( j) - xd%YawErr_filt ( j-1) = xd%YawErr_filt ( j) - xd%p_plane ( :,j-1) = xd%p_plane ( :,j) - xd%xhat_plane ( :,j-1) = xd%xhat_plane ( :,j) - xd%V_plane_filt ( :,j-1) = xd%V_plane_filt ( :,j) - xd%Vx_wake ( :,j-1) = xd%Vx_wake ( :,j) - xd%Vr_wake ( :,j-1) = xd%Vr_wake ( :,j) - xd%Vx_wake2 (:,:,j-1) = xd%Vx_wake2 (:,:,j) - xd%Vy_wake2 (:,:,j-1) = xd%Vy_wake2 (:,:,j) - xd%Vz_wake2 (:,:,j-1) = xd%Vz_wake2 (:,:,j) + ! Merge the i and i+1 plane by averaging them together + xd%Vx_wind_disk_filt(i) = (xd%Vx_wind_disk_filt(i) + xd%Vx_wind_disk_filt(i+1)) / 2.0_ReKi + xd%x_plane ( i) = (xd%x_plane ( i) + xd%x_plane ( i+1)) / 2.0_ReKi + xd%TI_amb_filt ( i) = (xd%TI_amb_filt ( i) + xd%TI_amb_filt ( i+1)) / 2.0_ReKi + xd%D_rotor_filt ( i) = (xd%D_rotor_filt ( i) + xd%D_rotor_filt ( i+1)) / 2.0_ReKi + xd%YawErr_filt ( i) = (xd%YawErr_filt ( i) + xd%YawErr_filt ( i+1)) / 2.0_ReKi + xd%p_plane ( :,i) = (xd%p_plane ( :,i) + xd%p_plane ( :,i+1)) / 2.0_ReKi + xd%xhat_plane ( :,i) = (xd%xhat_plane ( :,i) + xd%xhat_plane ( :,i+1)) / 2.0_ReKi + xd%V_plane_filt ( :,i) = (xd%V_plane_filt ( :,i) + xd%V_plane_filt ( :,i+1)) / 2.0_ReKi + xd%Vx_wake ( :,i) = (xd%Vx_wake ( :,i) + xd%Vx_wake ( :,i+1)) / 2.0_ReKi + xd%Vr_wake ( :,i) = (xd%Vr_wake ( :,i) + xd%Vr_wake ( :,i+1)) / 2.0_ReKi + xd%Vx_wake2 (:,:,i) = (xd%Vx_wake2 (:,:,i) + xd%Vx_wake2 (:,:,i+1)) / 2.0_ReKi + xd%Vy_wake2 (:,:,i) = (xd%Vy_wake2 (:,:,i) + xd%Vy_wake2 (:,:,i+1)) / 2.0_ReKi + xd%Vz_wake2 (:,:,i) = (xd%Vz_wake2 (:,:,i) + xd%Vz_wake2 (:,:,i+1)) / 2.0_ReKi + + ! Since i and i+1 planes are now merged effectively dropping a plane, shift all planes that follow forward + do j = i+1,NINT(xd%NumPlanes)-2 ! NumPlanes includes 0 index plane, so last valid index is NumPlanes-1. + xd%Vx_wind_disk_filt(j) = xd%Vx_wind_disk_filt(j+1) + xd%x_plane ( j) = xd%x_plane ( j+1) + xd%TI_amb_filt ( j) = xd%TI_amb_filt ( j+1) + xd%D_rotor_filt ( j) = xd%D_rotor_filt ( j+1) + xd%YawErr_filt ( j) = xd%YawErr_filt ( j+1) + xd%p_plane ( :,j) = xd%p_plane ( :,j+1) + xd%xhat_plane ( :,j) = xd%xhat_plane ( :,j+1) + xd%V_plane_filt ( :,j) = xd%V_plane_filt ( :,j+1) + xd%Vx_wake ( :,j) = xd%Vx_wake ( :,j+1) + xd%Vr_wake ( :,j) = xd%Vr_wake ( :,j+1) + xd%Vx_wake2 (:,:,j) = xd%Vx_wake2 (:,:,j+1) + xd%Vy_wake2 (:,:,j) = xd%Vy_wake2 (:,:,j+1) + xd%Vz_wake2 (:,:,j) = xd%Vz_wake2 (:,:,j+1) end do ! Now that we shifted the planes up, remove the last one From e4068931b795cef714eed58a2ae197e2485ea02a Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 5 May 2026 13:36:49 -0600 Subject: [PATCH 8/9] WD: normalize plane vector when merging planes --- modules/wakedynamics/src/WakeDynamics.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index b0b107b4b1..aeb17fc44d 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -996,7 +996,7 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg xd%D_rotor_filt ( i) = (xd%D_rotor_filt ( i) + xd%D_rotor_filt ( i+1)) / 2.0_ReKi xd%YawErr_filt ( i) = (xd%YawErr_filt ( i) + xd%YawErr_filt ( i+1)) / 2.0_ReKi xd%p_plane ( :,i) = (xd%p_plane ( :,i) + xd%p_plane ( :,i+1)) / 2.0_ReKi - xd%xhat_plane ( :,i) = (xd%xhat_plane ( :,i) + xd%xhat_plane ( :,i+1)) / 2.0_ReKi + xd%xhat_plane ( :,i) = TwoNorm(xd%xhat_plane ( :,i) + xd%xhat_plane ( :,i+1)) ! renormalize xd%V_plane_filt ( :,i) = (xd%V_plane_filt ( :,i) + xd%V_plane_filt ( :,i+1)) / 2.0_ReKi xd%Vx_wake ( :,i) = (xd%Vx_wake ( :,i) + xd%Vx_wake ( :,i+1)) / 2.0_ReKi xd%Vr_wake ( :,i) = (xd%Vr_wake ( :,i) + xd%Vr_wake ( :,i+1)) / 2.0_ReKi From b0e0ad536b64b4639396d24643e5cd9b5fdb089f Mon Sep 17 00:00:00 2001 From: andrew-platt Date: Tue, 5 May 2026 14:12:52 -0600 Subject: [PATCH 9/9] WD: fix commit e4068931b That commit was an idiotic mistake in normalizing -- combined two lines of code without thinking. It ended up with a scalar value applied to all components of the vector --- modules/wakedynamics/src/WakeDynamics.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index aeb17fc44d..05b357088e 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -996,7 +996,8 @@ subroutine WD_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errMsg xd%D_rotor_filt ( i) = (xd%D_rotor_filt ( i) + xd%D_rotor_filt ( i+1)) / 2.0_ReKi xd%YawErr_filt ( i) = (xd%YawErr_filt ( i) + xd%YawErr_filt ( i+1)) / 2.0_ReKi xd%p_plane ( :,i) = (xd%p_plane ( :,i) + xd%p_plane ( :,i+1)) / 2.0_ReKi - xd%xhat_plane ( :,i) = TwoNorm(xd%xhat_plane ( :,i) + xd%xhat_plane ( :,i+1)) ! renormalize + xd%xhat_plane ( :,i) = (xd%xhat_plane ( :,i) + xd%xhat_plane ( :,i+1)) / 2.0_ReKi + xd%xhat_plane ( :,i) = xd%xhat_plane ( :,i) / TwoNorm(xd%xhat_plane( :,i)) ! renormalize xd%V_plane_filt ( :,i) = (xd%V_plane_filt ( :,i) + xd%V_plane_filt ( :,i+1)) / 2.0_ReKi xd%Vx_wake ( :,i) = (xd%Vx_wake ( :,i) + xd%Vx_wake ( :,i+1)) / 2.0_ReKi xd%Vr_wake ( :,i) = (xd%Vr_wake ( :,i) + xd%Vr_wake ( :,i+1)) / 2.0_ReKi