Skip to content

Commit 287381a

Browse files
authored
Merge pull request #3430 from luwang00/b/OLAF
AD: fix OLAF treecode near-core regularization floor and TwrInfl OpenMP data race
2 parents 0ec4bb2 + 980d9e3 commit 287381a

5 files changed

Lines changed: 92 additions & 56 deletions

File tree

modules/aerodyn/src/AeroDyn.f90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5605,8 +5605,9 @@ SUBROUTINE TwrInflArray( p, u, RotInflow, m, Positions, Inflow, ErrStat, ErrMsg
56055605
! these models are valid for only small tower deflections; check for potential division-by-zero errors:
56065606
call CheckTwrInfl( u, ErrStat2, ErrMsg2 ); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ); if (ErrStat >= AbortErrLev) return
56075607

5608+
! FirstWarn_TowerStrike is firstprivate so each thread starts from the .false. set above (avoids reading uninitialized memory); ErrStat2/ErrMsg2 are private to avoid a data race
56085609
!$OMP PARALLEL default(shared)
5609-
!$OMP do private(i,Pos,theta_tower_trans,W_tower,xbar,ybar,zbar,TwrCd,TwrTI,TwrClrnc,FirstWarn_TowerStrike,DisturbInflow,v) schedule(runtime)
5610+
!$OMP do private(i,Pos,theta_tower_trans,W_tower,xbar,ybar,zbar,TwrCd,TwrTI,TwrClrnc,DisturbInflow,v,ErrStat2,ErrMsg2) firstprivate(FirstWarn_TowerStrike) schedule(runtime)
56105611
do i = 1, size(Positions,2)
56115612
Pos=Positions(1:3,i)
56125613

modules/aerodyn/src/FVW_BiotSavart.f90

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ module FVW_BiotSavart
1010
real(ReKi),parameter :: PRECISION_UI = epsilon(1.0_ReKi)/100 !< NOTE assuming problem of size 1
1111
real(ReKi),parameter :: PRECISION_EPS = epsilon(1.0_ReKi) !< Machine Precision For the given ReKi for problems of scale 1!
1212
real(ReKi),parameter :: MIN_EXP_VALUE=-10.0_ReKi
13+
real(ReKi),parameter :: PART_REG_NRAD = 2.0_ReKi !< Particle exp mollifier treated as 1 beyond this many core radii (matches 2*rc far-field multipole floor)
14+
real(ReKi),parameter :: PART_REG_CUT3 = PART_REG_NRAD**3 !< Corresponding (r/rc)^3 cutoff
1315
real(ReKi),parameter :: MINDENOM=0.0_ReKi
1416
! real(ReKi),parameter :: MINDENOM=1e-15_ReKi
1517
real(ReKi),parameter :: MINNORM=1e-4
@@ -374,26 +376,35 @@ subroutine ui_part_nograd_11(DeltaP, Alpha, RegFunction, RegParam, Ui)
374376
real(ReKi),dimension(3) :: C !< Cross product of Alpha and r
375377
real(ReKi) :: E !< Exponential poart for the mollifider
376378
real(ReKi) :: r3_inv !<
379+
real(ReKi) :: r2, r3, rc3!< |r|^2, |r|^3, RegParam^3 (reused to avoid recomputing ** intrinsics)
377380
real(ReKi) :: rDeltaP !< norm , distance between point and particle
378381
real(ReKi) :: ScalarPart !< the part containing the inverse of the distance, but not 4pi, Mollifier
379-
rDeltaP=sqrt(DeltaP(1)**2+ DeltaP(2)**2+ DeltaP(3)**2)! norm
382+
r2 = DeltaP(1)**2+ DeltaP(2)**2+ DeltaP(3)**2
383+
rDeltaP = sqrt(r2)! norm
380384
if (rDeltaP<MINNORM) then !--- Exactly on the Singularity
381385
Ui(1:3) = 0.0_ReKi
382386
return
383387
else !--- Normal Procedure
388+
r3 = r2*rDeltaP ! |r|^3, reused below
384389
C(1) = Alpha(2) * DeltaP(3) - Alpha(3) * DeltaP(2)
385390
C(2) = Alpha(3) * DeltaP(1) - Alpha(1) * DeltaP(3)
386391
C(3) = Alpha(1) * DeltaP(2) - Alpha(2) * DeltaP(1)
387392
select case (RegFunction) !
388393
case (idRegNone) ! No mollification
389-
r3_inv = 1._ReKi/(rDeltaP**3)
394+
r3_inv = 1._ReKi/r3
390395
ScalarPart = r3_inv*fourpi_inv
391396
case (idRegExp) ! Exponential mollifier
392-
r3_inv = 1._ReKi/(rDeltaP**3)
393-
E = exp(-rDeltaP**3/RegParam**3)
394-
ScalarPart = (1._ReKi-E)*r3_inv*fourpi_inv
397+
rc3 = RegParam*RegParam*RegParam
398+
r3_inv = 1._ReKi/r3
399+
if (r3 > PART_REG_CUT3*rc3) then ! r > 2*rc: mollifier -> 1 (skip exp), consistent with far-field multipole floor
400+
ScalarPart = r3_inv*fourpi_inv
401+
else
402+
E = exp(-r3/rc3)
403+
ScalarPart = (1._ReKi-E)*r3_inv*fourpi_inv
404+
endif
395405
case (idRegCompact) ! Compact support
396-
r3_inv = 1._ReKi/sqrt(RegParam**6+rDeltaP**6)
406+
rc3 = RegParam*RegParam*RegParam
407+
r3_inv = 1._ReKi/sqrt(rc3*rc3+r3*r3)
397408
ScalarPart = r3_inv*fourpi_inv
398409
case default
399410
print*,'[ERROR] Wrong regularization function for particles',RegFunction

modules/aerodyn/src/FVW_Subs.f90

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,8 @@ subroutine FVW_InitRegularization(x, p, m, ErrStat, ErrMsg)
10471047
write(*,'(A,1F8.4)') 'RegParam (Input ) : ',p%WakeRegParam
10481048
endif
10491049

1050-
if (p%RegDeterMethod==idRegDeterConstant) then
1050+
select case (p%RegDeterMethod)
1051+
case (idRegDeterConstant)
10511052
! Constant reg param throughout the wake
10521053
if (p%WakeRegMethod==idRegAge) then ! NOTE: age method implies a division by rc
10531054
p%WingRegParam=max(0.01_ReKi, p%WingRegParam)
@@ -1061,7 +1062,7 @@ subroutine FVW_InitRegularization(x, p, m, ErrStat, ErrMsg)
10611062
x%W(iW)%Eps_NW(1:3,:,2) = p%WakeRegParam ! Second age is always WakeRegParam
10621063
endif
10631064

1064-
else if (p%RegDeterMethod==idRegDeterAuto) then
1065+
case (idRegDeterAuto)
10651066
! TODO this is beta
10661067
print*,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
10671068
print*,'!!! NOTE: using optimized wake regularization parameters is still a beta feature!'
@@ -1078,14 +1079,14 @@ subroutine FVW_InitRegularization(x, p, m, ErrStat, ErrMsg)
10781079
write(*,'(A,1F8.4)') 'WakeRegParam : ', p%WakeRegParam
10791080
write(*,'(A,1F8.4)') 'WingRegParam : ', p%WingRegParam
10801081
write(*,'(A,1F9.4)') 'CoreSpreadEddyVisc: ', p%CoreSpreadEddyVisc
1081-
! Set reg param on wing and first NW
1082-
! NOTE: setting the same in all three directions for now, TODO!
1083-
x%W(iW)%Eps_NW(1:3,:,1) = p%WingRegParam ! First age is always WingRegParam (LL)
1084-
if (p%nNWMax>1) then
1085-
x%W(iW)%Eps_NW(1:3,:,2) = p%WakeRegParam ! Second age is always WakeRegParam
1086-
endif
1082+
! Set reg param on wing and first NW
1083+
! NOTE: setting the same in all three directions for now, TODO!
1084+
x%W(iW)%Eps_NW(1:3,:,1) = p%WingRegParam ! First age is always WingRegParam (LL)
1085+
if (p%nNWMax>1) then
1086+
x%W(iW)%Eps_NW(1:3,:,2) = p%WakeRegParam ! Second age is always WakeRegParam
1087+
endif
10871088

1088-
else if (p%RegDeterMethod==idRegDeterChord) then
1089+
case (idRegDeterChord)
10891090
! Using chord to scale the reg param
10901091
do iSpan=1,p%W(iW)%nSpan
10911092
x%W(iW)%Eps_NW(1:3, iSpan, 1) = p%WingRegParam * p%W(iW)%chord_CP(iSpan)
@@ -1094,7 +1095,7 @@ subroutine FVW_InitRegularization(x, p, m, ErrStat, ErrMsg)
10941095
endif
10951096
enddo
10961097

1097-
else if (p%RegDeterMethod==idRegDeterSpan) then
1098+
case (idRegDeterSpan)
10981099
! Using dr to scale the reg param
10991100
do iSpan=1,p%W(iW)%nSpan
11001101
ds = p%W(iW)%s_LL(iSpan+1)-p%W(iW)%s_LL(iSpan)
@@ -1103,10 +1104,11 @@ subroutine FVW_InitRegularization(x, p, m, ErrStat, ErrMsg)
11031104
x%W(iW)%Eps_NW(1:3, iSpan, 2) = p%WakeRegParam * ds
11041105
endif
11051106
enddo
1106-
else ! Should never happen (caught earlier)
1107+
1108+
case default ! Should never happen (caught earlier)
11071109
ErrStat = ErrID_Fatal
11081110
ErrMsg ='Regularization determination method not implemented'
1109-
endif
1111+
end select
11101112

11111113
if (iW==1) then
11121114
call WrScr(' - OLAF regularization parameters (for wing 1):')
@@ -1223,9 +1225,9 @@ subroutine SegmentsToPartWrap(Sgmt, nSeg, PartPerSegment, RegFunction, Part, all
12231225
Part%RegFunction = idRegExp ! TODO need to find a good equivalence and potentially adapt Epsilon in SegmentsToPart
12241226
endif
12251227
if (DEV_VERSION) then
1226-
call find_nan_2D(Part%P , 'SegmentsToPartWrap Part%P')
1227-
call find_nan_2D(Part%Alpha, 'SegmentsToPartWrap Part%Alpha')
1228-
if (any(Part%RegParam(:)<-9999.99_ReKi)) then
1228+
call find_nan_2D(Part%P(:,1:nPart) , 'SegmentsToPartWrap Part%P')
1229+
call find_nan_2D(Part%Alpha(:,1:nPart), 'SegmentsToPartWrap Part%Alpha')
1230+
if (any(Part%RegParam(1:nPart)<-9999.99_ReKi)) then ! Only the active particles are filled; the preallocated tail keeps its sentinel
12291231
print*,'Error in Segment to part conversion'
12301232
STOP
12311233
endif
@@ -1261,18 +1263,19 @@ subroutine InducedVelocitiesAll_Init(p, x, m, Sgmt, Part, Tree, Panl, ErrStat, E
12611263
Sgmt%nAct = nSeg
12621264
Sgmt%nActP = nSegP
12631265

1264-
! --- Convert to particles if needed
1265-
if ((p%VelocityMethod(iVel)==idVelocityTreePart) .or. (p%VelocityMethod(iVel)==idVelocityPart)) then
1266+
select case (p%VelocityMethod(iVel))
1267+
case (idVelocityPart)
1268+
! --- Convert segments to particles
12661269
call SegmentsToPartWrap(Sgmt, nSeg, p%PartPerSegment(iVel), p%RegFunction, Part, allocPart=allocPart)
1267-
endif
1268-
1269-
! --- Grow tree if needed
1270-
if (p%VelocityMethod(iVel)==idVelocityTreePart) then
1270+
case (idVelocityTreePart)
1271+
! --- Convert segments to particles
1272+
call SegmentsToPartWrap(Sgmt, nSeg, p%PartPerSegment(iVel), p%RegFunction, Part, allocPart=allocPart)
1273+
! --- Grow particle tree
12711274
call grow_tree_part(Tree, Part%nAct, Part%P, Part%Alpha, Part%RegFunction, Part%RegParam, 0)
1272-
1273-
elseif (p%VelocityMethod(iVel)==idVelocityTreeSeg) then
1275+
case (idVelocityTreeSeg)
1276+
! --- Grow segment tree
12741277
call grow_tree_segment(Tree, nSeg, Sgmt%Points, Sgmt%Connct(:,1:nSeg), Sgmt%Gamma(1:nSeg), p%RegFunction, Sgmt%Epsilon(1:nSeg), 0)
1275-
endif
1278+
end select
12761279

12771280
! --- Src
12781281
Panl%p_Src => p%SrcPnl
@@ -1298,20 +1301,26 @@ subroutine InducedVelocitiesAll_Calc(CPs, nCPs, Uind, p, Sgmt, Part, Tree, Panl,
12981301
ErrStat= ErrID_None
12991302
ErrMsg =''
13001303

1301-
if (p%VelocityMethod(iVel)==idVelocityBasic) then
1304+
select case (p%VelocityMethod(iVel))
1305+
case (idVelocityBasic)
13021306
call ui_seg( 1, nCPs, CPs, 1, Sgmt%nAct, Sgmt%Points, Sgmt%Connct, Sgmt%Gamma, Sgmt%RegFunction, Sgmt%Epsilon, Uind)
13031307

1304-
elseif (p%VelocityMethod(iVel)==idVelocityTreePart) then
1308+
case (idVelocityTreePart)
13051309
! Tree has already been grown with InducedVelocitiesAll_Init
13061310
!call print_tree(Tree)
1307-
call ui_tree_part(Tree, nCPs, CPs, p%TreeBranchFactor(iVel), Tree%DistanceDirect, Uind, ErrStat, ErrMsg)
1311+
call ui_tree_part(Tree, nCPs, CPs, p%TreeBranchFactor(iVel), 0.0_ReKi, Uind, ErrStat, ErrMsg)
13081312

1309-
elseif (p%VelocityMethod(iVel)==idVelocityPart) then
1313+
case (idVelocityPart)
13101314
call ui_part_nograd(nCPs, CPs, Part%nAct, Part%P, Part%Alpha, Part%RegFunction, Part%RegParam, Uind)
13111315

1312-
elseif (p%VelocityMethod(iVel)==idVelocityTreeSeg) then
1313-
call ui_tree_segment(Tree, CPs, nCPs, p%TreeBranchFactor(iVel), Tree%DistanceDirect, Uind, ErrStat, ErrMsg)
1314-
endif
1316+
case (idVelocityTreeSeg)
1317+
call ui_tree_segment(Tree, CPs, nCPs, p%TreeBranchFactor(iVel), 0.0_ReKi, Uind, ErrStat, ErrMsg)
1318+
1319+
case default
1320+
ErrStat = ErrID_Fatal
1321+
ErrMsg = 'Velocity method not implemented'
1322+
1323+
end select
13151324

13161325
! --- Src Panels
13171326
if (associated(Panl%p_Src)) then
@@ -1338,19 +1347,25 @@ subroutine InducedVelocitiesAll_End(p, Tree, Part, Panl, ErrStat, ErrMsg, deallo
13381347
ErrStat= ErrID_None
13391348
ErrMsg =''
13401349

1341-
if (p%VelocityMethod(iVel)==idVelocityBasic) then
1350+
select case (p%VelocityMethod(iVel))
1351+
case (idVelocityBasic)
13421352
! Nothing
13431353

1344-
elseif (p%VelocityMethod(iVel)==idVelocityTreePart) then
1354+
case (idVelocityTreePart)
13451355
if (deallocPart) deallocate(Part%P, Part%Alpha, Part%RegParam)
13461356
call cut_tree(Tree)
13471357

1348-
elseif (p%VelocityMethod(iVel)==idVelocityPart) then
1358+
case (idVelocityPart)
13491359
if (deallocPart) deallocate(Part%P, Part%Alpha, Part%RegParam)
13501360

1351-
elseif (p%VelocityMethod(iVel)==idVelocityTreeSeg) then
1361+
case (idVelocityTreeSeg)
13521362
call cut_tree(Tree) ! We do not deallocate segment
1353-
endif
1363+
1364+
case default
1365+
ErrStat = ErrID_Fatal
1366+
ErrMsg = 'Velocity method not implemented'
1367+
1368+
end select
13541369

13551370
! Src Panels (we nullify only)
13561371
nullify(Panl%p_Src)
@@ -1547,26 +1562,31 @@ subroutine LiftingLineInducedVelocities(p, x, InductionAtCP, iDepthStart, m, Err
15471562

15481563
! --- Compute velocity on LL
15491564
! TreeSeg is faster but introduce some noise, so we keep this open for the user to choose
1550-
if (p%VelocityMethod(iVel) == idVelocityBasic) then
1565+
select case (p%VelocityMethod(iVel))
1566+
case (idVelocityBasic)
15511567
call ui_seg( 1, nCPs, CPs, 1, nSeg, m%Sgmt%Points, m%Sgmt%Connct, m%Sgmt%Gamma, m%Sgmt%RegFunction, m%Sgmt%Epsilon, Uind)
15521568

1553-
else if (p%VelocityMethod(iVel) == idVelocityPart) then
1569+
case (idVelocityPart)
15541570
call SegmentsToPartWrap(m%Sgmt, nSeg, p%PartPerSegment(iVel), p%RegFunction, m%Part, allocPart=.false.)
15551571
call ui_part_nograd(nCPs, CPs, m%Part%nAct, m%Part%P, m%Part%Alpha, m%Part%RegFunction, m%Part%RegParam, Uind)
15561572
!deallocate(Part%P, Part%Alpha, Part%RegParam)
15571573

1558-
else if (p%VelocityMethod(iVel) == idVelocityTreeSeg) then
1574+
case (idVelocityTreeSeg)
15591575
call grow_tree_segment(Tree, nSeg, m%Sgmt%Points, m%Sgmt%Connct(:,1:nSeg), m%Sgmt%Gamma(1:nSeg), m%Sgmt%RegFunction, m%Sgmt%Epsilon(1:nSeg), 0)
15601576
call ui_tree_segment(Tree, CPs, nCPs, p%TreeBranchFactor(iVel), DistanceDirect, Uind, ErrStat, ErrMsg)
15611577
call cut_tree(Tree)
15621578

1563-
else if (p%VelocityMethod(iVel) == idVelocityTreePart) then
1579+
case (idVelocityTreePart)
15641580
call SegmentsToPartWrap(m%Sgmt, nSeg, p%PartPerSegment(iVel), p%RegFunction, m%Part, allocPart=.false.)
15651581
call grow_tree_part(Tree, m%Part%nAct, m%Part%P, m%Part%Alpha, m%Part%RegFunction, m%Part%RegParam, 0)
15661582
call ui_tree_part(Tree, nCPs, CPs, p%TreeBranchFactor(iVel), DistanceDirect, Uind, ErrStat, ErrMsg)
15671583
!deallocate(Part%P, Part%Alpha, Part%RegParam)
15681584
call cut_tree(Tree)
1569-
endif
1585+
1586+
case default
1587+
ErrStat = ErrID_Fatal
1588+
ErrMsg = 'Velocity method not implemented'
1589+
end select
15701590
! --- Src Panel contribution
15711591
if (p%SrcPnl%n>0) then
15721592
call ui_quad_src_nn(CPs, m%SrcPnl%RHS, p%SrcPnl%xi, p%SrcPnl%eta, p%SrcPnl%Pcent, p%SrcPnl%R_g2p, Uind, nCPs, p%SrcPnl%n)

modules/aerodyn/src/FVW_VortexTools.f90

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ module FVW_VortexTools
6363
real(ReKi) :: radius !< Typical dimension of a cell (max of x,y,z extent)
6464
real(ReKi),dimension(3) :: center !< Used to store first the geometric center, then the vorticity center
6565
real(ReKi),dimension(3,10) :: Moments
66+
real(ReKi) :: maxRegParam = 0.0_ReKi !< Max reg. param (eps) over all particles in this node
6667
integer,dimension(:),pointer :: iPart=>null() !< indexes of particles stored in this node
6768
integer,dimension(:),pointer :: leaves=>null() ! NOTE: leaves are introduced to save memory
6869
type(T_Node),dimension(:), pointer :: branches =>null()
@@ -71,11 +72,10 @@ module FVW_VortexTools
7172

7273
!> The type tree contains some basic data, a chained-list of nodes, and a pointer to the Particle data that were used
7374
type T_Tree
74-
type(T_VPart) :: Part !< Storage for all particles
75-
type(T_VSgmt) :: Seg !< Storage for all segments
75+
type(T_VPart) :: Part !< Storage for all particles
76+
type(T_VSgmt) :: Seg !< Storage for all segments
7677
integer :: iStep =-1 !< Time step at which the tree was built
7778
logical :: bGrown =.false. !< Is the tree build
78-
real(ReKi) :: DistanceDirect
7979
type(T_Node) :: Root !< Contains the chained-list of nodes
8080
end type T_Tree
8181

@@ -587,6 +587,7 @@ subroutine grow_tree_part(Tree, nPart, PartP, PartAlpha, PartRegFunction, PartRe
587587
node%radius=0
588588
node%center(1:3)=Part%P(1:3,1)
589589
node%Moments=0.0_ReKi
590+
node%maxRegParam = Part%RegParam(1)
590591
nullify(node%iPart)
591592
nullify(node%branches)
592593
allocate(node%leaves(1:1))
@@ -625,7 +626,6 @@ subroutine grow_tree_part(Tree, nPart, PartP, PartAlpha, PartRegFunction, PartRe
625626
endif
626627
Tree%iStep = iStep
627628
Tree%bGrown = .true.
628-
Tree%DistanceDirect = 2*sum(PartRegParam)/size(PartRegParam) ! 2*mean(eps), below that distance eps has a strong effect
629629
end subroutine grow_tree_part
630630

631631
!> Recursive function to grow/setup a tree.
@@ -675,13 +675,15 @@ subroutine grow_tree_part_substep(node, Part)
675675
GeomC = node%center ! NOTE: we rely on the fact that our parent has set this to the Geometric value
676676
VortC = 0.0_ReKi
677677
wTot = 0.0_ReKi
678+
node%maxRegParam = 0.0_ReKi
678679
! --- Barycenter of vorticity of the node
679680
do i = 1,node%nPart
680681
PartPos = Part%P(:,node%iPart(i))
681682
PartAlpha = Part%Alpha(:,node%iPart(i))
682683
wLoc = (PartAlpha(1)**2 + PartAlpha(2)**2 + PartAlpha(3)**2)**0.5_ReKi ! Vorticity norm
683684
VortC = VortC + wLoc*PartPos ! Sum coordinates weighted by vorticity
684685
wTot = wTot + wLoc ! Total vorticity
686+
node%maxRegParam = max(node%maxRegParam, Part%RegParam(node%iPart(i))) ! Regularization floor uses max eps in this cell
685687
end do
686688
! There is no vorticity, we make it a empty node and we exit
687689
if(EqualRealNos(abs(wTot),0.0_ReKi)) then
@@ -925,6 +927,7 @@ subroutine grow_tree_segment(Tree_Seg, nSeg, SegPoints, SegConnct, SegGamma, Seg
925927
node%radius=0
926928
node%center(1:3)=0.5_ReKi*(Seg%SP(1:3,1)+Seg%SP(1:3,2))
927929
node%Moments=0.0_ReKi
930+
node%maxRegParam = Seg%RegParam(1)
928931
nullify(node%iPart)
929932
nullify(node%branches)
930933
allocate(node%leaves(1:1))
@@ -973,7 +976,6 @@ subroutine grow_tree_segment(Tree_Seg, nSeg, SegPoints, SegConnct, SegGamma, Seg
973976
endif
974977
Tree_Seg%iStep = iStep
975978
Tree_Seg%bGrown = .true.
976-
Tree_Seg%DistanceDirect = 2*sum(SegRegParam)/size(SegRegParam) ! 2*mean(eps), below that distance eps has a strong effect ! TODO REMOVE
977979
end subroutine grow_tree_segment
978980

979981
!> Recursive function to grow/setup a tree.
@@ -1024,13 +1026,15 @@ subroutine grow_tree_segment_substep(node, Seg)
10241026
GeomC = node%center ! NOTE: we rely on the fact that our parent has set this to the Geometric value
10251027
VortC = 0.0_ReKi
10261028
wTot = 0.0_ReKi
1029+
node%maxRegParam = 0.0_ReKi
10271030
! --- Barycenter of vorticity of the node
10281031
do i = 1,node%nPart
10291032
P1 = Seg%SP(1:3,Seg%SConnct(1,node%iPart(i)))
10301033
P2 = Seg%SP(1:3,Seg%SConnct(2,node%iPart(i)))
10311034
SegCenter = 0.5_ReKi*(P1+P2)
10321035
VortC = VortC + abs(Seg%SGamma(node%iPart(i)))*SegCenter ! Sum coordinates weighted by vorticity
10331036
wTot = wTot + abs(Seg%SGamma(node%iPart(i))) ! Total vorticity
1037+
node%maxRegParam = max(node%maxRegParam, Seg%RegParam(node%iPart(i))) ! Regularization floor uses max eps in this cell
10341038
end do
10351039
! There is no vorticity, we make it a empty node and we exit
10361040
if(EqualRealNos(abs(wTot),0.0_ReKi)) then
@@ -1501,7 +1505,7 @@ recursive subroutine ui_tree_part_11(node, CP, Uind)
15011505
enddo
15021506
endif
15031507
else
1504-
distDirect = max(BranchFactor*node%radius, DistanceDirect) ! Under this distance-> Direct eval., Above it -> quadrupole calculation
1508+
distDirect = max(BranchFactor*node%radius + 2.0_ReKi*node%maxRegParam, DistanceDirect) ! Direct eval. below this distance; floor = branch radius + 2*max(eps) in cell
15051509
DeltaP = - node%center + CP(1:3) ! Vector between the control point and the center of the branch
15061510
r = sqrt( DeltaP(1)**2 + DeltaP(2)**2 + DeltaP(3)**2)
15071511
! Test if the control point is too close from the branch node so that a direct evaluation is needed
@@ -1704,7 +1708,7 @@ recursive subroutine ui_tree_segment_11(node, CP, Uind)
17041708
enddo
17051709
endif
17061710
else
1707-
distDirect = max(BranchFactor*node%radius, DistanceDirect) ! Under this distance-> Direct eval., Above it -> quadrupole calculation
1711+
distDirect = max(BranchFactor*node%radius + 2.0_ReKi*node%maxRegParam, DistanceDirect) ! Direct eval. below this distance; floor = branch radius + 2*max(eps) in cell
17081712
DeltaP = - node%center + CP(1:3) ! Vector between the control point and the center of the branch
17091713
r = sqrt( DeltaP(1)**2 + DeltaP(2)**2 + DeltaP(3)**2)
17101714
! Test if the control point is too close from the branch node so that a direct evaluation is needed

reg_tests/r-test

0 commit comments

Comments
 (0)