From 1ed04cca10f33bf21a1b9e6d81fd94688dd3d1c0 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 30 Jan 2022 20:07:37 +0300 Subject: [PATCH 01/76] hack to get cpmin with ks --- adflow/pyADflow.py | 2 ++ src/f2py/adflow.pyf | 1 + src/modules/inputParam.F90 | 1 + src/solver/surfaceIntegrations.F90 | 17 ++++++++++++----- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 626fb2120..398c983b1 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -4729,6 +4729,7 @@ def _getDefaultOptions(): "wallDistCutoff": [float, 1e20], "infChangeCorrection": [bool, True], "cavitationNumber": [float, 1.4], + "cavitationRho": [float, 100.0], # Common Parameters "nCycles": [int, 2000], "timeLimit": [float, -1.0], @@ -5074,6 +5075,7 @@ def _getOptionMap(self): "forcesastractions": ["physics", "forcesastractions"], "lowspeedpreconditioner": ["discr", "lowspeedpreconditioner"], "cavitationnumber": ["physics", "cavitationnumber"], + "cavitationrho": ["physics", "cavitationrho"], # Common Parameters "ncycles": ["iter", "ncycles"], "timelimit": ["iter", "timelimit"], diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index be6bcbfdd..7cd2306a4 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -1139,6 +1139,7 @@ python module libadflow real(kind=realtype) :: beta integer(kind=inttype) :: liftindex real(kind=realtype) :: cavitationnumber + real(kind=realtype) :: cavitationrho end module inputphysics module inputadjoint ! in :adflow:../modules/inputParam.f90 diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 565e7398f..49e8f6126 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -579,6 +579,7 @@ module inputPhysics real(kind=realType), dimension(3,2) :: momentAxis real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber + real(kind=realType) :: cavitationrho #ifndef USE_TAPENADE real(kind=realType) :: alphad, betad diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index a1c43387e..28e744e51 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -7,7 +7,9 @@ subroutine getCostFunctions(globalVals, funcValues) use constants use inputTimeSpectral, only : nTimeIntervalsSpectral use flowVarRefState, only : pRef, rhoRef, tRef, LRef, gammaInf, pInf, uRef, uInf - use inputPhysics, only : liftDirection, dragDirection, surfaceRef, machCoef, lengthRef, alpha, beta, liftIndex + use inputPhysics, only : liftDirection, dragDirection, surfaceRef, & + machCoef, lengthRef, alpha, beta, liftIndex, cavitationnumber, & + cavitationrho use inputTSStabDeriv, only : TSstability use utils, only : computeTSDerivatives use flowUtils, only : getDirVector @@ -256,6 +258,9 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncForceYCoefMomentum)*dragDirection(2) + & funcValues(costFuncForceZCoefMomentum)*dragDirection(3) + ! final part of the KS computation + funcValues(costFuncCavitation) = 2 * cavitationnumber & + + log(funcValues(costFuncCavitation)) / cavitationrho ! -------------------- Time Spectral Objectives ------------------ @@ -311,7 +316,7 @@ subroutine wallIntegrationFace(localValues, mm) use blockPointers use flowVarRefState use inputCostFunctions - use inputPhysics, only : MachCoef, pointRef, velDirFreeStream, equations, momentAxis, cavitationnumber + use inputPhysics, only : MachCoef, pointRef, velDirFreeStream, equations, momentAxis, cavitationnumber, cavitationrho use BCPointers implicit none @@ -504,9 +509,11 @@ subroutine wallIntegrationFace(localValues, mm) plocal = pp2(i,j) tmp = two/(gammaInf*MachCoef*MachCoef) Cp = tmp*(plocal-pinf) - Sensor1 = -Cp - cavitationnumber - Sensor1 = one/(one+exp(-2*10*Sensor1)) - Sensor1 = Sensor1 * cellArea * blk + ! Sensor1 = -Cp - cavitationnumber + ! Sensor1 = one/(one+exp(-2*10*Sensor1)) + ! Sensor1 = Sensor1 * cellArea * blk + ! KS formulation with a fixed CPmin at 2 sigmas + Sensor1 = exp(cavitationrho * (-Cp - 2 * cavitationnumber)) Cavitation = Cavitation + Sensor1 end if enddo From 34679eb4f10fd2afd4df4e7d1e9d692007c85403 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 30 Jan 2022 22:44:02 +0300 Subject: [PATCH 02/76] differentiated the hacky version --- src/adjoint/outputForward/solverutils_d.f90 | 174 ++++++++++++++++++ .../outputForward/surfaceintegrations_d.f90 | 42 +++-- src/adjoint/outputReverse/solverutils_b.f90 | 172 +++++++++++++++++ .../outputReverse/surfaceintegrations_b.f90 | 62 ++++--- .../outputReverseFast/solverutils_fast_b.f90 | 172 +++++++++++++++++ .../surfaceintegrations_fast_b.f90 | 17 +- 6 files changed, 595 insertions(+), 44 deletions(-) diff --git a/src/adjoint/outputForward/solverutils_d.f90 b/src/adjoint/outputForward/solverutils_d.f90 index 6a653d2e9..48110357e 100644 --- a/src/adjoint/outputForward/solverutils_d.f90 +++ b/src/adjoint/outputForward/solverutils_d.f90 @@ -534,6 +534,180 @@ subroutine timestep_block(onlyradii) end select end if end subroutine timestep_block + subroutine gridvelocitiesfinelevel_ts_block(nn, sps) + use precision + use constants + use blockpointers + use inputphysics, only : machgrid, veldirfreestream + use flowvarrefstate, only : gammainf, pinf, rhoinf + use inputtimespectral, only : dscalar, ntimeintervalsspectral + implicit none + integer(kind=inttype), intent(in) :: nn, sps + integer :: i, j, k, mm, ii, ie_l, je_l, ke_l + real(kind=realtype) :: x_vc, y_vc, z_vc + real(kind=realtype) :: x_fc, y_fc, z_fc + real(kind=realtype) :: ainf + real(kind=realtype) :: velxfreestream, velyfreestream, & +& velzfreestream + intrinsic sqrt + real(kind=realtype) :: arg1 +! get the grid free stream velocity + arg1 = gammainf*pinf/rhoinf + ainf = sqrt(arg1) + velxfreestream = ainf*machgrid*(-veldirfreestream(1)) + velyfreestream = ainf*machgrid*(-veldirfreestream(2)) + velzfreestream = ainf*machgrid*(-veldirfreestream(3)) +! grid velocities of the cell centers, including the +! 1st level halo cells. +! initialize with free stream velocity + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + s(i, j, k, 1) = velxfreestream + s(i, j, k, 2) = velyfreestream + s(i, j, k, 3) = velzfreestream + end do + end do + end do +! the velocity contributed from mesh deformation + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + x_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)) + y_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)) + z_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)) + s(i, j, k, 1) = s(i, j, k, 1) + dscalar(1, sps, mm)*x_vc + s(i, j, k, 2) = s(i, j, k, 2) + dscalar(1, sps, mm)*y_vc + s(i, j, k, 3) = s(i, j, k, 3) + dscalar(1, sps, mm)*z_vc + end do + end do + end do + end do +! normal grid velocities of the faces. +! sfacei= dot(si, v) +! =dot(si, v_freestream + v_meshmotion) +! =dot(si, v_freestream) + dot(si, v_meshmotion) +! sfacej, sfacek follow the same rule. +! dot(si, v_freestream) + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + sfacei(i, j, k) = velxfreestream*si(i, j, k, 1) + & +& velyfreestream*si(i, j, k, 2) + velzfreestream*si(i, j, k, 3& +& ) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + sfacej(i, j, k) = velxfreestream*sj(i, j, k, 1) + & +& velyfreestream*sj(i, j, k, 2) + velzfreestream*sj(i, j, k, 3& +& ) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + sfacek(i, j, k) = velxfreestream*sk(i, j, k, 1) + & +& velyfreestream*sk(i, j, k, 2) + velzfreestream*sk(i, j, k, 3& +& ) + end do + end do + end do +! dot(si, v_meshmotion) + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacei(i, j, k) = sfacei(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *si(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*si(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*si(i, j, k, 3) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacej(i, j, k) = sfacej(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sj(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sj(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sj(i, j, k, 3) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)) + sfacek(i, j, k) = sfacek(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sk(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sk(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sk(i, j, k, 3) + end do + end do + end do + end do + end subroutine gridvelocitiesfinelevel_ts_block subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps) ! ! gridvelocitiesfinelevel computes the grid velocities for diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 2cd13e19d..d25ed412a 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -24,7 +24,8 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex +& lengthref, alpha, alphad, beta, betad, liftindex, cavitationnumber, & +& cavitationrho use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector, getdirvector_d @@ -54,6 +55,7 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 intrinsic sqrt + intrinsic log real(kind=realtype) :: arg1 ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral @@ -533,6 +535,11 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) +! final part of the ks computation + funcvaluesd(costfunccavitation) = funcvaluesd(costfunccavitation)/& +& funcvalues(costfunccavitation)/cavitationrho + funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& +& (costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -547,7 +554,8 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex +& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & +& cavitationrho use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector @@ -569,6 +577,7 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 intrinsic sqrt + intrinsic log real(kind=realtype) :: arg1 ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral @@ -792,6 +801,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) +! final part of the ks computation + funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& +& (costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -831,7 +843,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cavitationnumber +& cavitationnumber, cavitationrho use bcpointers_d implicit none ! input/output variables @@ -1114,13 +1126,13 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) tmp = two/(gammainf*machcoef*machcoef) cpd = tmpd*(plocal-pinf) + tmp*(plocald-pinfd) cp = tmp*(plocal-pinf) - sensor1d = -cpd - sensor1 = -cp - cavitationnumber - sensor1d = -((-(one*2*10*sensor1d*exp(-(2*10*sensor1))))/(one+& -& exp(-(2*10*sensor1)))**2) - sensor1 = one/(one+exp(-(2*10*sensor1))) - sensor1d = blk*(sensor1d*cellarea+sensor1*cellaread) - sensor1 = sensor1*cellarea*blk +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas + sensor1d = -(cavitationrho*cpd*exp(cavitationrho*(-cp-2*& +& cavitationnumber))) + sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 end if @@ -1328,7 +1340,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber +& equations, momentaxis, cavitationnumber, cavitationrho use bcpointers_d implicit none ! input/output variables @@ -1506,9 +1518,11 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) - sensor1 = -cp - cavitationnumber - sensor1 = one/(one+exp(-(2*10*sensor1))) - sensor1 = sensor1*cellarea*blk +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas + sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) cavitation = cavitation + sensor1 end if end do diff --git a/src/adjoint/outputReverse/solverutils_b.f90 b/src/adjoint/outputReverse/solverutils_b.f90 index 714f3c416..fce7f7568 100644 --- a/src/adjoint/outputReverse/solverutils_b.f90 +++ b/src/adjoint/outputReverse/solverutils_b.f90 @@ -574,6 +574,178 @@ subroutine timestep_block(onlyradii) end select end if end subroutine timestep_block + subroutine gridvelocitiesfinelevel_ts_block(nn, sps) + use precision + use constants + use blockpointers + use inputphysics, only : machgrid, veldirfreestream + use flowvarrefstate, only : gammainf, pinf, rhoinf + use inputtimespectral, only : dscalar, ntimeintervalsspectral + implicit none + integer(kind=inttype), intent(in) :: nn, sps + integer :: i, j, k, mm, ii, ie_l, je_l, ke_l + real(kind=realtype) :: x_vc, y_vc, z_vc + real(kind=realtype) :: x_fc, y_fc, z_fc + real(kind=realtype) :: ainf + real(kind=realtype) :: velxfreestream, velyfreestream, & +& velzfreestream + intrinsic sqrt +! get the grid free stream velocity + ainf = sqrt(gammainf*pinf/rhoinf) + velxfreestream = ainf*machgrid*(-veldirfreestream(1)) + velyfreestream = ainf*machgrid*(-veldirfreestream(2)) + velzfreestream = ainf*machgrid*(-veldirfreestream(3)) +! grid velocities of the cell centers, including the +! 1st level halo cells. +! initialize with free stream velocity + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + s(i, j, k, 1) = velxfreestream + s(i, j, k, 2) = velyfreestream + s(i, j, k, 3) = velzfreestream + end do + end do + end do +! the velocity contributed from mesh deformation + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + x_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)) + y_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)) + z_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)) + s(i, j, k, 1) = s(i, j, k, 1) + dscalar(1, sps, mm)*x_vc + s(i, j, k, 2) = s(i, j, k, 2) + dscalar(1, sps, mm)*y_vc + s(i, j, k, 3) = s(i, j, k, 3) + dscalar(1, sps, mm)*z_vc + end do + end do + end do + end do +! normal grid velocities of the faces. +! sfacei= dot(si, v) +! =dot(si, v_freestream + v_meshmotion) +! =dot(si, v_freestream) + dot(si, v_meshmotion) +! sfacej, sfacek follow the same rule. +! dot(si, v_freestream) + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + sfacei(i, j, k) = velxfreestream*si(i, j, k, 1) + & +& velyfreestream*si(i, j, k, 2) + velzfreestream*si(i, j, k, 3& +& ) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + sfacej(i, j, k) = velxfreestream*sj(i, j, k, 1) + & +& velyfreestream*sj(i, j, k, 2) + velzfreestream*sj(i, j, k, 3& +& ) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + sfacek(i, j, k) = velxfreestream*sk(i, j, k, 1) + & +& velyfreestream*sk(i, j, k, 2) + velzfreestream*sk(i, j, k, 3& +& ) + end do + end do + end do +! dot(si, v_meshmotion) + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacei(i, j, k) = sfacei(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *si(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*si(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*si(i, j, k, 3) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacej(i, j, k) = sfacej(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sj(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sj(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sj(i, j, k, 3) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)) + sfacek(i, j, k) = sfacek(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sk(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sk(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sk(i, j, k, 3) + end do + end do + end do + end do + end subroutine gridvelocitiesfinelevel_ts_block subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps) ! ! gridvelocitiesfinelevel computes the grid velocities for diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index 3b7ccc14b..b0873976c 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -25,7 +25,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex +& lengthref, alpha, alphad, beta, betad, liftindex, cavitationnumber, & +& cavitationrho use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector, getdirvector_b @@ -55,6 +56,7 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 intrinsic sqrt + intrinsic log real(kind=realtype) :: tmp real(kind=realtype) :: tmp0 real(kind=realtype) :: tmp1 @@ -332,10 +334,19 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & funcvalues(costfuncforcezcoefviscous)*dragdirection(3) call pushreal8(funcvalues(costfuncdragcoefviscous)) funcvalues(costfuncdragcoefviscous) = tmp13 + tmp14 = funcvalues(costfuncforcexcoefmomentum)*dragdirection(1) + & +& funcvalues(costfuncforceycoefmomentum)*dragdirection(2) + & +& funcvalues(costfuncforcezcoefmomentum)*dragdirection(3) + call pushreal8(funcvalues(costfuncdragcoefmomentum)) + funcvalues(costfuncdragcoefmomentum) = tmp14 +! final part of the ks computation ! -------------------- time spectral objectives ------------------ if (tsstability) then stop else + funcvaluesd(costfunccavitation) = funcvaluesd(costfunccavitation)/& +& (cavitationrho*funcvalues(costfunccavitation)) + call popreal8(funcvalues(costfuncdragcoefmomentum)) tmpd = funcvaluesd(costfuncdragcoefmomentum) funcvaluesd(costfuncdragcoefmomentum) = 0.0_8 funcvaluesd(costfuncforcexcoefmomentum) = funcvaluesd(& @@ -771,7 +782,8 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex +& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & +& cavitationrho use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector @@ -793,6 +805,7 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 intrinsic sqrt + intrinsic log ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral ! sum pressure and viscous contributions @@ -1014,6 +1027,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) +! final part of the ks computation + funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& +& (costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1055,7 +1071,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cavitationnumber +& cavitationnumber, cavitationrho use bcpointers_b implicit none ! input/output variables @@ -1126,9 +1142,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: temp real(kind=realtype) :: tempd19 real(kind=realtype) :: tempd18 - real(kind=realtype) :: temp6 real(kind=realtype) :: tempd17 - real(kind=realtype) :: temp5 real(kind=realtype) :: tempd16 real(kind=realtype) :: temp4 real(kind=realtype) :: tempd15 @@ -1270,9 +1284,11 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) - sensor1 = -cp - cavitationnumber - sensor1 = one/(one+exp(-(2*10*sensor1))) - sensor1 = sensor1*cellarea*blk +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas + sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) cavitation = cavitation + sensor1 end if end do @@ -1573,17 +1589,13 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) - sensor1 = -cp - cavitationnumber - call pushreal8(sensor1) - sensor1 = one/(one+exp(-(2*10*sensor1))) +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas sensor1d = cavitationd - cellaread = blk*sensor1*sensor1d - sensor1d = blk*cellarea*sensor1d - call popreal8(sensor1) - temp6 = -(10*2*sensor1) - temp5 = one + exp(temp6) - sensor1d = exp(temp6)*one*10*2*sensor1d/temp5**2 - cpd = -sensor1d + cpd = -(cavitationrho*exp(cavitationrho*((-2)*cavitationnumber-& +& cp))*sensor1d) tmpd = (plocal-pinf)*cpd plocald = tmp*cpd pinfd = pinfd - tmp*cpd @@ -1591,8 +1603,6 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) machcoefd = machcoefd - gammainf*two*2*machcoef*tmpd/temp4**2 tmp = two/(gammainf*pinf*machcoef*machcoef) pp2d(i, j) = pp2d(i, j) + plocald - else - cellaread = 0.0_8 end if mxd = blk*mpd(1) myd = blk*mpd(2) @@ -1625,7 +1635,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) xxd(i, j+1, 1) = xxd(i, j+1, 1) + tempd7 xxd(i+1, j+1, 1) = xxd(i+1, j+1, 1) + tempd7 call popreal8(sensor) - cellaread = cellaread + blk*sensor*sensord + cellaread = blk*sensor*sensord sensord = blk*cellarea*sensord call popreal8(sensor) temp3 = -(2*sepsensorsharpness*(sensor-sepsensoroffset)) @@ -1766,7 +1776,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber +& equations, momentaxis, cavitationnumber, cavitationrho use bcpointers_b implicit none ! input/output variables @@ -1939,9 +1949,11 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) - sensor1 = -cp - cavitationnumber - sensor1 = one/(one+exp(-(2*10*sensor1))) - sensor1 = sensor1*cellarea*blk +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas + sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) cavitation = cavitation + sensor1 end if end do diff --git a/src/adjoint/outputReverseFast/solverutils_fast_b.f90 b/src/adjoint/outputReverseFast/solverutils_fast_b.f90 index 9c74f09ec..2a2d159c6 100644 --- a/src/adjoint/outputReverseFast/solverutils_fast_b.f90 +++ b/src/adjoint/outputReverseFast/solverutils_fast_b.f90 @@ -521,6 +521,178 @@ subroutine timestep_block(onlyradii) end select end if end subroutine timestep_block + subroutine gridvelocitiesfinelevel_ts_block(nn, sps) + use precision + use constants + use blockpointers + use inputphysics, only : machgrid, veldirfreestream + use flowvarrefstate, only : gammainf, pinf, rhoinf + use inputtimespectral, only : dscalar, ntimeintervalsspectral + implicit none + integer(kind=inttype), intent(in) :: nn, sps + integer :: i, j, k, mm, ii, ie_l, je_l, ke_l + real(kind=realtype) :: x_vc, y_vc, z_vc + real(kind=realtype) :: x_fc, y_fc, z_fc + real(kind=realtype) :: ainf + real(kind=realtype) :: velxfreestream, velyfreestream, & +& velzfreestream + intrinsic sqrt +! get the grid free stream velocity + ainf = sqrt(gammainf*pinf/rhoinf) + velxfreestream = ainf*machgrid*(-veldirfreestream(1)) + velyfreestream = ainf*machgrid*(-veldirfreestream(2)) + velzfreestream = ainf*machgrid*(-veldirfreestream(3)) +! grid velocities of the cell centers, including the +! 1st level halo cells. +! initialize with free stream velocity + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + s(i, j, k, 1) = velxfreestream + s(i, j, k, 2) = velyfreestream + s(i, j, k, 3) = velzfreestream + end do + end do + end do +! the velocity contributed from mesh deformation + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke + do k=1,ke_l + do j=1,je_l + do i=1,ie_l + x_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)) + y_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)) + z_vc = eighth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+flowdoms(nn, 1, mm)%& +& x(i-1, j, k-1, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+flowdoms(nn, 1, mm)%& +& x(i, j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)) + s(i, j, k, 1) = s(i, j, k, 1) + dscalar(1, sps, mm)*x_vc + s(i, j, k, 2) = s(i, j, k, 2) + dscalar(1, sps, mm)*y_vc + s(i, j, k, 3) = s(i, j, k, 3) + dscalar(1, sps, mm)*z_vc + end do + end do + end do + end do +! normal grid velocities of the faces. +! sfacei= dot(si, v) +! =dot(si, v_freestream + v_meshmotion) +! =dot(si, v_freestream) + dot(si, v_meshmotion) +! sfacej, sfacek follow the same rule. +! dot(si, v_freestream) + ie_l = flowdoms(nn, 1, sps)%ie + je_l = flowdoms(nn, 1, sps)%je + ke_l = flowdoms(nn, 1, sps)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + sfacei(i, j, k) = velxfreestream*si(i, j, k, 1) + & +& velyfreestream*si(i, j, k, 2) + velzfreestream*si(i, j, k, 3& +& ) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + sfacej(i, j, k) = velxfreestream*sj(i, j, k, 1) + & +& velyfreestream*sj(i, j, k, 2) + velzfreestream*sj(i, j, k, 3& +& ) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + sfacek(i, j, k) = velxfreestream*sk(i, j, k, 1) + & +& velyfreestream*sk(i, j, k, 2) + velzfreestream*sk(i, j, k, 3& +& ) + end do + end do + end do +! dot(si, v_meshmotion) + do mm=1,ntimeintervalsspectral + ie_l = flowdoms(nn, 1, mm)%ie + je_l = flowdoms(nn, 1, mm)%je + ke_l = flowdoms(nn, 1, mm)%ke +! i + do k=1,ke_l + do j=1,je_l + do i=0,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i, j-1, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacei(i, j, k) = sfacei(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *si(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*si(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*si(i, j, k, 3) + end do + end do + end do +! j + do k=1,ke_l + do j=0,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 1)+flowdoms(nn, 1, mm)%x(i, j, k-1, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 2)+flowdoms(nn, 1, mm)%x(i, j, k-1, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j, k-1, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i-& +& 1, j, k, 3)+flowdoms(nn, 1, mm)%x(i, j, k-1, 3)) + sfacej(i, j, k) = sfacej(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sj(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sj(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sj(i, j, k, 3) + end do + end do + end do +! k + do k=0,ke_l + do j=1,je_l + do i=1,ie_l + x_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 1)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 1)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 1)+flowdoms(nn, 1, mm)%x(i-1, j, k, 1)) + y_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 2)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 2)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 2)+flowdoms(nn, 1, mm)%x(i-1, j, k, 2)) + z_fc = fourth*(flowdoms(nn, 1, mm)%x(i-1, j-1, k, 3)+& +& flowdoms(nn, 1, mm)%x(i, j, k, 3)+flowdoms(nn, 1, mm)%x(i& +& , j-1, k, 3)+flowdoms(nn, 1, mm)%x(i-1, j, k, 3)) + sfacek(i, j, k) = sfacek(i, j, k) + dscalar(1, sps, mm)*x_fc& +& *sk(i, j, k, 1) + dscalar(1, sps, mm)*y_fc*sk(i, j, k, 2) & +& + dscalar(1, sps, mm)*z_fc*sk(i, j, k, 3) + end do + end do + end do + end do + end subroutine gridvelocitiesfinelevel_ts_block subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps) ! ! gridvelocitiesfinelevel computes the grid velocities for diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index b0e06c36b..3af5e2a0e 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -16,7 +16,8 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex +& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & +& cavitationrho use inputtsstabderiv, only : tsstability use utils_fast_b, only : computetsderivatives use flowutils_fast_b, only : getdirvector @@ -38,6 +39,7 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 intrinsic sqrt + intrinsic log ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral ! sum pressure and viscous contributions @@ -259,6 +261,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) +! final part of the ks computation + funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& +& (costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -284,7 +289,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber +& equations, momentaxis, cavitationnumber, cavitationrho use bcpointers_fast_b implicit none ! input/output variables @@ -457,9 +462,11 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) - sensor1 = -cp - cavitationnumber - sensor1 = one/(one+exp(-(2*10*sensor1))) - sensor1 = sensor1*cellarea*blk +! sensor1 = -cp - cavitationnumber +! sensor1 = one/(one+exp(-2*10*sensor1)) +! sensor1 = sensor1 * cellarea * blk +! ks formulation with a fixed cpmin at 2 sigmas + sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) cavitation = cavitation + sensor1 end if end do From d383f278a82ccb540e134ff96957181c6d11e3ea Mon Sep 17 00:00:00 2001 From: sseraj Date: Fri, 4 Mar 2022 17:26:07 -0500 Subject: [PATCH 03/76] fixed adjoint time print in Fortran --- src/adjoint/adjointAPI.F90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/adjoint/adjointAPI.F90 b/src/adjoint/adjointAPI.F90 index be48e6b07..fffffbaac 100644 --- a/src/adjoint/adjointAPI.F90 +++ b/src/adjoint/adjointAPI.F90 @@ -815,8 +815,7 @@ subroutine solveAdjoint(RHS, psi, checkSolution, nState) ! Determine the maximum time using MPI reduce ! with operation mpi_max. - ! call mpi_reduce(timeAdjLocal, timeAdj, 1, adflow_real, & - ! mpi_max, 0, ADFLOW_COMM_WORLD, ierr) + call mpi_reduce(timeAdjLocal, timeAdj, 1, adflow_real, mpi_max, 0, ADFLOW_COMM_WORLD, ierr) call MatMult(dRdWT, psi_like1, adjointRes, ierr) call EChk(ierr,__FILE__,__LINE__) From 008780f8af062cc9aa7ed1208b87ed78787da3ec Mon Sep 17 00:00:00 2001 From: sseraj Date: Mon, 7 Mar 2022 17:07:12 -0500 Subject: [PATCH 04/76] use modified Gram-Schmidt --- src/adjoint/adjointUtils.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/adjoint/adjointUtils.F90 b/src/adjoint/adjointUtils.F90 index 691e505f9..375e2e1be 100644 --- a/src/adjoint/adjointUtils.F90 +++ b/src/adjoint/adjointUtils.F90 @@ -1410,6 +1410,10 @@ subroutine setupStandardKSP(kspObject, kspObjectType, gmresRestart, preConSide, call KSPSetType(kspObject, kspObjectType, ierr) call EChk(ierr, __FILE__, __LINE__) + ! Use modified Gram-Schmidt orthogonalization + call KSPGMRESSetOrthogonalization(kspObject, KSPGMRESModifiedGramSchmidtOrthogonalization, ierr) + call EChk(ierr, __FILE__, __LINE__) + ! If we're using GMRES set the possible gmres restart call KSPGMRESSetRestart(kspObject, gmresRestart, ierr) call EChk(ierr, __FILE__, __LINE__) From 938b231c25bdb781ae657cc62eda8b21a1dfe512 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 11 Mar 2022 13:39:37 -0500 Subject: [PATCH 05/76] less janky cavitation --- src/adjoint/masterRoutines.F90 | 45 ++++++++---- .../outputForward/surfaceintegrations_d.f90 | 14 ++-- .../outputReverse/surfaceintegrations_b.f90 | 12 ++-- .../surfaceintegrations_fast_b.f90 | 6 +- src/solver/surfaceIntegrations.F90 | 71 ++++++++++++++++++- 5 files changed, 118 insertions(+), 30 deletions(-) diff --git a/src/adjoint/masterRoutines.F90 b/src/adjoint/masterRoutines.F90 index 639ca867f..367a1dc15 100644 --- a/src/adjoint/masterRoutines.F90 +++ b/src/adjoint/masterRoutines.F90 @@ -31,7 +31,8 @@ subroutine master(useSpatial, famLists, funcValues, forces, & use utils, only : setPointers, EChk use turbUtils, only : turbAdvection, computeEddyViscosity use residuals, only : initRes_block, sourceTerms_block - use surfaceIntegrations, only : getSolution + use surfaceIntegrations, only : getSolution, computeCavitationNumber + use inputCostFunctions, only : computeCavitation use adjointExtra, only : volume_block, metric_block, boundaryNormals,& xhalo_block, sumdwandfw, resScale use oversetData, only : oversetPresent @@ -39,7 +40,7 @@ subroutine master(useSpatial, famLists, funcValues, forces, & use oversetCommUtilities, only : updateOversetConnectivity use actuatorRegionData, only : nActuatorRegions use wallDistanceData, only : xSurfVec, xSurf - + implicit none ! Input Arguments: @@ -99,7 +100,7 @@ subroutine master(useSpatial, famLists, funcValues, forces, & call VecGetArrayF90(xSurfVec(1, sps), xSurf, ierr) call EChk(ierr,__FILE__,__LINE__) - + call volume_block call metric_block call boundaryNormals @@ -107,12 +108,12 @@ subroutine master(useSpatial, famLists, funcValues, forces, & if (equations == RANSEquations .and. useApproxWallDistance) then call updateWallDistancesQuickly(nn, 1, sps) end if - + ! These arrays need to be restored before we can move to the next spectral instance. call VecRestoreArrayF90(xSurfVec(1, sps), xSurf, ierr) call EChk(ierr,__FILE__,__LINE__) - - + + end if ! Compute the pressures/viscositites @@ -223,6 +224,12 @@ subroutine master(useSpatial, famLists, funcValues, forces, & ! Compute the final solution values if (present(famLists)) then + ! if we are computing cavitation, we need to know what cp min (roughly) is across the domain + if (computeCavitation) then + ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow + call computeCavitationNumber() + end if + call getSolution(famLists, funcValues) end if @@ -269,7 +276,8 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu use solverutils_d, only : timeStep_Block_d use turbbcroutines_d, only : applyAllTurbBCthisblock_d, bcTurbTreatment_d use initializeflow_d, only : referenceState_d - use surfaceIntegrations, only : getSolution_d + use surfaceIntegrations, only : getSolution_d, computeCavitationNumber + use inputCostFunctions, only : computeCavitation use adjointExtra_d, only : xhalo_block_d, volume_block_d, metric_BLock_d, boundarynormals_d use adjointextra_d, only : resscale_D, sumdwandfw_d use bcdata, only : setBCData_d, setBCDataFineGrid_d @@ -452,17 +460,17 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu ISIZE1OFDrfbcdata = nBocos ISIZE1OFDrfviscsubface = nViscBocos - ! initalize the residuals for this block + ! initalize the residuals for this block dw = zero dwd = zero - + ! Compute any source terms do iRegion=1, nActuatorRegions call sourceTerms_block_d(nn, .True. , iRegion, dummyReal, dummyReald) end do call timeStep_block_d(.false.) - + !Compute turbulence residual for RANS equations if( equations == RANSEquations) then !call unsteadyTurbSpectral_block(itu1, itu1, nn, sps) @@ -520,6 +528,12 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu ! Compute final solution values if (present(famLists)) then + + if (computeCavitation) then + ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow + call computeCavitationNumber() + end if + call getSolution_d(famLists, funcValues, funcValuesd) end if @@ -577,7 +591,8 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & use adjointPETSc, only : x_like use haloExchange, only : whalo2_b, exchangeCoor_b, exchangeCoor, whalo2 use wallDistanceData, only : xSurfVec, xSurfVecd, xSurf, xSurfd, wallScatter - use surfaceIntegrations, only : getSolution_b + use surfaceIntegrations, only : getSolution_b, computeCavitationNumber + use inputCostFunctions, only : computeCavitation use flowUtils, only : fixAllNodalGradientsFromAD use adjointextra_b, only : resscale_B, sumdwandfw_b use adjointExtra_b, only : xhalo_block_b, volume_block_b, metric_block_b, boundarynormals_b @@ -662,6 +677,12 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & ! Call the final getSolution_b routine if (present(famLists)) then + ! if we are computing cavitation, we need to know what cp min (roughly) is across the domain + if (computeCavitation) then + ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow + call computeCavitationNumber() + end if + call getSolution_b(famLists, funcValues, funcValuesd) end if @@ -719,7 +740,7 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & end if call timeStep_block_b(.false.) - + ! Just to be safe, zero the pLocald value...should not matter dummyReald = zero do iRegion=1, nActuatorRegions diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index d25ed412a..8d697a5dd 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -538,8 +538,8 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & ! final part of the ks computation funcvaluesd(costfunccavitation) = funcvaluesd(costfunccavitation)/& & funcvalues(costfunccavitation)/cavitationrho - funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& -& (costfunccavitation))/cavitationrho + funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& +& costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -802,8 +802,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& -& (costfunccavitation))/cavitationrho + funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& +& costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1130,9 +1130,9 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1d = -(cavitationrho*cpd*exp(cavitationrho*(-cp-2*& + sensor1d = -(cavitationrho*cpd*exp(cavitationrho*(-cp-& & cavitationnumber))) - sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) + sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 end if @@ -1522,7 +1522,7 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) + sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) cavitation = cavitation + sensor1 end if end do diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index b0873976c..e5b899395 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -1028,8 +1028,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& -& (costfunccavitation))/cavitationrho + funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& +& costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1288,7 +1288,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) + sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) cavitation = cavitation + sensor1 end if end do @@ -1594,8 +1594,8 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas sensor1d = cavitationd - cpd = -(cavitationrho*exp(cavitationrho*((-2)*cavitationnumber-& -& cp))*sensor1d) + cpd = -(cavitationrho*exp(cavitationrho*(-cavitationnumber-cp))*& +& sensor1d) tmpd = (plocal-pinf)*cpd plocald = tmp*cpd pinfd = pinfd - tmp*cpd @@ -1953,7 +1953,7 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) + sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) cavitation = cavitation + sensor1 end if end do diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index 3af5e2a0e..8daf4de62 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -262,8 +262,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = 2*cavitationnumber + log(funcvalues& -& (costfunccavitation))/cavitationrho + funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& +& costfunccavitation))/cavitationrho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -466,7 +466,7 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1 = exp(cavitationrho*(-cp-2*cavitationnumber)) + sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) cavitation = cavitation + sensor1 end if end do diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 28e744e51..5bd7965e2 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -259,7 +259,7 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncForceZCoefMomentum)*dragDirection(3) ! final part of the KS computation - funcValues(costFuncCavitation) = 2 * cavitationnumber & + funcValues(costFuncCavitation) = cavitationnumber & + log(funcValues(costFuncCavitation)) / cavitationrho ! -------------------- Time Spectral Objectives ------------------ @@ -513,7 +513,7 @@ subroutine wallIntegrationFace(localValues, mm) ! Sensor1 = one/(one+exp(-2*10*Sensor1)) ! Sensor1 = Sensor1 * cellArea * blk ! KS formulation with a fixed CPmin at 2 sigmas - Sensor1 = exp(cavitationrho * (-Cp - 2 * cavitationnumber)) + Sensor1 = exp(cavitationrho * (-Cp - cavitationnumber)) Cavitation = Cavitation + Sensor1 end if enddo @@ -948,6 +948,7 @@ subroutine getSolution(famLists, funcValues, globalValues) use zipperIntegrations, only :integrateZippers use userSurfaceIntegrations, only : integrateUserSurfaces use actuatorRegion, only : integrateActuatorRegions + use inputCostFunctions, only : computeCavitation implicit none ! Input/Output Variables @@ -961,6 +962,10 @@ subroutine getSolution(famLists, funcValues, globalValues) integer(kind=intType), dimension(:), pointer :: famList ! Master loop over the each of the groups we have + if (computeCavitation) then + call computeCavitationNumber() + end if + groupLoop: do iGroup=1, size(famLists, 1) ! Extract the current family list @@ -1061,6 +1066,68 @@ subroutine integrateSurfaces(localValues, famList) end subroutine integrateSurfaces + subroutine computeCavitationNumber() + use constants + use communication, only : ADflow_comm_world, myID + use inputPhysics, only : cavitationNumber, MachCoef + use blockPointers + use flowVarRefState + use BCPointers + use utils, only : setBCPointers, isWallType, EChk + + implicit none + + integer(kind=intType) :: mm + integer(kind=intType) :: i, j, ii, blk, ierr + real(kind=realType) :: Cp, plocal, tmp, cavitationNumberLocal + + ! here we do a simplified surface integration on walls only to get the cpmin over walls + ! write (*,*) "rank", myID, " current cav number", cavitationNumber + ! set the cavitation number to a small value so that we get the actual max (- min cp) + cavitationNumberLocal = -10000.0_realType + + ! Loop over all possible boundary conditions + bocos: do mm=1, nBocos + + ! Set a bunch of pointers depending on the face id to make + ! a generic treatment possible. + call setBCPointers(mm, .True.) + + ! no post gathered integrations currently + isWall: if( isWallType(BCType(mm)) ) then + + !$AD II-LOOP + do ii=0,(BCData(mm)%jnEnd - bcData(mm)%jnBeg)*(bcData(mm)%inEnd - bcData(mm)%inBeg) -1 + i = mod(ii, (bcData(mm)%inEnd-bcData(mm)%inBeg)) + bcData(mm)%inBeg + 1 + j = ii/(bcData(mm)%inEnd-bcData(mm)%inBeg) + bcData(mm)%jnBeg + 1 + + ! blank value + blk = max(BCData(mm)%iblank(i,j), 0) + + ! compute local CP + + plocal = pp2(i,j) + tmp = two/(gammaInf*MachCoef*MachCoef) + Cp = tmp*(plocal-pinf) + + ! compare it against the current value on this proc + cavitationNumberLocal = max(cavitationNumberLocal, -Cp * blk) + enddo + end if isWall + + end do bocos + + ! write (*,*) "rank", myID, " cav before comm", cavitationNumberLocal + + ! finally communicate across all + call mpi_allreduce(cavitationNumberLocal, cavitationNumber, 1, adflow_real, & + MPI_MAX, adflow_comm_world, ierr) + call EChk(ierr, __FILE__, __LINE__) + + ! write (*,*) "rank", myID, " final cav number ", cavitationNumber + + end subroutine computeCavitationNumber + #ifndef USE_COMPLEX subroutine integrateSurfaces_d(localValues, localValuesd, famList) !------------------------------------------------------------------------ From 04007ec25b1c3e0b43c30d137b049c2c7d33091c Mon Sep 17 00:00:00 2001 From: sseraj Date: Tue, 15 Mar 2022 11:51:20 -0400 Subject: [PATCH 06/76] implemented orthogonalization option --- adflow/pyADflow.py | 11 +++++++++++ doc/options.yaml | 9 +++++++++ src/adjoint/adjointUtils.F90 | 23 ++++++++++++++++------- src/f2py/adflow.pyf | 1 + src/modules/inputParam.F90 | 1 + 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 78a5bc9f5..bd7b54e7e 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5070,6 +5070,10 @@ def _getDefaultOptions(): "adjointSolver": [str, ["GMRES", "TFQMR", "Richardson", "BCGS", "IBCGS"]], "adjointMaxIter": [int, 500], "adjointSubspaceSize": [int, 100], + "GMRESOrthogonalizationType": [ + str, + ["modified Gram-Schmidt", "CGS never refine", "CGS refine if needed", "CGS always refine"], + ], "adjointMonitorStep": [int, 10], "dissipationLumpingParameter": [float, 6.0], "preconditionerSide": [str, ["right", "left"]], @@ -5431,6 +5435,13 @@ def _getOptionMap(self): "ibcgs": "ibcgs", "location": ["adjoint", "adjointsolvertype"], }, + "gmresorthogonalizationtype": { + "modified gram-schmidt": "modified_gram_schmidt", + "cgs never refine": "cgs_never_refine", + "cgs refine if needed": "cgs_refine_if_needed", + "cgs always refine": "cgs_always_refine", + "location": ["adjoint", "gmresorthogtype"], + }, "adjointmaxiter": ["adjoint", "adjmaxiter"], "adjointsubspacesize": ["adjoint", "adjrestart"], "adjointmonitorstep": ["adjoint", "adjmonstep"], diff --git a/doc/options.yaml b/doc/options.yaml index 218c9fd45..56e5031fe 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -1119,6 +1119,15 @@ adjointSolver: BCGS: BiCGStab IBCGS: Improved BiCGStab +GMRESOrthogonalizationType: + desc: > + Which orthogonalization method to use with GMRES. + This will have the most effect on the adjoint solution, but the same method is also used in the ANK and NK solvers. + modified Gram-Schmidt: Modified Gram-Schmidt. This typically gives the best accuracy and performance. + CGS never refine: Classical Gram-Schmidt with no refinement. Fast but not the most accurate. + CGS refine if needed: Classical Gram-Schmidt with refinement as needed. Slow and inaccurate. + CGS always refine: Classical Gram-Schmidt with refinement at every iteration. Slow and inaccurate. + adjointMaxIter: desc: > Maximum number of iterations for the adjoint solution. diff --git a/src/adjoint/adjointUtils.F90 b/src/adjoint/adjointUtils.F90 index 375e2e1be..a6983688a 100644 --- a/src/adjoint/adjointUtils.F90 +++ b/src/adjoint/adjointUtils.F90 @@ -1384,6 +1384,7 @@ subroutine setupStandardKSP(kspObject, kspObjectType, gmresRestart, preConSide, ! and if localPreConIts=1 then subKSP is set to preOnly. use constants use utils, only : ECHk + use inputADjoint, only : GMRESOrthogType #include use petsc implicit none @@ -1410,17 +1411,25 @@ subroutine setupStandardKSP(kspObject, kspObjectType, gmresRestart, preConSide, call KSPSetType(kspObject, kspObjectType, ierr) call EChk(ierr, __FILE__, __LINE__) - ! Use modified Gram-Schmidt orthogonalization - call KSPGMRESSetOrthogonalization(kspObject, KSPGMRESModifiedGramSchmidtOrthogonalization, ierr) - call EChk(ierr, __FILE__, __LINE__) - ! If we're using GMRES set the possible gmres restart call KSPGMRESSetRestart(kspObject, gmresRestart, ierr) call EChk(ierr, __FILE__, __LINE__) - ! If you're using GMRES, set refinement type - call KSPGMRESSetCGSRefinementType(kspObject, & - KSP_GMRES_CGS_REFINE_IFNEEDED, ierr) + ! Set the orthogonalization method for GMRES + select case (GMRESOrthogType) + case ('modified_gram_schmidt') + ! Use modified Gram-Schmidt + call KSPGMRESSetOrthogonalization(kspObject, KSPGMRESModifiedGramSchmidtOrthogonalization, ierr) + case ('cgs_never_refine') + ! Use classical Gram-Schmidt with no refinement + call KSPGMRESSetCGSRefinementType(kspObject, KSP_GMRES_CGS_REFINE_NEVER, ierr) + case ('cgs_refine_if_needed') + ! Use classical Gram-Schmidt with refinement if needed + call KSPGMRESSetCGSRefinementType(kspObject, KSP_GMRES_CGS_REFINE_IFNEEDED, ierr) + case ('cgs_always_refine') + ! Use classical Gram-Schmidt with refinement at every iteration + call KSPGMRESSetCGSRefinementType(kspObject, KSP_GMRES_CGS_REFINE_ALWAYS, ierr) + end select call EChk(ierr, __FILE__, __LINE__) ! Set the preconditioner side from option: diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index c5d9c563f..a8dbea684 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -1212,6 +1212,7 @@ python module libadflow character(len=maxstringlen) :: adjointpcside character(len=maxstringlen) :: matrixordering character(len=maxstringlen) :: adjointsolvertype + character(len=maxstringlen) :: gmresorthogtype character(len=maxstringlen) :: localpctype character(len=maxstringlen) :: precondtype real(kind=realtype) :: adjabstol diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 3b66f032d..49a679b9e 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -771,6 +771,7 @@ module inputADjoint ! Matrix Ordering : Type of matrix ordering to use ! LocalPCType : Type of preconditioner to use on subdomains character(maxStringLen) :: ADjointSolverType + character(maxStringLen) :: GMRESOrthogType character(maxStringLen) :: PreCondType character(maxStringLen) :: matrixOrdering character(maxStringLen) :: adjointPCSide From d72cbf381bdcd1aa21d261fdea4cb71cb85ff46b Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 14 May 2022 22:00:31 -0400 Subject: [PATCH 07/76] minor fix to get mg pc working with coupled ank --- src/NKSolver/NKSolvers.F90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NKSolver/NKSolvers.F90 b/src/NKSolver/NKSolvers.F90 index 06917af4c..0a81b52da 100644 --- a/src/NKSolver/NKSolvers.F90 +++ b/src/NKSolver/NKSolvers.F90 @@ -2092,6 +2092,12 @@ subroutine FormJacobianANK ! get the global cell index irow = globalCell(i, j, k) + if (useCoarseMats) then + do lvl=1, agmgLevels-1 + coarseRows(lvl+1) = coarseIndices(nn, lvl)%arr(i, j, k) + end do + end if + ! Add the contribution to the matrix in PETSc call setBlock() end do From ca12ac9cee12c97ae13f40058e54e4c22da7331b Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 16 May 2022 00:25:12 -0400 Subject: [PATCH 08/76] new config file to do the avx2 stuff by default --- config/defaults/config.LINUX_INTEL_AVX2.mk | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 config/defaults/config.LINUX_INTEL_AVX2.mk diff --git a/config/defaults/config.LINUX_INTEL_AVX2.mk b/config/defaults/config.LINUX_INTEL_AVX2.mk new file mode 100644 index 000000000..4d1be123f --- /dev/null +++ b/config/defaults/config.LINUX_INTEL_AVX2.mk @@ -0,0 +1,53 @@ +# ---------------------------------------------------------------------- +# Config file for Intel ifort +# ---------------------------------------------------------------------- + +# ------- Define a possible parallel make (use PMAKE = make otherwise)-- +PMAKE = make -j 4 + +# ------- Define the MPI Compilers-------------------------------------- +FF90 = mpiifort +CC = mpiicc + +# ------- Define Precision Flags --------------------------------------- +# Options for Integer precision flags: -DUSE_LONG_INT +# Options for Real precision flags: -DUSE_SINGLE_PRECISION, -DUSE_QUADRUPLE_PRECISION +# Default (nothing specified) is 4 byte integers and 8 byte reals + +FF90_INTEGER_PRECISION_FLAG = +FF90_REAL_PRECISION_FLAG = +CC_INTEGER_PRECISION_FLAG = +CC_REAL_PRECISION_FLAG = + +# ------- Define CGNS Inlcude and linker flags ------------------------- +# Define the CGNS include directory and linking flags for the CGNS library. +# We are assuming that HDF5 came from PETSc so it is included in ${PETSC_LIB}. +# Otherwise you will have to specify the HDF5 library. +CGNS_INCLUDE_FLAGS=-I$(CGNS_HOME)/include +CGNS_LINKER_FLAGS=-L$(CGNS_HOME)/lib -lcgns + +# ------- Define Compiler Flags ---------------------------------------- +FF90_FLAGS = -DHAS_ISNAN -fPIC -r8 -O2 -g -xCORE-AVX2 +C_FLAGS = -DHAS_ISNAN -O -fPIC -xCORE-AVX2 + +# ------- Define Archiver and Flags ----------------------------------- +AR = ar +AR_FLAGS = -rvs + +# ------- Define Linker Flags ------------------------------------------ +LINKER = $(FF90) +LINKER_FLAGS = -nofor_main + +# ------- Define Petsc Info --- +include ${PETSC_DIR}/lib/petsc/conf/variables +PETSC_INCLUDE_FLAGS=${PETSC_CC_INCLUDES} -I$(PETSC_DIR) +PETSC_LINKER_FLAGS=${PETSC_LIB} + +# Combine flags from above -- don't modify here +FF90_PRECISION_FLAGS = $(FF90_INTEGER_PRECISION_FLAG)$(FF90_REAL_PRECISION_FLAG) +CC_PRECISION_FLAGS = $(CC_INTEGER_PRECISION_FLAG) $(CC_REAL_PRECISION_FLAG) + +# Define potentially different python, python-config and f2py executables: +PYTHON = python +PYTHON-CONFIG = python3-config # use python-config for python 2 +F2PY = f2py From c307356cc810db7a53d0ec179df89c88b255b4ed Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 8 Jun 2022 12:39:42 +0200 Subject: [PATCH 09/76] added moment and related outputs to the lift distribution file --- src/output/tecplotIO.F90 | 149 +++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 45 deletions(-) diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index 00f9454ab..85250df00 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -20,7 +20,7 @@ module tecplotIO integer(kind=intType), dimension(:,:), allocatable :: ind, conn real(kind=realType), dimension(:, :), allocatable :: w, vars integer(kind=intType) :: nNodes - real(kind=realType) :: pL, vL, pD, vD, CLp, CLv, CDp, CDv + real(kind=realType) :: pL, vL, pD, vD, pM, vM, CLp, CLv, CDp, CDv, CMp, CMv real(kind=realType) :: chord, twist, thickness real(kind=realType), dimension(3) :: le, te real(kind=realType), dimension(3) :: pt, dir @@ -59,7 +59,7 @@ module tecplotIO ! Tecplot Variable names of the data in the lift distribution data file: character(len=maxCGNSNameLen), dimension(:), allocatable :: liftDistName - integer(kind=intType), parameter :: nLiftDistVar=18 + integer(kind=intType), parameter :: nLiftDistVar=23 contains subroutine addParaSlice(sliceName, pt, direction, famList, n) @@ -492,7 +492,7 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) integer(kind=intType) :: i, j, ii, jj, iDist, ierr real(kind=realType), dimension(:,:), allocatable :: values character(len=maxCGNSNameLen), dimension(:), allocatable :: liftDistNames - real(kind=realType) :: dmin, dmax, sumL, sumD, span, delta, xCur(3) + real(kind=realType) :: dmin, dmax, sumL, sumD, sumM, span, delta, xCur(3) type(slice) :: localSlice, globalSlice integer(kind=intType) :: sizeNode, sizeCell integer(kind=intType), dimension(:), pointer :: wallList @@ -555,18 +555,23 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) liftDistNames(4) = cgnsCoorZ liftDistNames(5) = "Lift" liftDistNames(6) = "Drag" - liftDistNames(7) = "Normalized Lift" - liftDistNames(8) = "Normalized Drag" - liftDistNames(9) = "CL" - liftDistNames(10) = "CD" - liftDistNames(11) = "CLp" - liftDistNames(12) = "CDp" - liftDistNames(13) = "CLv" - liftDistNames(14) = "CDv" - liftDistNames(15) = "Elliptical" - liftDistNames(16) = "thickness" - liftDistNames(17) = "twist" - liftDistNames(18) = "chord" + liftDistNames(7) = "Moment" + liftDistNames(8) = "Normalized Lift" + liftDistNames(9) = "Normalized Drag" + liftDistNames(10) = "Normalized Moment" + liftDistNames(11) = "CL" + liftDistNames(12) = "CD" + liftDistNames(13) = "CM" + liftDistNames(14) = "CLp" + liftDistNames(15) = "CDp" + liftDistNames(16) = "CMp" + liftDistNames(17) = "CLv" + liftDistNames(18) = "CDv" + liftDistNames(19) = "CMv" + liftDistNames(20) = "Elliptical" + liftDistNames(21) = "thickness" + liftDistNames(22) = "twist" + liftDistNames(23) = "chord" ! Only write header info for first distribution only if (myid == 0) then @@ -618,38 +623,44 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) d%dir, "does_not_matter", d%famList) call integrateSlice(localSlice, globalSlice, nodalValues, 0, .False.) - ! Total lift and drag + ! Total lift, drag, and moment values(i, 5) = globalSlice%pL + globalSlice%vL values(i, 6) = globalSlice%pD + globalSlice%vD + values(i, 7) = globalSlice%pM + globalSlice%vM - ! Total CL and CD - values(i, 9) = globalSlice%CLp + globalSlice%CLv - values(i, 10) = globalSlice%CDp + globalSlice%CDv + ! Total CL, CD, and CM + values(i, 11) = globalSlice%CLp + globalSlice%CLv + values(i, 12) = globalSlice%CDp + globalSlice%CDv + values(i, 13) = globalSlice%CMp + globalSlice%CMv - ! Pressure lift and drag coefficients - values(i, 11) = globalSlice%CLp - values(i, 12) = globalSlice%CDp + ! Pressure lift, drag, and moment coefficients + values(i, 14) = globalSlice%CLp + values(i, 15) = globalSlice%CDp + values(i, 16) = globalSlice%CMp - ! Viscous lift and drag coefficients - values(i, 13) = globalSlice%CLv - values(i, 14) = globalSlice%CDv + ! Viscous lift, drag, and moment coefficients + values(i, 17) = globalSlice%CLv + values(i, 18) = globalSlice%CDv + values(i, 19) = globalSlice%CMv ! t/c, twist, chord - values(i, 16) = globalSlice%thickness - values(i, 17) = globalSlice%twist - values(i, 18) = globalSlice%chord + values(i, 21) = globalSlice%thickness + values(i, 22) = globalSlice%twist + values(i, 23) = globalSlice%chord call destroySlice(localSlice) call destroySlice(globalSlice) end do - ! Sum up the lift and drag values from the slices: + ! Sum up the lift, drag, and moment values from the slices: sumL = zero sumD = zero + sumM = zero do i=1,d%nSegments-1 sumL = sumL + half*(values(i, 5) + values(i+1, 5)) sumD = sumD + half*(values(i, 6) + values(i+1, 6)) + sumM = sumM + half*(values(i, 7) + values(i+1, 7)) end do ! Now compute the normalized lift, drag and elliptical since @@ -662,15 +673,17 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) dmin = minval(values(:, 1)) sumL = sumL * delta sumD = sumD * delta + sumM = sumM * delta do i=1,d%nSegments - ! Normalized Lift - values(i, 7) = values(i, 5) / sumL - values(i, 8) = values(i, 6) / sumD + ! Normalized Lift, Drag, and Moment + values(i, 8) = values(i, 5) / sumL + values(i, 9) = values(i, 6) / sumD + values(i, 10) = values(i, 7) / abs(sumM) ! elliptical value - values(i, 15) = four/pi/span*sqrt(one-(values(i, 1)-dmin)**2/span**2) + values(i, 20) = four/pi/span*sqrt(one-(values(i, 1)-dmin)**2/span**2) end do ! Write all variables in block format @@ -1815,14 +1828,16 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) real(kind=realType), dimension(:, :), intent(in) :: nodalValues ! Working variables integer(kind=intType) :: i, j, i1, i2 - real(kind=realType), dimension(3) :: x1, x2, pT1, pT2, vT1, vT2, pF, vF - real(kind=realType) :: len, dmax, dmin, dist, fact, M(3,3), tmp(4) + real(kind=realType), dimension(3) :: x1, x2, pT1, pT2, vT1, vT2, pF, vF, pF_elem, vF_elem + real(kind=realType) :: len, dmax, dmin, dist, fact, M(3,3), tmp(6) real(kind=realType) :: r(3), r_new(3), hyp, te(3), le(3), theta, w1, w2 integer(kind=intType) :: bestPair(2), dir_ind, iProc, ierr, iSize real(kind=realtype), dimension(:,:), allocatable :: tempCoords real(kind=realtype), dimension(:,:), allocatable :: localVals integer(kind=intType), dimension(:), allocatable :: sliceNodeSizes, sliceCellSizes integer(kind=intType), dimension(:), allocatable :: nodeDisps, cellDisps + real(kind=realType), dimension(3) :: refPoint, pM, vM + real(kind=realType) :: xc, yc, zc ! Copy the info related to slice gSlc%sliceName = trim(lSlc%sliceName) @@ -1831,12 +1846,25 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) pF = zero vF = zero + pM = zero ! pressure moment + vM = zero ! viscous moment iSize = 3 + 6 + nFields allocate(localVals(iSize,lSlc%nNodes)) ! Compute all the local variables we need. + ! Back out what is the main index of the slice, x, y or z based on + ! the direction. Not the best approach, but that's ok + dir_ind = maxloc(abs(gSlc%dir),1) + + ! Determine the reference point for the moment computation in + ! meters. + + refPoint(1) = LRef*pointRef(1) + refPoint(2) = LRef*pointRef(2) + refPoint(3) = LRef*pointRef(3) + ! Interpolate the required values do i=1, lSlc%nNodes i1 = lSlc%ind(1, i) @@ -1846,6 +1874,7 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) localVals(1:iSize, i) = w1*nodalValues(i1, 1:iSize) + w2*nodalValues(i2, 1:iSize) end do + ! loop over elements do i=1, size(lSlc%conn, 2) ! extract nodes: @@ -1866,14 +1895,33 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! Length of this segment len = sqrt((x1(1)-x2(1))**2 + (x1(2)-x2(2))**2 + (x1(3)-x2(3))**2) + ! compute the pressure and viscous forces on this element + pF_elem = half*(pT1 + pT2)*len + vF_elem = half*(vT1 + vT2)*len + ! Integrate the pressure and viscous forces separately - pF = pF + half*(pT1 + pT2)*len - vF = vF + half*(vT1 + vT2)*len + pF = pF + pF_elem + vF = vF + vF_elem + + ! compute moment about the global reference locations + xc = half * (x1(1) + x2(1)) - refPoint(1) + yc = half * (x1(2) + x2(2)) - refPoint(2) + zc = half * (x1(3) + x2(3)) - refPoint(3) + + ! pressure components + pM(1) = pM(1) + yc*pF_elem(3) - zc*pF_elem(2) + pM(2) = pM(2) + zc*pF_elem(1) - xc*pF_elem(3) + pM(3) = pM(3) + xc*pF_elem(2) - yc*pF_elem(1) + + ! viscous components + vM(1) = vM(1) + yc*vF_elem(3) - zc*vF_elem(2) + vM(2) = vM(2) + zc*vF_elem(1) - xc*vF_elem(3) + vM(3) = vM(3) + xc*vF_elem(2) - yc*vF_elem(1) end do ! That is as far as we can go in parallel. We now have to gather up - ! pL, pD, vL vD as well as the nodes to the root proc. + ! pL, pD, pM, vL, vD, vM as well as the nodes to the root proc. ! Gather up the number of nodes to be set to the root proc: allocate(sliceNodeSizes(nProc), nodeDisps(0:nProc)) @@ -1937,16 +1985,24 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) lSlc%vL = liftDirection(1)*vF(1) + liftDirection(2)*vF(2) + liftDirection(3)*vF(3) lSlc%vD = dragDirection(1)*vF(1) + dragDirection(2)*vF(2) + dragDirection(3)*vF(3) + ! the moments are a bit different than lift and drag. we keep the 3 components of the moment + ! in pM in this routine but then the slc%pM variable only has the component of the moment + ! we are interested in. we use the direction index to get this value out and set it in the slice + lSlc%pM = pM(dir_ind) + lSlc%vM = vM(dir_ind) + ! Reduce the lift/drag values - call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%vL, lSlc%vD/), tmp, 4, adflow_real, MPI_SUM, & + call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%pM, lSlc%vL, lSlc%vD, lSlc%vM/), tmp, 6, adflow_real, MPI_SUM, & 0, adflow_comm_world, ierr) call EChk(ierr,__FILE__,__LINE__) if (myid == 0) then gSlc%pL = tmp(1) gSlc%pD = tmp(2) - gSlc%vL = tmp(3) - gSlc%vD = tmp(4) + gSlc%pM = tmp(3) + gSlc%vL = tmp(4) + gSlc%vD = tmp(5) + gSlc%vM = tmp(6) ! Compute the chord as the max length between any two nodes...this ! is n^2, so should be changed in the future @@ -1982,6 +2038,13 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) gSlc%CLv = gSlc%vL / gSlc%chord * fact gSlc%CDv = gSlc%vD / gSlc%chord * fact + ! Moment factor has an extra lengthRef + fact = fact/(lengthRef*LRef) + + ! moments + gSlc%CMp = gSlc%pM / gSlc%chord * fact + gSlc%CMv = gSlc%vM / gSlc%chord * fact + ! Default values gSlc%twist = zero gSlc%thickness = zero @@ -2013,10 +2076,6 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! section nodes and rotate them by the twist values we just computed ! and take the max and min - ! Back out what is the main index of the slice, x, y or z based on - ! the direction. Not the best approach, but that's ok - dir_ind = maxloc(abs(gSlc%dir),1) - ! Length of hyptoneuse is the same hyp = sqrt((x1(1)-x2(1))**2 + (x1(2)-x2(2))**2 + (x1(3)-x2(3))**2) From 8a5223bb0c804642dd2d72f85c9dd19b7057682f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 14 Jun 2022 14:25:41 +0300 Subject: [PATCH 10/76] rearranged and updated the slice integration to use the local quarter chord for the moment computations --- src/output/tecplotIO.F90 | 208 +++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 87 deletions(-) diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index 85250df00..b3fc2e0ab 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -1844,6 +1844,10 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) gSlc%pt = lSlc%pt gSlc%dir = lSlc%dir + ! Back out what is the main index of the slice, x, y or z based on + ! the direction. Not the best approach, but that's ok + dir_ind = maxloc(abs(gSlc%dir),1) + pF = zero vF = zero pM = zero ! pressure moment @@ -1852,20 +1856,7 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) allocate(localVals(iSize,lSlc%nNodes)) - ! Compute all the local variables we need. - - ! Back out what is the main index of the slice, x, y or z based on - ! the direction. Not the best approach, but that's ok - dir_ind = maxloc(abs(gSlc%dir),1) - - ! Determine the reference point for the moment computation in - ! meters. - - refPoint(1) = LRef*pointRef(1) - refPoint(2) = LRef*pointRef(2) - refPoint(3) = LRef*pointRef(3) - - ! Interpolate the required values + ! Interpolate the required values do i=1, lSlc%nNodes i1 = lSlc%ind(1, i) i2 = lSlc%ind(2, i) @@ -1874,54 +1865,9 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) localVals(1:iSize, i) = w1*nodalValues(i1, 1:iSize) + w2*nodalValues(i2, 1:iSize) end do - ! loop over elements - do i=1, size(lSlc%conn, 2) - - ! extract nodes: - i1 = lslc%conn(1, i) - i2 = lslc%conn(2, i) - - x1 = localVals(1:3, i1) - x2 = localVals(1:3, i2) - - ! extract pressure tractions - pT1 = localVals(4:6, i1) - pT2 = localVals(4:6, i2) - - ! extract viscous tractions - vT1 = localVals(7:9, i1) - vT2 = localVals(7:9, i2) - - ! Length of this segment - len = sqrt((x1(1)-x2(1))**2 + (x1(2)-x2(2))**2 + (x1(3)-x2(3))**2) - - ! compute the pressure and viscous forces on this element - pF_elem = half*(pT1 + pT2)*len - vF_elem = half*(vT1 + vT2)*len - - ! Integrate the pressure and viscous forces separately - pF = pF + pF_elem - vF = vF + vF_elem - - ! compute moment about the global reference locations - xc = half * (x1(1) + x2(1)) - refPoint(1) - yc = half * (x1(2) + x2(2)) - refPoint(2) - zc = half * (x1(3) + x2(3)) - refPoint(3) - - ! pressure components - pM(1) = pM(1) + yc*pF_elem(3) - zc*pF_elem(2) - pM(2) = pM(2) + zc*pF_elem(1) - xc*pF_elem(3) - pM(3) = pM(3) + xc*pF_elem(2) - yc*pF_elem(1) - - ! viscous components - vM(1) = vM(1) + yc*vF_elem(3) - zc*vF_elem(2) - vM(2) = vM(2) + zc*vF_elem(1) - xc*vF_elem(3) - vM(3) = vM(3) + xc*vF_elem(2) - yc*vF_elem(1) - - end do - - ! That is as far as we can go in parallel. We now have to gather up - ! pL, pD, pM, vL, vD, vM as well as the nodes to the root proc. + ! first communicate the coordinates and connectivities to get the chord and the LE/TE + ! we need this information to get the quarter-chord location, + ! which is needed for the moment computations ! Gather up the number of nodes to be set to the root proc: allocate(sliceNodeSizes(nProc), nodeDisps(0:nProc)) @@ -1938,7 +1884,6 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) if (myid == 0) then gSlc%nNodes = sum(sliceNodeSizes) allocate(gSlc%vars(iSize, gSlc%nNodes)) - end if call mpi_gatherv(localVals, iSize*lSlc%nNodes, adflow_real, gSlc%vars, sliceNodeSizes*iSize, & @@ -1955,7 +1900,6 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) 0, adflow_comm_world, ierr) call EChk(ierr,__FILE__,__LINE__) - if (myid == 0) then cellDisps(0) = 0 do iProc=1, nProc @@ -1979,34 +1923,25 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) end if deallocate(sliceNodeSizes, nodeDisps) - ! Set the local values we can in the slice - lSlc%pL = liftDirection(1)*pF(1) + liftDirection(2)*pF(2) + liftDirection(3)*pF(3) - lSlc%pD = dragDirection(1)*pF(1) + dragDirection(2)*pF(2) + dragDirection(3)*pF(3) - lSlc%vL = liftDirection(1)*vF(1) + liftDirection(2)*vF(2) + liftDirection(3)*vF(3) - lSlc%vD = dragDirection(1)*vF(1) + dragDirection(2)*vF(2) + dragDirection(3)*vF(3) - - ! the moments are a bit different than lift and drag. we keep the 3 components of the moment - ! in pM in this routine but then the slc%pM variable only has the component of the moment - ! we are interested in. we use the direction index to get this value out and set it in the slice - lSlc%pM = pM(dir_ind) - lSlc%vM = vM(dir_ind) - - ! Reduce the lift/drag values - call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%pM, lSlc%vL, lSlc%vD, lSlc%vM/), tmp, 6, adflow_real, MPI_SUM, & - 0, adflow_comm_world, ierr) - call EChk(ierr,__FILE__,__LINE__) + ! done communicating the geometry info + ! process the geometry on the root processor to figure out the LE, TE, and the chord if (myid == 0) then - gSlc%pL = tmp(1) - gSlc%pD = tmp(2) - gSlc%pM = tmp(3) - gSlc%vL = tmp(4) - gSlc%vD = tmp(5) - gSlc%vM = tmp(6) + ! TODO the comments below can be used for a _slightly_ more accurate LE/TE detection. + ! this does not really show any difference other than the twist computation, + ! but depending on the application, getting the twist distribution from ADflow data might be critical. + ! so we leave the comments below for a better implementation. + ! For now, we just work with the 2 max-distance nodes + + ! begin template: + ! loop over the elements and find the TE bends + ! if we have 2 TE bends, then take the mid-TE point as the TE + ! find the largest distance node + ! if we dont have 2 bends, just get the max distance between any 2 nodes, thats our chord line + ! end template. ! Compute the chord as the max length between any two nodes...this ! is n^2, so should be changed in the future - dmax = zero bestPair = (/1, 1/) do i=1,size(gSlc%vars, 2) @@ -2029,6 +1964,105 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! Set chord, protected from zero gSlc%chord = max(dmax, 1e-12) + ! figure out which node is the LE and the TE + if (gSlc%vars(1, bestPair(1)) < gSlc%vars(1, bestPair(2))) then + ! first entry in the "bestPair" is the LE node + x1 = gSlc%vars(1:3, bestPair(1)) + x2 = gSlc%vars(1:3, bestPair(2)) + else + ! second entry in the "bestPair" is the LE node + x1 = gSlc%vars(1:3, bestPair(2)) + x2 = gSlc%vars(1:3, bestPair(1)) + end if + + ! using the LE and TE coordinates, compute the quarter chord point + ! we will use this as reference for the moment computation + refPoint(1) = 0.75_realType * x1(1) + 0.25_realType * x2(1) + refPoint(2) = 0.75_realType * x1(2) + 0.25_realType * x2(2) + refPoint(3) = 0.75_realType * x1(3) + 0.25_realType * x2(3) + end if + + ! communicate the reference point coordinates across processors. + call mpi_bcast(refPoint, 3, adflow_real, 0, adflow_comm_world, ierr) + call EChk(ierr,__FILE__,__LINE__) + + ! now we are done with the global geometric operations. go back to integrating the slices locally on each proc + + ! loop over elements + do i=1, size(lSlc%conn, 2) + ! Compute all the local variables we need. + + ! extract nodes: + i1 = lslc%conn(1, i) + i2 = lslc%conn(2, i) + + x1 = localVals(1:3, i1) + x2 = localVals(1:3, i2) + + ! extract pressure tractions + pT1 = localVals(4:6, i1) + pT2 = localVals(4:6, i2) + + ! extract viscous tractions + vT1 = localVals(7:9, i1) + vT2 = localVals(7:9, i2) + + ! Length of this segment + len = sqrt((x1(1)-x2(1))**2 + (x1(2)-x2(2))**2 + (x1(3)-x2(3))**2) + + ! compute the pressure and viscous forces on this element + pF_elem = half*(pT1 + pT2)*len + vF_elem = half*(vT1 + vT2)*len + + ! Integrate the pressure and viscous forces separately + pF = pF + pF_elem + vF = vF + vF_elem + + ! compute moment about the global reference locations + xc = half * (x1(1) + x2(1)) - refPoint(1) + yc = half * (x1(2) + x2(2)) - refPoint(2) + zc = half * (x1(3) + x2(3)) - refPoint(3) + + ! pressure components + pM(1) = pM(1) + yc*pF_elem(3) - zc*pF_elem(2) + pM(2) = pM(2) + zc*pF_elem(1) - xc*pF_elem(3) + pM(3) = pM(3) + xc*pF_elem(2) - yc*pF_elem(1) + + ! viscous components + vM(1) = vM(1) + yc*vF_elem(3) - zc*vF_elem(2) + vM(2) = vM(2) + zc*vF_elem(1) - xc*vF_elem(3) + vM(3) = vM(3) + xc*vF_elem(2) - yc*vF_elem(1) + + end do + + ! That is as far as we can go in parallel. We now have to gather up + ! pL, pD, pM, vL, vD, vM as well as the nodes to the root proc. + + ! Set the local values we can in the slice + lSlc%pL = liftDirection(1)*pF(1) + liftDirection(2)*pF(2) + liftDirection(3)*pF(3) + lSlc%pD = dragDirection(1)*pF(1) + dragDirection(2)*pF(2) + dragDirection(3)*pF(3) + lSlc%vL = liftDirection(1)*vF(1) + liftDirection(2)*vF(2) + liftDirection(3)*vF(3) + lSlc%vD = dragDirection(1)*vF(1) + dragDirection(2)*vF(2) + dragDirection(3)*vF(3) + + ! the moments are a bit different than lift and drag. we keep the 3 components of the moment + ! in pM in this routine but then the slc%pM variable only has the component of the moment + ! we are interested in. we use the direction index to get this value out and set it in the slice + lSlc%pM = pM(dir_ind) + lSlc%vM = vM(dir_ind) + + ! Reduce the lift/drag values + call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%pM, lSlc%vL, lSlc%vD, lSlc%vM/), tmp, 6, adflow_real, MPI_SUM, & + 0, adflow_comm_world, ierr) + call EChk(ierr,__FILE__,__LINE__) + + if (myid == 0) then + gSlc%pL = tmp(1) + gSlc%pD = tmp(2) + gSlc%pM = tmp(3) + gSlc%vL = tmp(4) + gSlc%vD = tmp(5) + gSlc%vM = tmp(6) + ! Compute factor to get coefficient fact = two/(gammaInf*pInf*MachCoef*MachCoef*pRef) From f49fd5b3939c2fdc8e94f8fb95f72a0e15eb2dad Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 29 Jun 2022 13:28:08 +0200 Subject: [PATCH 11/76] added the missing deallocate call to mg pc --- src/adjoint/adjointUtils.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/adjoint/adjointUtils.F90 b/src/adjoint/adjointUtils.F90 index a6983688a..ada65304b 100644 --- a/src/adjoint/adjointUtils.F90 +++ b/src/adjoint/adjointUtils.F90 @@ -1611,6 +1611,7 @@ subroutine destroyPETScVars use constants use ADjointPETSc, only : dRdWT, dRdwPreT, adjointKSP, adjointPETScVarsAllocated use inputAdjoint, only : approxPC + use agmg, only : destroyAGMG use utils, only : EChk implicit none @@ -1629,6 +1630,9 @@ subroutine destroyPETScVars call KSPDestroy(adjointKSP, ierr) call EChk(ierr,__FILE__,__LINE__) + + call destroyAGMG() + adjointPETScVarsAllocated = .False. end if From f18a993d993f3025f22a7d70af12313f4a3ad46e Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 8 Jul 2022 09:10:40 -0400 Subject: [PATCH 12/76] adding cylindrical slicing. WIP --- adflow/pyADflow.py | 120 +++++++++++++++++++++++++++++++++++++-- src/f2py/adflow.pyf | 14 +++-- src/output/tecplotIO.F90 | 58 +++++++++++++------ 3 files changed, 162 insertions(+), 30 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index ce5311688..433c90c5e 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -557,27 +557,135 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): tmp = numpy.zeros((N, 3), self.dtype) if direction == "x": tmp[:, 0] = positions - dirVec = [1.0, 0.0, 0.0] + tmp[:, 1] = -1e50 + slice_dir = [0.0, 1.0, 0.0] + normal = [1.0, 0.0, 0.0] elif direction == "y": tmp[:, 1] = positions - dirVec = [0.0, 1.0, 0.0] + tmp[:, 2] = -1e50 + slice_dir = [0.0, 0.0, 1.0] + normal = [0.0, 1.0, 0.0] elif direction == "z": tmp[:, 2] = positions - dirVec = [0.0, 0.0, 1.0] + tmp[:, 0] = -1e50 + slice_dir = [1.0, 0.0, 0.0] + normal = [0.0, 0.0, 1.0] for i in range(len(positions)): # It is important to ensure each slice get a unique - # name...so we will number sequentially from pythhon + # name...so we will number sequentially from python j = self.nSlice + i + 1 if sliceType == "relative": sliceName = "Slice_%4.4d %s Para Init %s=%7.3f" % (j, groupTag, direction, positions[i]) - self.adflow.tecplotio.addparaslice(sliceName, tmp[i], dirVec, famList) + self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, famList) else: sliceName = "Slice_%4.4d %s Absolute %s=%7.3f" % (j, groupTag, direction, positions[i]) - self.adflow.tecplotio.addabsslice(sliceName, tmp[i], dirVec, famList) + self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, slice_dir, famList) self.nSlice += N + def addCylindricalSlices( + self, pt1, pt2, n_slice=180, slice_beg=0.0, slice_end=360.0, sliceType="relative", groupName=None + ): + """ + Add cylindrical projection slices. The cylinrical projection axis is defined + from pt1 to pt2. Then we start from the lift direction and rotate around this + axis until we are back at the beginning. The rotation direction follows the + right hand rule; we rotate the plane in the direction of vectors from pt1 to + pt2 crossed with the lift direction. + + Parameters + ---------- + pt1 : numpy array, length 3 + beginning point of the vector that defines the rotation axis + pt2 : numpy array, length 3 + end point of the vector that defines the rotation axis + n_slice : int + number of slices around a 360 degree full rotation. + slice_beg : float + beginning of the slices in the rotation direction + slice_end : float + end of the slices in the rotation direction + sliceType : str {'relative', 'absolute'} + Relative slices are 'sliced' at the beginning and then parametricly + move as the geometry deforms. As a result, the slice through the + geometry may not remain planar. An absolute slice is re-sliced for + every out put so is always exactly planar and always at the initial + position the user indicated. + groupName : str + The family to use for the slices. Default is None corresponding to all + wall groups. + """ + + # Create the zipper mesh if not done so + self._createZipperMesh() + + # Determine the families we want to use + if groupName is None: + groupName = self.allWallsGroup + groupTag = "%s: " % groupName + + famList = self._getFamilyList(groupName) + + sliceType = sliceType.lower() + if sliceType not in ["relative", "absolute"]: + raise Error("'sliceType' must be 'relative' or 'absolute'.") + + # get the angles that we are slicing in radians + angles = numpy.linspace(slice_beg, slice_end, n_slice) * numpy.pi / 180.0 + + # unit vector in the lift direction + lift_dir = numpy.zeros(3) + lift_dir[self.getOption("liftIndex") - 1] = 1.0 + + # the unit vector on the axis + vec1 = pt2 - pt1 + vec1 /= numpy.linalg.norm(vec1) + # update p2 so that the distance between p1 and p2 is one. + # not necessary, but probably better for numerical stability + pt2 = pt1 + vec1 + + # loop over angles + for ii, angle in enumerate(angles): + sin = numpy.sin(angle) + cos = numpy.cos(angle) + omc = 1.0 - cos + vx = vec1[0] + vy = vec1[1] + vz = vec1[2] + # rotation matrix by theta about vec1 + rot_mat = numpy.array([ + [cos + vx * vx * omc, vx * vy * omc - vz * sin, vx * vz * omc + vy * sin], + [vy * vx * omc + vz * sin, cos + vy * vy * omc, vy * vz * omc - vx * sin], + [vz * vx * omc - vy * sin, vz * vy * omc + vx * sin, cos + vz * vz * omc], + ]) + + # rotate the lift direction vector to get the slice direction + slice_dir = rot_mat.dot(lift_dir) + + # cross product vec1 and vec2 to get the normal vector of this plane + slice_normal = numpy.cross(vec1, slice_dir) + # normalize for good measure + slice_normal /= numpy.linalg.norm(slice_normal) + + # we can now define a plane for the slice using p1 and slice_normal. + # in the cylindrical version, we also pick a "direction". This is which direction we are going + # from the center axis. We will reject cells directly if their centroid are behind this + # direction (i.e. dot slice_dir is negative) and only use the cells that are in + # the same direction (i.e. dot product positive.) + + # It is important to ensure each slice get a unique + # name...so we will number sequentially from python + jj = self.nSlice + ii + 1 + if sliceType == "relative": + sliceName = f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, famList) + else: + sliceName = f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, famList) + + self.nSlice += n_slice + def addIntegrationSurface(self, fileName, familyName, isInflow=True): """Add a specific integration surface for performing massflow-like computations. diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index a8dbea684..7a148e2bc 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -69,13 +69,13 @@ python module libadflow integer(kind=inttype), intent(in) :: nvar character, dimension(nvar,32), intent(out):: monitor_variables end subroutine getmonitorvariablenames - + subroutine getsolvertypearray(niter, nsps, type_array) - integer(kind=inttype), intent(in) :: niter, nsps, + integer(kind=inttype), intent(in) :: niter, nsps, character, dimension(0:niter,nsps,8), intent(out):: type_array end subroutine getsolvertypearray - - + + end module utils module walldistance @@ -414,17 +414,19 @@ python module libadflow end module surfaceutils module tecplotio - subroutine addparaslice(slicename,pt,direction,famlist,n) ! in :test:liftDistribution.F90 + subroutine addparaslice(slicename,pt,normal,direction,famlist,n) ! in :test:liftDistribution.F90 character*(*) intent(in) :: slicename real(kind=realtype) dimension(3),intent(in) :: pt + real(kind=realtype) dimension(3),intent(in) :: normal real(kind=realtype) dimension(3),intent(in) :: direction integer(kind=inttype) dimension(n),intent(in) :: famlist integer(kind=inttype), optional,intent(in),check(len(famlist)>=n),depend(famlist) :: n=len(famlist) end subroutine addparaslice - subroutine addabsslice(slicename,pt,direction,famlist,n) ! in :test:liftDistribution.F90 + subroutine addabsslice(slicename,pt,normal,direction,famlist,n) ! in :test:liftDistribution.F90 character*(*) intent(in) :: slicename real(kind=realtype) dimension(3),intent(in) :: pt + real(kind=realtype) dimension(3),intent(in) :: normal real(kind=realtype) dimension(3),intent(in) :: direction integer(kind=inttype) dimension(n),intent(in) :: famlist integer(kind=inttype), optional,intent(in),check(len(famlist)>=n),depend(famlist) :: n=len(famlist) diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index b3fc2e0ab..bd1bff8e4 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -23,7 +23,8 @@ module tecplotIO real(kind=realType) :: pL, vL, pD, vD, pM, vM, CLp, CLv, CDp, CDv, CMp, CMv real(kind=realType) :: chord, twist, thickness real(kind=realType), dimension(3) :: le, te - real(kind=realType), dimension(3) :: pt, dir + ! TODO propagate the change to normal and dir throughout + real(kind=realType), dimension(3) :: pt, normal, dir integer(kind=intType), allocatable, dimension(:) :: famList end type slice @@ -38,6 +39,7 @@ module tecplotIO character(len=maxStringLen) :: distName integer(kind=intType) :: nSegments, dir_ind integer(kind=intType), dimension(:), allocatable :: famList + real(kind=realType) :: normal(3) real(kind=realType) :: dir(3) real(kind=realType) :: delta real(kind=realType), dimension(:,:), allocatable :: slicePts @@ -62,7 +64,7 @@ module tecplotIO integer(kind=intType), parameter :: nLiftDistVar=23 contains - subroutine addParaSlice(sliceName, pt, direction, famList, n) + subroutine addParaSlice(sliceName, pt, normal, direction, famList, n) ! ! This subroutine is intended to be called from python. ! This routine will add a parametric slice to the list of user @@ -76,7 +78,7 @@ subroutine addParaSlice(sliceName, pt, direction, famList, n) ! Input parameters character*(*), intent(in) :: sliceName - real(kind=realType), dimension(3), intent(in) :: pt, direction + real(kind=realType), dimension(3), intent(in) :: pt, normal, direction integer(kind=intType), intent(in) :: famList(n), n ! Working @@ -109,7 +111,7 @@ subroutine addParaSlice(sliceName, pt, direction, famList, n) call getSurfaceFamily(elemFam, sizeCell, wallList, size(wallList), .True.) ! Create actual slice - call createSlice(pts, conn, elemFam, paraSlices(nParaSlices, sps), pt, direction, & + call createSlice(pts, conn, elemFam, paraSlices(nParaSlices, sps), pt, normal, direction, & sliceName, famList) ! Clean up memory. @@ -118,7 +120,7 @@ subroutine addParaSlice(sliceName, pt, direction, famList, n) end subroutine addParaSlice - subroutine addAbsSlice(sliceName, pt, direction, famList, n) + subroutine addAbsSlice(sliceName, pt, normal, direction, famList, n) ! ! This subroutine is intended to be called from python. ! This routine will add an absolute slice to the list of user @@ -132,7 +134,7 @@ subroutine addAbsSlice(sliceName, pt, direction, famList, n) ! Input parameters character*(*), intent(in) :: sliceName - real(kind=realType), dimension(3), intent(in) :: pt, direction + real(kind=realType), dimension(3), intent(in) :: pt, normal, direction integer(kind=intType), intent(in) :: famList(n), n ! Working @@ -160,7 +162,7 @@ subroutine addAbsSlice(sliceName, pt, direction, famList, n) call getSurfaceConnectivity(conn, cgnsBlockID, sizeCell, wallList, size(wallList), .True.) call getSurfacePoints(pts, sizeNode, sps, wallList, size(wallList), .True.) call getSurfaceFamily(elemFam, sizeCell, wallList, size(wallList), .True.) - call createSlice(pts, conn, elemFam, absSlices(nAbsSlices, sps), pt, direction, & + call createSlice(pts, conn, elemFam, absSlices(nAbsSlices, sps), pt, normal, direction, & sliceName, famList) ! Clean up memory. @@ -195,6 +197,7 @@ subroutine addLiftDistribution(nSegments, dir_vec, dir_ind, distName, famList, n liftDists(nLIftDists)%nSegments = nSegments liftDists(nLiftDists)%dir = dir_vec + liftDists(nLiftDists)%normal = dir_vec liftDists(nLiftDists)%distName = distName liftDists(nLIftDists)%dir_ind = dir_ind @@ -373,8 +376,9 @@ subroutine writeSlicesFile(fileName, nodalValues) call destroySlice(absSlices(i, sps)) ! Make new one in the same location + ! TODO update here call createSlice(pts, conn, elemFam, absSlices(i, sps), & - absSlices(i, sps)%pt, absSlices(i, sps)%dir, & + absSlices(i, sps)%pt, absSlices(i, sps)%normal, absSlices(i, sps)%dir, & absSlices(i, sps)%sliceName, famList) call integrateSlice(absSlices(i, sps), globalSlice, & @@ -619,8 +623,9 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) do i=1, d%nSegments ! Make new one in the same location + ! TODO update here call createSlice(pts, conn, elemFam, localSlice, d%slicePts(:, i), & - d%dir, "does_not_matter", d%famList) + d%normal, d%dir, "does_not_matter", d%famList) call integrateSlice(localSlice, globalSlice, nodalValues, 0, .False.) ! Total lift, drag, and moment @@ -1624,7 +1629,7 @@ subroutine computeSurfaceOutputNodalData(exch, zipper, includeTractions, nodalVa end subroutine computeSurfaceOutputNodalData - subroutine createSlice(pts, conn, elemFam, slc, pt, dir, sliceName, famList) + subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir, sliceName, famList) ! ! This subroutine creates a slice on a plane defined by pt and ! and dir. It only uses the families specified in the famList. @@ -1640,25 +1645,26 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, dir, sliceName, famList) integer(kind=intType), dimension(:,:), intent(in) :: conn integer(kind=intType), dimension(:), intent(in) :: elemFam type(slice), intent(inout) :: slc - real(kind=realType), dimension(3), intent(in) :: pt, dir + real(kind=realType), dimension(3), intent(in) :: pt, dir, normal character*(*), intent(in) :: sliceName integer(kind=intType), dimension(:), intent(in) :: famList ! Working param integer(kind=intType) :: i, nMax, nUnique, oldInd, newInd integer(kind=intType) :: patchIndices(4), indexSquare, jj, kk, icon, iCoor, num1, num2 - real(kind=realType) :: f(4), d, ovrdnom, tol + real(kind=realType) :: f(4), d, ovrdnom, tol, len_vec logical :: logic1, foundFam real(kind=realType), dimension(:, :), pointer :: tmpWeight, dummy, tmpNodes integer(kind=intType), dimension(:, :), pointer :: tmpInd integer(kind=intType), dimension(:), allocatable :: link real(kind=realType), dimension(:), allocatable :: fc + real(kind=realType), dimension(3) :: elemc, vec ! Allocate the family list this slice is to use: slc%sliceName = sliceName ! Set the info for the slice: slc%pt = pt - slc%dir = dir + slc%normal = normal slc%nNodes = 0 allocate(slc%famList(size(famList))) slc%famList = famList @@ -1666,15 +1672,15 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, dir, sliceName, famList) ! for the contour. ! Equation of plane: ax + by + cz + d = 0 - d = -pt(1)*dir(1) - pt(2)*dir(2) - pt(3)*dir(3) - ovrdnom = one/sqrt(dir(1)**2 + dir(2)**2 + dir(3)**2) + d = -pt(1)*normal(1) - pt(2)*normal(2) - pt(3)*normal(3) + ovrdnom = one/sqrt(normal(1)**2 + normal(2)**2 + normal(3)**2) ! Compute the distance function on all possible surfaces on this ! processor. allocate(fc(size(pts,2))) do i=1, size(pts, 2) ! Now compute the signed distance - fc(i) = (dir(1)*pts(1, i) + dir(2)*pts(2, i) + dir(3)*pts(3, i) + d)*ovrdnom + fc(i) = (normal(1)*pts(1, i) + normal(2)*pts(2, i) + normal(3)*pts(3, i) + d)*ovrdnom end do ! Estimate size of slice by the sqrt of the number of nodes in the @@ -1690,12 +1696,28 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, dir, sliceName, famList) famInclude: if (famInList(elemFam(i), famList)) then + ! zero out the centroid + elemc = zero + ! Extract the indices and function values at each corner do jj=1,4 patchIndices(jj) = conn(jj, i) f(jj) = fc(patchIndices(jj)) + elemc = elemc + 0.25_realType * pts(:, patchIndices(jj)) end do + ! check if the centroid of this element is in the correct direction + vec = elemc - pt + ! normalize vector + len_vec = sqrt(vec(1) * vec(1) + vec(2) * vec(2) + vec(3) * vec(3)) + vec = vec / len_vec + if ((vec(1)*dir(1) + vec(2)*dir(2) + vec(3)*dir(3)) .lt. zero) then + ! we reject this element; just set all signed distances to 1.0 + do jj=1,4 + f(jj) = one + end do + end if + ! Based on the values at each corner, determine which ! type contour we have indexSquare = 1 @@ -1842,11 +1864,11 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! Copy the info related to slice gSlc%sliceName = trim(lSlc%sliceName) gSlc%pt = lSlc%pt - gSlc%dir = lSlc%dir + gSlc%normal = lSlc%normal ! Back out what is the main index of the slice, x, y or z based on ! the direction. Not the best approach, but that's ok - dir_ind = maxloc(abs(gSlc%dir),1) + dir_ind = maxloc(abs(gSlc%normal),1) pF = zero vF = zero From bd75ecce619a9995d3d414ac573ac61fb7d1e04f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 8 Jul 2022 09:18:00 -0400 Subject: [PATCH 13/76] added the missing mgpc destroy routine --- src/adjoint/adjointUtils.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/adjoint/adjointUtils.F90 b/src/adjoint/adjointUtils.F90 index a6983688a..ada65304b 100644 --- a/src/adjoint/adjointUtils.F90 +++ b/src/adjoint/adjointUtils.F90 @@ -1611,6 +1611,7 @@ subroutine destroyPETScVars use constants use ADjointPETSc, only : dRdWT, dRdwPreT, adjointKSP, adjointPETScVarsAllocated use inputAdjoint, only : approxPC + use agmg, only : destroyAGMG use utils, only : EChk implicit none @@ -1629,6 +1630,9 @@ subroutine destroyPETScVars call KSPDestroy(adjointKSP, ierr) call EChk(ierr,__FILE__,__LINE__) + + call destroyAGMG() + adjointPETScVarsAllocated = .False. end if From 6976f7f8651f92b508057d9ef298c8806c9cf4b1 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 8 Jul 2022 13:15:25 -0400 Subject: [PATCH 14/76] properly implemented the cavitation constraint --- src/adjoint/masterRoutines.F90 | 24 +--- .../outputForward/surfaceintegrations_d.f90 | 20 ++- .../outputReverse/surfaceintegrations_b.f90 | 27 +++- .../surfaceintegrations_fast_b.f90 | 9 +- src/solver/surfaceIntegrations.F90 | 117 ++++++++++++------ 5 files changed, 128 insertions(+), 69 deletions(-) diff --git a/src/adjoint/masterRoutines.F90 b/src/adjoint/masterRoutines.F90 index 367a1dc15..ab6472d76 100644 --- a/src/adjoint/masterRoutines.F90 +++ b/src/adjoint/masterRoutines.F90 @@ -31,7 +31,7 @@ subroutine master(useSpatial, famLists, funcValues, forces, & use utils, only : setPointers, EChk use turbUtils, only : turbAdvection, computeEddyViscosity use residuals, only : initRes_block, sourceTerms_block - use surfaceIntegrations, only : getSolution, computeCavitationNumber + use surfaceIntegrations, only : getSolution use inputCostFunctions, only : computeCavitation use adjointExtra, only : volume_block, metric_block, boundaryNormals,& xhalo_block, sumdwandfw, resScale @@ -224,12 +224,6 @@ subroutine master(useSpatial, famLists, funcValues, forces, & ! Compute the final solution values if (present(famLists)) then - ! if we are computing cavitation, we need to know what cp min (roughly) is across the domain - if (computeCavitation) then - ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow - call computeCavitationNumber() - end if - call getSolution(famLists, funcValues) end if @@ -276,7 +270,7 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu use solverutils_d, only : timeStep_Block_d use turbbcroutines_d, only : applyAllTurbBCthisblock_d, bcTurbTreatment_d use initializeflow_d, only : referenceState_d - use surfaceIntegrations, only : getSolution_d, computeCavitationNumber + use surfaceIntegrations, only : getSolution_d use inputCostFunctions, only : computeCavitation use adjointExtra_d, only : xhalo_block_d, volume_block_d, metric_BLock_d, boundarynormals_d use adjointextra_d, only : resscale_D, sumdwandfw_d @@ -528,12 +522,6 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu ! Compute final solution values if (present(famLists)) then - - if (computeCavitation) then - ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow - call computeCavitationNumber() - end if - call getSolution_d(famLists, funcValues, funcValuesd) end if @@ -591,7 +579,7 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & use adjointPETSc, only : x_like use haloExchange, only : whalo2_b, exchangeCoor_b, exchangeCoor, whalo2 use wallDistanceData, only : xSurfVec, xSurfVecd, xSurf, xSurfd, wallScatter - use surfaceIntegrations, only : getSolution_b, computeCavitationNumber + use surfaceIntegrations, only : getSolution_b use inputCostFunctions, only : computeCavitation use flowUtils, only : fixAllNodalGradientsFromAD use adjointextra_b, only : resscale_B, sumdwandfw_b @@ -677,12 +665,6 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & ! Call the final getSolution_b routine if (present(famLists)) then - ! if we are computing cavitation, we need to know what cp min (roughly) is across the domain - if (computeCavitation) then - ! this routine puts the cpmin value in cavitationnumber so the KS can go ahead w/o overflow - call computeCavitationNumber() - end if - call getSolution_b(famLists, funcValues, funcValuesd) end if diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 8d697a5dd..53995ea89 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -1130,11 +1130,18 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then sensor1d = -(cavitationrho*cpd*exp(cavitationrho*(-cp-& & cavitationnumber))) sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) - cavitationd = cavitationd + sensor1d - cavitation = cavitation + sensor1 +! else +! sensor1 = zero +! end if + cavitationd = cavitationd + blk*sensor1d + cavitation = cavitation + sensor1*blk end if end do ! @@ -1522,8 +1529,15 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) - cavitation = cavitation + sensor1 +! else +! sensor1 = zero +! end if + cavitation = cavitation + sensor1*blk end if end do ! diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index e5b899395..c2d3e722f 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -1288,8 +1288,15 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) - cavitation = cavitation + sensor1 +! else +! sensor1 = zero +! end if + cavitation = cavitation + sensor1*blk end if end do ! @@ -1593,7 +1600,14 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas - sensor1d = cavitationd +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then +! else +! sensor1 = zero +! end if + sensor1d = blk*cavitationd cpd = -(cavitationrho*exp(cavitationrho*(-cavitationnumber-cp))*& & sensor1d) tmpd = (plocal-pinf)*cpd @@ -1953,8 +1967,15 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) - cavitation = cavitation + sensor1 +! else +! sensor1 = zero +! end if + cavitation = cavitation + sensor1*blk end if end do ! diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index 8daf4de62..dd4969568 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -466,8 +466,15 @@ subroutine wallintegrationface(localvalues, mm) ! sensor1 = one/(one+exp(-2*10*sensor1)) ! sensor1 = sensor1 * cellarea * blk ! ks formulation with a fixed cpmin at 2 sigmas +! only include the cavitation contribution if we are not underflowing. +! otherwise, this will cause nans with bwd ad because of the order of the operations +! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. +! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) - cavitation = cavitation + sensor1 +! else +! sensor1 = zero +! end if + cavitation = cavitation + sensor1*blk end if end do ! diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 5bd7965e2..7e193dd68 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -513,8 +513,15 @@ subroutine wallIntegrationFace(localValues, mm) ! Sensor1 = one/(one+exp(-2*10*Sensor1)) ! Sensor1 = Sensor1 * cellArea * blk ! KS formulation with a fixed CPmin at 2 sigmas + ! only include the cavitation contribution if we are not underflowing. + ! otherwise, this will cause NaNs with bwd AD because of the order of the operations + ! TODO the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. + ! if ((cavitationrho * (-Cp - cavitationnumber)) .lt. -200.0_realType) then Sensor1 = exp(cavitationrho * (-Cp - cavitationnumber)) - Cavitation = Cavitation + Sensor1 + ! else + ! Sensor1 = zero + ! end if + Cavitation = Cavitation + Sensor1 * blk end if enddo @@ -962,10 +969,6 @@ subroutine getSolution(famLists, funcValues, globalValues) integer(kind=intType), dimension(:), pointer :: famList ! Master loop over the each of the groups we have - if (computeCavitation) then - call computeCavitationNumber() - end if - groupLoop: do iGroup=1, size(famLists, 1) ! Extract the current family list @@ -974,6 +977,11 @@ subroutine getSolution(famLists, funcValues, globalValues) funcValues = zero localVal = zero + ! compute the current cp min value for the cavitation computation with KS aggregation + if (computeCavitation) then + call computeCavitationNumber(famList) + end if + do sps=1, nTimeIntervalsSpectral ! Integrate the normal block surfaces. do nn=1, nDom @@ -1066,18 +1074,22 @@ subroutine integrateSurfaces(localValues, famList) end subroutine integrateSurfaces - subroutine computeCavitationNumber() + subroutine computeCavitationNumber(famList) use constants + use inputTimeSpectral , only : nTimeIntervalsSpectral use communication, only : ADflow_comm_world, myID + use blockPointers, only : nDom use inputPhysics, only : cavitationNumber, MachCoef use blockPointers use flowVarRefState use BCPointers - use utils, only : setBCPointers, isWallType, EChk + use utils, only : setPointers, setBCPointers, isWallType, EChk + use sorting, only : famInList implicit none - integer(kind=intType) :: mm + integer(kind=intType), dimension(:), intent(in) :: famList + integer(kind=intType) :: mm, nn, sps integer(kind=intType) :: i, j, ii, blk, ierr real(kind=realType) :: Cp, plocal, tmp, cavitationNumberLocal @@ -1086,45 +1098,56 @@ subroutine computeCavitationNumber() ! set the cavitation number to a small value so that we get the actual max (- min cp) cavitationNumberLocal = -10000.0_realType - ! Loop over all possible boundary conditions - bocos: do mm=1, nBocos - - ! Set a bunch of pointers depending on the face id to make - ! a generic treatment possible. - call setBCPointers(mm, .True.) - - ! no post gathered integrations currently - isWall: if( isWallType(BCType(mm)) ) then - - !$AD II-LOOP - do ii=0,(BCData(mm)%jnEnd - bcData(mm)%jnBeg)*(bcData(mm)%inEnd - bcData(mm)%inBeg) -1 - i = mod(ii, (bcData(mm)%inEnd-bcData(mm)%inBeg)) + bcData(mm)%inBeg + 1 - j = ii/(bcData(mm)%inEnd-bcData(mm)%inBeg) + bcData(mm)%jnBeg + 1 - - ! blank value - blk = max(BCData(mm)%iblank(i,j), 0) - - ! compute local CP - - plocal = pp2(i,j) - tmp = two/(gammaInf*MachCoef*MachCoef) - Cp = tmp*(plocal-pinf) - - ! compare it against the current value on this proc - cavitationNumberLocal = max(cavitationNumberLocal, -Cp * blk) - enddo - end if isWall - - end do bocos - - ! write (*,*) "rank", myID, " cav before comm", cavitationNumberLocal + ! loop over the TS instances just because its the same convention everywhere. + ! in an actual TS computation, this wont work most likely. + ts: do sps=1, nTimeIntervalsSpectral + domains: do nn=1, nDom + call setPointers(nn, 1, sps) + + ! Loop over all possible boundary conditions + bocos: do mm=1, nBocos + ! Determine if this boundary condition is to be incldued in the + ! currently active group + famInclude: if (famInList(BCData(mm)%famID, famList)) then + + ! Set a bunch of pointers depending on the face id to make + ! a generic treatment possible. + call setBCPointers(mm, .True.) + + ! no post gathered integrations currently + isWall: if( isWallType(BCType(mm)) ) then + + !$AD II-LOOP + do ii=0,(BCData(mm)%jnEnd - bcData(mm)%jnBeg)*(bcData(mm)%inEnd - bcData(mm)%inBeg) -1 + i = mod(ii, (bcData(mm)%inEnd-bcData(mm)%inBeg)) + bcData(mm)%inBeg + 1 + j = ii/(bcData(mm)%inEnd-bcData(mm)%inBeg) + bcData(mm)%jnBeg + 1 + + ! compute local CP + plocal = pp2(i,j) + tmp = two/(gammaInf*MachCoef*MachCoef) + Cp = tmp*(plocal-pinf) + + ! only take this if its a compute cell + if (BCData(mm)%iblank(i,j) .gt. zero) then + ! compare it against the current value on this proc + cavitationNumberLocal = max(cavitationNumberLocal, -Cp) + end if + enddo + end if isWall + + end if famInclude + end do bocos + end do domains + end do ts + + ! write (*,*) "rank", myID, " cav before comm", cavitationNumberLocal ! finally communicate across all call mpi_allreduce(cavitationNumberLocal, cavitationNumber, 1, adflow_real, & MPI_MAX, adflow_comm_world, ierr) call EChk(ierr, __FILE__, __LINE__) - ! write (*,*) "rank", myID, " final cav number ", cavitationNumber + ! write (*,*) "rank", myID, " final cav number ", cavitationNumber end subroutine computeCavitationNumber @@ -1237,6 +1260,7 @@ subroutine getSolution_d(famLists, funcValues, funcValuesd) use zipperIntegrations, only :integrateZippers_d use userSurfaceIntegrations, only : integrateUserSurfaces_d use actuatorRegion, only : integrateActuatorRegions_d + use inputCostFunctions, only : computeCavitation implicit none ! Input/Output Variables @@ -1255,6 +1279,11 @@ subroutine getSolution_d(famLists, funcValues, funcValuesd) nFam = famLists(iGroup, 1) famList => famLists(iGroup, 2:2+nFam-1) + ! compute the current cp min value for the cavitation computation with KS aggregation + if (computeCavitation) then + call computeCavitationNumber(famList) + end if + localVal = zero localVald = zero do sps=1, nTimeIntervalsSpectral @@ -1313,6 +1342,7 @@ subroutine getSolution_b(famLists, funcValues, funcValuesd) use zipperIntegrations, only :integrateZippers_b use userSurfaceIntegrations, only : integrateUserSurfaces_b use actuatorRegion, only : integrateActuatorRegions_b + use inputCostFunctions, only : computeCavitation implicit none ! Input/Output Variables @@ -1335,6 +1365,11 @@ subroutine getSolution_b(famLists, funcValues, funcValuesd) nFam = famLists(iGroup, 1) famList => famLists(iGroup, 2:2+nFam-1) + ! compute the current cp min value for the cavitation computation with KS aggregation + if (computeCavitation) then + call computeCavitationNumber(famList) + end if + localVal = zero localVald = zero From 4a250417421190a67bf9456a372a91697e1580bb Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 8 Jul 2022 13:51:07 -0400 Subject: [PATCH 15/76] changed the behavior of cavitation number option --- adflow/pyADflow.py | 2 +- doc/options.yaml | 8 +++++ src/f2py/adflow.pyf | 10 +++--- src/modules/inputParam.F90 | 1 + src/output/outputMod.F90 | 62 +++++++++++++++++++------------------- 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 72059b3e1..663d6e028 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5269,7 +5269,7 @@ def _getOptionMap(self): "restrictionrelaxation": ["iter", "fcoll"], "forcesastractions": ["physics", "forcesastractions"], "lowspeedpreconditioner": ["discr", "lowspeedpreconditioner"], - "cavitationnumber": ["physics", "cavitationnumber"], + "cavitationnumber": ["physics", "cavitationsensor"], "cavitationrho": ["physics", "cavitationrho"], # Common Parameters "ncycles": ["iter", "ncycles"], diff --git a/doc/options.yaml b/doc/options.yaml index 3db7ea50d..9f6fae1e7 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -331,6 +331,14 @@ infChangeCorrection: cavitationNumber: desc: > The -Cp value used to trigger the cavitation sensor. + This "sensor" is only used for the surface output. + The actual cavitation cost function in adflow uses a KS aggregation under the hood and returns the cpmin value for a given family. + +cavitationRho: + desc: > + The rho parameter used for the KS aggregation used for computing cavitation. + KS aggregation is used to compute the differentiable min Cp within the given family group. + A higher rho value will approach the actual min Cp more accurately, at the cost of a more nonlinear function. nCycles: desc: > diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index b8075e523..783f014ad 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -69,13 +69,13 @@ python module libadflow integer(kind=inttype), intent(in) :: nvar character, dimension(nvar,32), intent(out):: monitor_variables end subroutine getmonitorvariablenames - + subroutine getsolvertypearray(niter, nsps, type_array) - integer(kind=inttype), intent(in) :: niter, nsps, + integer(kind=inttype), intent(in) :: niter, nsps character, dimension(0:niter,nsps,8), intent(out):: type_array end subroutine getsolvertypearray - - + + end module utils module walldistance @@ -1204,7 +1204,7 @@ python module libadflow real(kind=realtype) :: alpha real(kind=realtype) :: beta integer(kind=inttype) :: liftindex - real(kind=realtype) :: cavitationnumber + real(kind=realtype) :: cavitationsensor real(kind=realtype) :: cavitationrho end module inputphysics diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index b0a6ca3ac..ec777df94 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -579,6 +579,7 @@ module inputPhysics real(kind=realType), dimension(3,2) :: momentAxis real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber + real(kind=realType) :: cavitationsensor real(kind=realType) :: cavitationrho #ifndef USE_TAPENADE diff --git a/src/output/outputMod.F90 b/src/output/outputMod.F90 index 58844bc01..acf2b096e 100644 --- a/src/output/outputMod.F90 +++ b/src/output/outputMod.F90 @@ -1404,8 +1404,8 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & real(kind=realType), dimension(*), intent(out) :: buffer character(len=*), intent(in) :: solName logical, intent(in) :: viscousSubface, useRindLayer - - ! if useRindLayer is true, then iBeg, iEnd, jBeg, jEnd are use to determine + + ! if useRindLayer is true, then iBeg, iEnd, jBeg, jEnd are use to determine ! when the indices are in the rind layer. integer(kind=intType), optional, intent(in) :: iBeg, iEnd, jBeg, jEnd ! @@ -1438,7 +1438,7 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & ! The original i,j beging of the local block in the entire cgns block. real(kind=realType) :: subface_jBegOr, subface_jEndOr, subface_iBegOr, subface_iEndOr - + ! Set the pointers to this block. call setPointers(blockID, 1_intType, sps) @@ -1525,10 +1525,10 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & if(equations == RANSEquations) dd2Wall => d2Wall(2,:,:) subface_iBegOr = jBegOr subface_iEndOr = jEndOr - + subface_jBegOr = kBegOr subface_jEndOr = kEndOr - + !=============================================================== case (iMax) @@ -1554,13 +1554,13 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & endif if(equations == RANSEquations) dd2Wall => d2Wall(il,:,:) - + subface_iBegOr = jBegOr subface_iEndOr = jEndOr - + subface_jBegOr = kBegOr subface_jEndOr = kEndOr - + !=============================================================== case (jMin) @@ -1587,10 +1587,10 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & if(equations == RANSEquations) dd2Wall => d2Wall(:,2,:) - + subface_iBegOr = iBegOr subface_iEndOr = iEndOr - + subface_jBegOr = kBegOr subface_jEndOr = kEndOr @@ -1622,7 +1622,7 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & subface_iBegOr = iBegOr subface_iEndOr = iEndOr - + subface_jBegOr = kBegOr subface_jEndOr = kEndOr @@ -1654,7 +1654,7 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & subface_iBegOr = iBegOr subface_iEndOr = iEndOr - + subface_jBegOr = jBegOr subface_jEndOr = jEndOr @@ -1686,7 +1686,7 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & subface_iBegOr = iBegOr subface_iEndOr = iEndOr - + subface_jBegOr = jBegOr subface_jEndOr = jEndOr @@ -1927,14 +1927,14 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & ! if statements are used to copy the value of the interior ! cell since the value isn't defined in the rind cell - if (present(jBeg) .and. present(jEnd) .and. (useRindLayer)) then + if (present(jBeg) .and. present(jEnd) .and. (useRindLayer)) then jor = j + subface_jBegOr - 1 - if (jor == jBeg) then - jj = j + 1 + if (jor == jBeg) then + jj = j + 1 else if (jor == jEnd +1 ) then jj = j - 1 else - jj = j + jj = j endif else jj = j @@ -1942,19 +1942,19 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & end if do i=rangeFace(1,1), rangeFace(1,2) - if (present(iBeg) .and. present( iEnd) .and. (useRindLayer)) then + if (present(iBeg) .and. present( iEnd) .and. (useRindLayer)) then ior = i + subface_iBegOr - 1 - if (ior == iBeg) then - ii = i + 1 + if (ior == iBeg) then + ii = i + 1 else if (ior == iEnd + 1) then ii = i - 1 else - ii = i + ii = i endif else ii = i endif - + ! Determine the viscous subface on which this ! face is located. @@ -2040,14 +2040,14 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & ! if statements are used to copy the value of the interior ! cell since the value isn't defined in the rind cell - if (present(jBeg) .and. present(jEnd) .and. (useRindLayer)) then + if (present(jBeg) .and. present(jEnd) .and. (useRindLayer)) then jor = j + jBegOr - 1 - if (jor == jBeg) then - jj = j + 1 + if (jor == jBeg) then + jj = j + 1 else if (jor == jEnd + 1) then jj = j - 1 else - jj = j + jj = j endif else jj = j @@ -2055,14 +2055,14 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & end if do i=rangeFace(1,1), rangeFace(1,2) - if (present(iBeg) .and. present( iEnd) .and. (useRindLayer)) then + if (present(iBeg) .and. present( iEnd) .and. (useRindLayer)) then ior = i + iBegor - 1 - if (ior == iBeg) then - ii = i + 1 + if (ior == iBeg) then + ii = i + 1 else if (ior == iEnd + 1) then ii = i - 1 else - ii = i + ii = i endif else ii = i @@ -2140,7 +2140,7 @@ subroutine storeSurfsolInBuffer(sps, buffer, nn, blockID, & ! Get local pressure plocal = half*(pp1(i,j) + pp2(i,j)) - sensor1 = (-(fact)*(plocal-pInf))- cavitationnumber + sensor1 = (-(fact)*(plocal-pInf))- cavitationsensor sensor1 = one/(one + exp(-2*10*sensor1)) buffer(nn) = sensor1 !print*, sensor From 435b19de092b01c81851b98f5937926bc7205c68 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 12 Jul 2022 13:57:40 -0400 Subject: [PATCH 16/76] updates to the slice business --- adflow/pyADflow.py | 20 +++--- src/f2py/adflow.pyf | 16 ++--- src/output/tecplotIO.F90 | 129 +++++++++++++++++++++------------------ 3 files changed, 90 insertions(+), 75 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 433c90c5e..ad33f6af7 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -557,30 +557,28 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): tmp = numpy.zeros((N, 3), self.dtype) if direction == "x": tmp[:, 0] = positions - tmp[:, 1] = -1e50 - slice_dir = [0.0, 1.0, 0.0] normal = [1.0, 0.0, 0.0] elif direction == "y": tmp[:, 1] = positions - tmp[:, 2] = -1e50 - slice_dir = [0.0, 0.0, 1.0] normal = [0.0, 1.0, 0.0] elif direction == "z": tmp[:, 2] = positions - tmp[:, 0] = -1e50 - slice_dir = [1.0, 0.0, 0.0] normal = [0.0, 0.0, 1.0] + # for regular slices, we dont use the direction vector to pick a projection direction + slice_dir = [1.0, 0.0, 0.0] + use_dir = False + for i in range(len(positions)): # It is important to ensure each slice get a unique # name...so we will number sequentially from python j = self.nSlice + i + 1 if sliceType == "relative": sliceName = "Slice_%4.4d %s Para Init %s=%7.3f" % (j, groupTag, direction, positions[i]) - self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) else: sliceName = "Slice_%4.4d %s Absolute %s=%7.3f" % (j, groupTag, direction, positions[i]) - self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, slice_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) self.nSlice += N @@ -673,16 +671,18 @@ def addCylindricalSlices( # from the center axis. We will reject cells directly if their centroid are behind this # direction (i.e. dot slice_dir is negative) and only use the cells that are in # the same direction (i.e. dot product positive.) + # this flag determines that we will use the direction vector as well to pick the slice dir. + use_dir = True # It is important to ensure each slice get a unique # name...so we will number sequentially from python jj = self.nSlice + ii + 1 if sliceType == "relative": sliceName = f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" - self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) else: sliceName = f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" - self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) self.nSlice += n_slice diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 7a148e2bc..bf61a1bc9 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -414,28 +414,30 @@ python module libadflow end module surfaceutils module tecplotio - subroutine addparaslice(slicename,pt,normal,direction,famlist,n) ! in :test:liftDistribution.F90 + subroutine addparaslice(slicename,pt,normal,dir_vec,use_dir,famlist,n) ! in :test:liftDistribution.F90 character*(*) intent(in) :: slicename real(kind=realtype) dimension(3),intent(in) :: pt real(kind=realtype) dimension(3),intent(in) :: normal - real(kind=realtype) dimension(3),intent(in) :: direction + real(kind=realtype) dimension(3),intent(in) :: dir_vec + logical, intent(in) :: use_dir integer(kind=inttype) dimension(n),intent(in) :: famlist integer(kind=inttype), optional,intent(in),check(len(famlist)>=n),depend(famlist) :: n=len(famlist) end subroutine addparaslice - subroutine addabsslice(slicename,pt,normal,direction,famlist,n) ! in :test:liftDistribution.F90 + subroutine addabsslice(slicename,pt,normal,dir_vec,use_dir,famlist,n) ! in :test:liftDistribution.F90 character*(*) intent(in) :: slicename real(kind=realtype) dimension(3),intent(in) :: pt real(kind=realtype) dimension(3),intent(in) :: normal - real(kind=realtype) dimension(3),intent(in) :: direction + real(kind=realtype) dimension(3),intent(in) :: dir_vec + logical, intent(in) :: use_dir integer(kind=inttype) dimension(n),intent(in) :: famlist integer(kind=inttype), optional,intent(in),check(len(famlist)>=n),depend(famlist) :: n=len(famlist) end subroutine addabsslice - subroutine addliftdistribution(nsegments,dir_vec,dir_ind, distname,famlist,n) ! in :test:liftDistribution.F90 + subroutine addliftdistribution(nsegments,normal,normal_ind, distname,famlist,n) ! in :test:liftDistribution.F90 integer(kind=inttype) intent(in) :: nsegments - real(kind=realtype) dimension(3), intent(in) :: dir_vec - integer(kind=inttype), intent(in) :: dir_ind + real(kind=realtype) dimension(3), intent(in) :: normal + integer(kind=inttype), intent(in) :: normal_ind character*(*) intent(in) :: distname integer(kind=inttype) dimension(n),intent(in) :: famlist integer(kind=inttype), optional,intent(in),check(len(famlist)>=n),depend(famlist) :: n=len(famlist) diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index bd1bff8e4..2a3472564 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -14,6 +14,13 @@ module tecplotIO ! pL, vL, pD, vD : Pressure and viscous lift, pressure and viscous drag ! CLp, CLv, CDp, CDv : Coefficients of pressure and viscous lift and drag ! chord: chord of section + ! pt, normal: The point and the normal that defines the slicing plane + ! dir_vec: a direction vector that we use to filter sliced line elements. + ! use_dir: flag to determine if we use the dir vec or not. if we are doing + ! a regular slice, e.g. wing section, we dont want to use the dir + ! and want to use the full slice. if we are doing a cylindrical slice + ! we then want to pick which direction since we would get 2 slices + ! on something like a nacelle in this case. character(len=maxStringLen) :: sliceName integer(kind=intType) :: sps @@ -23,24 +30,23 @@ module tecplotIO real(kind=realType) :: pL, vL, pD, vD, pM, vM, CLp, CLv, CDp, CDv, CMp, CMv real(kind=realType) :: chord, twist, thickness real(kind=realType), dimension(3) :: le, te - ! TODO propagate the change to normal and dir throughout - real(kind=realType), dimension(3) :: pt, normal, dir + real(kind=realType), dimension(3) :: pt, normal, dir_vec + logical :: use_dir integer(kind=intType), allocatable, dimension(:) :: famList end type slice type liftDist ! nSegments: Number of nodes to use for distribution - ! dir_ind: Index of direction..1 for x, 2 for y, 3 for z - ! dir: Slice direction + ! normal: Slice direction (normal of the plane) + ! normal_ind: Index of direction..1 for x, 2 for y, 3 for z ! distName: Name of lift distribution ! slices: The list of slices this distribution will use ! delta: The current delta spacing for the distribution ! slicePoints: The list of points where the slices are taken character(len=maxStringLen) :: distName - integer(kind=intType) :: nSegments, dir_ind + integer(kind=intType) :: nSegments, normal_ind integer(kind=intType), dimension(:), allocatable :: famList real(kind=realType) :: normal(3) - real(kind=realType) :: dir(3) real(kind=realType) :: delta real(kind=realType), dimension(:,:), allocatable :: slicePts end type liftDist @@ -64,7 +70,7 @@ module tecplotIO integer(kind=intType), parameter :: nLiftDistVar=23 contains - subroutine addParaSlice(sliceName, pt, normal, direction, famList, n) + subroutine addParaSlice(sliceName, pt, normal, dir_vec, use_dir, famList, n) ! ! This subroutine is intended to be called from python. ! This routine will add a parametric slice to the list of user @@ -78,7 +84,8 @@ subroutine addParaSlice(sliceName, pt, normal, direction, famList, n) ! Input parameters character*(*), intent(in) :: sliceName - real(kind=realType), dimension(3), intent(in) :: pt, normal, direction + real(kind=realType), dimension(3), intent(in) :: pt, normal, dir_vec + logical, intent(in) :: use_dir integer(kind=intType), intent(in) :: famList(n), n ! Working @@ -111,8 +118,8 @@ subroutine addParaSlice(sliceName, pt, normal, direction, famList, n) call getSurfaceFamily(elemFam, sizeCell, wallList, size(wallList), .True.) ! Create actual slice - call createSlice(pts, conn, elemFam, paraSlices(nParaSlices, sps), pt, normal, direction, & - sliceName, famList) + call createSlice(pts, conn, elemFam, paraSlices(nParaSlices, sps), pt, normal, dir_vec, & + use_dir, sliceName, famList) ! Clean up memory. deallocate(pts, conn, elemFam) @@ -120,7 +127,7 @@ subroutine addParaSlice(sliceName, pt, normal, direction, famList, n) end subroutine addParaSlice - subroutine addAbsSlice(sliceName, pt, normal, direction, famList, n) + subroutine addAbsSlice(sliceName, pt, normal, dir_vec, use_dir, famList, n) ! ! This subroutine is intended to be called from python. ! This routine will add an absolute slice to the list of user @@ -134,7 +141,8 @@ subroutine addAbsSlice(sliceName, pt, normal, direction, famList, n) ! Input parameters character*(*), intent(in) :: sliceName - real(kind=realType), dimension(3), intent(in) :: pt, normal, direction + real(kind=realType), dimension(3), intent(in) :: pt, normal, dir_vec + logical, intent(in) :: use_dir integer(kind=intType), intent(in) :: famList(n), n ! Working @@ -162,8 +170,8 @@ subroutine addAbsSlice(sliceName, pt, normal, direction, famList, n) call getSurfaceConnectivity(conn, cgnsBlockID, sizeCell, wallList, size(wallList), .True.) call getSurfacePoints(pts, sizeNode, sps, wallList, size(wallList), .True.) call getSurfaceFamily(elemFam, sizeCell, wallList, size(wallList), .True.) - call createSlice(pts, conn, elemFam, absSlices(nAbsSlices, sps), pt, normal, direction, & - sliceName, famList) + call createSlice(pts, conn, elemFam, absSlices(nAbsSlices, sps), pt, normal, dir_vec, & + use_dir, sliceName, famList) ! Clean up memory. deallocate(pts, conn, elemFam) @@ -171,7 +179,7 @@ subroutine addAbsSlice(sliceName, pt, normal, direction, famList, n) end subroutine addAbsSlice - subroutine addLiftDistribution(nSegments, dir_vec, dir_ind, distName, famList, n) + subroutine addLiftDistribution(nSegments, normal, normal_ind, distName, famList, n) ! ! This subroutine is intended to be called from python. ! This routine will add the description of a lift distribution @@ -184,8 +192,8 @@ subroutine addLiftDistribution(nSegments, dir_vec, dir_ind, distName, famList, n ! Input parameters character*(*), intent(in) :: distName integer(kind=intType), intent(in) :: nSegments - real(kind=realType), dimension(3) :: dir_vec - integer(kind=intType), intent(in) :: dir_ind + real(kind=realType), dimension(3) :: normal + integer(kind=intType), intent(in) :: normal_ind integer(kind=intType), intent(in) :: famList(n), n nLiftDists = nLiftDists + 1 @@ -196,10 +204,9 @@ subroutine addLiftDistribution(nSegments, dir_vec, dir_ind, distName, famList, n end if liftDists(nLIftDists)%nSegments = nSegments - liftDists(nLiftDists)%dir = dir_vec - liftDists(nLiftDists)%normal = dir_vec + liftDists(nLiftDists)%normal = normal + liftDists(nLIftDists)%normal_ind = normal_ind liftDists(nLiftDists)%distName = distName - liftDists(nLIftDists)%dir_ind = dir_ind allocate(liftDists(nLiftDists)%famList(n)) liftDists(nLiftDists)%famList(:) = famList @@ -376,10 +383,9 @@ subroutine writeSlicesFile(fileName, nodalValues) call destroySlice(absSlices(i, sps)) ! Make new one in the same location - ! TODO update here call createSlice(pts, conn, elemFam, absSlices(i, sps), & - absSlices(i, sps)%pt, absSlices(i, sps)%normal, absSlices(i, sps)%dir, & - absSlices(i, sps)%sliceName, famList) + absSlices(i, sps)%pt, absSlices(i, sps)%normal, absSlices(i, sps)%dir_vec, & + absSlices(i, sps)%use_dir, absSlices(i, sps)%sliceName, famList) call integrateSlice(absSlices(i, sps), globalSlice, & nodalValues(:, :, sps), nSolVar, .True.) @@ -544,7 +550,7 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) adflow_comm_world, ierr) call EChk(ierr,__FILE__,__LINE__) - d%delta = (xMax(d%dir_ind) - xMin(d%dir_ind))/dble((d%nSegments - 1)) + d%delta = (xMax(d%normal_ind) - xMin(d%normal_ind))/dble((d%nSegments - 1)) allocate(d%slicePts(3, d%nSegments)) ! Zero out all segments @@ -599,33 +605,33 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) do i=1,d%nSegments if (i==1) then - d%slicePts(d%dir_ind, i) = xMin(d%dir_ind) + tol + d%slicePts(d%normal_ind, i) = xMin(d%normal_ind) + tol else if (i == d%nSegments) then - d%slicePts(d%dir_ind, i) = xMin(d%dir_ind) + (i-1)*d%delta - tol + d%slicePts(d%normal_ind, i) = xMin(d%normal_ind) + (i-1)*d%delta - tol else - d%slicePts(d%dir_ind, i) = xMin(d%dir_ind) + (i-1)*d%delta + d%slicePts(d%normal_ind, i) = xMin(d%normal_ind) + (i-1)*d%delta end if end do ! Scaled Eta values - dmin = minVal(d%slicePts(d%dir_ind, :)) - dmax = maxval(d%slicePts(d%dir_ind, :)) + dmin = minVal(d%slicePts(d%normal_ind, :)) + dmax = maxval(d%slicePts(d%normal_ind, :)) - values(:, 1) = (d%slicePts(d%dir_ind, :) - dmin)/(dmax-dmin) + values(:, 1) = (d%slicePts(d%normal_ind, :) - dmin)/(dmax-dmin) ! Coordinate Varaibles - if (d%dir_ind == 1) then! X slices + if (d%normal_ind == 1) then! X slices values(:, 2) = d%slicePts(1, :) - else if (d%dir_ind == 2) then ! Y slices + else if (d%normal_ind == 2) then ! Y slices values(:, 3) = d%slicePts(2, :) - else if (d%dir_ind == 3) then ! Z slices + else if (d%normal_ind == 3) then ! Z slices values(:, 4) = d%slicePts(3, :) end if do i=1, d%nSegments ! Make new one in the same location - ! TODO update here + ! we just pass the normal again as the direction vector because its not used call createSlice(pts, conn, elemFam, localSlice, d%slicePts(:, i), & - d%normal, d%dir, "does_not_matter", d%famList) + d%normal, d%normal, .False., "does_not_matter", d%famList) call integrateSlice(localSlice, globalSlice, nodalValues, 0, .False.) ! Total lift, drag, and moment @@ -1629,7 +1635,7 @@ subroutine computeSurfaceOutputNodalData(exch, zipper, includeTractions, nodalVa end subroutine computeSurfaceOutputNodalData - subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir, sliceName, famList) + subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir_vec, use_dir, sliceName, famList) ! ! This subroutine creates a slice on a plane defined by pt and ! and dir. It only uses the families specified in the famList. @@ -1645,7 +1651,8 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir, sliceName, famL integer(kind=intType), dimension(:,:), intent(in) :: conn integer(kind=intType), dimension(:), intent(in) :: elemFam type(slice), intent(inout) :: slc - real(kind=realType), dimension(3), intent(in) :: pt, dir, normal + real(kind=realType), dimension(3), intent(in) :: pt, dir_vec, normal + logical, intent(in) :: use_dir character*(*), intent(in) :: sliceName integer(kind=intType), dimension(:), intent(in) :: famList @@ -1665,6 +1672,8 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir, sliceName, famL ! Set the info for the slice: slc%pt = pt slc%normal = normal + slc%dir_vec = dir_vec + slc%use_dir = use_dir slc%nNodes = 0 allocate(slc%famList(size(famList))) slc%famList = famList @@ -1706,16 +1715,19 @@ subroutine createSlice(pts, conn, elemFam, slc, pt, normal, dir, sliceName, famL elemc = elemc + 0.25_realType * pts(:, patchIndices(jj)) end do - ! check if the centroid of this element is in the correct direction - vec = elemc - pt - ! normalize vector - len_vec = sqrt(vec(1) * vec(1) + vec(2) * vec(2) + vec(3) * vec(3)) - vec = vec / len_vec - if ((vec(1)*dir(1) + vec(2)*dir(2) + vec(3)*dir(3)) .lt. zero) then - ! we reject this element; just set all signed distances to 1.0 - do jj=1,4 - f(jj) = one - end do + ! check if we are using the direction to pick sliced elements + if (use_dir) then + ! check if the centroid of this element is in the correct direction + vec = elemc - pt + ! normalize vector + len_vec = sqrt(vec(1) * vec(1) + vec(2) * vec(2) + vec(3) * vec(3)) + vec = vec / len_vec + if ((vec(1)*dir_vec(1) + vec(2)*dir_vec(2) + vec(3)*dir_vec(3)) .lt. zero) then + ! we reject this element; just set all signed distances to 1.0 + do jj=1,4 + f(jj) = one + end do + end if end if ! Based on the values at each corner, determine which @@ -1853,7 +1865,7 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) real(kind=realType), dimension(3) :: x1, x2, pT1, pT2, vT1, vT2, pF, vF, pF_elem, vF_elem real(kind=realType) :: len, dmax, dmin, dist, fact, M(3,3), tmp(6) real(kind=realType) :: r(3), r_new(3), hyp, te(3), le(3), theta, w1, w2 - integer(kind=intType) :: bestPair(2), dir_ind, iProc, ierr, iSize + integer(kind=intType) :: bestPair(2), normal_ind, iProc, ierr, iSize real(kind=realtype), dimension(:,:), allocatable :: tempCoords real(kind=realtype), dimension(:,:), allocatable :: localVals integer(kind=intType), dimension(:), allocatable :: sliceNodeSizes, sliceCellSizes @@ -1868,7 +1880,8 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! Back out what is the main index of the slice, x, y or z based on ! the direction. Not the best approach, but that's ok - dir_ind = maxloc(abs(gSlc%normal),1) + ! TODO this can be improved since we are now doing arbitrary slice directions + normal_ind = maxloc(abs(gSlc%normal),1) pF = zero vF = zero @@ -2069,8 +2082,8 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! the moments are a bit different than lift and drag. we keep the 3 components of the moment ! in pM in this routine but then the slc%pM variable only has the component of the moment ! we are interested in. we use the direction index to get this value out and set it in the slice - lSlc%pM = pM(dir_ind) - lSlc%vM = vM(dir_ind) + lSlc%pM = pM(normal_ind) + lSlc%vM = vM(normal_ind) ! Reduce the lift/drag values call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%pM, lSlc%vL, lSlc%vD, lSlc%vM/), tmp, 6, adflow_real, MPI_SUM, & @@ -2135,11 +2148,11 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) ! Length of hyptoneuse is the same hyp = sqrt((x1(1)-x2(1))**2 + (x1(2)-x2(2))**2 + (x1(3)-x2(3))**2) - if (dir_ind == 1) then + if (normal_ind == 1) then ! Xslice...we don't how what to do here..could be y or z. Don't ! do anything. gSlc%twist = zero - else if (dir_ind == 2) then + else if (normal_ind == 2) then ! Yslice theta = asin((le(3)-te(3))/hyp) gSlc%twist = theta*180.0/pi @@ -2149,11 +2162,11 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) gSlc%twist = theta*180.0/pi end if - if (dir_ind == 1) then + if (normal_ind == 1) then M(1,1) = one; M(1,2) = zero; M(1, 3) = zero; M(2,1) = zero; M(2,2) = one; M(2, 3) = zero; M(3,1) = zero; M(3,2) = zero; M(3,3) = one; - else if(dir_ind == 2) then + else if(normal_ind == 2) then ! Y-rotation matrix M(1,1) = cos(-theta); M(1,2) = zero; M(1, 3) = sin(-theta); M(2,1) = zero; M(2,2) = one; M(2, 3) = zero; @@ -2174,13 +2187,13 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) end do ! Now get the max and the min and divide by the chord for t/c - if (dir_ind == 1) then + if (normal_ind == 1) then gSlc%thickness = 0 ! Again, don't know what to do here - else if(dir_ind == 2) then + else if(normal_ind == 2) then dmax = maxval(tempCoords(3, :)) dmin = minval(tempCoords(3, :)) gSlc%thickness = (dmax-dmin)/hyp - else if(dir_ind == 3) then + else if(normal_ind == 3) then dmax = maxval(tempCoords(2, :)) dmin = minval(tempCoords(2, :)) gSlc%thickness = (dmax-dmin)/hyp From 4e9d8bcdddb9557f41320d90f5569ee8d283ad9f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 12 Jul 2022 17:26:10 -0400 Subject: [PATCH 17/76] fixes for the bad merge --- src/output/tecplotIO.F90 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index 58895943c..178c70998 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -675,9 +675,9 @@ subroutine writeLiftDistributions(sps, fileID, nodalValues) values(i, 23) = globalSlice%chord ! here we now save our new, added values that we have desired to use - values(i, 19) = globalSlice%fx - values(i, 20) = globalSlice%fy - values(i, 21) = globalSlice%fz + values(i, 24) = globalSlice%fx + values(i, 25) = globalSlice%fy + values(i, 26) = globalSlice%fz call destroySlice(localSlice) call destroySlice(globalSlice) @@ -2106,6 +2106,12 @@ subroutine integrateSlice(lSlc, gSlc, nodalValues, nFields, doConnectivity) lSlc%pM = pM(normal_ind) lSlc%vM = vM(normal_ind) + ! save the x,y,z-forces into the appropriate real-container + ! from their type(slice) definition (see the top of this file) + lSlc%fx = pF(1) + vF(1) + lSlc%fy = pF(2) + vF(2) + lSlc%fz = pF(3) + vF(3) + ! Reduce the lift/drag values call mpi_reduce((/lSlc%pL, lSlc%pD, lSlc%pM, lSlc%vL, lSlc%vD, lSlc%vM/), tmp, 6, adflow_real, MPI_SUM, & 0, adflow_comm_world, ierr) From 17f3cdf435873ea570963090166b64d48243eb09 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 12 Jul 2022 20:30:17 -0400 Subject: [PATCH 18/76] added optional displacement vector when adding integration surfaces --- adflow/pyADflow.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index e74dd280f..ef0cda3b5 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -687,7 +687,7 @@ def addCylindricalSlices( self.nSlice += n_slice - def addIntegrationSurface(self, fileName, familyName, isInflow=True): + def addIntegrationSurface(self, fileName, familyName, isInflow=True, disp_vec=None): """Add a specific integration surface for performing massflow-like computations. @@ -730,6 +730,12 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True): # small that we do not have to worry about parallelization. pts, conn = self._readPlot3DSurfFile(fileName) + + # displace the points if asked for + if disp_vec is not None: + for idim in range(3): + pts[:, idim] += disp_vec[idim] + self.adflow.usersurfaceintegrations.addintegrationsurface(pts.T, conn.T, familyName, famID, isInflow) def addActuatorRegion( From 4792727e1471a04e1afe9dce66d12a5c6f870654 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 24 Jul 2022 22:47:08 -0400 Subject: [PATCH 19/76] added cutoff tolerance for the pc update algorithm based on rel convergence. also fixed the mgpc setup for ank turb ksp --- adflow/pyADflow.py | 2 + src/NKSolver/NKSolvers.F90 | 75 +++++++++++++++++++++++++++++++++----- src/f2py/adflow.pyf | 1 + 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index ef0cda3b5..36c98c411 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5218,6 +5218,7 @@ def _getDefaultOptions(): "ANKTurbCFLScale": [float, 1.0], "ANKUseFullVisc": [bool, True], "ANKPCUpdateTol": [float, 0.5], + "ANKPCUpdateCutoff": [float, 1e-6], "ANKADPC": [bool, False], "ANKNSubiterTurb": [int, 1], "ANKTurbKSPDebug": [bool, False], @@ -5590,6 +5591,7 @@ def _getOptionMap(self): "ankturbcflscale": ["ank", "ank_turbcflscale"], "ankusefullvisc": ["ank", "ank_usefullvisc"], "ankpcupdatetol": ["ank", "ank_pcupdatetol"], + "ankpcupdatecutoff": ["ank", "ank_pcupdatecutoff"], "ankadpc": ["ank", "ank_adpc"], "anknsubiterturb": ["ank", "ank_nsubiterturb"], "ankturbkspdebug": ["ank", "ank_turbdebug"], diff --git a/src/NKSolver/NKSolvers.F90 b/src/NKSolver/NKSolvers.F90 index 0a81b52da..c4234b551 100644 --- a/src/NKSolver/NKSolvers.F90 +++ b/src/NKSolver/NKSolvers.F90 @@ -1685,6 +1685,7 @@ module ANKSolver real(kind=realType) :: ANK_secondOrdSwitchTol, ANK_coupledSwitchTol real(kind=realType) :: ANK_physLSTol, ANK_unstdyLSTol real(kind=realType) :: ANK_pcUpdateTol + real(kind=realType) :: ANK_pcUpdateCutoff real(kind=realType) :: lambda logical :: ANK_solverSetup=.False. integer(kind=intTYpe) :: ANK_iter @@ -2196,8 +2197,9 @@ subroutine FormJacobianANKTurb use inputDiscretization, only : approxSA use iteration, only : totalR0, totalR use utils, only : EChk, setPointers - use adjointUtils, only :setupStateResidualMatrix, setupStandardKSP - use communication + use adjointUtils, only :setupStateResidualMatrix, setupStandardKSP, setupStandardMultigrid + use inputadjoint, only : precondtype + use agmg, only : setupShellPC, destroyShellPC, applyShellPC, agmgLevels, coarseIndices, A implicit none ! Local Variables @@ -2205,8 +2207,16 @@ subroutine FormJacobianANKTurb integer(kind=intType) ::ierr logical :: useAD, usePC, useTranspose, useObjective, tmp, frozenTurb real(kind=realType) :: dtinv, rho - integer(kind=intType) :: i, j, k, l, l1, ii, irow, nn, sps, outerPreConIts, subspace + integer(kind=intType) :: i, j, k, l, l1, ii, irow, nn, sps, outerPreConIts, subspace, lvl + integer(kind=intType), dimension(2:10) :: coarseRows real(kind=realType), dimension(:,:), allocatable :: blk + logical :: useCoarseMats + + if (preCondType == 'mg') then + useCoarseMats = .True. + else + useCoarseMats = .False. + end if ! Assemble the approximate PC (fine leve, level 1) useAD = ANK_ADPC @@ -2222,7 +2232,7 @@ subroutine FormJacobianANKTurb ! Create the preconditoner matrix call setupStateResidualMatrix(dRdwPreTurb, useAD, usePC, useTranspose, & - useObjective, frozenTurb, 1_intType, .True.) + useObjective, frozenTurb, 1_intType, .True., useCoarseMats=useCoarseMats) ! Reset saved value viscPC = tmp @@ -2266,6 +2276,12 @@ subroutine FormJacobianANKTurb ! get the global cell index irow = globalCell(i, j, k) + if (useCoarseMats) then + do lvl=1, agmgLevels-1 + coarseRows(lvl+1) = coarseIndices(nn, lvl)%arr(i, j, k) + end do + end if + ! Add the contribution to the matrix in PETSc call setBlock() end do @@ -2299,10 +2315,28 @@ subroutine FormJacobianANKTurb call MatAssemblyEnd (dRdwPreTurb, MAT_FINAL_ASSEMBLY, ierr) call EChk(ierr, __FILE__, __LINE__) + if (useCoarseMats) then + do lvl=2, agmgLevels + call MatAssemblyBegin(A(lvl), MAT_FINAL_ASSEMBLY, ierr) + call EChk(ierr, __FILE__, __LINE__) + call MatAssemblyEnd(A(lvl), MAT_FINAL_ASSEMBLY, ierr) + call EChk(ierr, __FILE__, __LINE__) + end do + end if + - call setupStandardKSP(ANK_KSPTurb, kspObjectType, subSpace, & - preConSide, globalPCType, ANK_asmOverlap, outerPreConIts, localPCType, & - localOrdering, ANK_iluFill, ANK_innerPreConIts) + if (PreCondType == 'asm') then + call setupStandardKSP(ANK_KSPTurb, kspObjectType, subSpace, & + preConSide, globalPCType, ANK_asmOverlap, outerPreConIts, localPCType, & + localOrdering, ANK_iluFill, ANK_innerPreConIts) + + else if (PreCondType == 'mg') then + + ! Setup the MG preconditioner! + call setupStandardMultigrid(ANK_KSP, kspObjectType, subSpace, & + preConSide, ANK_asmOverlap, outerPreConIts, & + localOrdering, ANK_iluFill) + end if ! Don't do iterative refinement for the NKSolver. call KSPGMRESSetCGSRefinementType(ANK_KSPTurb, & @@ -2320,6 +2354,14 @@ subroutine setBlock() ADD_VALUES, ierr) call EChk(ierr, __FILE__, __LINE__) + ! Extension for setting coarse grids: + if (useCoarseMats) then + do lvl=2, agmgLevels + call MatSetValuesBlocked(A(lvl), 1, coarseRows(lvl), 1, coarseRows(lvl), & + blk, ADD_VALUES, ierr) + end do + end if + end subroutine setBlock end subroutine FormJacobianANKTurb @@ -3701,7 +3743,7 @@ subroutine ANKStep(firstCall) real(kind=realType) :: atol, val, v2, factK, gm1 real(kind=alwaysRealType) :: rtol, totalR_dummy, linearRes, norm real(kind=alwaysRealType) :: resHist(ANK_maxIter+1) - real(kind=alwaysRealType) :: unsteadyNorm, unsteadyNorm_old + real(kind=alwaysRealType) :: unsteadyNorm, unsteadyNorm_old, rel_pcUpdateTol logical :: correctForK, LSFailed ! Enter this check if this is the first ANK step OR we are switching to the coupled ANK solver @@ -3767,13 +3809,28 @@ subroutine ANKStep(firstCall) ANK_iter = ANK_iter + 1 end if + ! figure out if we want to scale the ANKPCUpdateTol + if (.not. ANK_coupled) then + rel_pcUpdateTol = ANK_pcUpdateTol + else + ! for coupled ANK, we dont want to update the PC as frequently, + ! so we reduce the relative tol by 4 orders of magnitude, + ! *if* we are converged past pc update cutoff wrt free stream already + if (totalR / totalR0 .lt. ANK_pcUpdateCutoff) then + rel_pcUpdateTol = ANK_pcUpdateTol * 1e-4_realType + else + ! if we are not that far down converged, use the option directly + rel_pcUpdateTol = ANK_pcUpdateTol + end if + end if + ! Compute the norm of rVec, which is identical to the ! norm of the unsteady residual vector. call VecNorm(rVec, NORM_2, unsteadyNorm_old, ierr) call EChk(ierr, __FILE__, __LINE__) ! Determine if if we need to form the Preconditioner - if (mod(ANK_iter, ANK_jacobianLag) == 0 .or. totalR/totalR_pcUpdate < ANK_pcUpdateTol) then + if (mod(ANK_iter, ANK_jacobianLag) == 0 .or. totalR/totalR_pcUpdate < rel_pcUpdateTol) then ! First of all, update the minimum cfl wrt the overall convergence ANK_CFLMin = min(ANK_CFLLimit, ANK_CFLMinBase*(totalR0/totalR)**ANK_CFLExponent) diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 208b6e6b1..3b8f4891d 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -287,6 +287,7 @@ python module libadflow real(kind=realtype) :: ank_turbcflscale logical :: ank_usefullvisc real(kind=realtype) :: ank_pcupdatetol + real(kind=realtype) :: ank_pcupdatecutoff logical :: ank_adpc integer(kind=inttype) :: ank_nsubiterturb logical :: ank_turbdebug From 7c5b2c01ea9170666901644677dfbfeef3ef07c6 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 25 Jul 2022 22:54:20 -0400 Subject: [PATCH 20/76] reverted the agmg changes for turbksp. needs a proper implementation to handle two different agmg pcs kicking around at the same time --- src/NKSolver/NKSolvers.F90 | 55 +++++--------------------------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/src/NKSolver/NKSolvers.F90 b/src/NKSolver/NKSolvers.F90 index c4234b551..fc2739fea 100644 --- a/src/NKSolver/NKSolvers.F90 +++ b/src/NKSolver/NKSolvers.F90 @@ -2197,9 +2197,8 @@ subroutine FormJacobianANKTurb use inputDiscretization, only : approxSA use iteration, only : totalR0, totalR use utils, only : EChk, setPointers - use adjointUtils, only :setupStateResidualMatrix, setupStandardKSP, setupStandardMultigrid - use inputadjoint, only : precondtype - use agmg, only : setupShellPC, destroyShellPC, applyShellPC, agmgLevels, coarseIndices, A + use adjointUtils, only :setupStateResidualMatrix, setupStandardKSP + use communication implicit none ! Local Variables @@ -2207,16 +2206,8 @@ subroutine FormJacobianANKTurb integer(kind=intType) ::ierr logical :: useAD, usePC, useTranspose, useObjective, tmp, frozenTurb real(kind=realType) :: dtinv, rho - integer(kind=intType) :: i, j, k, l, l1, ii, irow, nn, sps, outerPreConIts, subspace, lvl - integer(kind=intType), dimension(2:10) :: coarseRows + integer(kind=intType) :: i, j, k, l, l1, ii, irow, nn, sps, outerPreConIts, subspace real(kind=realType), dimension(:,:), allocatable :: blk - logical :: useCoarseMats - - if (preCondType == 'mg') then - useCoarseMats = .True. - else - useCoarseMats = .False. - end if ! Assemble the approximate PC (fine leve, level 1) useAD = ANK_ADPC @@ -2232,7 +2223,7 @@ subroutine FormJacobianANKTurb ! Create the preconditoner matrix call setupStateResidualMatrix(dRdwPreTurb, useAD, usePC, useTranspose, & - useObjective, frozenTurb, 1_intType, .True., useCoarseMats=useCoarseMats) + useObjective, frozenTurb, 1_intType, .True.) ! Reset saved value viscPC = tmp @@ -2276,12 +2267,6 @@ subroutine FormJacobianANKTurb ! get the global cell index irow = globalCell(i, j, k) - if (useCoarseMats) then - do lvl=1, agmgLevels-1 - coarseRows(lvl+1) = coarseIndices(nn, lvl)%arr(i, j, k) - end do - end if - ! Add the contribution to the matrix in PETSc call setBlock() end do @@ -2315,28 +2300,10 @@ subroutine FormJacobianANKTurb call MatAssemblyEnd (dRdwPreTurb, MAT_FINAL_ASSEMBLY, ierr) call EChk(ierr, __FILE__, __LINE__) - if (useCoarseMats) then - do lvl=2, agmgLevels - call MatAssemblyBegin(A(lvl), MAT_FINAL_ASSEMBLY, ierr) - call EChk(ierr, __FILE__, __LINE__) - call MatAssemblyEnd(A(lvl), MAT_FINAL_ASSEMBLY, ierr) - call EChk(ierr, __FILE__, __LINE__) - end do - end if - - - if (PreCondType == 'asm') then - call setupStandardKSP(ANK_KSPTurb, kspObjectType, subSpace, & - preConSide, globalPCType, ANK_asmOverlap, outerPreConIts, localPCType, & - localOrdering, ANK_iluFill, ANK_innerPreConIts) - else if (PreCondType == 'mg') then - - ! Setup the MG preconditioner! - call setupStandardMultigrid(ANK_KSP, kspObjectType, subSpace, & - preConSide, ANK_asmOverlap, outerPreConIts, & - localOrdering, ANK_iluFill) - end if + call setupStandardKSP(ANK_KSPTurb, kspObjectType, subSpace, & + preConSide, globalPCType, ANK_asmOverlap, outerPreConIts, localPCType, & + localOrdering, ANK_iluFill, ANK_innerPreConIts) ! Don't do iterative refinement for the NKSolver. call KSPGMRESSetCGSRefinementType(ANK_KSPTurb, & @@ -2354,14 +2321,6 @@ subroutine setBlock() ADD_VALUES, ierr) call EChk(ierr, __FILE__, __LINE__) - ! Extension for setting coarse grids: - if (useCoarseMats) then - do lvl=2, agmgLevels - call MatSetValuesBlocked(A(lvl), 1, coarseRows(lvl), 1, coarseRows(lvl), & - blk, ADD_VALUES, ierr) - end do - end if - end subroutine setBlock end subroutine FormJacobianANKTurb From 866878424d6ad4fe405526a565f4a593d4b199d9 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 25 Jul 2022 23:11:22 -0400 Subject: [PATCH 21/76] added option to always use approx sa with ank solver variants --- adflow/pyADflow.py | 2 ++ src/NKSolver/NKSolvers.F90 | 9 +++++++++ src/f2py/adflow.pyf | 1 + 3 files changed, 12 insertions(+) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 36c98c411..8955a433e 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5191,6 +5191,7 @@ def _getDefaultOptions(): # Approximate Newton-Krylov Parameters "useANKSolver": [bool, True], "ANKUseTurbDADI": [bool, True], + "ANKUseApproxSA": [bool, False], "ANKSwitchTol": [float, 1e3], "ANKSubspaceSize": [int, -1], "ANKMaxIter": [int, 40], @@ -5564,6 +5565,7 @@ def _getOptionMap(self): # Approximate Newton-Krylov Parameters "useanksolver": ["ank", "useanksolver"], "ankuseturbdadi": ["ank", "ank_useturbdadi"], + "ankuseapproxsa": ["ank", "ank_useapproxsa"], "ankswitchtol": ["ank", "ank_switchtol"], "anksubspacesize": ["ank", "ank_subspace"], "ankmaxiter": ["ank", "ank_maxiter"], diff --git a/src/NKSolver/NKSolvers.F90 b/src/NKSolver/NKSolvers.F90 index fc2739fea..5f5305ee6 100644 --- a/src/NKSolver/NKSolvers.F90 +++ b/src/NKSolver/NKSolvers.F90 @@ -1671,6 +1671,7 @@ module ANKSolver real(kind=realType) :: ANK_switchTol real(kind=realType) :: ANK_divTol = 10 logical :: ANK_useTurbDADI + logical :: ANK_useApproxSA real(kind=realType) :: ANK_turbcflscale logical :: ANK_useFullVisc logical :: ANK_ADPC @@ -3904,6 +3905,10 @@ subroutine ANKStep(firstCall) rtol = min(ANK_rtol, rtol) end if + ! also check if we are using approxSA always + if (ANK_useApproxSA) & + approxSA = .True. + ! Record the total residual and relative convergence for next iteration totalR_old = totalR rtolLast = rtol @@ -3968,6 +3973,10 @@ subroutine ANKStep(firstCall) end if + ! put back the approxsa flag if we were using it + if (ANK_useApproxSA) & + approxSA = .False. + ! Compute the maximum step that will limit the change in pressure ! and energy to some user defined fraction. call physicalityCheckANK(lambda) diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 3b8f4891d..63d52ce5d 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -263,6 +263,7 @@ python module libadflow integer(kind=inttype) :: ank_jacobianlag logical :: useanksolver logical :: ank_useturbdadi + logical :: ank_useapproxsa integer(kind=inttype) :: ank_subspace integer(kind=inttype) :: ank_maxiter integer(kind=inttype) :: ank_asmoverlap From cb5363cba245b1d7090ba476429b756af0fb03a3 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 27 Jul 2022 22:57:37 -0400 Subject: [PATCH 22/76] added the same update to the turbksp solver --- src/NKSolver/NKSolvers.F90 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NKSolver/NKSolvers.F90 b/src/NKSolver/NKSolvers.F90 index 5f5305ee6..6045964d8 100644 --- a/src/NKSolver/NKSolvers.F90 +++ b/src/NKSolver/NKSolvers.F90 @@ -3474,6 +3474,10 @@ subroutine ANKTurbSolveKSP rtol = min(ANK_rtol, rtol) end if + ! also check if we are using approxSA always + if (ANK_useApproxSA) & + approxSA = .True. + ! Record the total residual and relative convergence for next iteration totalR_old = totalR rtolLast = rtol @@ -3533,6 +3537,10 @@ subroutine ANKTurbSolveKSP approxSA = .False. end if + ! put back the approxsa flag if we were using it + if (ANK_useApproxSA) & + approxSA = .False. + ! Compute the maximum step that will limit the change ! in SA variable to some user defined fraction. call physicalityCheckANKTurb(lambdaTurb) From 4b9319b6dfacb1f9046ca20a2ee977ed8c513326 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Thu, 11 Aug 2022 10:14:23 +0200 Subject: [PATCH 23/76] added python option to disable the overset debug print of connectivity errors --- adflow/pyADflow.py | 2 ++ src/f2py/adflow.pyf | 1 + src/modules/inputParam.F90 | 1 + src/overset/oversetUtilities.F90 | 4 +++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 8955a433e..0e97c14c9 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5139,6 +5139,7 @@ def _getDefaultOptions(): "useOversetWallScaling": [bool, False], "selfZipCutoff": [float, 120.0], "oversetPriority": [dict, {}], + "oversetDebugPrint": [bool, False], # Unsteady Parameters "timeIntegrationScheme": [str, ["BDF", "explicit RK", "implicit RK"]], "timeAccuracy": [int, [2, 1, 3]], @@ -5504,6 +5505,7 @@ def _getOptionMap(self): "usezippermesh": ["overset", "usezippermesh"], "useoversetwallscaling": ["overset", "useoversetwallscaling"], "selfzipcutoff": ["overset", "selfzipcutoff"], + "oversetdebugprint": ["overset", "oversetdebugprint"], # Unsteady Params "timeintegrationscheme": { "bdf": self.adflow.constants.bdf, diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 63d52ce5d..005e35f9d 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -1274,6 +1274,7 @@ python module libadflow logical :: debugzipper logical :: usezippermesh logical :: useoversetwallscaling + logical :: oversetdebugprint real(kind=realtype) :: selfzipcutoff end module inputoverset diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 70bf9a953..73368df04 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -867,4 +867,5 @@ module inputOverset integer(kind=intType)::nFloodIter logical :: useZipperMesh logical :: useOversetWallScaling + logical :: oversetDebugPrint end module inputOverset diff --git a/src/overset/oversetUtilities.F90 b/src/overset/oversetUtilities.F90 index 3b3d5fe17..e5d308d71 100644 --- a/src/overset/oversetUtilities.F90 +++ b/src/overset/oversetUtilities.F90 @@ -1561,6 +1561,7 @@ subroutine checkOverset (level, sps, totalOrphans, printBadCells) use stencils, only : visc_drdw_stencil, N_visc_drdw use communication, only : myid, adflow_comm_world use utils, only : setPointers, EChk + use inputOverset, only : oversetDebugPrint implicit none ! Input/Output @@ -1595,7 +1596,8 @@ subroutine checkOverset (level, sps, totalOrphans, printBadCells) end if end do stencilLoop if (badCell .and. printBadCells) then - print *,'Error in connectivity at :',nbkglobal, i+iBegOr, j+jBegOr, k+kBegOr + if (oversetDebugPrint) & + print *,'Error in connectivity at :',nbkglobal, i+iBegOr, j+jBegOr, k+kBegOr ! we can modify iBlankLast because this is the last checkOverset call. ! we set iBlankLast to -5 to mark orphan cells, this value will then ! be moved to iBlank after we are done with other loops. From 8de2284fa9d01692358d6275e82d5093b12744c5 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Thu, 11 Aug 2022 10:34:20 +0200 Subject: [PATCH 24/76] removed dumb typo --- src/f2py/adflow.pyf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 779bdebd1..8acfb2315 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -80,7 +80,7 @@ python module libadflow module walldistance - subroutine updatewalldistancealllevelsx + subroutine updatewalldistancealllevels end subroutine updatewalldistancealllevels end module walldistance From cb8443538e3e8227844e21088165e62e53d3fd15 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Thu, 11 Aug 2022 10:36:59 +0200 Subject: [PATCH 25/76] reran tapenade --- src/adjoint/outputForward/solverutils_d.f90 | 24 ++++++++--------- .../outputForward/surfaceintegrations_d.f90 | 27 +++++++++---------- src/adjoint/outputReverse/solverutils_b.f90 | 24 ++++++++--------- .../outputReverse/surfaceintegrations_b.f90 | 24 ++++++++--------- .../outputReverseFast/solverutils_fast_b.f90 | 16 +++++------ .../surfaceintegrations_fast_b.f90 | 12 ++++----- 6 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/adjoint/outputForward/solverutils_d.f90 b/src/adjoint/outputForward/solverutils_d.f90 index f9955bd97..110f730d5 100644 --- a/src/adjoint/outputForward/solverutils_d.f90 +++ b/src/adjoint/outputForward/solverutils_d.f90 @@ -118,8 +118,8 @@ subroutine timestep_block_d(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) sfaced = 0.0_8 ! no preconditioner. simply the standard spectral radius. ! loop over the cells, including the first level halo. @@ -332,10 +332,10 @@ subroutine timestep_block_d(onlyradii) end do end do end do - case (turkel) + case (turkel) call terminate('timestep', & & 'turkel preconditioner not implemented yet') - case (choimerkle) + case (choimerkle) call terminate('timestep', & & 'choi merkle preconditioner not implemented yet') end select @@ -561,8 +561,8 @@ subroutine timestep_block(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) ! no preconditioner. simply the standard spectral radius. ! loop over the cells, including the first level halo. do k=1,ke @@ -674,10 +674,10 @@ subroutine timestep_block(onlyradii) end do end do end do - case (turkel) + case (turkel) call terminate('timestep', & & 'turkel preconditioner not implemented yet') - case (choimerkle) + case (choimerkle) call terminate('timestep', & & 'choi merkle preconditioner not implemented yet') end select @@ -1021,8 +1021,8 @@ subroutine gridvelocitiesfinelevel_block_d(useoldcoor, t, sps, nn) ! normal grid velocities of the faces. ! ! loop over the three directions. -! the original code is elegant but the tapenade has a difficult time -! to understand it. thus, we unfold it and make it easier for the +! the original code is elegant but the tapenade has a difficult time +! to understand it. thus, we unfold it and make it easier for the ! tapenade. ! i-direction do k=1,ke @@ -1319,8 +1319,8 @@ subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps, nn) ! normal grid velocities of the faces. ! ! loop over the three directions. -! the original code is elegant but the tapenade has a difficult time -! to understand it. thus, we unfold it and make it easier for the +! the original code is elegant but the tapenade has a difficult time +! to understand it. thus, we unfold it and make it easier for the ! tapenade. ! i-direction do k=1,ke diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 2e2855ddb..53995ea89 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -887,12 +887,10 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype) :: arg1d real(kind=realtype) :: result1 real(kind=realtype) :: result1d - real(kind=realtype) :: pwr1 - real(kind=realtype) :: pwr1d - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1378,11 +1376,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic exp real(kind=realtype) :: arg1 real(kind=realtype) :: result1 - real(kind=realtype) :: pwr1 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1744,10 +1741,10 @@ subroutine flowintegrationface_d(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2116,10 +2113,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverse/solverutils_b.f90 b/src/adjoint/outputReverse/solverutils_b.f90 index ed19fe30c..99508bc75 100644 --- a/src/adjoint/outputReverse/solverutils_b.f90 +++ b/src/adjoint/outputReverse/solverutils_b.f90 @@ -141,8 +141,8 @@ subroutine timestep_block_b(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) call pushreal8(sface) ! no preconditioner. simply the standard spectral radius. ! loop over the cells, including the first level halo. @@ -246,9 +246,9 @@ subroutine timestep_block_b(onlyradii) end if end do call pushcontrol2b(1) - case (turkel) + case (turkel) call pushcontrol2b(2) - case (choimerkle) + case (choimerkle) call pushcontrol2b(3) case default call pushcontrol2b(0) @@ -957,8 +957,8 @@ subroutine timestep_block(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) ! no preconditioner. simply the standard spectral radius. ! loop over the cells, including the first level halo. do ii=0,ie*je*ke-1 @@ -1060,10 +1060,10 @@ subroutine timestep_block(onlyradii) radk(i, j, k) = rk end if end do - case (turkel) + case (turkel) call terminate('timestep', & & 'turkel preconditioner not implemented yet') - case (choimerkle) + case (choimerkle) call terminate('timestep', & & 'choi merkle preconditioner not implemented yet') end select @@ -1352,8 +1352,8 @@ subroutine gridvelocitiesfinelevel_block_b(useoldcoor, t, sps, nn) ! normal grid velocities of the faces. ! ! loop over the three directions. -! the original code is elegant but the tapenade has a difficult time -! to understand it. thus, we unfold it and make it easier for the +! the original code is elegant but the tapenade has a difficult time +! to understand it. thus, we unfold it and make it easier for the ! tapenade. ! i-direction do k=1,ke @@ -1965,8 +1965,8 @@ subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps, nn) ! normal grid velocities of the faces. ! ! loop over the three directions. -! the original code is elegant but the tapenade has a difficult time -! to understand it. thus, we unfold it and make it easier for the +! the original code is elegant but the tapenade has a difficult time +! to understand it. thus, we unfold it and make it easier for the ! tapenade. ! i-direction do k=1,ke diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index c8deab1a6..c2d3e722f 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -1146,10 +1146,10 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: tempd16 real(kind=realtype) :: temp4 real(kind=realtype) :: tempd15 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1817,10 +1817,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -2189,10 +2189,10 @@ subroutine flowintegrationface_b(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2511,10 +2511,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverseFast/solverutils_fast_b.f90 b/src/adjoint/outputReverseFast/solverutils_fast_b.f90 index ca607239a..b91397e80 100644 --- a/src/adjoint/outputReverseFast/solverutils_fast_b.f90 +++ b/src/adjoint/outputReverseFast/solverutils_fast_b.f90 @@ -102,8 +102,8 @@ subroutine timestep_block_fast_b(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) do ii=0,ie*je*ke-1 i = mod(ii, ie) + 1 j = mod(ii/ie, je) + 1 @@ -411,8 +411,8 @@ subroutine timestep_block(onlyradii) ! inviscid contribution, depending on the preconditioner. ! compute the cell centered values of the spectral radii. ! - select case (precond) - case (noprecond) + select case (precond) + case (noprecond) ! no preconditioner. simply the standard spectral radius. ! loop over the cells, including the first level halo. do ii=0,ie*je*ke-1 @@ -514,10 +514,10 @@ subroutine timestep_block(onlyradii) radk(i, j, k) = rk end if end do - case (turkel) + case (turkel) call terminate('timestep', & & 'turkel preconditioner not implemented yet') - case (choimerkle) + case (choimerkle) call terminate('timestep', & & 'choi merkle preconditioner not implemented yet') end select @@ -771,8 +771,8 @@ subroutine gridvelocitiesfinelevel_block(useoldcoor, t, sps, nn) ! normal grid velocities of the faces. ! ! loop over the three directions. -! the original code is elegant but the tapenade has a difficult time -! to understand it. thus, we unfold it and make it easier for the +! the original code is elegant but the tapenade has a difficult time +! to understand it. thus, we unfold it and make it easier for the ! tapenade. ! i-direction do k=1,ke diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index cedbc4013..dd4969568 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -316,10 +316,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -642,10 +642,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows From 68cd86bc86ba028a5e4722db6514ba8f687522b8 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Fri, 12 Aug 2022 01:09:23 +0200 Subject: [PATCH 26/76] added arbitrary slices --- adflow/pyADflow.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index b8a221e0a..56770f74d 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -583,6 +583,72 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): self.nSlice += N + def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None): + """ + Add slices that vary arbitrarily in space. this is a generalization + of the routine above, where we have the user specify a list of "normals" + and "points" that define slice planes. Rest of the code is the same. + this way users can add slices that follow the dihedral of a wing for example. + + Parameters + ---------- + normals : 3-d array or ndarray (n_slice, 3) + The normals of the slice directions. If an array of size 3 is passed, + we use the same normal for all slices. if an array of multiple normals + are passed, we use the individual normals for each point. in this case, + the numbers of points and normals must match. + points : ndarray (n_slice, 3) + Point coordinates that define a slicing plane along with the normals + sliceType : str {'relative', 'absolute'} + Relative slices are 'sliced' at the beginning and then parametricly + move as the geometry deforms. As a result, the slice through the + geometry may not remain planar. An absolute slice is re-sliced for + every out put so is always exactly planar and always at the initial + position the user indicated. + groupName : str + The family to use for the slices. Default is None corresponding to all + wall groups. + """ + + # Create the zipper mesh if not done so + self._createZipperMesh() + + # Determine the families we want to use + if groupName is None: + groupName = self.allWallsGroup + groupTag = "%s: " % groupName + famList = self._getFamilyList(groupName) + + sliceType = sliceType.lower() + if sliceType not in ["relative", "absolute"]: + raise Error("'sliceType' must be 'relative' or 'absolute'.") + + n_slice = len(points) + normals = numpy.atleast_2d(normals) + points = numpy.atleast_2d(points) + + if len(normals) == 1: + tmp = numpy.zeros((n_slice, 3), self.dtype) + tmp[:] = normals + normals = tmp + + # for regular slices, we dont use the direction vector to pick a projection direction + slice_dir = [1.0, 0.0, 0.0] + use_dir = False + + for i in range(n_slice): + # It is important to ensure each slice get a unique + # name...so we will number sequentially from python + j = self.nSlice + i + 1 + if sliceType == "relative": + sliceName = "Slice_%4.4d %s Para Init Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % (j, groupTag, normals[i, 0], normals[i, 1], normals[i, 2], points[i, 0], points[i, 1], points[i, 2]) + self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) + else: + sliceName = "Slice_%4.4d %s Absolute Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % (j, groupTag, normals[i, 0], normals[i, 1], normals[i, 2], points[i, 0], points[i, 1], points[i, 2]) + self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) + + self.nSlice += n_slice + def addCylindricalSlices( self, pt1, pt2, n_slice=180, slice_beg=0.0, slice_end=360.0, sliceType="relative", groupName=None ): From 5758d2b88e05251f6f2994ce13ed847df26b9733 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 7 Sep 2022 20:47:18 -0400 Subject: [PATCH 27/76] added the option to disable lift and slices in writesolution routine --- adflow/pyADflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 56770f74d..786b6c576 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -2368,7 +2368,7 @@ def solveSep( if abs(fnm1) < tol: break - def writeSolution(self, outputDir=None, baseName=None, number=None): + def writeSolution(self, outputDir=None, baseName=None, number=None, writeSlices=True, writeLift=True): """This is a generic shell function that potentially writes the various output files. The intent is that the user or calling program can call this file and ADflow write all the @@ -2439,7 +2439,7 @@ def writeSolution(self, outputDir=None, baseName=None, number=None): writeSurf = self.getOption("writeTecplotSurfaceSolution") # # Call fully compbined fortran routine. - self.adflow.tecplotio.writetecplot(sliceName, True, liftName, True, surfName, writeSurf, famList) + self.adflow.tecplotio.writetecplot(sliceName, writeSlices, liftName, writeLift, surfName, writeSurf, famList) def writeMeshFile(self, fileName): """Write the current mesh to a CGNS file. This call isn't used From cc5a2d952c4d20dbab2a0cecd61f0e5277553426 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 14 Sep 2022 09:40:25 -0400 Subject: [PATCH 28/76] added function to explicitly flag overset cells that are inside provided surface geometries --- adflow/pyADflow.py | 53 ++++++++- src/f2py/adflow.pyf | 10 ++ src/overset/oversetAPI.F90 | 225 +++++++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+), 4 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 786b6c576..c4750df4a 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -297,7 +297,8 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # index needs to go in as fortran numbering, so add 1 name = getPy3SafeString(self.adflow.utils.getcgnszonename(i + 1).strip()) self.CGNSZoneNameIDs[name] = i + 1 - # do we need to do this on root and broadcast? + # TODO check this: do we need to do this on root and broadcast? + # Looks like it is fine # Call the user supplied callback if necessary cutCallBack = self.getOption("cutCallBack") @@ -307,8 +308,48 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): cellIDs = self.adflow.utils.getcellcgnsblockids(1, n) cutCallBack(xCen, self.CGNSZoneNameIDs, cellIDs, flag) + # TODO remove these, barriers, but for now, to get an accurate timing, sync procs + self.comm.barrier() cutCallBackTime = time.time() + # exlclude the cells inside closed surfaces if we are provided with them + explicitSurfaceCallback = self.getOption("explicitSurfaceCallback") + if explicitSurfaceCallback is not None: + # the user wants to exclude cells that lie within a list of surfaces. + + # first, call the callback function with cgns zone name IDs. + # this need to return us a dictionary with the surface mesh information, + # as well as which blocks in the cgns mesh to include in the search + surf_dict = explicitSurfaceCallback(self.CGNSZoneNameIDs) + + # loop over the surfaces + for surf in surf_dict: + + if self.comm.rank == 0: + print(f"Explicitly blanking surface: {surf}") + + # this is the plot3d surface that defines the closed volume + surf_file = surf_dict[surf]["surf_file"] + # the indices of cgns blocks that we want to consider when blanking inside the surface + block_ids = surf_dict[surf]["block_ids"] + + # read the plot3d surface + pts, conn = self._readPlot3DSurfFile(surf_file, convertToTris=False) + + # get a new flag array + surf_flag = numpy.zeros(n, "intc") + + # call the fortran routine to determine if the cells are inside or outside. + # this code is very similar to the actuator zone creation. + self.adflow.oversetapi.flagcellsinsurface(pts.T, conn.T, surf_flag, block_ids) + + # update the flag array with the new info + flag = numpy.any([flag, surf_flag], axis=0) + + # TODO remove these, barriers, but for now, to get an accurate timing, sync procs + self.comm.barrier() + explicitSurfaceCutTime = time.time() + # Need to reset the oversetPriority option since the CGNSGrid # structure wasn't available before; self.setOption("oversetPriority", self.getOption("oversetPriority")) @@ -344,13 +385,14 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): print("|") print("| %-30s: %10.3f sec" % ("Library Load Time", libLoadTime - startInitTime)) print("| %-30s: %10.3f sec" % ("Set Defaults Time", defSetupTime - libLoadTime)) - print("| %-30s: %10.3f sec" % ("Base class init Time", baseClassTime - defSetupTime)) + print("| %-30s: %10.3f sec" % ("Base Class Init Time", baseClassTime - defSetupTime)) print("| %-30s: %10.3f sec" % ("Introductory Time", introTime - baseClassTime)) print("| %-30s: %10.3f sec" % ("Partitioning Time", partitioningTime - introTime)) print("| %-30s: %10.3f sec" % ("Preprocessing Time", preprocessingTime - partitioningTime)) print("| %-30s: %10.3f sec" % ("Family Setup Time", familySetupTime - preprocessingTime)) - print("| %-30s: %10.3f sec" % ("Cut callback Time", cutCallBackTime - familySetupTime)) - print("| %-30s: %10.3f sec" % ("Overset Preprocessing Time", oversetPreTime - cutCallBackTime)) + print("| %-30s: %10.3f sec" % ("Cut Callback Time", cutCallBackTime - familySetupTime)) + print("| %-30s: %10.3f sec" % ("Explicit Surface Cut Time", explicitSurfaceCutTime - cutCallBackTime)) + print("| %-30s: %10.3f sec" % ("Overset Preprocessing Time", oversetPreTime - explicitSurfaceCutTime)) print("| %-30s: %10.3f sec" % ("Initialize Flow Time", initFlowTime - oversetPreTime)) print("|") print("| %-30s: %10.3f sec" % ("Total Init Time", finalInitTime - startInitTime)) @@ -5200,6 +5242,7 @@ def _getDefaultOptions(): "debugZipper": [bool, False], "zipperSurfaceFamily": [(str, type(None)), None], "cutCallback": [(types.FunctionType, type(None)), None], + "explicitSurfaceCallback": [(types.FunctionType, type(None)), None], "oversetUpdateMode": [str, ["frozen", "fast", "full"]], "nRefine": [int, 10], "nFloodIter": [int, -1], @@ -5391,6 +5434,7 @@ def _getImmutableOptions(self): "closedsurfacefamilies", "zippersurfacefamily", "cutcallback", + "explicitsurfacecallback", ) def _getOptionMap(self): @@ -5767,6 +5811,7 @@ def _getSpecialOptionLists(self): "zippersurfacefamily", "outputsurfacefamily", "cutcallback", + "explicitsurfacecallback", "infchangecorrection", "restartadjoint", "skipafterfailedadjoint", diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 8acfb2315..925d391b5 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -589,6 +589,16 @@ python module libadflow real(kind=realtype), intent(in) :: value logical, intent(out) :: setvalue end subroutine setblockpriority + subroutine flagcellsinsurface(pts,npts,conn,nconn,flag,ncell,blockids,nblocks) + real(kind=realtype) dimension(3,npts),intent(in) :: pts + integer(kind=inttype), optional,intent(in),check(shape(pts,1)==npts),depend(pts) :: npts=shape(pts,1) + integer(kind=inttype) dimension(4,nconn),intent(in) :: conn + integer(kind=inttype), optional,intent(in),check(shape(conn,1)==nconn),depend(conn) :: nconn=shape(conn,1) + integer(kind=inttype) dimension(ncell),intent(inout) :: flag + integer(kind=inttype), optional,intent(in),check(len(flag)==ncell),depend(flag) :: ncell=len(flag) + integer(kind=inttype) dimension(nblocks),intent(in) :: blockids + integer(kind=inttype), optional,intent(in),check(len(blockids)==nblocks),depend(blockids) :: nblocks=len(blockids) + end subroutine flagcellsinsurface end module oversetapi module oversetutilities diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index 952838238..f08fc9202 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2098,6 +2098,231 @@ subroutine setExplicitHoleCut(flag) end subroutine setExplicitHoleCut + subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nblocks) + + use constants + use communication, only : myID + use adtBuild, only : buildSerialQuad, destroySerialQuad + use adtLocalSearch, only : minDistanceTreeSearchSinglePoint + use ADTUtils, only : stack + use ADTData + use blockPointers, only : x, il, jl, kl, nDom, iBlank, vol, nbkGlobal + use adjointVars, only : nCellsLocal + use utils, only : setPointers, EChk + implicit none + + ! Input/Output + real(kind=realType), intent(in), dimension(3,npts) :: pts + integer(kind=intType), intent(in), dimension(4,nconn) :: conn + integer(kind=intType), intent(inout), dimension(ncell) :: flag + integer(kind=intType), intent(in), dimension(nblocks) :: blockids + integer(kind=intType), intent(in) :: npts, nconn, ncell, nblocks + + ! Working variables + integer(kind=intType) :: i, j, k, l, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr, iblock, cell_counter + real(kind=realType) :: dStar, frac, volLocal + real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, xCen, axisVec + real(kind=realType), dimension(3) :: diag1, diag2, diag3, diag4 + real(kind=realType) :: dd1, dd2, dd3, dd4, diag_max + type(adtType) :: ADT + real(kind=realType), dimension(:, :), allocatable :: norm + integer(kind=intType), dimension(:), allocatable :: normCount + integer(kind=intType), dimension(:, :), pointer :: tmp + + ! ADT Type required data + integer(kind=intType), dimension(:), pointer :: frontLeaves, frontLeavesNew + type(adtBBoxTargetType), dimension(:), pointer :: BB + real(kind=realType) :: coor(4), uvw(5) + real(kind=realType) :: dummy(3, 2) + + ! we use the same approach as the actuator zone addition; we project the cell centers to the + ! surface provided. This way, we can fairly quickly determine the coordinates + ! that are inside the closed volumes. The surface mesh is duplicated on all procs, whereas + ! the nodes projected are distributed based on the grid paritioning. + + ! Since this is effectively a wall-distance calc it gets super + ! costly for the points far away. Luckly, we can do a fairly + ! simple shortcut: Just compute the bounding box of the region and + ! use that as the "already found" distance in the cloest point + ! search. This will eliminate all the points further away + ! immediately and this should be sufficiently fast. + + ! So...compute that bounding box: + do iDim=1,3 + minX(iDim) = minval(pts(iDim, :)) + maxX(iDim) = maxval(pts(iDim, :)) + end do + + ! Get the max distance. This should be quite conservative. + dStar = (maxX(1)-minx(1))**2 + (maxX(2)-minX(2))**2 + (maxX(3)-minX(3))**2 + + ! Now build the tree. + call buildSerialQuad(size(conn, 2), size(pts, 2), pts, conn, ADT) + + ! Compute the (averaged) uniqe nodal vectors: + allocate(norm(3, size(pts, 2)), normCount(size(pts, 2))) + + norm = zero + normCount = 0 + + do i=1, size(conn, 2) + + ! Compute cross product normal and normize + v1 = pts(:, conn(3, i)) - pts(:, conn(1, i)) + v2 = pts(:, conn(4, i)) - pts(:, conn(2, i)) + + sss(1) = (v1(2)*v2(3) - v1(3)*v2(2)) + sss(2) = (v1(3)*v2(1) - v1(1)*v2(3)) + sss(3) = (v1(1)*v2(2) - v1(2)*v2(1)) + sss = sss / sqrt(sss(1)**2 + sss(2)**2 + sss(3)**2) + + ! Add to each of the four pts and increment the number added + do j=1, 4 + norm(:, conn(j, i)) = norm(:, conn(j, i)) + sss + normCount(conn(j, i)) = normCount(conn(j, i)) + 1 + end do + end do + + ! Now just divide by the norm count + do i=1, size(pts, 2) + norm(:, i) = norm(:, i) / normCount(i) + end do + + ! Node count is no longer needed + deallocate(normCount) + + ! write(*,*) myid, "after weird norm calc" + + ! Allocate the extra data the tree search requires. + allocate(stack(100), BB(20), frontLeaves(25), frontLeavesNew(25)) + + ! Now search for all the coordinate. Note that We have explictly + ! set sps to 1 becuase it is only implemented for single grid. + sps = 1 + level = 1 + cell_counter = 1 + + do nn=1, nDom + call setPointers(nn, level, sps) + + ! only check this cell if it is within one of the block IDs we are asked to look at + if (any( blockids .eq. nbkGlobal) )then + do k=2, kl + do j=2, jl + do i=2, il + ! calculate the 4 diagonals of the cell + diag1 = x(i-1,j-1,k-1,:) - x(i,j,k,:) + diag2 = x(i,j-1,k-1,:) - x(i-1,j,k,:) + diag3 = x(i,j,k-1,:) - x(i-1,j-1,k,:) + diag4 = x(i-1,j,k-1,:) - x(i,j-1,k,:) + + dd1 = diag1(1)*diag1(1) + diag1(2)*diag1(2) + diag1(3)*diag1(3) + dd2 = diag2(1)*diag2(1) + diag2(2)*diag2(2) + diag2(3)*diag2(3) + dd3 = diag3(1)*diag3(1) + diag3(2)*diag3(2) + diag3(3)*diag3(3) + dd4 = diag4(1)*diag4(1) + diag4(2)*diag4(2) + diag4(3)*diag4(3) + + ! get the max + diag_max = max(dd1, dd2, dd3, dd4) + ! if the projection is greater than this for any node, we stop testing the current point. + ! we can work with squared distances for the sake of efficiency. the projection routine + ! will also return the squared distance for the same reason. + + ! actually test each node + do l=1, 8 + select case (l) + case (1) + xCen = x(i-1,j-1,k-1,:) + case (2) + xCen = x(i, j-1,k-1,:) + case (3) + xCen = x(i, j, k-1,:) + case (4) + xCen = x(i-1,j, k-1,:) + case (5) + xCen = x(i-1,j-1,k, :) + case (6) + xCen = x(i, j-1,k, :) + case (7) + xCen = x(i, j, k, :) + case (8) + xCen = x(i-1,j, k, :) + end select + + ! The current point to search for and continually + ! reset the "closest point already found" variable. + coor(1:3) = xCen + coor(4) = dStar + intInfo(3) = 0 + call minDistancetreeSearchSinglePoint(ADT, coor, intInfo, & + uvw, dummy, 0, BB, frontLeaves, frontLeavesNew) + cellID = intInfo(3) + if (cellID > 0) then + ! Now check if this was successful or not: + if (checkInside()) then + ! Whoohoo! We are inside the region. Flag this cell + flag(cell_counter) = 1 + exit + else + ! we are outside. now check if the projection distance is larger than + ! the max diagonal. if so, we can quit early here. + if (uvw(4) .gt. diag_max) then + ! projection is larger than our biggest diagonal. + ! other nodes wont be in the surface, so we can exit the cell early here + exit + end if + end if + end if + end do + cell_counter = cell_counter + 1 + end do + end do + end do + else + ! we dont want to consider block, but we need to increment the counter + cell_counter = cell_counter + (kl - 1) * (jl - 1) * (il - 1) + end if + end do + + ! Final memory cleanup + deallocate(norm, frontLeaves, frontLeavesNew, BB) + call destroySerialQuad(ADT) + + contains + + function checkInside() + + implicit none + logical :: checkInside + integer(kind=intType) :: jj + real(kind=realType) :: shp(4), xp(3), normal(3), v1(3), dp + + ! bi-linear shape functions (CCW ordering) + shp(1) = (one-uvw(1))*(one-uvw(2)) + shp(2) = ( uvw(1))*(one-uvw(2)) + shp(3) = ( uvw(1))*( uvw(2)) + shp(4) = (one-uvw(1))*( uvw(2)) + + xp = zero + normal = zero + do jj=1, 4 + xp = xp + shp(jj)*pts(:, conn(jj, cellID)) + normal = normal + shp(jj)*norm(:, conn(jj, cellID)) + end do + + ! Compute the dot product of normal with cell center + ! (stored in coor) with the point on the surface. + v1 = coor(1:3) - xp + dp = normal(1)*v1(1) + normal(2)*v1(2) + normal(3)*v1(3) + + if (dp < zero) then + checkInside = .True. + else + checkInside = .False. + end if + end function checkInside + + end subroutine flagCellsInSurface + subroutine updateOverset(flag, n, closedFamList, nFam) ! This is the main gateway routine for updating the overset From 9ad0a81245e7a217fabc5d6e367a8633611fd5ef Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 19 Sep 2022 23:13:05 -0400 Subject: [PATCH 29/76] added a few more options to the explicit surface cutting --- adflow/pyADflow.py | 20 +++++- src/f2py/adflow.pyf | 3 +- src/overset/oversetAPI.F90 | 138 ++++++++++++++++++++----------------- 3 files changed, 94 insertions(+), 67 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index c4750df4a..83e42eec9 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -308,7 +308,7 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): cellIDs = self.adflow.utils.getcellcgnsblockids(1, n) cutCallBack(xCen, self.CGNSZoneNameIDs, cellIDs, flag) - # TODO remove these, barriers, but for now, to get an accurate timing, sync procs + # TODO remove these barriers, but for now, to get an accurate timing, sync procs self.comm.barrier() cutCallBackTime = time.time() @@ -333,20 +333,34 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # the indices of cgns blocks that we want to consider when blanking inside the surface block_ids = surf_dict[surf]["block_ids"] + # check if there is a kmin provided + if "kmin" in surf_dict[surf]: + kmin = surf_dict[surf]["kmin"] + else: + kmin = -1 + # read the plot3d surface pts, conn = self._readPlot3DSurfFile(surf_file, convertToTris=False) + # optionally add the offsets to the surface mesh we just read + if "dx" in surf_dict[surf]: + pts[:, 0] += surf_dict[surf]["dx"] + if "dy" in surf_dict[surf]: + pts[:, 1] += surf_dict[surf]["dy"] + if "dz" in surf_dict[surf]: + pts[:, 2] += surf_dict[surf]["dz"] + # get a new flag array surf_flag = numpy.zeros(n, "intc") # call the fortran routine to determine if the cells are inside or outside. # this code is very similar to the actuator zone creation. - self.adflow.oversetapi.flagcellsinsurface(pts.T, conn.T, surf_flag, block_ids) + self.adflow.oversetapi.flagcellsinsurface(pts.T, conn.T, surf_flag, block_ids, kmin) # update the flag array with the new info flag = numpy.any([flag, surf_flag], axis=0) - # TODO remove these, barriers, but for now, to get an accurate timing, sync procs + # TODO remove these barriers, but for now, to get an accurate timing, sync procs self.comm.barrier() explicitSurfaceCutTime = time.time() diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 925d391b5..76049e3bf 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -589,7 +589,7 @@ python module libadflow real(kind=realtype), intent(in) :: value logical, intent(out) :: setvalue end subroutine setblockpriority - subroutine flagcellsinsurface(pts,npts,conn,nconn,flag,ncell,blockids,nblocks) + subroutine flagcellsinsurface(pts,npts,conn,nconn,flag,ncell,blockids,nblocks,k_min) real(kind=realtype) dimension(3,npts),intent(in) :: pts integer(kind=inttype), optional,intent(in),check(shape(pts,1)==npts),depend(pts) :: npts=shape(pts,1) integer(kind=inttype) dimension(4,nconn),intent(in) :: conn @@ -598,6 +598,7 @@ python module libadflow integer(kind=inttype), optional,intent(in),check(len(flag)==ncell),depend(flag) :: ncell=len(flag) integer(kind=inttype) dimension(nblocks),intent(in) :: blockids integer(kind=inttype), optional,intent(in),check(len(blockids)==nblocks),depend(blockids) :: nblocks=len(blockids) + integer(kind=inttype), intent(in) :: k_min end subroutine flagcellsinsurface end module oversetapi diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index f08fc9202..b9ba567a0 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2098,7 +2098,7 @@ subroutine setExplicitHoleCut(flag) end subroutine setExplicitHoleCut - subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nblocks) + subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nblocks, k_min) use constants use communication, only : myID @@ -2106,7 +2106,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl use adtLocalSearch, only : minDistanceTreeSearchSinglePoint use ADTUtils, only : stack use ADTData - use blockPointers, only : x, il, jl, kl, nDom, iBlank, vol, nbkGlobal + use blockPointers, only : x, il, jl, kl, nDom, iBlank, vol, nbkGlobal, kBegOr use adjointVars, only : nCellsLocal use utils, only : setPointers, EChk implicit none @@ -2117,9 +2117,11 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl integer(kind=intType), intent(inout), dimension(ncell) :: flag integer(kind=intType), intent(in), dimension(nblocks) :: blockids integer(kind=intType), intent(in) :: npts, nconn, ncell, nblocks + integer(kind=intType), intent(in) :: k_min ! Working variables - integer(kind=intType) :: i, j, k, l, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr, iblock, cell_counter + integer(kind=intType) :: i, j, k, l, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr + integer(kind=intType) :: iblock, cell_counter, k_cgns real(kind=realType) :: dStar, frac, volLocal real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, xCen, axisVec real(kind=realType), dimension(3) :: diag1, diag2, diag3, diag4 @@ -2210,69 +2212,79 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl do k=2, kl do j=2, jl do i=2, il - ! calculate the 4 diagonals of the cell - diag1 = x(i-1,j-1,k-1,:) - x(i,j,k,:) - diag2 = x(i,j-1,k-1,:) - x(i-1,j,k,:) - diag3 = x(i,j,k-1,:) - x(i-1,j-1,k,:) - diag4 = x(i-1,j,k-1,:) - x(i,j-1,k,:) - - dd1 = diag1(1)*diag1(1) + diag1(2)*diag1(2) + diag1(3)*diag1(3) - dd2 = diag2(1)*diag2(1) + diag2(2)*diag2(2) + diag2(3)*diag2(3) - dd3 = diag3(1)*diag3(1) + diag3(2)*diag3(2) + diag3(3)*diag3(3) - dd4 = diag4(1)*diag4(1) + diag4(2)*diag4(2) + diag4(3)*diag4(3) - - ! get the max - diag_max = max(dd1, dd2, dd3, dd4) - ! if the projection is greater than this for any node, we stop testing the current point. - ! we can work with squared distances for the sake of efficiency. the projection routine - ! will also return the squared distance for the same reason. - - ! actually test each node - do l=1, 8 - select case (l) - case (1) - xCen = x(i-1,j-1,k-1,:) - case (2) - xCen = x(i, j-1,k-1,:) - case (3) - xCen = x(i, j, k-1,:) - case (4) - xCen = x(i-1,j, k-1,:) - case (5) - xCen = x(i-1,j-1,k, :) - case (6) - xCen = x(i, j-1,k, :) - case (7) - xCen = x(i, j, k, :) - case (8) - xCen = x(i-1,j, k, :) - end select - - ! The current point to search for and continually - ! reset the "closest point already found" variable. - coor(1:3) = xCen - coor(4) = dStar - intInfo(3) = 0 - call minDistancetreeSearchSinglePoint(ADT, coor, intInfo, & - uvw, dummy, 0, BB, frontLeaves, frontLeavesNew) - cellID = intInfo(3) - if (cellID > 0) then - ! Now check if this was successful or not: - if (checkInside()) then - ! Whoohoo! We are inside the region. Flag this cell - flag(cell_counter) = 1 - exit - else - ! we are outside. now check if the projection distance is larger than - ! the max diagonal. if so, we can quit early here. - if (uvw(4) .gt. diag_max) then - ! projection is larger than our biggest diagonal. - ! other nodes wont be in the surface, so we can exit the cell early here + + ! get the k index of this cell in the cgns grid + k_cgns = k + kBegOr - 2 + + ! check if we are above the kmin range needed. if no kmin is provided, then the value + ! defaults to -1 from python, so all points satisfy the check + if (k_cgns .gt. k_min) then + + ! calculate the 4 diagonals of the cell + diag1 = x(i-1,j-1,k-1,:) - x(i,j,k,:) + diag2 = x(i,j-1,k-1,:) - x(i-1,j,k,:) + diag3 = x(i,j,k-1,:) - x(i-1,j-1,k,:) + diag4 = x(i-1,j,k-1,:) - x(i,j-1,k,:) + + dd1 = diag1(1)*diag1(1) + diag1(2)*diag1(2) + diag1(3)*diag1(3) + dd2 = diag2(1)*diag2(1) + diag2(2)*diag2(2) + diag2(3)*diag2(3) + dd3 = diag3(1)*diag3(1) + diag3(2)*diag3(2) + diag3(3)*diag3(3) + dd4 = diag4(1)*diag4(1) + diag4(2)*diag4(2) + diag4(3)*diag4(3) + + ! get the max + diag_max = max(dd1, dd2, dd3, dd4) + ! if the projection is greater than this for any node, we stop testing the current point. + ! we can work with squared distances for the sake of efficiency. the projection routine + ! will also return the squared distance for the same reason. + + ! actually test each node + do l=1, 8 + select case (l) + case (1) + xCen = x(i-1,j-1,k-1,:) + case (2) + xCen = x(i, j-1,k-1,:) + case (3) + xCen = x(i, j, k-1,:) + case (4) + xCen = x(i-1,j, k-1,:) + case (5) + xCen = x(i-1,j-1,k, :) + case (6) + xCen = x(i, j-1,k, :) + case (7) + xCen = x(i, j, k, :) + case (8) + xCen = x(i-1,j, k, :) + end select + + ! The current point to search for and continually + ! reset the "closest point already found" variable. + coor(1:3) = xCen + coor(4) = dStar + intInfo(3) = 0 + call minDistancetreeSearchSinglePoint(ADT, coor, intInfo, & + uvw, dummy, 0, BB, frontLeaves, frontLeavesNew) + cellID = intInfo(3) + if (cellID > 0) then + ! Now check if this was successful or not: + if (checkInside()) then + ! Whoohoo! We are inside the region. Flag this cell + flag(cell_counter) = 1 exit + else + ! we are outside. now check if the projection distance is larger than + ! the max diagonal. if so, we can quit early here. + if (uvw(4) .gt. diag_max) then + ! projection is larger than our biggest diagonal. + ! other nodes wont be in the surface, so we can exit the cell early here + exit + end if end if end if - end if - end do + end do + end if + cell_counter = cell_counter + 1 end do end do From a52f2356863399ddce3d1f44c36343322ae7dc8b Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 24 Sep 2022 22:52:47 -0400 Subject: [PATCH 30/76] re-implementing the ks-based cpmin. added the original cavitation sensor back --- adflow/pyADflow.py | 5 +- doc/options.yaml | 4 +- src/adjoint/masterRoutines.F90 | 3 - .../outputForward/surfaceintegrations_d.f90 | 101 +++++++++------- .../outputReverse/surfaceintegrations_b.f90 | 114 ++++++++++-------- .../surfaceintegrations_fast_b.f90 | 37 +++--- src/f2py/adflow.pyf | 3 +- src/modules/constants.F90 | 10 +- src/modules/inputParam.F90 | 3 +- src/solver/surfaceIntegrations.F90 | 87 +++++++------ 10 files changed, 194 insertions(+), 173 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 83e42eec9..d24359c02 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5231,7 +5231,7 @@ def _getDefaultOptions(): "wallDistCutoff": [float, 1e20], "infChangeCorrection": [bool, True], "cavitationNumber": [float, 1.4], - "cavitationRho": [float, 100.0], + "cpMinRho": [float, 100.0], # Common Parameters "nCycles": [int, 2000], "timeLimit": [float, -1.0], @@ -5593,7 +5593,7 @@ def _getOptionMap(self): "forcesastractions": ["physics", "forcesastractions"], "lowspeedpreconditioner": ["discr", "lowspeedpreconditioner"], "cavitationnumber": ["physics", "cavitationsensor"], - "cavitationrho": ["physics", "cavitationrho"], + "cpminrho": ["physics", "cpmin_rho"], # Common Parameters "ncycles": ["iter", "ncycles"], "timelimit": ["iter", "timelimit"], @@ -5940,6 +5940,7 @@ def _getObjectivesAndDVs(self): "sepsensoravgy": self.adflow.constants.costfuncsepsensoravgy, "sepsensoravgz": self.adflow.constants.costfuncsepsensoravgz, "cavitation": self.adflow.constants.costfunccavitation, + "cpmin": self.adflow.constants.costfunccpmin, "mdot": self.adflow.constants.costfuncmdot, "mavgptot": self.adflow.constants.costfuncmavgptot, "aavgptot": self.adflow.constants.costfuncaavgptot, diff --git a/doc/options.yaml b/doc/options.yaml index 0db71dc93..1a549be76 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -334,9 +334,9 @@ cavitationNumber: This "sensor" is only used for the surface output. The actual cavitation cost function in adflow uses a KS aggregation under the hood and returns the cpmin value for a given family. -cavitationRho: +cpMinRho: desc: > - The rho parameter used for the KS aggregation used for computing cavitation. + The rho parameter used for the KS aggregation used for computing minimum Cp. KS aggregation is used to compute the differentiable min Cp within the given family group. A higher rho value will approach the actual min Cp more accurately, at the cost of a more nonlinear function. diff --git a/src/adjoint/masterRoutines.F90 b/src/adjoint/masterRoutines.F90 index c5adcd2cf..6d4781699 100644 --- a/src/adjoint/masterRoutines.F90 +++ b/src/adjoint/masterRoutines.F90 @@ -32,7 +32,6 @@ subroutine master(useSpatial, famLists, funcValues, forces, & use turbUtils, only : turbAdvection, computeEddyViscosity use residuals, only : initRes_block, sourceTerms_block use surfaceIntegrations, only : getSolution - use inputCostFunctions, only : computeCavitation use adjointExtra, only : volume_block, metric_block, boundaryNormals,& xhalo_block, sumdwandfw, resScale use oversetData, only : oversetPresent @@ -270,7 +269,6 @@ subroutine master_d(wdot, xdot, forcesDot, dwDot, famLists, funcValues, funcValu use turbbcroutines_d, only : applyAllTurbBCthisblock_d, bcTurbTreatment_d use initializeflow_d, only : referenceState_d use surfaceIntegrations, only : getSolution_d - use inputCostFunctions, only : computeCavitation use adjointExtra_d, only : xhalo_block_d, volume_block_d, metric_BLock_d, boundarynormals_d use adjointextra_d, only : resscale_D, sumdwandfw_d use bcdata, only : setBCData_d, setBCDataFineGrid_d @@ -600,7 +598,6 @@ subroutine master_b(wbar, xbar, extraBar, forcesBar, dwBar, nState, famLists, & use haloExchange, only : whalo2_b, exchangeCoor_b, exchangeCoor, whalo2 use wallDistanceData, only : xSurfVec, xSurfVecd, xSurf, xSurfd, wallScatter use surfaceIntegrations, only : getSolution_b - use inputCostFunctions, only : computeCavitation use flowUtils, only : fixAllNodalGradientsFromAD use adjointextra_b, only : resscale_B, sumdwandfw_b use adjointExtra_b, only : xhalo_block_b, volume_block_b, metric_block_b, boundarynormals_b diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 53995ea89..20335e678 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -24,8 +24,8 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex, cavitationnumber, & -& cavitationrho +& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & +& cpmin_rho use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector, getdirvector_d @@ -536,10 +536,10 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvaluesd(costfunccavitation) = funcvaluesd(costfunccavitation)/& -& funcvalues(costfunccavitation)/cavitationrho - funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& -& costfunccavitation))/cavitationrho + funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin)/funcvalues(& +& costfunccpmin)/cpmin_rho + funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& +& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -554,8 +554,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & -& cavitationrho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector @@ -802,8 +801,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& -& costfunccavitation))/cavitationrho + funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& +& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -843,7 +842,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cavitationnumber, cavitationrho +& cpmin_exact, cpmin_rho use bcpointers_d implicit none ! input/output variables @@ -856,7 +855,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype), dimension(3) :: fpd, fvd, mpd, mvd real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation +& cavitation, cp_min_ks real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn @@ -887,6 +886,11 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype) :: arg1d real(kind=realtype) :: result1 real(kind=realtype) :: result1d + real(kind=realtype) :: pwr1 + real(kind=realtype) :: pwr1d + real :: cavitationnumber + real(kind=realtype) :: ks_exponent + real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -918,6 +922,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) yplusmax = zero sepsensor = zero cavitation = zero + cp_min_ks = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -1126,22 +1131,29 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) tmp = two/(gammainf*machcoef*machcoef) cpd = tmpd*(plocal-pinf) + tmp*(plocald-pinfd) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then - sensor1d = -(cavitationrho*cpd*exp(cavitationrho*(-cp-& -& cavitationnumber))) - sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) -! else -! sensor1 = zero -! end if - cavitationd = cavitationd + blk*sensor1d - cavitation = cavitation + sensor1*blk + sensor1d = -cpd + sensor1 = -cp - cavitationnumber + if (sensor1 .gt. 0.0_8 .or. (sensor1 .lt. 0.0_8 .and. & +& cavexponent .eq. int(cavexponent))) then + pwr1d = cavexponent*sensor1**(cavexponent-1)*sensor1d + else if (sensor1 .eq. 0.0_8 .and. cavexponent .eq. 1.0) then + pwr1d = sensor1d + else + pwr1d = 0.0_8 + end if + pwr1 = sensor1**cavexponent + arg1d = -(2*cavsensorsharpness*sensor1d) + arg1 = 2*cavsensorsharpness*(-sensor1+cavsensoroffset) + sensor1d = (pwr1d*(one+exp(arg1))-pwr1*arg1d*exp(arg1))/(one+exp& +& (arg1))**2 + sensor1 = pwr1/(one+exp(arg1)) + sensor1d = blk*(sensor1d*cellarea+sensor1*cellaread) + sensor1 = sensor1*cellarea*blk + cavitationd = cavitationd + sensor1d + cavitation = cavitation + sensor1 +! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do ! @@ -1319,6 +1331,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvaluesd(icavitation) = localvaluesd(icavitation) + cavitationd localvalues(icavitation) = localvalues(icavitation) + cavitation + localvalues(icpmin) = localvalues(icpmin) + cp_min_ks localvaluesd(isepavg:isepavg+2) = localvaluesd(isepavg:isepavg+2) + & & sepsensoravgd localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & @@ -1347,7 +1360,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber, cavitationrho +& equations, momentaxis, cpmin_exact, cpmin_rho use bcpointers_d implicit none ! input/output variables @@ -1357,7 +1370,7 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation +& cavitation, cp_min_ks integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l @@ -1376,6 +1389,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic exp real(kind=realtype) :: arg1 real(kind=realtype) :: result1 + real(kind=realtype) :: pwr1 + real :: cavitationnumber + real(kind=realtype) :: ks_exponent + real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -1403,6 +1420,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero + cp_min_ks = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -1525,19 +1543,15 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then - sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) -! else -! sensor1 = zero -! end if - cavitation = cavitation + sensor1*blk + sensor1 = -cp - cavitationnumber + pwr1 = sensor1**cavexponent + arg1 = 2*cavsensorsharpness*(-sensor1+cavsensoroffset) + sensor1 = pwr1/(one+exp(arg1)) + sensor1 = sensor1*cellarea*blk + cavitation = cavitation + sensor1 +! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do ! @@ -1656,6 +1670,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation + localvalues(icpmin) = localvalues(icpmin) + cp_min_ks localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index c2d3e722f..7c4327e5a 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -25,8 +25,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex, cavitationnumber, & -& cavitationrho +& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & +& cpmin_rho use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector, getdirvector_b @@ -344,8 +344,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & if (tsstability) then stop else - funcvaluesd(costfunccavitation) = funcvaluesd(costfunccavitation)/& -& (cavitationrho*funcvalues(costfunccavitation)) + funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin)/(cpmin_rho& +& *funcvalues(costfunccpmin)) call popreal8(funcvalues(costfuncdragcoefmomentum)) tmpd = funcvaluesd(costfuncdragcoefmomentum) funcvaluesd(costfuncdragcoefmomentum) = 0.0_8 @@ -782,8 +782,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & -& cavitationrho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector @@ -1028,8 +1027,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& -& costfunccavitation))/cavitationrho + funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& +& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1071,7 +1070,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cavitationnumber, cavitationrho +& cpmin_exact, cpmin_rho use bcpointers_b implicit none ! input/output variables @@ -1084,7 +1083,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype), dimension(3) :: fpd, fvd, mpd, mvd real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation +& cavitation, cp_min_ks real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn @@ -1122,6 +1121,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: temp0 real(kind=realtype) :: tempd11 real(kind=realtype) :: tempd10 + real :: cavitationnumber real(kind=realtype) :: tempd9 real(kind=realtype) :: tempd real(kind=realtype) :: tempd8(3) @@ -1134,15 +1134,19 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: tempd1 real(kind=realtype) :: tempd0 real(kind=realtype) :: tmpd0(3) + real(kind=realtype) :: ks_exponent real(kind=realtype) :: tempd24 real(kind=realtype) :: tempd23 real(kind=realtype) :: tempd22 real(kind=realtype) :: tempd21 real(kind=realtype) :: tempd20 + real*8 :: cpmin_ks_sum real(kind=realtype) :: temp real(kind=realtype) :: tempd19 real(kind=realtype) :: tempd18 + real(kind=realtype) :: temp6 real(kind=realtype) :: tempd17 + real(kind=realtype) :: temp5 real(kind=realtype) :: tempd16 real(kind=realtype) :: temp4 real(kind=realtype) :: tempd15 @@ -1284,19 +1288,14 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then - sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) -! else -! sensor1 = zero -! end if - cavitation = cavitation + sensor1*blk + sensor1 = -cp - cavitationnumber + sensor1 = sensor1**cavexponent/(one+exp(2*cavsensorsharpness*(-& +& sensor1+cavsensoroffset))) + sensor1 = sensor1*cellarea*blk + cavitation = cavitation + sensor1 +! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do ! @@ -1596,20 +1595,27 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then -! else -! sensor1 = zero -! end if - sensor1d = blk*cavitationd - cpd = -(cavitationrho*exp(cavitationrho*(-cavitationnumber-cp))*& -& sensor1d) + sensor1 = -cp - cavitationnumber + call pushreal8(sensor1) + sensor1 = sensor1**cavexponent/(one+exp(2*cavsensorsharpness*(-& +& sensor1+cavsensoroffset))) +! also do the ks-based cpmin computation + sensor1d = cavitationd + cellaread = blk*sensor1*sensor1d + sensor1d = blk*cellarea*sensor1d + call popreal8(sensor1) + temp6 = 2*cavsensorsharpness*(cavsensoroffset-sensor1) + temp5 = one + exp(temp6) + if (sensor1 .le. 0.0_8 .and. (cavexponent .eq. 0.0_8 .or. & +& cavexponent .ne. int(cavexponent))) then + sensor1d = cavsensorsharpness*2*exp(temp6)*sensor1**& +& cavexponent*sensor1d/temp5**2 + else + sensor1d = (cavsensorsharpness*2*exp(temp6)*sensor1**& +& cavexponent/temp5**2+cavexponent*sensor1**(cavexponent-1)/& +& temp5)*sensor1d + end if + cpd = -sensor1d tmpd = (plocal-pinf)*cpd plocald = tmp*cpd pinfd = pinfd - tmp*cpd @@ -1617,6 +1623,8 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) machcoefd = machcoefd - gammainf*two*2*machcoef*tmpd/temp4**2 tmp = two/(gammainf*pinf*machcoef*machcoef) pp2d(i, j) = pp2d(i, j) + plocald + else + cellaread = 0.0_8 end if mxd = blk*mpd(1) myd = blk*mpd(2) @@ -1649,7 +1657,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) xxd(i, j+1, 1) = xxd(i, j+1, 1) + tempd7 xxd(i+1, j+1, 1) = xxd(i+1, j+1, 1) + tempd7 call popreal8(sensor) - cellaread = blk*sensor*sensord + cellaread = cellaread + blk*sensor*sensord sensord = blk*cellarea*sensord call popreal8(sensor) temp3 = -(2*sepsensorsharpness*(sensor-sepsensoroffset)) @@ -1790,7 +1798,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber, cavitationrho +& equations, momentaxis, cpmin_exact, cpmin_rho use bcpointers_b implicit none ! input/output variables @@ -1800,7 +1808,7 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation +& cavitation, cp_min_ks integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l @@ -1817,6 +1825,9 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp + real :: cavitationnumber + real(kind=realtype) :: ks_exponent + real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -1844,6 +1855,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero + cp_min_ks = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -1963,19 +1975,14 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then - sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) -! else -! sensor1 = zero -! end if - cavitation = cavitation + sensor1*blk + sensor1 = -cp - cavitationnumber + sensor1 = sensor1**cavexponent/(one+exp(2*cavsensorsharpness*(-& +& sensor1+cavsensoroffset))) + sensor1 = sensor1*cellarea*blk + cavitation = cavitation + sensor1 +! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do ! @@ -2093,6 +2100,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation + localvalues(icpmin) = localvalues(icpmin) + cp_min_ks localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index dd4969568..fd56f75d7 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -16,8 +16,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cavitationnumber, & -& cavitationrho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho use inputtsstabderiv, only : tsstability use utils_fast_b, only : computetsderivatives use flowutils_fast_b, only : getdirvector @@ -262,8 +261,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) ! final part of the ks computation - funcvalues(costfunccavitation) = cavitationnumber + log(funcvalues(& -& costfunccavitation))/cavitationrho + funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& +& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -289,7 +288,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cavitationnumber, cavitationrho +& equations, momentaxis, cpmin_exact, cpmin_rho use bcpointers_fast_b implicit none ! input/output variables @@ -299,7 +298,7 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation +& cavitation, cp_min_ks integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l @@ -316,6 +315,9 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp + real :: cavitationnumber + real(kind=realtype) :: ks_exponent + real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -343,6 +345,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero + cp_min_ks = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -462,19 +465,14 @@ subroutine wallintegrationface(localvalues, mm) plocal = pp2(i, j) tmp = two/(gammainf*machcoef*machcoef) cp = tmp*(plocal-pinf) -! sensor1 = -cp - cavitationnumber -! sensor1 = one/(one+exp(-2*10*sensor1)) -! sensor1 = sensor1 * cellarea * blk -! ks formulation with a fixed cpmin at 2 sigmas -! only include the cavitation contribution if we are not underflowing. -! otherwise, this will cause nans with bwd ad because of the order of the operations -! todo the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. -! if ((cavitationrho * (-cp - cavitationnumber)) .lt. -200.0_realtype) then - sensor1 = exp(cavitationrho*(-cp-cavitationnumber)) -! else -! sensor1 = zero -! end if - cavitation = cavitation + sensor1*blk + sensor1 = -cp - cavitationnumber + sensor1 = sensor1**cavexponent/(one+exp(2*cavsensorsharpness*(-& +& sensor1+cavsensoroffset))) + sensor1 = sensor1*cellarea*blk + cavitation = cavitation + sensor1 +! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do ! @@ -592,6 +590,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation + localvalues(icpmin) = localvalues(icpmin) + cp_min_ks localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index 76049e3bf..cc79ac0f4 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -1010,6 +1010,7 @@ python module libadflow integer(kind=inttype) parameter,optional :: costfunccperror2=86 integer(kind=inttype) parameter,optional :: costfuncaavgptot=87 integer(kind=inttype) parameter,optional :: costfuncaavgps=88 + integer(kind=inttype) parameter,optional :: costfunccpmin=89 end module constants module communication ! in :adflow:../../modules/communication.f90 @@ -1222,7 +1223,7 @@ python module libadflow real(kind=realtype) :: beta integer(kind=inttype) :: liftindex real(kind=realtype) :: cavitationsensor - real(kind=realtype) :: cavitationrho + real(kind=realtype) :: cpmin_rho end module inputphysics module inputadjoint ! in :adflow:../modules/inputParam.f90 diff --git a/src/modules/constants.F90 b/src/modules/constants.F90 index e076c1e5d..b49c9f40e 100644 --- a/src/modules/constants.F90 +++ b/src/modules/constants.F90 @@ -341,7 +341,7 @@ module constants integer(kind=intType), parameter :: iTotal=16 ! Cost functions. - integer(kind=intType), parameter :: nCostFunction = 88 + integer(kind=intType), parameter :: nCostFunction = 89 integer(kind=intType), parameter :: & costFuncLift = 1,& costFuncDrag = 2,& @@ -430,9 +430,10 @@ module constants costfuncmavgvz = 85, & costfunccperror2 = 86, & costfuncaavgptot = 87, & - costfuncaavgps = 88 + costfuncaavgps = 88, & + costfunccpmin = 89 - integer(kind=intType), parameter :: nLocalValues=49 + integer(kind=intType), parameter :: nLocalValues=50 integer(kind=intType), parameter :: & iFp = 1, & iFv = 4, & @@ -466,7 +467,8 @@ module constants iPower = 46, & iCpError2 = 47, & iAreaPTot = 48, & - iAreaPs = 49 + iAreaPs = 49, & + iCpMin = 50 ! Constants for zipper comm diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index c943bb4d0..d8805007d 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -583,7 +583,8 @@ module inputPhysics real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber real(kind=realType) :: cavitationsensor - real(kind=realType) :: cavitationrho + real(kind=realType) :: cpmin_rho + real(kind=realType) :: cpmin_exact #ifndef USE_TAPENADE real(kind=realType) :: alphad, betad diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 47ad824bb..b078e4702 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -8,8 +8,8 @@ subroutine getCostFunctions(globalVals, funcValues) use inputTimeSpectral, only : nTimeIntervalsSpectral use flowVarRefState, only : pRef, rhoRef, tRef, LRef, gammaInf, pInf, uRef, uInf use inputPhysics, only : liftDirection, dragDirection, surfaceRef, & - machCoef, lengthRef, alpha, beta, liftIndex, cavitationnumber, & - cavitationrho + machCoef, lengthRef, alpha, beta, liftIndex, cpmin_exact, & + cpmin_rho use inputTSStabDeriv, only : TSstability use utils, only : computeTSDerivatives use flowUtils, only : getDirVector @@ -259,8 +259,8 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncForceZCoefMomentum)*dragDirection(3) ! final part of the KS computation - funcValues(costFuncCavitation) = cavitationnumber & - + log(funcValues(costFuncCavitation)) / cavitationrho + funcValues(costfunccpmin) = cpmin_exact & + + log(funcValues(costfunccpmin)) / cpmin_rho ! -------------------- Time Spectral Objectives ------------------ @@ -316,7 +316,8 @@ subroutine wallIntegrationFace(localValues, mm) use blockPointers use flowVarRefState use inputCostFunctions - use inputPhysics, only : MachCoef, pointRef, velDirFreeStream, equations, momentAxis, cavitationnumber, cavitationrho + use inputPhysics, only : MachCoef, pointRef, velDirFreeStream, & + equations, momentAxis, cpmin_exact, cpmin_rho, cavitationnumber use BCPointers implicit none @@ -326,13 +327,13 @@ subroutine wallIntegrationFace(localValues, mm) ! Local variables. real(kind=realType), dimension(3) :: Fp, Fv, Mp, Mv - real(kind=realType) :: yplusMax, sepSensor, sepSensorAvg(3), Cavitation + real(kind=realType) :: yplusMax, sepSensor, sepSensorAvg(3), Cavitation, cpmin_ks_sum integer(kind=intType) :: i, j, ii, blk real(kind=realType) :: pm1, fx, fy, fz, fn real(kind=realType) :: xc, yc, zc, qf(3), r(3), n(3), L real(kind=realType) :: fact, rho, mul, yplus, dwall - real(kind=realType) :: V(3), sensor, sensor1, Cp, tmp, plocal + real(kind=realType) :: V(3), sensor, sensor1, Cp, tmp, plocal, ks_exponent real(kind=realType) :: tauXx, tauYy, tauZz real(kind=realType) :: tauXy, tauXz, tauYz @@ -371,6 +372,7 @@ subroutine wallIntegrationFace(localValues, mm) yplusMax = zero sepSensor = zero Cavitation = zero + cpmin_ks_sum = zero sepSensorAvg = zero Mpaxis = zero; Mvaxis = zero; CpError2 = zero; @@ -509,19 +511,14 @@ subroutine wallIntegrationFace(localValues, mm) plocal = pp2(i,j) tmp = two/(gammaInf*MachCoef*MachCoef) Cp = tmp*(plocal-pinf) - ! Sensor1 = -Cp - cavitationnumber - ! Sensor1 = one/(one+exp(-2*10*Sensor1)) - ! Sensor1 = Sensor1 * cellArea * blk - ! KS formulation with a fixed CPmin at 2 sigmas - ! only include the cavitation contribution if we are not underflowing. - ! otherwise, this will cause NaNs with bwd AD because of the order of the operations - ! TODO the if checks below might be needed for preventing nans with bwd ad but it seems to work without it. - ! if ((cavitationrho * (-Cp - cavitationnumber)) .lt. -200.0_realType) then - Sensor1 = exp(cavitationrho * (-Cp - cavitationnumber)) - ! else - ! Sensor1 = zero - ! end if - Cavitation = Cavitation + Sensor1 * blk + Sensor1 = -Cp - cavitationnumber + Sensor1 = (Sensor1**cavExponent)/(one+exp(2*cavSensorSharpness*(-Sensor1+cavSensorOffset))) + Sensor1 = Sensor1 * cellArea * blk + Cavitation = Cavitation + Sensor1 + + ! also do the ks-based cpmin computation + ks_exponent = exp(cpmin_rho * (-Cp - cpmin_exact)) + cpmin_ks_sum = cpmin_ks_sum + ks_exponent * blk end if enddo @@ -672,6 +669,7 @@ subroutine wallIntegrationFace(localValues, mm) localValues(iMv:iMv+2) = localValues(iMv:iMv+2) + Mv localValues(iSepSensor) = localValues(iSepSensor) + sepSensor localValues(iCavitation) = localValues(iCavitation) + cavitation + localValues(iCpMin) = localValues(iCpMin) + cpmin_ks_sum localValues(iSepAvg:iSepAvg+2) = localValues(iSepAvg:iSepAvg+2) + sepSensorAvg localValues(iAxisMoment) = localValues(iAxisMoment) + Mpaxis + Mvaxis localValues(iCpError2) = localValues(iCpError2) + CpError2 @@ -979,7 +977,7 @@ subroutine getSolution(famLists, funcValues, globalValues) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCavitationNumber(famList) + call computeCpMinExact(famList) end if do sps=1, nTimeIntervalsSpectral @@ -1074,12 +1072,12 @@ subroutine integrateSurfaces(localValues, famList) end subroutine integrateSurfaces - subroutine computeCavitationNumber(famList) + subroutine computeCpMinExact(famList) use constants use inputTimeSpectral , only : nTimeIntervalsSpectral use communication, only : ADflow_comm_world, myID use blockPointers, only : nDom - use inputPhysics, only : cavitationNumber, MachCoef + use inputPhysics, only : cpmin_exact, MachCoef use blockPointers use flowVarRefState use BCPointers @@ -1091,12 +1089,14 @@ subroutine computeCavitationNumber(famList) integer(kind=intType), dimension(:), intent(in) :: famList integer(kind=intType) :: mm, nn, sps integer(kind=intType) :: i, j, ii, blk, ierr - real(kind=realType) :: Cp, plocal, tmp, cavitationNumberLocal + real(kind=realType) :: Cp, plocal, tmp, cpmin_local - ! here we do a simplified surface integration on walls only to get the cpmin over walls - ! write (*,*) "rank", myID, " current cav number", cavitationNumber - ! set the cavitation number to a small value so that we get the actual max (- min cp) - cavitationNumberLocal = -10000.0_realType + ! this routine loops over the surface cells in the given family and computes the true minimum Cp value. + ! this is then used in the surface integration routine to compute the cpmin using KS aggregation. + ! the goal is to get a differentiable cpmin output + + ! set the local cp min to a small value so that we get the actual min + cpmin_local = -10000.0_realType ! loop over the TS instances just because its the same convention everywhere. ! in an actual TS computation, this wont work most likely. @@ -1122,15 +1122,16 @@ subroutine computeCavitationNumber(famList) i = mod(ii, (bcData(mm)%inEnd-bcData(mm)%inBeg)) + bcData(mm)%inBeg + 1 j = ii/(bcData(mm)%inEnd-bcData(mm)%inBeg) + bcData(mm)%jnBeg + 1 - ! compute local CP - plocal = pp2(i,j) - tmp = two/(gammaInf*MachCoef*MachCoef) - Cp = tmp*(plocal-pinf) - ! only take this if its a compute cell if (BCData(mm)%iblank(i,j) .gt. zero) then - ! compare it against the current value on this proc - cavitationNumberLocal = max(cavitationNumberLocal, -Cp) + + ! compute local CP + plocal = pp2(i,j) + tmp = two/(gammaInf*MachCoef*MachCoef) + Cp = tmp*(plocal-pinf) + + ! compare it against the current value on this proc + cpmin_local = min(cpmin_local, Cp) end if enddo end if isWall @@ -1140,16 +1141,12 @@ subroutine computeCavitationNumber(famList) end do domains end do ts - ! write (*,*) "rank", myID, " cav before comm", cavitationNumberLocal - - ! finally communicate across all - call mpi_allreduce(cavitationNumberLocal, cavitationNumber, 1, adflow_real, & - MPI_MAX, adflow_comm_world, ierr) + ! finally communicate across all processors + call mpi_allreduce(cpmin_local, cpmin_exact, 1, adflow_real, & + MPI_MAX, adflow_comm_world, ierr) call EChk(ierr, __FILE__, __LINE__) - ! write (*,*) "rank", myID, " final cav number ", cavitationNumber - - end subroutine computeCavitationNumber + end subroutine computeCpMinExact #ifndef USE_COMPLEX subroutine integrateSurfaces_d(localValues, localValuesd, famList) @@ -1281,7 +1278,7 @@ subroutine getSolution_d(famLists, funcValues, funcValuesd) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCavitationNumber(famList) + call computeCpMinExact(famList) end if localVal = zero @@ -1367,7 +1364,7 @@ subroutine getSolution_b(famLists, funcValues, funcValuesd) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCavitationNumber(famList) + call computeCpMinExact(famList) end if localVal = zero From 335e0979a13a800cb8781da366b02185c6cf2583 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 24 Sep 2022 22:56:35 -0400 Subject: [PATCH 31/76] reran tapenade --- .../outputForward/surfaceintegrations_d.f90 | 38 ++++++++++--------- .../outputReverse/surfaceintegrations_b.f90 | 35 ++++++++--------- .../surfaceintegrations_fast_b.f90 | 14 +++---- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 20335e678..4c8d24c90 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -842,7 +842,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cpmin_exact, cpmin_rho +& cpmin_exact, cpmin_rho, cavitationnumber use bcpointers_d implicit none ! input/output variables @@ -855,16 +855,19 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype), dimension(3) :: fpd, fvd, mpd, mvd real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation, cp_min_ks - real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd +& cavitation, cpmin_ks_sum + real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd, & +& cpmin_ks_sumd integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: pm1d, fxd, fyd, fzd real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l real(kind=realtype) :: xcd, ycd, zcd, rd(3) real(kind=realtype) :: fact, rho, mul, yplus, dwall - real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal - real(kind=realtype) :: vd(3), sensord, sensor1d, cpd, tmpd, plocald + real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal, & +& ks_exponent + real(kind=realtype) :: vd(3), sensord, sensor1d, cpd, tmpd, plocald& +& , ks_exponentd real(kind=realtype) :: tauxx, tauyy, tauzz real(kind=realtype) :: tauxxd, tauyyd, tauzzd real(kind=realtype) :: tauxy, tauxz, tauyz @@ -888,9 +891,6 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype) :: result1d real(kind=realtype) :: pwr1 real(kind=realtype) :: pwr1d - real :: cavitationnumber - real(kind=realtype) :: ks_exponent - real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -922,13 +922,14 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) yplusmax = zero sepsensor = zero cavitation = zero - cp_min_ks = zero + cpmin_ks_sum = zero sepsensoravg = zero mpaxis = zero mvaxis = zero cperror2 = zero sepsensoravgd = 0.0_8 rd = 0.0_8 + cpmin_ks_sumd = 0.0_8 vd = 0.0_8 mpaxisd = 0.0_8 cperror2d = 0.0_8 @@ -1152,7 +1153,9 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation + ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp-cpmin_exact))) ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + cpmin_ks_sumd = cpmin_ks_sumd + blk*ks_exponentd cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -1331,7 +1334,8 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvaluesd(icavitation) = localvaluesd(icavitation) + cavitationd localvalues(icavitation) = localvalues(icavitation) + cavitation - localvalues(icpmin) = localvalues(icpmin) + cp_min_ks + localvaluesd(icpmin) = localvaluesd(icpmin) + cpmin_ks_sumd + localvalues(icpmin) = localvalues(icpmin) + cpmin_ks_sum localvaluesd(isepavg:isepavg+2) = localvaluesd(isepavg:isepavg+2) + & & sepsensoravgd localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & @@ -1360,7 +1364,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho +& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber use bcpointers_d implicit none ! input/output variables @@ -1370,12 +1374,13 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation, cp_min_ks +& cavitation, cpmin_ks_sum integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l real(kind=realtype) :: fact, rho, mul, yplus, dwall - real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal + real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal, & +& ks_exponent real(kind=realtype) :: tauxx, tauyy, tauzz real(kind=realtype) :: tauxy, tauxz, tauyz real(kind=realtype), dimension(3) :: refpoint @@ -1390,9 +1395,6 @@ subroutine wallintegrationface(localvalues, mm) real(kind=realtype) :: arg1 real(kind=realtype) :: result1 real(kind=realtype) :: pwr1 - real :: cavitationnumber - real(kind=realtype) :: ks_exponent - real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -1420,7 +1422,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero - cp_min_ks = zero + cpmin_ks_sum = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -1670,7 +1672,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation - localvalues(icpmin) = localvalues(icpmin) + cp_min_ks + localvalues(icpmin) = localvalues(icpmin) + cpmin_ks_sum localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index 7c4327e5a..ec03b574b 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -1070,7 +1070,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cpmin_exact, cpmin_rho +& cpmin_exact, cpmin_rho, cavitationnumber use bcpointers_b implicit none ! input/output variables @@ -1083,16 +1083,19 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype), dimension(3) :: fpd, fvd, mpd, mvd real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation, cp_min_ks - real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd +& cavitation, cpmin_ks_sum + real(kind=realtype) :: sepsensord, sepsensoravgd(3), cavitationd, & +& cpmin_ks_sumd integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: pm1d, fxd, fyd, fzd real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l real(kind=realtype) :: xcd, ycd, zcd, rd(3) real(kind=realtype) :: fact, rho, mul, yplus, dwall - real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal - real(kind=realtype) :: vd(3), sensord, sensor1d, cpd, tmpd, plocald + real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal, & +& ks_exponent + real(kind=realtype) :: vd(3), sensord, sensor1d, cpd, tmpd, plocald& +& , ks_exponentd real(kind=realtype) :: tauxx, tauyy, tauzz real(kind=realtype) :: tauxxd, tauyyd, tauzzd real(kind=realtype) :: tauxy, tauxz, tauyz @@ -1121,7 +1124,6 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: temp0 real(kind=realtype) :: tempd11 real(kind=realtype) :: tempd10 - real :: cavitationnumber real(kind=realtype) :: tempd9 real(kind=realtype) :: tempd real(kind=realtype) :: tempd8(3) @@ -1134,13 +1136,11 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: tempd1 real(kind=realtype) :: tempd0 real(kind=realtype) :: tmpd0(3) - real(kind=realtype) :: ks_exponent real(kind=realtype) :: tempd24 real(kind=realtype) :: tempd23 real(kind=realtype) :: tempd22 real(kind=realtype) :: tempd21 real(kind=realtype) :: tempd20 - real*8 :: cpmin_ks_sum real(kind=realtype) :: temp real(kind=realtype) :: tempd19 real(kind=realtype) :: tempd18 @@ -1321,6 +1321,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) mvaxisd = localvaluesd(iaxismoment) sepsensoravgd = 0.0_8 sepsensoravgd = localvaluesd(isepavg:isepavg+2) + cpmin_ks_sumd = localvaluesd(icpmin) cavitationd = localvaluesd(icavitation) sepsensord = localvaluesd(isepsensor) mvd = 0.0_8 @@ -1615,7 +1616,9 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) & cavexponent/temp5**2+cavexponent*sensor1**(cavexponent-1)/& & temp5)*sensor1d end if - cpd = -sensor1d + ks_exponentd = blk*cpmin_ks_sumd + cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(-cpmin_exact-cp))*& +& ks_exponentd tmpd = (plocal-pinf)*cpd plocald = tmp*cpd pinfd = pinfd - tmp*cpd @@ -1798,7 +1801,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho +& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber use bcpointers_b implicit none ! input/output variables @@ -1808,12 +1811,13 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation, cp_min_ks +& cavitation, cpmin_ks_sum integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l real(kind=realtype) :: fact, rho, mul, yplus, dwall - real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal + real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal, & +& ks_exponent real(kind=realtype) :: tauxx, tauyy, tauzz real(kind=realtype) :: tauxy, tauxz, tauyz real(kind=realtype), dimension(3) :: refpoint @@ -1825,9 +1829,6 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - real :: cavitationnumber - real(kind=realtype) :: ks_exponent - real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -1855,7 +1856,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero - cp_min_ks = zero + cpmin_ks_sum = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -2100,7 +2101,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation - localvalues(icpmin) = localvalues(icpmin) + cp_min_ks + localvalues(icpmin) = localvalues(icpmin) + cpmin_ks_sum localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index fd56f75d7..f37be683e 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -288,7 +288,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho +& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber use bcpointers_fast_b implicit none ! input/output variables @@ -298,12 +298,13 @@ subroutine wallintegrationface(localvalues, mm) ! local variables. real(kind=realtype), dimension(3) :: fp, fv, mp, mv real(kind=realtype) :: yplusmax, sepsensor, sepsensoravg(3), & -& cavitation, cp_min_ks +& cavitation, cpmin_ks_sum integer(kind=inttype) :: i, j, ii, blk real(kind=realtype) :: pm1, fx, fy, fz, fn real(kind=realtype) :: xc, yc, zc, qf(3), r(3), n(3), l real(kind=realtype) :: fact, rho, mul, yplus, dwall - real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal + real(kind=realtype) :: v(3), sensor, sensor1, cp, tmp, plocal, & +& ks_exponent real(kind=realtype) :: tauxx, tauyy, tauzz real(kind=realtype) :: tauxy, tauxz, tauyz real(kind=realtype), dimension(3) :: refpoint @@ -315,9 +316,6 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - real :: cavitationnumber - real(kind=realtype) :: ks_exponent - real*8 :: cpmin_ks_sum select case (bcfaceid(mm)) case (imin, jmin, kmin) fact = -one @@ -345,7 +343,7 @@ subroutine wallintegrationface(localvalues, mm) yplusmax = zero sepsensor = zero cavitation = zero - cp_min_ks = zero + cpmin_ks_sum = zero sepsensoravg = zero mpaxis = zero mvaxis = zero @@ -590,7 +588,7 @@ subroutine wallintegrationface(localvalues, mm) localvalues(imv:imv+2) = localvalues(imv:imv+2) + mv localvalues(isepsensor) = localvalues(isepsensor) + sepsensor localvalues(icavitation) = localvalues(icavitation) + cavitation - localvalues(icpmin) = localvalues(icpmin) + cp_min_ks + localvalues(icpmin) = localvalues(icpmin) + cpmin_ks_sum localvalues(isepavg:isepavg+2) = localvalues(isepavg:isepavg+2) + & & sepsensoravg localvalues(iaxismoment) = localvalues(iaxismoment) + mpaxis + & From e1cd57312cfc65799bed62aa3fe8a29ba5a5570a Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 24 Sep 2022 23:00:52 -0400 Subject: [PATCH 32/76] more fixes to recover the og cavitation sensor --- src/f2py/adflow.pyf | 2 +- src/modules/inputParam.F90 | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/f2py/adflow.pyf b/src/f2py/adflow.pyf index cc79ac0f4..2d234a9d1 100644 --- a/src/f2py/adflow.pyf +++ b/src/f2py/adflow.pyf @@ -1222,7 +1222,7 @@ python module libadflow real(kind=realtype) :: alpha real(kind=realtype) :: beta integer(kind=inttype) :: liftindex - real(kind=realtype) :: cavitationsensor + real(kind=realtype) :: cavitationnumber real(kind=realtype) :: cpmin_rho end module inputphysics diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index d8805007d..1b9453881 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -582,7 +582,6 @@ module inputPhysics real(kind=realType), dimension(3,2) :: momentAxis real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber - real(kind=realType) :: cavitationsensor real(kind=realType) :: cpmin_rho real(kind=realType) :: cpmin_exact From 16ccd461025da3a00ca2f8859e8661efb34e305f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 24 Sep 2022 23:03:18 -0400 Subject: [PATCH 33/76] remove high quality debug print --- src/overset/oversetAPI.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index b9ba567a0..8d344abb3 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2193,8 +2193,6 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl ! Node count is no longer needed deallocate(normCount) - ! write(*,*) myid, "after weird norm calc" - ! Allocate the extra data the tree search requires. allocate(stack(100), BB(20), frontLeaves(25), frontLeavesNew(25)) From 8c94d2502c271e3e26905b4c74e6efc38c60992a Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 24 Sep 2022 23:13:15 -0400 Subject: [PATCH 34/76] variable cleanup --- src/overset/oversetAPI.F90 | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index 8d344abb3..49beab441 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2123,7 +2123,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl integer(kind=intType) :: i, j, k, l, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr integer(kind=intType) :: iblock, cell_counter, k_cgns real(kind=realType) :: dStar, frac, volLocal - real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, xCen, axisVec + real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, axisVec real(kind=realType), dimension(3) :: diag1, diag2, diag3, diag4 real(kind=realType) :: dd1, dd2, dd3, dd4, diag_max type(adtType) :: ADT @@ -2239,26 +2239,24 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl do l=1, 8 select case (l) case (1) - xCen = x(i-1,j-1,k-1,:) + coor(1:3) = x(i-1,j-1,k-1,:) case (2) - xCen = x(i, j-1,k-1,:) + coor(1:3) = x(i, j-1,k-1,:) case (3) - xCen = x(i, j, k-1,:) + coor(1:3) = x(i, j, k-1,:) case (4) - xCen = x(i-1,j, k-1,:) + coor(1:3) = x(i-1,j, k-1,:) case (5) - xCen = x(i-1,j-1,k, :) + coor(1:3) = x(i-1,j-1,k, :) case (6) - xCen = x(i, j-1,k, :) + coor(1:3) = x(i, j-1,k, :) case (7) - xCen = x(i, j, k, :) + coor(1:3) = x(i, j, k, :) case (8) - xCen = x(i-1,j, k, :) + coor(1:3) = x(i-1,j, k, :) end select - ! The current point to search for and continually ! reset the "closest point already found" variable. - coor(1:3) = xCen coor(4) = dStar intInfo(3) = 0 call minDistancetreeSearchSinglePoint(ADT, coor, intInfo, & From 444819f37e7867900a34ee3bc66111ee772048ba Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 21:53:58 -0400 Subject: [PATCH 35/76] bug fixes --- adflow/pyADflow.py | 2 +- src/solver/surfaceIntegrations.F90 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index d24359c02..38f4eb842 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -5592,7 +5592,7 @@ def _getOptionMap(self): "restrictionrelaxation": ["iter", "fcoll"], "forcesastractions": ["physics", "forcesastractions"], "lowspeedpreconditioner": ["discr", "lowspeedpreconditioner"], - "cavitationnumber": ["physics", "cavitationsensor"], + "cavitationnumber": ["physics", "cavitationnumber"], "cpminrho": ["physics", "cpmin_rho"], # Common Parameters "ncycles": ["iter", "ncycles"], diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index b078e4702..4cf63b04a 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -1096,7 +1096,7 @@ subroutine computeCpMinExact(famList) ! the goal is to get a differentiable cpmin output ! set the local cp min to a small value so that we get the actual min - cpmin_local = -10000.0_realType + cpmin_local = 10000.0_realType ! loop over the TS instances just because its the same convention everywhere. ! in an actual TS computation, this wont work most likely. @@ -1143,7 +1143,7 @@ subroutine computeCpMinExact(famList) ! finally communicate across all processors call mpi_allreduce(cpmin_local, cpmin_exact, 1, adflow_real, & - MPI_MAX, adflow_comm_world, ierr) + MPI_MIN, adflow_comm_world, ierr) call EChk(ierr, __FILE__, __LINE__) end subroutine computeCpMinExact From 8f2e330effb1c9ad8b0f2cbb411d808ddfc2d59d Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 22:24:09 -0400 Subject: [PATCH 36/76] complexify fixes --- src/overset/oversetAPI.F90 | 7 ++++++- src/solver/surfaceIntegrations.F90 | 19 +++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index 49beab441..3826c45e6 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2109,6 +2109,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl use blockPointers, only : x, il, jl, kl, nDom, iBlank, vol, nbkGlobal, kBegOr use adjointVars, only : nCellsLocal use utils, only : setPointers, EChk + use sorting, only : famInList implicit none ! Input/Output @@ -2206,7 +2207,11 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl call setPointers(nn, level, sps) ! only check this cell if it is within one of the block IDs we are asked to look at - if (any( blockids .eq. nbkGlobal) )then + ! here, we reuse the famInList function from sorting.F90. The reason is just having + ! if (any(blockids == nbkGlobal)) does not work with complexify; complexify changes the + ! == (or .eq.) to .ceq., which does not work with integers. The famInList is originally + ! written for surface integrations, but the same idea applies here. + if (famInList(nbkGlobal, blockids))then do k=2, kl do j=2, jl do i=2, il diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 4cf63b04a..927b888d9 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -1073,8 +1073,9 @@ subroutine integrateSurfaces(localValues, famList) end subroutine integrateSurfaces subroutine computeCpMinExact(famList) + use constants - use inputTimeSpectral , only : nTimeIntervalsSpectral + use inputTimeSpectral, only : nTimeIntervalsSpectral use communication, only : ADflow_comm_world, myID use blockPointers, only : nDom use inputPhysics, only : cpmin_exact, MachCoef @@ -1084,15 +1085,17 @@ subroutine computeCpMinExact(famList) use utils, only : setPointers, setBCPointers, isWallType, EChk use sorting, only : famInList - implicit none + implicit none integer(kind=intType), dimension(:), intent(in) :: famList integer(kind=intType) :: mm, nn, sps integer(kind=intType) :: i, j, ii, blk, ierr real(kind=realType) :: Cp, plocal, tmp, cpmin_local - ! this routine loops over the surface cells in the given family and computes the true minimum Cp value. - ! this is then used in the surface integration routine to compute the cpmin using KS aggregation. + ! this routine loops over the surface cells in the given family + ! and computes the true minimum Cp value. + ! this is then used in the surface integration routine to compute + ! the cpmin using KS aggregation. ! the goal is to get a differentiable cpmin output ! set the local cp min to a small value so that we get the actual min @@ -1100,8 +1103,8 @@ subroutine computeCpMinExact(famList) ! loop over the TS instances just because its the same convention everywhere. ! in an actual TS computation, this wont work most likely. - ts: do sps=1, nTimeIntervalsSpectral - domains: do nn=1, nDom + do sps=1, nTimeIntervalsSpectral + do nn=1, nDom call setPointers(nn, 1, sps) ! Loop over all possible boundary conditions @@ -1138,8 +1141,8 @@ subroutine computeCpMinExact(famList) end if famInclude end do bocos - end do domains - end do ts + end do + end do ! finally communicate across all processors call mpi_allreduce(cpmin_local, cpmin_exact, 1, adflow_real, & From 6c3db5f66873e7365ff8c158c92c79d691ffa37a Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 22:40:13 -0400 Subject: [PATCH 37/76] fix black --- adflow/pyADflow.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 38f4eb842..a83f58d5f 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -697,10 +697,28 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No # name...so we will number sequentially from python j = self.nSlice + i + 1 if sliceType == "relative": - sliceName = "Slice_%4.4d %s Para Init Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % (j, groupTag, normals[i, 0], normals[i, 1], normals[i, 2], points[i, 0], points[i, 1], points[i, 2]) + sliceName = "Slice_%4.4d %s Para Init Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( + j, + groupTag, + normals[i, 0], + normals[i, 1], + normals[i, 2], + points[i, 0], + points[i, 1], + points[i, 2], + ) self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) else: - sliceName = "Slice_%4.4d %s Absolute Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % (j, groupTag, normals[i, 0], normals[i, 1], normals[i, 2], points[i, 0], points[i, 1], points[i, 2]) + sliceName = "Slice_%4.4d %s Absolute Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( + j, + groupTag, + normals[i, 0], + normals[i, 1], + normals[i, 2], + points[i, 0], + points[i, 1], + points[i, 2], + ) self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) self.nSlice += n_slice @@ -775,11 +793,13 @@ def addCylindricalSlices( vy = vec1[1] vz = vec1[2] # rotation matrix by theta about vec1 - rot_mat = numpy.array([ - [cos + vx * vx * omc, vx * vy * omc - vz * sin, vx * vz * omc + vy * sin], - [vy * vx * omc + vz * sin, cos + vy * vy * omc, vy * vz * omc - vx * sin], - [vz * vx * omc - vy * sin, vz * vy * omc + vx * sin, cos + vz * vz * omc], - ]) + rot_mat = numpy.array( + [ + [cos + vx * vx * omc, vx * vy * omc - vz * sin, vx * vz * omc + vy * sin], + [vy * vx * omc + vz * sin, cos + vy * vy * omc, vy * vz * omc - vx * sin], + [vz * vx * omc - vy * sin, vz * vy * omc + vx * sin, cos + vz * vz * omc], + ] + ) # rotate the lift direction vector to get the slice direction slice_dir = rot_mat.dot(lift_dir) From 65a364fb03b691b0788d2b59edff2c0cb3a8111c Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 22:40:28 -0400 Subject: [PATCH 38/76] add cavitation test trained with the og cavitation sensor --- tests/reg_tests/refs/cavitation_tests.json | 243 +++++++++++++++++++ tests/reg_tests/reg_aeroproblems.py | 15 ++ tests/reg_tests/test_cavitation.py | 265 +++++++++++++++++++++ 3 files changed, 523 insertions(+) create mode 100644 tests/reg_tests/refs/cavitation_tests.json create mode 100644 tests/reg_tests/test_cavitation.py diff --git a/tests/reg_tests/refs/cavitation_tests.json b/tests/reg_tests/refs/cavitation_tests.json new file mode 100644 index 000000000..ec196479e --- /dev/null +++ b/tests/reg_tests/refs/cavitation_tests.json @@ -0,0 +1,243 @@ +{ + "Dot product test for w -> cavitation": -0.3915858868609155, + "Dot product test for xV -> cavitation": 0.04422042901616901, + "cavitation outputs": { + "naca0012_rans_2D_cavitation": 0.12991147313880522 + }, + "cavitation totals": { + "naca0012_rans_2D_cavitation": { + "alpha": 0.09506523526801869 + } + }, + "metadata": { + "ADPC": false, + "AGMGLevels": 1, + "AGMGNSmooth": 3, + "ANKADPC": false, + "ANKASMOverlap": 1, + "ANKCFL0": 5.0, + "ANKCFLCutback": 0.5, + "ANKCFLExponent": 0.5, + "ANKCFLFactor": 10.0, + "ANKCFLLimit": 100000.0, + "ANKCFLMin": 1.0, + "ANKConstCFLStep": 0.4, + "ANKCoupledSwitchTol": 1e-16, + "ANKInnerPreconIts": 1, + "ANKJacobianLag": 10, + "ANKLinResMax": 0.1, + "ANKLinearSolveTol": 0.05, + "ANKMaxIter": 40, + "ANKNSubiterTurb": 1, + "ANKOuterPreconIts": 1, + "ANKPCILUFill": 2, + "ANKPCUpdateTol": 0.5, + "ANKPhysicalLSTol": 0.2, + "ANKPhysicalLSTolTurb": 0.99, + "ANKSecondOrdSwitchTol": 0.01, + "ANKStepFactor": 1.0, + "ANKStepMin": 0.01, + "ANKSubspaceSize": -1, + "ANKSwitchTol": 1000.0, + "ANKTurbCFLScale": 1.0, + "ANKTurbKSPDebug": false, + "ANKUnsteadyLSTol": 1.0, + "ANKUseFullVisc": true, + "ANKUseMatrixFree": true, + "ANKUseTurbDADI": true, + "ASMOverlap": 1, + "CFL": 1.7, + "CFLCoarse": 1.0, + "CFLLimit": 1.5, + "GMRESOrthogonalizationType": "modified Gram-Schmidt", + "ILUFill": 2, + "L2Convergence": 1e-13, + "L2ConvergenceCoarse": 0.01, + "L2ConvergenceRel": 1e-16, + "MGCycle": "sg", + "MGStartLevel": -1, + "NKADPC": false, + "NKASMOverlap": 1, + "NKFixedStep": 0.25, + "NKInnerPreconIts": 1, + "NKJacobianLag": 20, + "NKLS": "cubic", + "NKLinearSolveTol": 0.3, + "NKOuterPreconIts": 1, + "NKPCILUFill": 2, + "NKSubspaceSize": 60, + "NKSwitchTol": 1e-06, + "NKUseEW": true, + "NKViscPC": false, + "RKReset": false, + "TSStability": false, + "adjointDivTol": 100000.0, + "adjointL2Convergence": 1e-13, + "adjointL2ConvergenceAbs": 1e-16, + "adjointL2ConvergenceRel": 1e-16, + "adjointMaxIter": 500, + "adjointMaxL2DeviationFactor": 1.0, + "adjointMonitorStep": 10, + "adjointSolver": "GMRES", + "adjointSubspaceSize": 100, + "alphaFollowing": true, + "alphaMode": false, + "altitudeMode": false, + "applyAdjointPCSubspaceSize": 20, + "applyPCSubspaceSize": 10, + "approxPC": true, + "backgroundVolScale": 1.0, + "betaMode": false, + "blockSplitting": true, + "cavExponent": 0, + "cavSensorOffset": 0.0, + "cavSensorSharpness": 10.0, + "cavitationNumber": 1.0, + "closedSurfaceFamilies": null, + "coarseDiscretization": "central plus scalar dissipation", + "computeCavitation": true, + "coupledSolution": false, + "cutCallback": null, + "debugZipper": false, + "deltaT": 0.01, + "designSurfaceFamily": null, + "discretization": "central plus scalar dissipation", + "dissipationLumpingParameter": 6.0, + "dissipationScalingExponent": 0.67, + "eddyVisInfRatio": 0.009, + "equationMode": "steady", + "equationType": "RANS", + "eulerWallTreatment": "linear pressure extrapolation", + "firstRun": true, + "flowType": "external", + "forcesAsTractions": true, + "frozenTurbulence": false, + "globalPreconditioner": "additive Schwarz", + "gridFile": "input_files/naca0012_rans-L2.cgns", + "gridPrecision": "double", + "gridPrecisionSurface": "single", + "infChangeCorrection": true, + "innerPreconIts": 1, + "isoVariables": [], + "isosurface": {}, + "liftIndex": 2, + "limiter": "van Albada", + "loadBalanceIter": 10, + "loadImbalance": 0.1, + "localPreconditioner": "ILU", + "lowSpeedPreconditioner": false, + "machMode": false, + "matrixOrdering": "RCM", + "maxL2DeviationFactor": 1.0, + "meshSurfaceFamily": null, + "monitorVariables": [ + "cpu", + "resrho", + "resturb", + "cl", + "cd" + ], + "nCycles": 1000, + "nCyclesCoarse": 500, + "nFloodIter": -1, + "nRKReset": 5, + "nRefine": 10, + "nSaveSurface": 1, + "nSaveVolume": 1, + "nSubiter": 1, + "nSubiterTurb": 3, + "nTimeStepsCoarse": 48, + "nTimeStepsFine": 400, + "nearWallDist": 0.1, + "numberSolutions": true, + "outerPreconIts": 3, + "outputDirectory": "tests/output_files", + "outputSurfaceFamily": "allSurfaces", + "overlapFactor": 0.9, + "oversetLoadBalance": true, + "oversetPriority": {}, + "oversetProjTol": 1e-12, + "oversetUpdateMode": "frozen", + "pMode": false, + "partitionLikeNProc": -1, + "partitionOnly": false, + "preconditionerSide": "right", + "printAllOptions": true, + "printIntro": true, + "printIterations": true, + "printTiming": true, + "printWarnings": true, + "qMode": false, + "rMode": false, + "resAveraging": "alternate", + "restartAdjoint": true, + "restartFile": null, + "restrictionRelaxation": 0.8, + "selfZipCutoff": 120.0, + "sepSensorOffset": 0.0, + "sepSensorSharpness": 10.0, + "setMonitor": true, + "skipAfterFailedAdjoint": true, + "smoothParameter": 1.5, + "smoother": "Runge-Kutta", + "solutionPrecision": "single", + "solutionPrecisionSurface": "single", + "storeConvHist": true, + "storeRindLayer": true, + "surfaceVariables": [ + "cp", + "vx", + "vy", + "vz", + "mach" + ], + "timeAccuracy": 2, + "timeIntegrationScheme": "BDF", + "timeIntervals": 1, + "timeLimit": -1.0, + "turbResScale": 10000.0, + "turbulenceModel": "SA", + "turbulenceOrder": "first order", + "turbulenceProduction": "strain", + "useALE": true, + "useANKSolver": true, + "useApproxWallDistance": true, + "useBlockettes": true, + "useDiagTSPC": true, + "useExternalDynamicMesh": false, + "useGridMotion": false, + "useLinResMonitor": false, + "useMatrixFreedrdw": true, + "useNKSolver": true, + "useOversetWallScaling": false, + "useQCR": false, + "useRotationSA": false, + "useTSInterpolatedGridVelocity": false, + "useWallFunctions": false, + "useZipperMesh": true, + "useft2SA": true, + "verifyExtra": true, + "verifySpatial": true, + "verifyState": true, + "vis2": 0.25, + "vis2Coarse": 0.5, + "vis4": 0.0156, + "viscPC": false, + "viscWallTreatment": "constant pressure extrapolation", + "viscousSurfaceVelocities": true, + "volumeVariables": [ + "temp", + "mach", + "resrho", + "cp" + ], + "wallDistCutoff": 1e+20, + "windAxis": false, + "writeSolutionEachIter": false, + "writeSurfaceSolution": false, + "writeTecplotSurfaceSolution": false, + "writeVolumeSolution": false, + "zipperSurfaceFamily": null + }, + "total cavitation derivative wrt random volume perturbation": -2.0565995469114675 +} \ No newline at end of file diff --git a/tests/reg_tests/reg_aeroproblems.py b/tests/reg_tests/reg_aeroproblems.py index b1728049a..7c736ea47 100644 --- a/tests/reg_tests/reg_aeroproblems.py +++ b/tests/reg_tests/reg_aeroproblems.py @@ -103,6 +103,21 @@ sinCoefFourier=[deltaAlpha], ) +ap_naca0012_cavitation = AeroProblem( + name="0012cavitation", + alpha=alpha_m, + mach=M, + machRef=M, + reynolds=4800000.0, + reynoldsLength=c, + T=T, + R=R, + areaRef=1.0, + chordRef=c, + evalFuncs=["cavitation"], + xRef=0.25, +) + ap_naca64A010_time_spectral = AeroProblem( name="64A010pitchingTS", alpha=0.0, diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py new file mode 100644 index 000000000..4d121af7a --- /dev/null +++ b/tests/reg_tests/test_cavitation.py @@ -0,0 +1,265 @@ +# built-ins +import unittest +import numpy as np +import os +import copy + +# MACH classes +from adflow import ADFLOW +from adflow import ADFLOW_C + +# import the testing utilities that live a few directories up +from reg_default_options import adflowDefOpts +from reg_aeroproblems import ap_naca0012_cavitation +import reg_test_classes + +baseDir = os.path.dirname(os.path.abspath(__file__)) + + +class CavitationBasicTests(reg_test_classes.RegTest): + """ + Tests for the cavitation metrics. + """ + + N_PROCS = 2 + ref_file = "cavitation_tests.json" + + def setUp(self): + super().setUp() + + gridFile = os.path.join(baseDir, "../../input_files/naca0012_rans-L2.cgns") + + options = copy.copy(adflowDefOpts) + options.update( + { + "gridfile": gridFile, + "outputdirectory": os.path.join(baseDir, "../output_files"), + "writevolumesolution": False, + "writesurfacesolution": False, + "writetecplotsurfacesolution": False, + "mgcycle": "sg", + "ncycles": 1000, + "useanksolver": True, + "usenksolver": True, + "anksecondordswitchtol": 1e-2, + "nkswitchtol": 1e-6, + "volumevariables": ["temp", "mach", "resrho", "cp"], + "equationType": "RANS", + "l2convergence": 1e-13, + "adjointl2convergence": 1e-13, + "computeCavitation": True, + "cavitationNumber": 1.0, + "cpminrho": 1.0, + } + ) + + # Setup aeroproblem + self.ap = copy.copy(ap_naca0012_cavitation) + # change the name + self.ap.name = "naca0012_rans_2D" + + # add aoa DV + self.ap.addDV("alpha", name="alpha") + + CFDSolver = ADFLOW(options=options) + + self.CFDSolver = CFDSolver + + def test_cavitation_metrics_and_derivatives(self): + "Tests if the correct amount of momentum is added to the flow by the actuator" + + evalFuncs = ["cavitation"] + + self.CFDSolver(self.ap) + + # check if solution failed + self.assert_solution_failure() + + ################ + # TEST ALL FUNCS + ################ + funcs = {} + self.CFDSolver.evalFunctions(self.ap, funcs, evalFuncs=evalFuncs) + self.handler.root_print("cavitation outputs") + self.handler.root_add_dict("cavitation outputs", funcs, rtol=1e-10, atol=1e-10) + + ############# + # TEST TOTALS + ############# + funcsSens = {} + self.CFDSolver.evalFunctionsSens(self.ap, funcsSens, evalFuncs=evalFuncs) + self.handler.root_print("cavitation totals") + self.handler.root_add_dict("cavitation totals", funcsSens, rtol=1e-10, atol=1e-10) + + # Now that we have the adjoint solution, + # also get a total derivative wrt a random spatial perturbation DV + psi = -self.CFDSolver.getAdjoint("cavitation") + funcsBar = self.CFDSolver._getFuncsBar("cavitation") + + # this is the reverse seed up to the volume coordinates + xVBar = self.CFDSolver.computeJacobianVectorProductBwd(resBar=psi, funcsBar=funcsBar, xVDeriv=True) + # get a random volume perturbation + xVDot = self.CFDSolver.getSpatialPerturbation(314) + + # dot product these two vectors to get a total derivative + dotLocal = np.dot(xVDot, xVBar) + self.handler.par_add_sum("total cavitation derivative wrt random volume perturbation", dotLocal, rtol=1e-10) + + ################## + # DOT PRODUCT TEST + ################## + wDot = self.CFDSolver.getStatePerturbation(314) + # xVDot was evaluated above so no need to re-run the spatial perturbation routine + + for func_name in evalFuncs: + fDot_w = self.CFDSolver.computeJacobianVectorProductFwd(wDot=wDot, funcDeriv=True) + fDot_xv = self.CFDSolver.computeJacobianVectorProductFwd(xVDot=xVDot, funcDeriv=True) + funcsBar = {func_name: 1.0} + wBar, xVBar = self.CFDSolver.computeJacobianVectorProductBwd(funcsBar=funcsBar, wDeriv=True, xVDeriv=True) + + # do the dot product. we test both state partials and volume coordinate partials + # state + dotLocal1 = np.dot(wDot, wBar) + dotLocal2 = fDot_w[func_name] / self.CFDSolver.comm.size + + self.handler.par_add_sum(f"Dot product test for w -> {func_name}", dotLocal1, rtol=1e-10) + self.handler.par_add_sum(f"Dot product test for w -> {func_name}", dotLocal2, rtol=1e-10, compare=True) + + # volume coords + dotLocal1 = np.dot(xVDot, xVBar) + dotLocal2 = fDot_xv[func_name] / self.CFDSolver.comm.size + self.handler.par_add_sum(f"Dot product test for xV -> {func_name}", dotLocal1, rtol=1e-10) + self.handler.par_add_sum(f"Dot product test for xV -> {func_name}", dotLocal2, rtol=1e-10, compare=True) + + +class CavitationCmplxTests(reg_test_classes.CmplxRegTest): + """ + Complex step tests for the cavitation functions. + """ + + N_PROCS = 2 + ref_file = "cavitation_tests.json" + h = 1e-40 + + def setUp(self): + super().setUp() + + gridFile = os.path.join(baseDir, "../../input_files/naca0012_rans-L2.cgns") + + options = copy.copy(adflowDefOpts) + options.update( + { + "gridfile": gridFile, + "outputdirectory": os.path.join(baseDir, "../output_files"), + "writevolumesolution": False, + "writesurfacesolution": False, + "writetecplotsurfacesolution": False, + "mgcycle": "sg", + "ncycles": 1000, + "useanksolver": True, + "usenksolver": True, + "anksecondordswitchtol": 1e-2, + "nkswitchtol": 1e-6, + "volumevariables": ["temp", "mach", "resrho", "cp"], + "equationType": "RANS", + "l2convergence": 1e-13, + "adjointl2convergence": 1e-13, + "computeCavitation": True, + "cavitationNumber": 1.0, + "NKUseEW": False, + "NKLinearSolveTol": 1e-4, + } + ) + + # Setup aeroproblem + self.ap = copy.copy(ap_naca0012_cavitation) + # change the name + self.ap.name = "naca0012_rans_2D" + + # add aoa DV + self.ap.addDV("alpha", name="alpha") + + CFDSolver = ADFLOW_C(options=options, debug=True) + + self.CFDSolver = CFDSolver + + def cmplx_test_cavitation_adjoints(self): + + aDV = {"alpha": self.ap.alpha} + funcs = {} + funcsSensCS = {} + + # run the baseline evaluation + self.CFDSolver(self.ap) + # check if solution failed + self.assert_solution_failure() + self.CFDSolver.evalFunctions(self.ap, funcs) + + funcs_plus = {} + for dv in ["alpha", "vol_perturbation"]: + if dv == "alpha": + # save the old alpha + dvsave = aDV["alpha"] + # perturb + aDV["alpha"] += self.h * 1j + self.ap.setDesignVars(aDV) + elif dv == "vol_perturbation": + xVDot = self.CFDSolver.getSpatialPerturbation(314) + # grid_save = np.zeros_like(xVDot) + # get the original grid + grid_save = self.CFDSolver.adflow.warping.getgrid(self.CFDSolver.getSpatialSize()) + # perturb using the random seed + # this is very intrusive but it works and its testing these functions sensitivities + # wrt geometric DVs w/o actually having a mesh or dvgeo object + self.CFDSolver.adflow.warping.setgrid(grid_save + self.h * 1j * xVDot) + self.CFDSolver.adflow.preprocessingapi.updatecoordinatesalllevels() + self.CFDSolver.adflow.walldistance.updatewalldistancealllevels() + self.CFDSolver.adflow.preprocessingapi.updatemetricsalllevels() + self.CFDSolver.adflow.preprocessingapi.updategridvelocitiesalllevels() + + # call solver again + # we can also not re-set the flow and call the solver a few times until complex parts converge + self.CFDSolver.resetFlow(self.ap) + self.CFDSolver(self.ap) # the complex residuals dont converge well for the coordinate perturbation + + # check if solution failed + self.assert_solution_failure() + + # save the new funcs in a dict + funcs_plus[dv] = {} + + # eval functions + self.CFDSolver.evalFunctions(self.ap, funcs_plus[dv]) + + # compute the sens + funcsSensCS[dv] = {} + for f in ["cavitation"]: + funcsSensCS[dv][self.ap[f]] = np.imag(funcs_plus[dv][self.ap[f]]) / self.h + + # reset the DV + if dv == "alpha": + aDV["alpha"] = dvsave + self.ap.setDesignVars(aDV) + elif dv == "vol_perturbation": + # set the original grid back + self.CFDSolver.adflow.warping.setgrid(grid_save) + + ################## + # TEST DERIVATIVES + ################## + + # here we compare the CS derivatives to the adjoint values computed by the real test + # we treat the CS value as the truth, so if this test passes, + # we assume the adjoint sensitivities are also true + + func_name = "naca0012_rans_2D_cavitation" + + ref_val = self.handler.db["cavitation totals"][func_name]["alpha"] + np.testing.assert_allclose(funcsSensCS["alpha"][func_name], ref_val, atol=1e-10, rtol=1e-10) + + ref_val = self.handler.db["total cavitation derivative wrt random volume perturbation"] + np.testing.assert_allclose(funcsSensCS["vol_perturbation"][func_name], ref_val, rtol=1e-4) + + +if __name__ == "__main__": + unittest.main() From 3b3beefe014a38700a6bf40b4bc77723afc0b7c3 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 23:53:19 -0400 Subject: [PATCH 39/76] bugfixes and reran tapenade --- .../outputForward/surfaceintegrations_d.f90 | 26 ++++++++-------- .../outputReverse/surfaceintegrations_b.f90 | 31 +++++++++---------- .../surfaceintegrations_fast_b.f90 | 10 +++--- src/solver/surfaceIntegrations.F90 | 11 +++---- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 4c8d24c90..4862f4f76 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -54,8 +54,8 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & real(kind=realtype), dimension(8) :: dcdq, dcdqdot real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 - intrinsic sqrt intrinsic log + intrinsic sqrt real(kind=realtype) :: arg1 ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral @@ -226,6 +226,11 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & + ovrnts*globalvalsd(icavitation, sps) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) +! final part of the ks computation + funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin) - ovrnts*& +& globalvalsd(icpmin, sps)/(globalvals(icpmin, sps)*cpmin_rho) + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) funcvaluesd(costfuncaxismoment) = funcvaluesd(costfuncaxismoment) & & + ovrnts*globalvalsd(iaxismoment, sps) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & @@ -535,11 +540,6 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) -! final part of the ks computation - funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin)/funcvalues(& -& costfunccpmin)/cpmin_rho - funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& -& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -575,8 +575,8 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdq, dcdqdot real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 - intrinsic sqrt intrinsic log + intrinsic sqrt real(kind=realtype) :: arg1 ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral @@ -666,6 +666,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(isepsensor, sps) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) +! final part of the ks computation + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& @@ -800,9 +803,6 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) -! final part of the ks computation - funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& -& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1153,8 +1153,8 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp-cpmin_exact))) - ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_exact))) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) cpmin_ks_sumd = cpmin_ks_sumd + blk*ks_exponentd cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if @@ -1552,7 +1552,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index ec03b574b..3bd525b34 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -55,8 +55,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & real(kind=realtype), dimension(8) :: dcdq, dcdqdot real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 - intrinsic sqrt intrinsic log + intrinsic sqrt real(kind=realtype) :: tmp real(kind=realtype) :: tmp0 real(kind=realtype) :: tmp1 @@ -184,6 +184,9 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & ovrnts*globalvals(isepsensor, sps) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) +! final part of the ks computation + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& @@ -334,19 +337,10 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & funcvalues(costfuncforcezcoefviscous)*dragdirection(3) call pushreal8(funcvalues(costfuncdragcoefviscous)) funcvalues(costfuncdragcoefviscous) = tmp13 - tmp14 = funcvalues(costfuncforcexcoefmomentum)*dragdirection(1) + & -& funcvalues(costfuncforceycoefmomentum)*dragdirection(2) + & -& funcvalues(costfuncforcezcoefmomentum)*dragdirection(3) - call pushreal8(funcvalues(costfuncdragcoefmomentum)) - funcvalues(costfuncdragcoefmomentum) = tmp14 -! final part of the ks computation ! -------------------- time spectral objectives ------------------ if (tsstability) then stop else - funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin)/(cpmin_rho& -& *funcvalues(costfunccpmin)) - call popreal8(funcvalues(costfuncdragcoefmomentum)) tmpd = funcvaluesd(costfuncdragcoefmomentum) funcvaluesd(costfuncdragcoefmomentum) = 0.0_8 funcvaluesd(costfuncforcexcoefmomentum) = funcvaluesd(& @@ -600,6 +594,7 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & do sps=1,ntimeintervalsspectral ! ------------ ! ------------ +! final part of the ks computation ! mass flow like objective mflow = globalvals(imassflow, sps) if (mflow .ne. zero) then @@ -682,6 +677,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & funcvaluesd(costfuncsepsensoravgx) globalvalsd(iaxismoment, sps) = globalvalsd(iaxismoment, sps) + & & ovrnts*funcvaluesd(costfuncaxismoment) + globalvalsd(icpmin, sps) = globalvalsd(icpmin, sps) - ovrnts*& +& funcvaluesd(costfunccpmin)/(cpmin_rho*globalvals(icpmin, sps)) globalvalsd(icavitation, sps) = globalvalsd(icavitation, sps) + & & ovrnts*funcvaluesd(costfunccavitation) globalvalsd(isepsensor, sps) = globalvalsd(isepsensor, sps) + & @@ -803,8 +800,8 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdq, dcdqdot real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 - intrinsic sqrt intrinsic log + intrinsic sqrt ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral ! sum pressure and viscous contributions @@ -893,6 +890,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(isepsensor, sps) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) +! final part of the ks computation + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& @@ -1026,9 +1026,6 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) -! final part of the ks computation - funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& -& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -1294,7 +1291,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -1617,7 +1614,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) & temp5)*sensor1d end if ks_exponentd = blk*cpmin_ks_sumd - cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(-cpmin_exact-cp))*& + cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(cpmin_exact-cp))*& & ks_exponentd tmpd = (plocal-pinf)*cpd plocald = tmp*cpd @@ -1982,7 +1979,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index f37be683e..212ed381b 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -37,8 +37,8 @@ subroutine getcostfunctions(globalvals, funcvalues) real(kind=realtype), dimension(8) :: dcdq, dcdqdot real(kind=realtype), dimension(8) :: dcdalpha, dcdalphadot real(kind=realtype), dimension(8) :: coef0 - intrinsic sqrt intrinsic log + intrinsic sqrt ! factor used for time-averaged quantities. ovrnts = one/ntimeintervalsspectral ! sum pressure and viscous contributions @@ -127,6 +127,9 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(isepsensor, sps) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) +! final part of the ks computation + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& @@ -260,9 +263,6 @@ subroutine getcostfunctions(globalvals, funcvalues) & costfuncforcexcoefmomentum)*dragdirection(1) + funcvalues(& & costfuncforceycoefmomentum)*dragdirection(2) + funcvalues(& & costfuncforcezcoefmomentum)*dragdirection(3) -! final part of the ks computation - funcvalues(costfunccpmin) = cpmin_exact + log(funcvalues(& -& costfunccpmin))/cpmin_rho ! -------------------- time spectral objectives ------------------ if (tsstability) then print*, & @@ -469,7 +469,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp-cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 927b888d9..938bf07db 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -107,6 +107,9 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncSepSensor) = funcValues(costFuncSepSensor) + ovrNTS*globalVals(iSepSensor, sps) funcValues(costFuncCavitation) = funcValues(costFuncCavitation) + ovrNTS*globalVals(iCavitation, sps) + ! final part of the KS computation + funcValues(costfunccpmin) = funcValues(costfunccpmin) + ovrNTS * & + (cpmin_exact - log(globalVals(iCpMin, sps)) / cpmin_rho) funcValues(costFuncAxisMoment) = funcValues(costFuncAxisMoment) + ovrNTS*globalVals(iAxisMoment, sps) funcValues(costFuncSepSensorAvgX) = funcValues(costFuncSepSensorAvgX) + ovrNTS*globalVals(iSepAvg , sps) funcValues(costFuncSepSensorAvgY) = funcValues(costFuncSepSensorAvgY) + ovrNTS*globalVals(iSepAvg+1, sps) @@ -258,10 +261,6 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncForceYCoefMomentum)*dragDirection(2) + & funcValues(costFuncForceZCoefMomentum)*dragDirection(3) - ! final part of the KS computation - funcValues(costfunccpmin) = cpmin_exact & - + log(funcValues(costfunccpmin)) / cpmin_rho - ! -------------------- Time Spectral Objectives ------------------ if (TSSTability) then @@ -517,7 +516,7 @@ subroutine wallIntegrationFace(localValues, mm) Cavitation = Cavitation + Sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho * (-Cp - cpmin_exact)) + ks_exponent = exp(cpmin_rho * (-Cp + cpmin_exact)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent * blk end if enddo @@ -1145,7 +1144,7 @@ subroutine computeCpMinExact(famList) end do ! finally communicate across all processors - call mpi_allreduce(cpmin_local, cpmin_exact, 1, adflow_real, & + call mpi_allreduce(cpmin_local, cpmin_exact, 1, MPI_DOUBLE, & MPI_MIN, adflow_comm_world, ierr) call EChk(ierr, __FILE__, __LINE__) From 8e08637b75a1836ef749d2eb1474a97cda84f1a5 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 23:54:22 -0400 Subject: [PATCH 40/76] updated cavitation test to include the ks-based cpmin --- tests/reg_tests/refs/cavitation_tests.json | 22 +++++++++--- tests/reg_tests/reg_aeroproblems.py | 2 +- tests/reg_tests/test_cavitation.py | 41 ++++++++++++---------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/tests/reg_tests/refs/cavitation_tests.json b/tests/reg_tests/refs/cavitation_tests.json index ec196479e..fceb735d6 100644 --- a/tests/reg_tests/refs/cavitation_tests.json +++ b/tests/reg_tests/refs/cavitation_tests.json @@ -1,12 +1,18 @@ { - "Dot product test for w -> cavitation": -0.3915858868609155, - "Dot product test for xV -> cavitation": 0.04422042901616901, + "Dot product test for w -> cavitation": -0.39158588686091544, + "Dot product test for w -> cpmin": 0.6673403415536877, + "Dot product test for xV -> cavitation": 0.044220429016168836, + "Dot product test for xV -> cpmin": 0.0, "cavitation outputs": { - "naca0012_rans_2D_cavitation": 0.12991147313880522 + "naca0012_rans_2D_cavitation": 0.12991147313880522, + "naca0012_rans_2D_cpmin": -1.2254790918172702 }, "cavitation totals": { "naca0012_rans_2D_cavitation": { - "alpha": 0.09506523526801869 + "alpha": 0.09506523526801867 + }, + "naca0012_rans_2D_cpmin": { + "alpha": -0.40811659835075603 } }, "metadata": { @@ -31,6 +37,7 @@ "ANKNSubiterTurb": 1, "ANKOuterPreconIts": 1, "ANKPCILUFill": 2, + "ANKPCUpdateCutoff": 1e-06, "ANKPCUpdateTol": 0.5, "ANKPhysicalLSTol": 0.2, "ANKPhysicalLSTolTurb": 0.99, @@ -42,6 +49,7 @@ "ANKTurbCFLScale": 1.0, "ANKTurbKSPDebug": false, "ANKUnsteadyLSTol": 1.0, + "ANKUseApproxSA": false, "ANKUseFullVisc": true, "ANKUseMatrixFree": true, "ANKUseTurbDADI": true, @@ -97,6 +105,7 @@ "coarseDiscretization": "central plus scalar dissipation", "computeCavitation": true, "coupledSolution": false, + "cpMinRho": 1000.0, "cutCallback": null, "debugZipper": false, "deltaT": 0.01, @@ -108,6 +117,7 @@ "equationMode": "steady", "equationType": "RANS", "eulerWallTreatment": "linear pressure extrapolation", + "explicitSurfaceCallback": null, "firstRun": true, "flowType": "external", "forcesAsTractions": true, @@ -154,6 +164,7 @@ "outputDirectory": "tests/output_files", "outputSurfaceFamily": "allSurfaces", "overlapFactor": 0.9, + "oversetDebugPrint": false, "oversetLoadBalance": true, "oversetPriority": {}, "oversetProjTol": 1e-12, @@ -239,5 +250,6 @@ "writeVolumeSolution": false, "zipperSurfaceFamily": null }, - "total cavitation derivative wrt random volume perturbation": -2.0565995469114675 + "total cavitation derivative wrt random volume perturbation": -2.0565995469114533, + "total cpmin derivative wrt random volume perturbation": -80.3115105107785 } \ No newline at end of file diff --git a/tests/reg_tests/reg_aeroproblems.py b/tests/reg_tests/reg_aeroproblems.py index 7c736ea47..88a1bb36b 100644 --- a/tests/reg_tests/reg_aeroproblems.py +++ b/tests/reg_tests/reg_aeroproblems.py @@ -114,7 +114,7 @@ R=R, areaRef=1.0, chordRef=c, - evalFuncs=["cavitation"], + evalFuncs=["cavitation", "cpmin"], xRef=0.25, ) diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 4d121af7a..32c1e2357 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -49,7 +49,7 @@ def setUp(self): "adjointl2convergence": 1e-13, "computeCavitation": True, "cavitationNumber": 1.0, - "cpminrho": 1.0, + "cpminrho": 1e3, } ) @@ -68,7 +68,7 @@ def setUp(self): def test_cavitation_metrics_and_derivatives(self): "Tests if the correct amount of momentum is added to the flow by the actuator" - evalFuncs = ["cavitation"] + evalFuncs = ["cavitation", "cpmin"] self.CFDSolver(self.ap) @@ -91,27 +91,30 @@ def test_cavitation_metrics_and_derivatives(self): self.handler.root_print("cavitation totals") self.handler.root_add_dict("cavitation totals", funcsSens, rtol=1e-10, atol=1e-10) - # Now that we have the adjoint solution, - # also get a total derivative wrt a random spatial perturbation DV - psi = -self.CFDSolver.getAdjoint("cavitation") - funcsBar = self.CFDSolver._getFuncsBar("cavitation") + for func_name in evalFuncs: + ################## + # GEOMETRIC TOTALS + ################## - # this is the reverse seed up to the volume coordinates - xVBar = self.CFDSolver.computeJacobianVectorProductBwd(resBar=psi, funcsBar=funcsBar, xVDeriv=True) - # get a random volume perturbation - xVDot = self.CFDSolver.getSpatialPerturbation(314) + # random state and volume coordinate perturbations for tests below + wDot = self.CFDSolver.getStatePerturbation(314) + xVDot = self.CFDSolver.getSpatialPerturbation(314) - # dot product these two vectors to get a total derivative - dotLocal = np.dot(xVDot, xVBar) - self.handler.par_add_sum("total cavitation derivative wrt random volume perturbation", dotLocal, rtol=1e-10) + # Now that we have the adjoint solution for both functionals + # also get a total derivative wrt a random spatial perturbation DV + psi = -self.CFDSolver.getAdjoint(func_name) + funcsBar = self.CFDSolver._getFuncsBar(func_name) - ################## - # DOT PRODUCT TEST - ################## - wDot = self.CFDSolver.getStatePerturbation(314) - # xVDot was evaluated above so no need to re-run the spatial perturbation routine + # this is the reverse seed up to the volume coordinates + xVBar = self.CFDSolver.computeJacobianVectorProductBwd(resBar=psi, funcsBar=funcsBar, xVDeriv=True) - for func_name in evalFuncs: + # dot product these two vectors to get a total derivative + dotLocal = np.dot(xVDot, xVBar) + self.handler.par_add_sum(f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-10) + + ################## + # DOT PRODUCT TEST + ################## fDot_w = self.CFDSolver.computeJacobianVectorProductFwd(wDot=wDot, funcDeriv=True) fDot_xv = self.CFDSolver.computeJacobianVectorProductFwd(xVDot=xVDot, funcDeriv=True) funcsBar = {func_name: 1.0} From 38b83aa875da27c90c7529a7907dc081bfbe391f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 25 Sep 2022 23:54:53 -0400 Subject: [PATCH 41/76] formatting --- tests/reg_tests/test_cavitation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 32c1e2357..4eb73178d 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -110,7 +110,9 @@ def test_cavitation_metrics_and_derivatives(self): # dot product these two vectors to get a total derivative dotLocal = np.dot(xVDot, xVBar) - self.handler.par_add_sum(f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-10) + self.handler.par_add_sum( + f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-10 + ) ################## # DOT PRODUCT TEST From 62d42d67307cb0480a0ee9d9b8fe6059a38bcee7 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 21:12:53 -0400 Subject: [PATCH 42/76] update cavitation tests --- tests/reg_tests/refs/cavitation_tests.json | 22 +++++++++---------- tests/reg_tests/test_cavitation.py | 25 ++++++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/tests/reg_tests/refs/cavitation_tests.json b/tests/reg_tests/refs/cavitation_tests.json index fceb735d6..dbd1e74d8 100644 --- a/tests/reg_tests/refs/cavitation_tests.json +++ b/tests/reg_tests/refs/cavitation_tests.json @@ -1,18 +1,18 @@ { - "Dot product test for w -> cavitation": -0.39158588686091544, - "Dot product test for w -> cpmin": 0.6673403415536877, - "Dot product test for xV -> cavitation": 0.044220429016168836, + "Dot product test for w -> cavitation": -0.3915858868621817, + "Dot product test for w -> cpmin": 0.6673403415494966, + "Dot product test for xV -> cavitation": 0.04422042901525445, "Dot product test for xV -> cpmin": 0.0, "cavitation outputs": { - "naca0012_rans_2D_cavitation": 0.12991147313880522, - "naca0012_rans_2D_cpmin": -1.2254790918172702 + "naca0012_rans_2D_cavitation": 0.12991147313819204, + "naca0012_rans_2D_cpmin": -1.225479091815022 }, "cavitation totals": { "naca0012_rans_2D_cavitation": { - "alpha": 0.09506523526801867 + "alpha": 0.09506523526898285 }, "naca0012_rans_2D_cpmin": { - "alpha": -0.40811659835075603 + "alpha": -0.4081165983499211 } }, "metadata": { @@ -59,7 +59,7 @@ "CFLLimit": 1.5, "GMRESOrthogonalizationType": "modified Gram-Schmidt", "ILUFill": 2, - "L2Convergence": 1e-13, + "L2Convergence": 1e-15, "L2ConvergenceCoarse": 0.01, "L2ConvergenceRel": 1e-16, "MGCycle": "sg", @@ -80,7 +80,7 @@ "RKReset": false, "TSStability": false, "adjointDivTol": 100000.0, - "adjointL2Convergence": 1e-13, + "adjointL2Convergence": 1e-15, "adjointL2ConvergenceAbs": 1e-16, "adjointL2ConvergenceRel": 1e-16, "adjointMaxIter": 500, @@ -250,6 +250,6 @@ "writeVolumeSolution": false, "zipperSurfaceFamily": null }, - "total cavitation derivative wrt random volume perturbation": -2.0565995469114533, - "total cpmin derivative wrt random volume perturbation": -80.3115105107785 + "total cavitation derivative wrt random volume perturbation": -2.0566154094703144, + "total cpmin derivative wrt random volume perturbation": -80.31134681285023 } \ No newline at end of file diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 4eb73178d..711063bfc 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -45,8 +45,8 @@ def setUp(self): "nkswitchtol": 1e-6, "volumevariables": ["temp", "mach", "resrho", "cp"], "equationType": "RANS", - "l2convergence": 1e-13, - "adjointl2convergence": 1e-13, + "l2convergence": 1e-15, + "adjointl2convergence": 1e-15, "computeCavitation": True, "cavitationNumber": 1.0, "cpminrho": 1e3, @@ -110,8 +110,11 @@ def test_cavitation_metrics_and_derivatives(self): # dot product these two vectors to get a total derivative dotLocal = np.dot(xVDot, xVBar) + # this is not the best test out there; the final answer does get affected quite a bit + # by the processor count or architecture. We just have it here to have some test on the + # cavitation functionals' derivatives w.r.t. spatial changes in a lazy way. self.handler.par_add_sum( - f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-10 + f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-4 ) ################## @@ -171,6 +174,8 @@ def setUp(self): "adjointl2convergence": 1e-13, "computeCavitation": True, "cavitationNumber": 1.0, + "cpminrho": 1e3, + # to get slightly better complex convergence "NKUseEW": False, "NKLinearSolveTol": 1e-4, } @@ -238,7 +243,7 @@ def cmplx_test_cavitation_adjoints(self): # compute the sens funcsSensCS[dv] = {} - for f in ["cavitation"]: + for f in ["cavitation", "cpmin"]: funcsSensCS[dv][self.ap[f]] = np.imag(funcs_plus[dv][self.ap[f]]) / self.h # reset the DV @@ -257,13 +262,15 @@ def cmplx_test_cavitation_adjoints(self): # we treat the CS value as the truth, so if this test passes, # we assume the adjoint sensitivities are also true - func_name = "naca0012_rans_2D_cavitation" + for func_name in ["cavitation", "cpmin"]: + + full_name = f"naca0012_rans_2D_{func_name}" - ref_val = self.handler.db["cavitation totals"][func_name]["alpha"] - np.testing.assert_allclose(funcsSensCS["alpha"][func_name], ref_val, atol=1e-10, rtol=1e-10) + ref_val = self.handler.db["cavitation totals"][full_name]["alpha"] + np.testing.assert_allclose(funcsSensCS["alpha"][full_name], ref_val, atol=1e-10, rtol=1e-10) - ref_val = self.handler.db["total cavitation derivative wrt random volume perturbation"] - np.testing.assert_allclose(funcsSensCS["vol_perturbation"][func_name], ref_val, rtol=1e-4) + ref_val = self.handler.db[f"total {func_name} derivative wrt random volume perturbation"] + np.testing.assert_allclose(funcsSensCS["vol_perturbation"][full_name], ref_val, rtol=1e-4) if __name__ == "__main__": From 1ba4d613ca8c7398eb7b38205920748bc3ddf2b9 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 22:20:40 -0400 Subject: [PATCH 43/76] further increase the weird test tolerance --- tests/reg_tests/test_cavitation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 711063bfc..b4db52cf5 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -114,7 +114,7 @@ def test_cavitation_metrics_and_derivatives(self): # by the processor count or architecture. We just have it here to have some test on the # cavitation functionals' derivatives w.r.t. spatial changes in a lazy way. self.handler.par_add_sum( - f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-4 + f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-3 ) ################## @@ -270,7 +270,7 @@ def cmplx_test_cavitation_adjoints(self): np.testing.assert_allclose(funcsSensCS["alpha"][full_name], ref_val, atol=1e-10, rtol=1e-10) ref_val = self.handler.db[f"total {func_name} derivative wrt random volume perturbation"] - np.testing.assert_allclose(funcsSensCS["vol_perturbation"][full_name], ref_val, rtol=1e-4) + np.testing.assert_allclose(funcsSensCS["vol_perturbation"][full_name], ref_val, rtol=1e-3) if __name__ == "__main__": From a5a8bd94e59760314a5932af2a9c41f86f013535 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 22:21:03 -0400 Subject: [PATCH 44/76] added the explicit surface blanking doc in options --- doc/options.yaml | 99 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/doc/options.yaml b/doc/options.yaml index 1a549be76..e405acbb3 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -491,6 +491,105 @@ cutCallback: Therefore, we are flagging every cell where the y-component of the center coordinate (index 0:x, 1:y, 2:z) has a negative value. The flags array is initialized to zero internally by pyADflow, and a value of 1 for a cell tags it for flooding. +explicitSurfaceCallback: + desc: > + A user-provided Python function that is used as a callback method to pass the information required for the explicit surface blanking method. + To be able to understand what this option does, you should really understand how the overset flooding method works. + + With some configurations, the automatic flooding algorithm makes it extremely challenging to prevent the entire mesh from flooding. + The overlap of volume blocks can even be such that setting the ``"oversetPriority"`` option for each block is not enough. + To handle these extreme cases, we have a surface based explicit blanking method. + The idea is very similar to the ``cutCallback`` option above; this option is used to tag cells that are _inside_ a closed geometry provided by the user. + This way, we try to eliminate as much of the flood seeds and flooded cells as possible. + The approach is not perfect; we only tag the cells that have at least one vertex inside the provided surface geometry as explicitly blanked (-4). + This results in two layers of fringe cells that are automatically added, which prevent flooding under most cases. + However, the flooding algorithm is actually more involved than this; normally, potential wall donors are tagged as flood seeds, not just the cells that have a vertex inside a wall BC. + Regardless, the method works well enough that it can give you a valid hole cutting with cases that are practically impossible to get a valid hole cutting with just the default approach. + + The way user interacts with this method is through this callback function. + The reason we have the callback function is that we need the CGNS block names for each "computational block". + These names are used to determine which volume blocks will be explicitly blanked by which surface; we do not want every surface to act on every computational domain because that would result in most near wall cells getting tagged and would be very error prone. + + To understand how this option is used, consider an example where we have a wing and a fuselage, in an overset mesh. + The wing and fuselage component meshes are joined together with a collar mesh and a background cartesian mesh. + Some of the wing mesh is inside the fuselage surface, and some of the fuselage mesh is overlapping with the wing surface. + Normally, this case would be handled by the automatic flooding, which works fairly well for most applications including this example, but here, we are just demonstrating the alternative approach. + With the regular flooding algorithm, some cells in these overlap regions would get tagged as flood seeds on both the wing and the fuselage. + Then, these flood seeds are used to flood the cells that are located inside these geometries; e.g. all of the wing volume cells that are inside the fuselage surface. + + Instead of relying on the flooding, here, we want to explicitly blank cells that are inside the other component's surface. + To do this, we want to explicitly tag the wing mesh volume cells that have at least one vertex inside the fuselage surface, and similarly, tag the fuselage volume cells that have at least one vertex inside the wing surface. + The ``explicitSurfaceCallback`` option that would achieve this would look something like this: + + .. code-block:: python + + def explicitSurfaceCallback(CGNSZoneNameIDs): + # arrays to save the integer CGNS block IDs for each component + fuselage_blocks = [] + wing_blocks = [] + + for name, id in CGNSZoneNameIDs.items(): + # We can only get the blocks we want by checking the CGNS blocks' name. + # In this example, we don't want the explicit blanking algorithm to work + # on the cartesian background or the collar meshes. + if "wing" in name: + wing_blocks.append(id) + elif "fuselage" in name: + fuselage_blocks.append(id) + + surf_dict = { + "wing": { + # The surface file for each entry must be provided. + # This is a closed plot3d surface mesh. It does not + # necessarily need to be closed; we project the cell + # vertices on this mesh and if the projection direction + # is coming from the inside of the surface, the cell is + # tagged. So a CFD mesh with a symmetry plane can + # have a plot3d surface thats open at the symmetry plane. + # The normals must always point outside. + "surf_file": "wing_surface.x", + + # The block IDs we will search and blank using this surface. + # Here, we only blank the fuselage cells that are inside the wing + # and don't want to consider the background or collar meshes. + "block_ids": fuselage_blocks, + + # Optional entry: coord_xfer + # This is another callback function that performs a coordinate + # transformation on the loaded plot3d mesh nodes. See the + # addPointSet method in DVGeo.py at + # https://github.com/mdolab/pygeo for the call signature. + # We use this approach so that the users can have complete + # control over the surface mesh nodes after they are loaded. + "coord_xfer": coord_xfer, + }, + + # Similar entries for the fuselage. + "fuselage": { + "surf_file": "fuselage_surface.x", + "block_ids": wing_blocks, + }, + + # We can have multiple entries with the same surface to blank different + # subsets of CGNS blocks. The entries of this top level dictionary + # is just for bookkeeping, and is not important. The code prints + # which entry it is blanking as it works through the dictionary. + # With large meshes (millions of cells) on few number of processors (<10) + # this process can take up to a minute or so. The process should run quicker + # with more processors. The surface mesh is loaded on all processors + # so there is a memory limit on the surface mesh refinement. + "wing_self": { + # Here, assume we also want to blank some of the wing cells because + # they intersect the wing geometry itself somehow. E.g. very large splay. + # However, we only want to blank cells that have a k-index that is + # larger than 32 to avoid tagging cells near the wall. The + # "kmin" option is used to achieves this. + "surf_file": "wing_surface.x", + "block_ids": wing_blocks, + "kmin": 32, + }, + } + oversetUpdateMode: desc: > How to update the overset connectivity after mesh warping. From fc7f24532d00f150c8cb57cc064dca16afe951b5 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 22:24:51 -0400 Subject: [PATCH 45/76] added the coord transfer changes --- adflow/pyADflow.py | 70 +++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index a83f58d5f..dedd81b6f 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -308,8 +308,6 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): cellIDs = self.adflow.utils.getcellcgnsblockids(1, n) cutCallBack(xCen, self.CGNSZoneNameIDs, cellIDs, flag) - # TODO remove these barriers, but for now, to get an accurate timing, sync procs - self.comm.barrier() cutCallBackTime = time.time() # exlclude the cells inside closed surfaces if we are provided with them @@ -339,16 +337,14 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): else: kmin = -1 - # read the plot3d surface - pts, conn = self._readPlot3DSurfFile(surf_file, convertToTris=False) + # optional coordinate transformation to do general manipulation of the coordinates + if "coord_xfer" in surf_dict[surf]: + coord_xfer = surf_dict[surf]["coord_xfer"] + else: + coord_xfer = None - # optionally add the offsets to the surface mesh we just read - if "dx" in surf_dict[surf]: - pts[:, 0] += surf_dict[surf]["dx"] - if "dy" in surf_dict[surf]: - pts[:, 1] += surf_dict[surf]["dy"] - if "dz" in surf_dict[surf]: - pts[:, 2] += surf_dict[surf]["dz"] + # read the plot3d surface + pts, conn = self._readPlot3DSurfFile(surf_file, convertToTris=False, coord_xfer=coord_xfer) # get a new flag array surf_flag = numpy.zeros(n, "intc") @@ -360,8 +356,6 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # update the flag array with the new info flag = numpy.any([flag, surf_flag], axis=0) - # TODO remove these barriers, but for now, to get an accurate timing, sync procs - self.comm.barrier() explicitSurfaceCutTime = time.time() # Need to reset the oversetPriority option since the CGNSGrid @@ -829,7 +823,7 @@ def addCylindricalSlices( self.nSlice += n_slice - def addIntegrationSurface(self, fileName, familyName, isInflow=True, disp_vec=None): + def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer=None): """Add a specific integration surface for performing massflow-like computations. @@ -848,6 +842,14 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, disp_vec=No isInflow : bool Flag to treat momentum forces as if it is an inflow or outflow face. Default is True + + coord_xfer : function + A callback function that performs a coordinate transformation + between the original reference frame and any other reference + frame relevant to the current CFD case. This allows user to apply + arbitrary modifications to the loaded plot3d surface. The call + signature is documented in the DVGeometry's addPointset method: + https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py """ self.hasIntegrationSurfaces = True @@ -871,17 +873,22 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, disp_vec=No # of nodes/elements of the defined surface are sufficiently # small that we do not have to worry about parallelization. - pts, conn = self._readPlot3DSurfFile(fileName) - - # displace the points if asked for - if disp_vec is not None: - for idim in range(3): - pts[:, idim] += disp_vec[idim] + pts, conn = self._readPlot3DSurfFile(fileName, coord_xfer=coord_xfer) self.adflow.usersurfaceintegrations.addintegrationsurface(pts.T, conn.T, familyName, famID, isInflow) def addActuatorRegion( - self, fileName, axis1, axis2, familyName, thrust=0.0, torque=0.0, heat=0.0, relaxStart=None, relaxEnd=None + self, + fileName, + axis1, + axis2, + familyName, + thrust=0.0, + torque=0.0, + heat=0.0, + relaxStart=None, + relaxEnd=None, + coord_xfer=None, ): """ Add an actuator disk zone defined by the supplied closed @@ -960,13 +967,21 @@ def addActuatorRegion( The end of the relaxation in terms of orders of magnitude of relative convergence + coord_xfer : function + A callback function that performs a coordinate transformation + between the original reference frame and any other reference + frame relevant to the current CFD case. This allows user to apply + arbitrary modifications to the loaded plot3d surface. The call + signature is documented in the DVGeometry's addPointset method: + https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py + """ # ActuatorDiskRegions cannot be used in timeSpectralMode if self.getOption("equationMode").lower() == "time spectral": raise Error("ActuatorRegions cannot be used in Time Spectral Mode.") # Load in the user supplied surface file. - pts, conn = self._readPlot3DSurfFile(fileName, convertToTris=False) + pts, conn = self._readPlot3DSurfFile(fileName, convertToTris=False, coord_xfer=coord_xfer) # We should do a topology check to ensure that the surface the # user supplied is actually closed. @@ -6147,7 +6162,7 @@ def _convertFortranStringArrayToList(self, fortArray): return strList - def _readPlot3DSurfFile(self, fileName, convertToTris=True): + def _readPlot3DSurfFile(self, fileName, convertToTris=True, coord_xfer=None): """Read a plot3d file and return the points and connectivity in an unstructured mesh format""" @@ -6192,6 +6207,15 @@ def _readPlot3DSurfFile(self, fileName, convertToTris=True): uniquePts, link, nUnique = self.adflow.utils.pointreduce(pts.T, 1e-12) pts = uniquePts[:, 0:nUnique].T + # coordinate transformation for the coordinates if we have any. + # this is where the user can rotate, translate, or generally manipulate + # the coordinates coming from the plot3d file before they are used + if coord_xfer is not None: + # this callback function has the same call signature with the + # method described in the DVGeometry addPointSet method: + # https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py + pts = coord_xfer(pts, mode="fwd", apply_displacement=True) + # Update the conn newConn = numpy.zeros_like(conn) for i in range(elemCount): From fcfcde691d1c90904526476ddaba0425fac841bc Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 22:30:50 -0400 Subject: [PATCH 46/76] added missing option docs --- doc/options.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/options.yaml b/doc/options.yaml index e405acbb3..dc1828b43 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -643,6 +643,11 @@ oversetPriority: A lower factor will encourage the usage of that block mesh. This option may be required to get the flooding algorithm working properly. +oversetDebugPrint: + desc: > + Flag to enable or disable the debug printout from the overset algorithm when a hole cutting process fails. + This information is not useful anymore and users should obtain the volume solution after an unsuccessful hole cutting and debug the mesh by plotting the cells with incomplete connectivities, which receive an iblank value of -5. + timeIntegrationScheme: desc: > The type of time integration scheme to use for unsteady analysis. From 54a3814faa39cc2a4852e29d8d33c81e93d58671 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 22:35:50 -0400 Subject: [PATCH 47/76] more docs --- doc/options.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/options.yaml b/doc/options.yaml index dc1828b43..113f393e5 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -886,6 +886,12 @@ ANKUseTurbDADI: Only applies to decoupled ANK. If False, an internal ANK-like solver is used for the turbulence in the decoupled mode. +ANKUseApproxSA: + desc: > + The ANK solver switches from the approximate to the exact SA implicit formulation when the solver switches from the first order to the second order routines (printed as SANK or CSANK). + Setting this flag to false will force the SA implicit treatment to always use the approximate formulation with the ANK solver variants. + This should have no effect on the final solution, but can help with convergence with challenging cases. + ANKSwitchTol: desc: > Relative convergence in the residual norm before we switch to the ANK solver. @@ -1025,6 +1031,13 @@ ANKPCUpdateTol: desc: > If the ANK solver converges by this amount relative to the last nonlinear iteration where the preconditioner was updated, the preconditioner is updated again. +ANKPCUpdateCutoff: + desc: > + The cutoff tolerance below which we disable the PC update based on nonlinear convergence introduced in the option above. + E.g. the default value of 1e-6 will trigger PC updates with the ANK if the solver converges by a certain amount, but past a relative L2 convergence of 1e-6, this algorithm is disabled and the preconditioner is only updated with the mechanisms other than relative convergence. + This is useful when CSANK is used, which can take steps that converge the L2 norm by multiple orders of magnitude in each iteration towards the end of the convergence. + Here, we do not need to update the PC at each solver iteration, so we disable it with this option. + ANKADPC: desc: > Whether or not to use the AD-based preconditioner for the ANK solver. From a5efb6093b1f9f41271ed3381780b5d0efe2a9c9 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 26 Sep 2022 23:32:08 -0400 Subject: [PATCH 48/76] minor modification to options docs --- doc/options.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/options.yaml b/doc/options.yaml index 113f393e5..08ebb9124 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -583,13 +583,17 @@ explicitSurfaceCallback: # they intersect the wing geometry itself somehow. E.g. very large splay. # However, we only want to blank cells that have a k-index that is # larger than 32 to avoid tagging cells near the wall. The - # "kmin" option is used to achieves this. + # optional "kmin" entry is used to achieve this. "surf_file": "wing_surface.x", "block_ids": wing_blocks, "kmin": 32, }, } + # pyADflow will loop over the entries of this dictionary and perform the + # explicit blanking with the information provided. + return surf_dict + oversetUpdateMode: desc: > How to update the overset connectivity after mesh warping. From fd13f9ef3dbccbab8c677c103e144d2e608e5e23 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 27 Sep 2022 17:41:22 -0400 Subject: [PATCH 49/76] added note on plot3d file creation --- doc/options.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/options.yaml b/doc/options.yaml index 08ebb9124..1e4b8e536 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -546,7 +546,10 @@ explicitSurfaceCallback: # is coming from the inside of the surface, the cell is # tagged. So a CFD mesh with a symmetry plane can # have a plot3d surface thats open at the symmetry plane. - # The normals must always point outside. + # The normals must always point outside. An easy way to + # obtain this surface file is to convert the surface + # CGNS grid used to generate the mesh into the plot3d + # format using the cgns2plot3d method in cgnsutils. "surf_file": "wing_surface.x", # The block IDs we will search and blank using this surface. From e702fcc3b328f45c77b3b9e423214e4b682fb991 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 2 Oct 2022 16:08:25 -0400 Subject: [PATCH 50/76] bug fix for explicit hole cutting --- adflow/pyADflow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index dedd81b6f..faeb1cd4f 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -330,6 +330,8 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): surf_file = surf_dict[surf]["surf_file"] # the indices of cgns blocks that we want to consider when blanking inside the surface block_ids = surf_dict[surf]["block_ids"] + # the fortran lookup expects this list in increaasing order + block_ids.sort() # check if there is a kmin provided if "kmin" in surf_dict[surf]: From 7fd5c676e424c2aa2e918de65bc2bd48a500d498 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 21:22:37 -0500 Subject: [PATCH 51/76] addressing sabet's review part 1 --- adflow/pyADflow.py | 6 ++---- doc/conf.py | 5 +++-- doc/options.yaml | 10 +++++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index faeb1cd4f..01fbf318f 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -297,8 +297,6 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # index needs to go in as fortran numbering, so add 1 name = getPy3SafeString(self.adflow.utils.getcgnszonename(i + 1).strip()) self.CGNSZoneNameIDs[name] = i + 1 - # TODO check this: do we need to do this on root and broadcast? - # Looks like it is fine # Call the user supplied callback if necessary cutCallBack = self.getOption("cutCallBack") @@ -851,7 +849,7 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer= frame relevant to the current CFD case. This allows user to apply arbitrary modifications to the loaded plot3d surface. The call signature is documented in the DVGeometry's addPointset method: - https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py + :meth:`addPointset ` """ self.hasIntegrationSurfaces = True @@ -975,7 +973,7 @@ def addActuatorRegion( frame relevant to the current CFD case. This allows user to apply arbitrary modifications to the loaded plot3d surface. The call signature is documented in the DVGeometry's addPointset method: - https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py + :meth:`addPointset ` """ # ActuatorDiskRegions cannot be used in timeSpectralMode diff --git a/doc/conf.py b/doc/conf.py index d1a4336bc..f6b006f4a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -33,5 +33,6 @@ # intersphinx intersphinx_mapping = { - "mach-aero": (f"https://mdolab-mach-aero.readthedocs-hosted.com/en/latest", None), -} + "mach-aero": ("https://mdolab-mach-aero.readthedocs-hosted.com/en/latest", None), + "pygeo": ("https://mdolab-pygeo.readthedocs-hosted.com/en/latest", None), +} \ No newline at end of file diff --git a/doc/options.yaml b/doc/options.yaml index 1e4b8e536..26db0e762 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -331,8 +331,6 @@ infChangeCorrection: cavitationNumber: desc: > The -Cp value used to trigger the cavitation sensor. - This "sensor" is only used for the surface output. - The actual cavitation cost function in adflow uses a KS aggregation under the hood and returns the cpmin value for a given family. cpMinRho: desc: > @@ -499,7 +497,7 @@ explicitSurfaceCallback: With some configurations, the automatic flooding algorithm makes it extremely challenging to prevent the entire mesh from flooding. The overlap of volume blocks can even be such that setting the ``"oversetPriority"`` option for each block is not enough. To handle these extreme cases, we have a surface based explicit blanking method. - The idea is very similar to the ``cutCallback`` option above; this option is used to tag cells that are _inside_ a closed geometry provided by the user. + The idea is very similar to the ``cutCallback`` option above; this option is used to tag cells that are *inside* a closed geometry provided by the user. This way, we try to eliminate as much of the flood seeds and flooded cells as possible. The approach is not perfect; we only tag the cells that have at least one vertex inside the provided surface geometry as explicitly blanked (-4). This results in two layers of fringe cells that are automatically added, which prevent flooding under most cases. @@ -597,6 +595,10 @@ explicitSurfaceCallback: # explicit blanking with the information provided. return surf_dict + The call signature of the ``coord_xfer`` option is documented in the DVGeometry's addPointset method: + :meth:`addPointset ` + + oversetUpdateMode: desc: > How to update the overset connectivity after mesh warping. @@ -1044,6 +1046,8 @@ ANKPCUpdateCutoff: E.g. the default value of 1e-6 will trigger PC updates with the ANK if the solver converges by a certain amount, but past a relative L2 convergence of 1e-6, this algorithm is disabled and the preconditioner is only updated with the mechanisms other than relative convergence. This is useful when CSANK is used, which can take steps that converge the L2 norm by multiple orders of magnitude in each iteration towards the end of the convergence. Here, we do not need to update the PC at each solver iteration, so we disable it with this option. + This option only changes the PC update behavior with the coupled ANK variants. + Decoupled ANK variants don't get affected by this. ANKADPC: desc: > From 7b751853a622e6c18c512c410006acb019b16178 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 21:22:56 -0500 Subject: [PATCH 52/76] addressing sabet's review part 2: fix the import comment in tests --- tests/reg_tests/test_actuator.py | 2 +- tests/reg_tests/test_cavitation.py | 3 +-- tests/reg_tests/test_error_estimation.py | 2 +- tests/reg_tests/test_solve.py | 2 +- tests/reg_tests/test_solver_combos.py | 2 +- tests/reg_tests/test_time_accurate_naca0012.py | 2 +- tests/reg_tests/test_time_spectral_naca64A010.py | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/reg_tests/test_actuator.py b/tests/reg_tests/test_actuator.py index 9b9814e31..12d3a8931 100644 --- a/tests/reg_tests/test_actuator.py +++ b/tests/reg_tests/test_actuator.py @@ -11,7 +11,7 @@ from adflow import ADFLOW from adflow import ADFLOW_C -# import the testing utilities that live a few directories up +# import the testing utilities import reg_test_utils as utils from reg_default_options import adflowDefOpts from reg_aeroproblems import ap_actuator_pipe diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index b4db52cf5..1a103e4ea 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -8,7 +8,7 @@ from adflow import ADFLOW from adflow import ADFLOW_C -# import the testing utilities that live a few directories up +# import the testing utilities from reg_default_options import adflowDefOpts from reg_aeroproblems import ap_naca0012_cavitation import reg_test_classes @@ -66,7 +66,6 @@ def setUp(self): self.CFDSolver = CFDSolver def test_cavitation_metrics_and_derivatives(self): - "Tests if the correct amount of momentum is added to the flow by the actuator" evalFuncs = ["cavitation", "cpmin"] diff --git a/tests/reg_tests/test_error_estimation.py b/tests/reg_tests/test_error_estimation.py index 47f81cdd0..b08772092 100644 --- a/tests/reg_tests/test_error_estimation.py +++ b/tests/reg_tests/test_error_estimation.py @@ -8,7 +8,7 @@ # MACH classes from adflow import ADFLOW -# import the testing utilities that live a few directories up +# import the testing utilities from reg_default_options import adflowDefOpts from reg_aeroproblems import ap_tutorial_wing import reg_test_classes diff --git a/tests/reg_tests/test_solve.py b/tests/reg_tests/test_solve.py index 45a361010..ef8622410 100644 --- a/tests/reg_tests/test_solve.py +++ b/tests/reg_tests/test_solve.py @@ -7,7 +7,7 @@ # MACH classes from adflow import ADFLOW -# import the testing utilities that live a few directories up +# import the testing utilities import reg_test_utils as utils from reg_default_options import adflowDefOpts from reg_aeroproblems import ap_tutorial_wing diff --git a/tests/reg_tests/test_solver_combos.py b/tests/reg_tests/test_solver_combos.py index 808c4c3ad..f3d7b0045 100644 --- a/tests/reg_tests/test_solver_combos.py +++ b/tests/reg_tests/test_solver_combos.py @@ -9,7 +9,7 @@ from adflow import ADFLOW from adflow import ADFLOW_C -# import the testing utilities that live a few directories up +# import the testing utilities from reg_default_options import adflowDefOpts from reg_aeroproblems import ap_simple_cart_cube import reg_test_classes diff --git a/tests/reg_tests/test_time_accurate_naca0012.py b/tests/reg_tests/test_time_accurate_naca0012.py index 286004385..3698d8965 100644 --- a/tests/reg_tests/test_time_accurate_naca0012.py +++ b/tests/reg_tests/test_time_accurate_naca0012.py @@ -7,7 +7,7 @@ # MACH testing class from adflow import ADFLOW -# import the testing utilities that live a few directories up +# import the testing utilities import reg_test_utils as utils from reg_default_options import adflowDefOpts diff --git a/tests/reg_tests/test_time_spectral_naca64A010.py b/tests/reg_tests/test_time_spectral_naca64A010.py index 287557a4b..ee8f4712b 100644 --- a/tests/reg_tests/test_time_spectral_naca64A010.py +++ b/tests/reg_tests/test_time_spectral_naca64A010.py @@ -8,7 +8,7 @@ from adflow import ADFLOW from idwarp import USMesh -# import the testing utilities that live a few directories up +# import the testing utilities import reg_test_utils as utils from reg_default_options import adflowDefOpts From cdcbe9340d981dc54b61d89d26e694164d09fe2d Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 21:34:08 -0500 Subject: [PATCH 53/76] part 3: overset API typos --- src/overset/oversetAPI.F90 | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index 3826c45e6..cb671c930 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2124,7 +2124,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl integer(kind=intType) :: i, j, k, l, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr integer(kind=intType) :: iblock, cell_counter, k_cgns real(kind=realType) :: dStar, frac, volLocal - real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, axisVec + real(kind=realType), dimension(3) :: minX, maxX, v1, v2, v3, axisVec real(kind=realType), dimension(3) :: diag1, diag2, diag3, diag4 real(kind=realType) :: dd1, dd2, dd3, dd4, diag_max type(adtType) :: ADT @@ -2146,7 +2146,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl ! Since this is effectively a wall-distance calc it gets super ! costly for the points far away. Luckly, we can do a fairly ! simple shortcut: Just compute the bounding box of the region and - ! use that as the "already found" distance in the cloest point + ! use that as the "already found" distance in the closest point ! search. This will eliminate all the points further away ! immediately and this should be sufficiently fast. @@ -2162,7 +2162,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl ! Now build the tree. call buildSerialQuad(size(conn, 2), size(pts, 2), pts, conn, ADT) - ! Compute the (averaged) uniqe nodal vectors: + ! Compute the (averaged) unique nodal vectors: allocate(norm(3, size(pts, 2)), normCount(size(pts, 2))) norm = zero @@ -2170,18 +2170,18 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl do i=1, size(conn, 2) - ! Compute cross product normal and normize + ! Compute cross product normal and normalize v1 = pts(:, conn(3, i)) - pts(:, conn(1, i)) v2 = pts(:, conn(4, i)) - pts(:, conn(2, i)) - sss(1) = (v1(2)*v2(3) - v1(3)*v2(2)) - sss(2) = (v1(3)*v2(1) - v1(1)*v2(3)) - sss(3) = (v1(1)*v2(2) - v1(2)*v2(1)) - sss = sss / sqrt(sss(1)**2 + sss(2)**2 + sss(3)**2) + v3(1) = (v1(2)*v2(3) - v1(3)*v2(2)) + v3(2) = (v1(3)*v2(1) - v1(1)*v2(3)) + v3(3) = (v1(1)*v2(2) - v1(2)*v2(1)) + v3 = v3 / sqrt(v3(1)**2 + v3(2)**2 + v3(3)**2) ! Add to each of the four pts and increment the number added do j=1, 4 - norm(:, conn(j, i)) = norm(:, conn(j, i)) + sss + norm(:, conn(j, i)) = norm(:, conn(j, i)) + v3 normCount(conn(j, i)) = normCount(conn(j, i)) + 1 end do end do @@ -2191,7 +2191,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl norm(:, i) = norm(:, i) / normCount(i) end do - ! Node count is no longer needed + ! Norm count is no longer needed deallocate(normCount) ! Allocate the extra data the tree search requires. @@ -2297,7 +2297,7 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl end do ! Final memory cleanup - deallocate(norm, frontLeaves, frontLeavesNew, BB) + deallocate(stack, norm, frontLeaves, frontLeavesNew, BB) call destroySerialQuad(ADT) contains From 6d2a31488d1c59fb3d90ab1125ab9a82e7e1a6bc Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 21:34:32 -0500 Subject: [PATCH 54/76] part 4: applying the same fixes to the actuator region code, which is where the overset api changes mostly came from --- src/solver/actuatorRegion.F90 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/solver/actuatorRegion.F90 b/src/solver/actuatorRegion.F90 index 364abb906..6e647d993 100644 --- a/src/solver/actuatorRegion.F90 +++ b/src/solver/actuatorRegion.F90 @@ -33,7 +33,7 @@ subroutine addActuatorRegion(pts, conn, axis1, axis2, famName, famID, & integer(kind=intType) :: i, j, k, nn, iDim, cellID, intInfo(3), sps, level, iii, ierr real(kind=realType) :: dStar, frac, volLocal type(actuatorRegionType), pointer :: region - real(kind=realType), dimension(3) :: minX, maxX, sss, v1, v2, xCen, axisVec + real(kind=realType), dimension(3) :: minX, maxX, v1, v2, v3, xCen, axisVec type(adtType) :: ADT real(kind=realType) :: axisVecNorm real(kind=realType), dimension(:, :), allocatable :: norm @@ -103,7 +103,7 @@ subroutine addActuatorRegion(pts, conn, axis1, axis2, famName, famID, & ! Now build the tree. call buildSerialQuad(size(conn, 2), size(pts, 2), pts, conn, ADT) - ! Compute the (averaged) uniqe nodal vectors: + ! Compute the (averaged) unique nodal vectors: allocate(norm(3, size(pts, 2)), normCount(size(pts, 2))) norm = zero @@ -111,18 +111,18 @@ subroutine addActuatorRegion(pts, conn, axis1, axis2, famName, famID, & do i=1, size(conn, 2) - ! Compute cross product normal and normize + ! Compute cross product normal and normalize v1 = pts(:, conn(3, i)) - pts(:, conn(1, i)) v2 = pts(:, conn(4, i)) - pts(:, conn(2, i)) - sss(1) = (v1(2)*v2(3) - v1(3)*v2(2)) - sss(2) = (v1(3)*v2(1) - v1(1)*v2(3)) - sss(3) = (v1(1)*v2(2) - v1(2)*v2(1)) - sss = sss / sqrt(sss(1)**2 + sss(2)**2 + sss(3)**2) + v3(1) = (v1(2)*v2(3) - v1(3)*v2(2)) + v3(2) = (v1(3)*v2(1) - v1(1)*v2(3)) + v3(3) = (v1(1)*v2(2) - v1(2)*v2(1)) + v3 = v3 / sqrt(v3(1)**2 + v3(2)**2 + v3(3)**2) ! Add to each of the four pts and increment the number added do j=1, 4 - norm(:, conn(j, i)) = norm(:, conn(j, i)) + sss + norm(:, conn(j, i)) = norm(:, conn(j, i)) + v3 normCount(conn(j, i)) = normCount(conn(j, i)) + 1 end do end do @@ -132,7 +132,7 @@ subroutine addActuatorRegion(pts, conn, axis1, axis2, famName, famID, & norm(:, i) = norm(:, i) / normCount(i) end do - ! Node count is no longer needed + ! Norm count is no longer needed deallocate(normCount) ! Allocate the extra data the tree search requires. @@ -214,7 +214,7 @@ subroutine addActuatorRegion(pts, conn, axis1, axis2, famName, famID, & call ECHK(ierr, __FILE__, __LINE__) ! Final memory cleanup - deallocate(norm, frontLeaves, frontLeavesNew, BB) + deallocate(stack, norm, frontLeaves, frontLeavesNew, BB) call destroySerialQuad(ADT) contains From 8ad6922c5064d66ed0ec58813a5534b98d8a8661 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 22:46:26 -0500 Subject: [PATCH 55/76] part 5: comments and typos on the slice changes --- adflow/pyADflow.py | 31 +++++++++++++++---------------- src/output/tecplotIO.F90 | 4 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 01fbf318f..5b328a3a5 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -576,10 +576,10 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): positions : float or array The list of slice positions *along the axis given by direction*. sliceType : str {'relative', 'absolute'} - Relative slices are 'sliced' at the beginning and then parametricly + Relative slices are 'sliced' at the beginning and then parametrically move as the geometry deforms. As a result, the slice through the geometry may not remain planar. An absolute slice is re-sliced for - every out put so is always exactly planar and always at the initial + every output so is always exactly planar and always at the initial position the user indicated. groupName : str The family to use for the slices. Default is None corresponding to all @@ -635,10 +635,10 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None): """ - Add slices that vary arbitrarily in space. this is a generalization - of the routine above, where we have the user specify a list of "normals" + Add slices that vary arbitrarily in space. This is a generalization + of the :meth:`addSlices <.addSlices>` routine, where we have the user specify a list of "normals" and "points" that define slice planes. Rest of the code is the same. - this way users can add slices that follow the dihedral of a wing for example. + This way users can add slices that follow the dihedral of a wing for example. Parameters ---------- @@ -650,10 +650,10 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No points : ndarray (n_slice, 3) Point coordinates that define a slicing plane along with the normals sliceType : str {'relative', 'absolute'} - Relative slices are 'sliced' at the beginning and then parametricly + Relative slices are 'sliced' at the beginning and then parametrically move as the geometry deforms. As a result, the slice through the geometry may not remain planar. An absolute slice is re-sliced for - every out put so is always exactly planar and always at the initial + every output so is always exactly planar and always at the initial position the user indicated. groupName : str The family to use for the slices. Default is None corresponding to all @@ -682,7 +682,9 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No tmp[:] = normals normals = tmp - # for regular slices, we dont use the direction vector to pick a projection direction + # for non-cylindrical slices, we dont use the direction vector to pick a projection direction + # so the slice_dir value can be set arbitrarily, and because the use_dir flag is False, the code + # doesn't actually use it. slice_dir = [1.0, 0.0, 0.0] use_dir = False @@ -721,7 +723,7 @@ def addCylindricalSlices( self, pt1, pt2, n_slice=180, slice_beg=0.0, slice_end=360.0, sliceType="relative", groupName=None ): """ - Add cylindrical projection slices. The cylinrical projection axis is defined + Add cylindrical projection slices. The cylindrical projection axis is defined from pt1 to pt2. Then we start from the lift direction and rotate around this axis until we are back at the beginning. The rotation direction follows the right hand rule; we rotate the plane in the direction of vectors from pt1 to @@ -736,14 +738,14 @@ def addCylindricalSlices( n_slice : int number of slices around a 360 degree full rotation. slice_beg : float - beginning of the slices in the rotation direction + beginning of the slices in the rotation direction in degrees slice_end : float - end of the slices in the rotation direction + end of the slices in the rotation direction in degrees sliceType : str {'relative', 'absolute'} - Relative slices are 'sliced' at the beginning and then parametricly + Relative slices are 'sliced' at the beginning and then parametrically move as the geometry deforms. As a result, the slice through the geometry may not remain planar. An absolute slice is re-sliced for - every out put so is always exactly planar and always at the initial + every output so is always exactly planar and always at the initial position the user indicated. groupName : str The family to use for the slices. Default is None corresponding to all @@ -774,9 +776,6 @@ def addCylindricalSlices( # the unit vector on the axis vec1 = pt2 - pt1 vec1 /= numpy.linalg.norm(vec1) - # update p2 so that the distance between p1 and p2 is one. - # not necessary, but probably better for numerical stability - pt2 = pt1 + vec1 # loop over angles for ii, angle in enumerate(angles): diff --git a/src/output/tecplotIO.F90 b/src/output/tecplotIO.F90 index 178c70998..680688ff4 100644 --- a/src/output/tecplotIO.F90 +++ b/src/output/tecplotIO.F90 @@ -11,8 +11,8 @@ module tecplotIO ! side of node ! w(2, nNodes) : Weights used to multiply the two global nodes defined in ! ind to get compute nodal values (positions, forces etc) - ! pL, vL, pD, vD : Pressure and viscous lift, pressure and viscous drag - ! CLp, CLv, CDp, CDv : Coefficients of pressure and viscous lift and drag + ! pL, vL, pD, vD, pM, vM : Pressure and viscous components of lift, drag, and moment + ! CLp, CLv, CDp, CDv, CMp, CMv : Coefficients of pressure and viscous lift, drag, and moment ! chord: chord of section ! pt, normal: The point and the normal that defines the slicing plane ! dir_vec: a direction vector that we use to filter sliced line elements. From d5ff2ea7b90f711c92c106b5173bf9ca049de5c6 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 23:02:28 -0500 Subject: [PATCH 56/76] part 5: trying to fix the cylindrical slice edge case --- adflow/pyADflow.py | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 5b328a3a5..f9bd8ad0d 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -633,7 +633,7 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): self.nSlice += N - def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None): + def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None, slice_dir=None): """ Add slices that vary arbitrarily in space. This is a generalization of the :meth:`addSlices <.addSlices>` routine, where we have the user specify a list of "normals" @@ -649,6 +649,11 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No the numbers of points and normals must match. points : ndarray (n_slice, 3) Point coordinates that define a slicing plane along with the normals + slice_dir : ndarray (n_slice, 3) + If this is provided, only the intersections that is in this direction + starting from the normal is kept. This is useful if you are slicing a + closed geometry and only want to keep one side of it. It is similar to + the functionality provided in :meth:`addCylindricalSlices <.addCylindricalSlices>`. sliceType : str {'relative', 'absolute'} Relative slices are 'sliced' at the beginning and then parametrically move as the geometry deforms. As a result, the slice through the @@ -682,16 +687,25 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No tmp[:] = normals normals = tmp - # for non-cylindrical slices, we dont use the direction vector to pick a projection direction - # so the slice_dir value can be set arbitrarily, and because the use_dir flag is False, the code - # doesn't actually use it. - slice_dir = [1.0, 0.0, 0.0] - use_dir = False + if slice_dir is None: + # if we dont have a direction vector to pick a projection direction, we can just set this + # array to an arbitrary direction. Because the use_dir flag is false, the code won't actually + # use this array + dummy_slice_dir = [1.0, 0.0, 0.0] + use_dir = False + else: + use_dir = True for i in range(n_slice): # It is important to ensure each slice get a unique # name...so we will number sequentially from python j = self.nSlice + i + 1 + + if use_dir: + direction = slice_dir[j] + else: + direction = dummy_slice_dir + if sliceType == "relative": sliceName = "Slice_%4.4d %s Para Init Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( j, @@ -703,7 +717,7 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No points[i, 1], points[i, 2], ) - self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], direction, use_dir, famList) else: sliceName = "Slice_%4.4d %s Absolute Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( j, @@ -715,7 +729,7 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No points[i, 1], points[i, 2], ) - self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], slice_dir, use_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], direction, use_dir, famList) self.nSlice += n_slice @@ -727,7 +741,9 @@ def addCylindricalSlices( from pt1 to pt2. Then we start from the lift direction and rotate around this axis until we are back at the beginning. The rotation direction follows the right hand rule; we rotate the plane in the direction of vectors from pt1 to - pt2 crossed with the lift direction. + pt2 crossed with the lift direction. This routine will not work as is if the + cylinder axis is exactly aligned with the lift direction. If that use case is + needed, consider using :meth:`addArbitrarySlices <.addArbitrarySlices>`. Parameters ---------- @@ -797,6 +813,12 @@ def addCylindricalSlices( # rotate the lift direction vector to get the slice direction slice_dir = rot_mat.dot(lift_dir) + # In general, the "slice_dir" does not need to be orthogonal to vec1, which is the center axis of the cylinder. So we make it orthogonal + slice_dir -= vec1.dot(slice_dir) * vec1 + + # normalize slice_dir + slice_dir /= numpy.linalg.norm(slice_dir) + # cross product vec1 and vec2 to get the normal vector of this plane slice_normal = numpy.cross(vec1, slice_dir) # normalize for good measure From dc0c7d95bb0caa7a53923e8284cb17ca4a714e3b Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 23:04:25 -0500 Subject: [PATCH 57/76] part 5.1: divide the strings up --- adflow/pyADflow.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index f9bd8ad0d..0bfe05c2b 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -836,10 +836,14 @@ def addCylindricalSlices( # name...so we will number sequentially from python jj = self.nSlice + ii + 1 if sliceType == "relative": - sliceName = f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + sliceName = f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f}" + \ + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + \ + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) else: - sliceName = f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f} pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, {slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + sliceName = f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f}" + \ + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + \ + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) self.nSlice += n_slice From 25e6e1f3e722b1d3bacc0b012ffbaf0cb6cd1574 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sat, 19 Nov 2022 23:09:31 -0500 Subject: [PATCH 58/76] part 6: surface integration modifications --- src/solver/surfaceIntegrations.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 938bf07db..a2ed5268e 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -1097,7 +1097,7 @@ subroutine computeCpMinExact(famList) ! the cpmin using KS aggregation. ! the goal is to get a differentiable cpmin output - ! set the local cp min to a small value so that we get the actual min + ! set the local cp min to a large value so that we get the actual min cpmin_local = 10000.0_realType ! loop over the TS instances just because its the same convention everywhere. @@ -1125,7 +1125,7 @@ subroutine computeCpMinExact(famList) j = ii/(bcData(mm)%inEnd-bcData(mm)%inBeg) + bcData(mm)%jnBeg + 1 ! only take this if its a compute cell - if (BCData(mm)%iblank(i,j) .gt. zero) then + if (BCData(mm)%iblank(i,j) .eq. one) then ! compute local CP plocal = pp2(i,j) From 1b96407b1246668bd2441c33e26ee51892993399 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 11:50:01 -0500 Subject: [PATCH 59/76] clarified computecavitation option behavior --- doc/options.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/options.yaml b/doc/options.yaml index 26db0e762..863057661 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -1399,7 +1399,8 @@ sepSensorSharpness: computeCavitation: desc: > - Whether or not to compute cavitation. + Whether or not to compute cavitation related cost functions, which are `cavitation` and `cpMin`. + If this option is not set to `True`, the code will return zero for these two cost functions. cavSensorOffset: desc: > From 8c194dc6855f95ca4452a6b775567fbc60258155 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 11:51:14 -0500 Subject: [PATCH 60/76] changes for the cpmin computation so it returns zero when computeCavitation is set to False. --- src/inputParam/inputParamRoutines.F90 | 3 ++- src/solver/surfaceIntegrations.F90 | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/inputParam/inputParamRoutines.F90 b/src/inputParam/inputParamRoutines.F90 index fafb9791b..85fccba46 100644 --- a/src/inputParam/inputParamRoutines.F90 +++ b/src/inputParam/inputParamRoutines.F90 @@ -3808,7 +3808,7 @@ subroutine setDefaultValues cpFile = "" ! Serves as a check later on. storeConvInnerIter = .false. ! Do not store the convergence of - ! iterations(inner iterations in unsteady mode). + ! iterations(inner iterations in unsteady mode). #ifdef USE_SINGLE_PRECISION precisionGrid = precisionSingle ! Default IO precision depends @@ -4042,6 +4042,7 @@ subroutine setDefaultValues usematrixfreedrdw = .False. sepSensorOffset = zero sepSensorSharpness = 10_realType + cpmin_exact = zero end subroutine setDefaultValues subroutine initializeIsoSurfaceVariables(values, nValues) diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index a2ed5268e..5aae3cb2d 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -10,6 +10,7 @@ subroutine getCostFunctions(globalVals, funcValues) use inputPhysics, only : liftDirection, dragDirection, surfaceRef, & machCoef, lengthRef, alpha, beta, liftIndex, cpmin_exact, & cpmin_rho + use inputCostFunctions, only : computeCavitation use inputTSStabDeriv, only : TSstability use utils, only : computeTSDerivatives use flowUtils, only : getDirVector @@ -108,8 +109,14 @@ subroutine getCostFunctions(globalVals, funcValues) funcValues(costFuncSepSensor) = funcValues(costFuncSepSensor) + ovrNTS*globalVals(iSepSensor, sps) funcValues(costFuncCavitation) = funcValues(costFuncCavitation) + ovrNTS*globalVals(iCavitation, sps) ! final part of the KS computation - funcValues(costfunccpmin) = funcValues(costfunccpmin) + ovrNTS * & - (cpmin_exact - log(globalVals(iCpMin, sps)) / cpmin_rho) + if (computeCavitation) then + ! only calculate the log part if we are actually computing for cavitation. + ! If we are not computing cavitation, the iCpMin in globalVals will be zero, + ! which doesn't play well with log. we just want to return zero here. + funcValues(costfunccpmin) = funcValues(costfunccpmin) + ovrNTS * & + (cpmin_exact - log(globalVals(iCpMin, sps)) / cpmin_rho) + endif + funcValues(costFuncAxisMoment) = funcValues(costFuncAxisMoment) + ovrNTS*globalVals(iAxisMoment, sps) funcValues(costFuncSepSensorAvgX) = funcValues(costFuncSepSensorAvgX) + ovrNTS*globalVals(iSepAvg , sps) funcValues(costFuncSepSensorAvgY) = funcValues(costFuncSepSensorAvgY) + ovrNTS*globalVals(iSepAvg+1, sps) From bdce382ff795848ba403c353bf09be7ea8c41f0e Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 11:51:19 -0500 Subject: [PATCH 61/76] rerun tapenade --- .../outputForward/surfaceintegrations_d.f90 | 23 +++++++++++---- .../outputReverse/surfaceintegrations_b.f90 | 29 +++++++++++++++---- .../surfaceintegrations_fast_b.f90 | 9 ++++-- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 4862f4f76..21ed50fec 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -26,6 +26,7 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & & lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & & cpmin_rho + use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector, getdirvector_d @@ -227,10 +228,15 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation - funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin) - ovrnts*& -& globalvalsd(icpmin, sps)/(globalvals(icpmin, sps)*cpmin_rho) - funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + if (computecavitation) then +! only calculate the log part if we are actually computing for cavitation. +! if we are not computing cavitation, the icpmin in globalvals will be zero, +! which doesn't play well with log. we just want to return zero here. + funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin) - ovrnts& +& *globalvalsd(icpmin, sps)/(globalvals(icpmin, sps)*cpmin_rho) + funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& +& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + end if funcvaluesd(costfuncaxismoment) = funcvaluesd(costfuncaxismoment) & & + ovrnts*globalvalsd(iaxismoment, sps) funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & @@ -555,6 +561,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& & machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho + use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives use flowutils_d, only : getdirvector @@ -667,8 +674,12 @@ subroutine getcostfunctions(globalvals, funcvalues) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation - funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& +& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& sps))/cpmin_rho) +! only calculate the log part if we are actually computing for cavitation. +! if we are not computing cavitation, the icpmin in globalvals will be zero, +! which doesn't play well with log. we just want to return zero here. funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index 3bd525b34..01fea2047 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -27,6 +27,7 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & & lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & & cpmin_rho + use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector, getdirvector_b @@ -185,8 +186,12 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation - funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& +& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& sps))/cpmin_rho) +! only calculate the log part if we are actually computing for cavitation. +! if we are not computing cavitation, the icpmin in globalvals will be zero, +! which doesn't play well with log. we just want to return zero here. funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& @@ -595,6 +600,11 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & ! ------------ ! ------------ ! final part of the ks computation + if (computecavitation) then + call pushcontrol1b(0) + else + call pushcontrol1b(1) + end if ! mass flow like objective mflow = globalvals(imassflow, sps) if (mflow .ne. zero) then @@ -677,8 +687,10 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & funcvaluesd(costfuncsepsensoravgx) globalvalsd(iaxismoment, sps) = globalvalsd(iaxismoment, sps) + & & ovrnts*funcvaluesd(costfuncaxismoment) - globalvalsd(icpmin, sps) = globalvalsd(icpmin, sps) - ovrnts*& -& funcvaluesd(costfunccpmin)/(cpmin_rho*globalvals(icpmin, sps)) + call popcontrol1b(branch) + if (branch .eq. 0) globalvalsd(icpmin, sps) = globalvalsd(icpmin& +& , sps) - ovrnts*funcvaluesd(costfunccpmin)/(cpmin_rho*& +& globalvals(icpmin, sps)) globalvalsd(icavitation, sps) = globalvalsd(icavitation, sps) + & & ovrnts*funcvaluesd(costfunccavitation) globalvalsd(isepsensor, sps) = globalvalsd(isepsensor, sps) + & @@ -780,6 +792,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& & machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho + use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives use flowutils_b, only : getdirvector @@ -891,8 +904,12 @@ subroutine getcostfunctions(globalvals, funcvalues) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation - funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& +& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& sps))/cpmin_rho) +! only calculate the log part if we are actually computing for cavitation. +! if we are not computing cavitation, the icpmin in globalvals will be zero, +! which doesn't play well with log. we just want to return zero here. funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index 212ed381b..86c7f7bb7 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -17,6 +17,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& & machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho + use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_fast_b, only : computetsderivatives use flowutils_fast_b, only : getdirvector @@ -128,8 +129,12 @@ subroutine getcostfunctions(globalvals, funcvalues) funcvalues(costfunccavitation) = funcvalues(costfunccavitation) + & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation - funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) + if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& +& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& sps))/cpmin_rho) +! only calculate the log part if we are actually computing for cavitation. +! if we are not computing cavitation, the icpmin in globalvals will be zero, +! which doesn't play well with log. we just want to return zero here. funcvalues(costfuncaxismoment) = funcvalues(costfuncaxismoment) + & & ovrnts*globalvals(iaxismoment, sps) funcvalues(costfuncsepsensoravgx) = funcvalues(& From 72d3cf9d813dd047d598217b5643530b2bc4133b Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 14:20:54 -0500 Subject: [PATCH 62/76] fixed variable declaration order. added test output to gitignore. --- .gitignore | 1 + src/overset/oversetAPI.F90 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 03c447853..309f6bb48 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ tests/*out # for the .cgnsTimestep... files tests/output_files/*.cgns* +tests/output_files/*.plt *.cgns *.txt diff --git a/src/overset/oversetAPI.F90 b/src/overset/oversetAPI.F90 index f76182fc3..442558a1c 100644 --- a/src/overset/oversetAPI.F90 +++ b/src/overset/oversetAPI.F90 @@ -2113,11 +2113,11 @@ subroutine flagCellsInSurface(pts, npts, conn, nconn, flag, ncell, blockids, nbl implicit none ! Input/Output + integer(kind=intType), intent(in) :: npts, nconn, ncell, nblocks real(kind=realType), intent(in), dimension(3,npts) :: pts integer(kind=intType), intent(in), dimension(4,nconn) :: conn integer(kind=intType), intent(inout), dimension(ncell) :: flag integer(kind=intType), intent(in), dimension(nblocks) :: blockids - integer(kind=intType), intent(in) :: npts, nconn, ncell, nblocks integer(kind=intType), intent(in) :: k_min ! Working variables From 9f91cc27a3e5fcec88f329aa4d02f3ffde8e01cb Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 15:23:02 -0500 Subject: [PATCH 63/76] black formatting --- adflow/pyADflow.py | 16 ++++++++++------ doc/conf.py | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 5c3f08b1b..6d5365d4f 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -836,14 +836,18 @@ def addCylindricalSlices( # name...so we will number sequentially from python jj = self.nSlice + ii + 1 if sliceType == "relative": - sliceName = f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f}" + \ - f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + \ - f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + sliceName = ( + f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f}" + + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + ) self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) else: - sliceName = f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f}" + \ - f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + \ - f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + sliceName = ( + f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f}" + + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " + + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" + ) self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) self.nSlice += n_slice diff --git a/doc/conf.py b/doc/conf.py index f6b006f4a..47f697777 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -35,4 +35,4 @@ intersphinx_mapping = { "mach-aero": ("https://mdolab-mach-aero.readthedocs-hosted.com/en/latest", None), "pygeo": ("https://mdolab-pygeo.readthedocs-hosted.com/en/latest", None), -} \ No newline at end of file +} From 40ede436fff6fbb7cc47c2d33ccf142af0b37ecc Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Sun, 20 Nov 2022 21:25:23 -0500 Subject: [PATCH 64/76] updated avx2 config file to be consistent with the newer config files --- config/defaults/config.LINUX_INTEL_AVX2.mk | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config/defaults/config.LINUX_INTEL_AVX2.mk b/config/defaults/config.LINUX_INTEL_AVX2.mk index 4d1be123f..581095c4a 100644 --- a/config/defaults/config.LINUX_INTEL_AVX2.mk +++ b/config/defaults/config.LINUX_INTEL_AVX2.mk @@ -27,8 +27,10 @@ CGNS_INCLUDE_FLAGS=-I$(CGNS_HOME)/include CGNS_LINKER_FLAGS=-L$(CGNS_HOME)/lib -lcgns # ------- Define Compiler Flags ---------------------------------------- -FF90_FLAGS = -DHAS_ISNAN -fPIC -r8 -O2 -g -xCORE-AVX2 -C_FLAGS = -DHAS_ISNAN -O -fPIC -xCORE-AVX2 +FF77_FLAGS = -fPIC -r8 +FF90_FLAGS = $(FF77_FLAGS) -std08 +FFXX_OPT_FLAGS = -O2 -xCORE-AVX2 +C_FLAGS = -fPIC -O -xCORE-AVX2 # ------- Define Archiver and Flags ----------------------------------- AR = ar @@ -36,7 +38,7 @@ AR_FLAGS = -rvs # ------- Define Linker Flags ------------------------------------------ LINKER = $(FF90) -LINKER_FLAGS = -nofor_main +LINKER_FLAGS = -nofor-main # ------- Define Petsc Info --- include ${PETSC_DIR}/lib/petsc/conf/variables From f093da4800394892d18721b1268ab827b4ecc63f Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 21 Nov 2022 22:16:53 -0500 Subject: [PATCH 65/76] minor update in docstrings --- adflow/pyADflow.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 6d5365d4f..5f3956b12 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -877,8 +877,7 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer= between the original reference frame and any other reference frame relevant to the current CFD case. This allows user to apply arbitrary modifications to the loaded plot3d surface. The call - signature is documented in the DVGeometry's addPointset method: - :meth:`addPointset ` + signature is documented in DVGeometry's :meth:`addPointset ` method. """ self.hasIntegrationSurfaces = True @@ -1001,8 +1000,7 @@ def addActuatorRegion( between the original reference frame and any other reference frame relevant to the current CFD case. This allows user to apply arbitrary modifications to the loaded plot3d surface. The call - signature is documented in the DVGeometry's addPointset method: - :meth:`addPointset ` + signature is documented in DVGeometry's :meth:`addPointset ` method. """ # ActuatorDiskRegions cannot be used in timeSpectralMode From f9bf2dd07e001a50ccbe798d8e4eb8a51406d849 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 7 Dec 2022 09:41:24 -0500 Subject: [PATCH 66/76] cleaned up slice names --- adflow/pyADflow.py | 54 ++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 23bd1df76..0c39c1437 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -592,7 +592,6 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): # Determine the families we want to use if groupName is None: groupName = self.allWallsGroup - groupTag = "%s: " % groupName famList = self._getFamilyList(groupName) direction = direction.lower() @@ -624,11 +623,13 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): # It is important to ensure each slice get a unique # name...so we will number sequentially from python j = self.nSlice + i + 1 + sliceName = ( + f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular " + f"{direction} = {positions[i]:.8f}" + ) if sliceType == "relative": - sliceName = "Slice_%4.4d %s Para Init %s=%7.3f" % (j, groupTag, direction, positions[i]) self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) else: - sliceName = "Slice_%4.4d %s Absolute %s=%7.3f" % (j, groupTag, direction, positions[i]) self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) self.nSlice += N @@ -671,16 +672,15 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No # Determine the families we want to use if groupName is None: groupName = self.allWallsGroup - groupTag = "%s: " % groupName famList = self._getFamilyList(groupName) sliceType = sliceType.lower() if sliceType not in ["relative", "absolute"]: raise Error("'sliceType' must be 'relative' or 'absolute'.") - n_slice = len(points) normals = numpy.atleast_2d(normals) points = numpy.atleast_2d(points) + n_slice = len(points) if len(normals) == 1: tmp = numpy.zeros((n_slice, 3), self.dtype) @@ -706,29 +706,14 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No else: direction = dummy_slice_dir + sliceName = ( + f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Arbitrary " + f"Point = ({points[i, 0]:.8f}, {points[i, 1]:.8f}, {points[i, 2]:.8f}) " + f"Normal = ({normals[i, 0]:.8f}, {normals[i, 1]:.8f}, {normals[i, 2]:.8f})" + ) if sliceType == "relative": - sliceName = "Slice_%4.4d %s Para Init Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( - j, - groupTag, - normals[i, 0], - normals[i, 1], - normals[i, 2], - points[i, 0], - points[i, 1], - points[i, 2], - ) self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], direction, use_dir, famList) else: - sliceName = "Slice_%4.4d %s Absolute Normal=(%7.3f, %7.3f, %7.3f) Point=(%7.3f, %7.3f, %7.3f)" % ( - j, - groupTag, - normals[i, 0], - normals[i, 1], - normals[i, 2], - points[i, 0], - points[i, 1], - points[i, 2], - ) self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], direction, use_dir, famList) self.nSlice += n_slice @@ -774,7 +759,6 @@ def addCylindricalSlices( # Determine the families we want to use if groupName is None: groupName = self.allWallsGroup - groupTag = "%s: " % groupName famList = self._getFamilyList(groupName) @@ -835,19 +819,17 @@ def addCylindricalSlices( # It is important to ensure each slice get a unique # name...so we will number sequentially from python jj = self.nSlice + ii + 1 + + sliceName = ( + f"Slice_{jj:04d} {groupName} {sliceType.capitalize()} Cylindrical " + f"Point = ({pt1[0]:.8f}, {pt1[1]:.8f}, {pt1[2]:.8f}) " + f"Normal = ({slice_normal[0]:.8f}, {slice_normal[1]:.8f}, {slice_normal[2]:.8f}) " + f"Axis = ({vec1[0]:.8f}, {vec1[1]:.8f}, {vec1[2]:.8f}) " + f"Theta = {angle * 180.0 / numpy.pi:.8f}" + ) if sliceType == "relative": - sliceName = ( - f"Slice_{jj:04d} {groupTag} Para Init Theta={angle * 180.0 / numpy.pi:.4f}" - + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " - + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" - ) self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) else: - sliceName = ( - f"Slice_{jj:04d} {groupTag} Absolute Theta={angle * 180.0 / numpy.pi:.4f}" - + f" pt=({pt1[0]:.4f}, {pt1[1]:.4f}, {pt1[2]:.4f}) normal=({slice_normal[0]:.4f}, " - + f"{slice_normal[1]:.4f}, {slice_normal[2]:.4f})" - ) self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) self.nSlice += n_slice From 2347815a3a22df3c9e90a146c7138f3d1e490939 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 7 Dec 2022 09:43:58 -0500 Subject: [PATCH 67/76] black formatting --- adflow/pyADflow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 0c39c1437..4e1f443e6 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -624,8 +624,7 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): # name...so we will number sequentially from python j = self.nSlice + i + 1 sliceName = ( - f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular " - f"{direction} = {positions[i]:.8f}" + f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular {direction} = {positions[i]:.8f}" ) if sliceType == "relative": self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) From 486303b3e22f69d9ec9191c31cf7b262ade7c7e8 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Wed, 7 Dec 2022 09:46:02 -0500 Subject: [PATCH 68/76] black formatter is gaslighting me --- adflow/pyADflow.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 4e1f443e6..6c7f36754 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -623,9 +623,8 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): # It is important to ensure each slice get a unique # name...so we will number sequentially from python j = self.nSlice + i + 1 - sliceName = ( - f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular {direction} = {positions[i]:.8f}" - ) + sliceName = f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular {direction} = {positions[i]:.8f}" + if sliceType == "relative": self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) else: From ea1bba1eb3400cb8876a85034bebd132e48010ac Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 12 Dec 2022 08:42:18 -0500 Subject: [PATCH 69/76] first pass at eirikur's comments --- adflow/pyADflow.py | 8 ++++++-- src/modules/inputParam.F90 | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 6c7f36754..fb659a642 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -308,7 +308,7 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): cutCallBackTime = time.time() - # exlclude the cells inside closed surfaces if we are provided with them + # exclude the cells inside closed surfaces if we are provided with them explicitSurfaceCallback = self.getOption("explicitSurfaceCallback") if explicitSurfaceCallback is not None: # the user wants to exclude cells that lie within a list of surfaces. @@ -328,7 +328,7 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): surf_file = surf_dict[surf]["surf_file"] # the indices of cgns blocks that we want to consider when blanking inside the surface block_ids = surf_dict[surf]["block_ids"] - # the fortran lookup expects this list in increaasing order + # the fortran lookup expects this list in increasing order block_ids.sort() # check if there is a kmin provided @@ -2483,6 +2483,10 @@ def writeSolution(self, outputDir=None, baseName=None, number=None, writeSlices= Use this supplied string for the base filename. Typically only used from an external solver. number : int Use the user supplied number to index solution. Again, only typically used from an external solver. + writeSlices : bool + Flag to determine if the slice files are written, if we have any slices added. + writeLift : bool + Flag to determine if the lift files are written, if we have any lift distributions added. """ if outputDir is None: outputDir = self.getOption("outputDirectory") diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 1b9453881..7d4cc9781 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -557,6 +557,12 @@ module inputPhysics ! muSuthDim: Reference viscosity at reference temperature for Sutherlands law (SI Units) ! TSuthDim: Reference temperature for Sutherlands law (SI Units) ! momentAxis(3,2) Axis about which to calculate a moment, provided as 2 points in 3-D + ! cavitationnumber Negative Cp value that triggers the traditional + ! step-function based cavitation sensor. + ! cpmin_rho The rho parameter used with the KS-based cavitation sensor. + ! cpmin_exact The "exact" cpmin for a given surface family that does not have + ! KS-aggregation. The "exact" wording refers to the fact that + ! we directly take the min. integer(kind=intType) :: equations, equationMode, flowType From 828f0b1e46be6f4e8d7be58852afc5c9cde44f56 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 12 Dec 2022 22:36:48 -0500 Subject: [PATCH 70/76] reduced some code duplication between slice addition methods --- adflow/pyADflow.py | 62 +++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index fb659a642..985579a31 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -586,22 +586,13 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): wall groups. """ - # Create the zipper mesh if not done so - self._createZipperMesh() + # call the preprocessing routine that avoids some code duplication across 3 types of slices + sliceType, famList = self._preprocessSliceInput(sliceType, groupName) - # Determine the families we want to use - if groupName is None: - groupName = self.allWallsGroup - - famList = self._getFamilyList(groupName) direction = direction.lower() if direction not in ["x", "y", "z"]: raise Error("'direction' must be one of 'x', 'y', or 'z'") - sliceType = sliceType.lower() - if sliceType not in ["relative", "absolute"]: - raise Error("'sliceType' must be 'relative' or 'absolute'.") - positions = numpy.atleast_1d(positions) N = len(positions) tmp = numpy.zeros((N, 3), self.dtype) @@ -664,17 +655,8 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No wall groups. """ - # Create the zipper mesh if not done so - self._createZipperMesh() - - # Determine the families we want to use - if groupName is None: - groupName = self.allWallsGroup - famList = self._getFamilyList(groupName) - - sliceType = sliceType.lower() - if sliceType not in ["relative", "absolute"]: - raise Error("'sliceType' must be 'relative' or 'absolute'.") + # call the preprocessing routine that avoids some code duplication across 3 types of slices + sliceType, famList = self._preprocessSliceInput(sliceType, groupName) normals = numpy.atleast_2d(normals) points = numpy.atleast_2d(points) @@ -751,18 +733,8 @@ def addCylindricalSlices( wall groups. """ - # Create the zipper mesh if not done so - self._createZipperMesh() - - # Determine the families we want to use - if groupName is None: - groupName = self.allWallsGroup - - famList = self._getFamilyList(groupName) - - sliceType = sliceType.lower() - if sliceType not in ["relative", "absolute"]: - raise Error("'sliceType' must be 'relative' or 'absolute'.") + # call the preprocessing routine that avoids some code duplication across 3 types of slices + sliceType, famList = self._preprocessSliceInput(sliceType, groupName) # get the angles that we are slicing in radians angles = numpy.linspace(slice_beg, slice_end, n_slice) * numpy.pi / 180.0 @@ -832,6 +804,25 @@ def addCylindricalSlices( self.nSlice += n_slice + def _preprocessSliceInput(self, sliceType, groupName): + """ + Preprocessing routine that holds some of the duplicated code required for 3 types of slice methods. + """ + # Create the zipper mesh if not done so + self._createZipperMesh() + + # Determine the families we want to use + if groupName is None: + groupName = self.allWallsGroup + famList = self._getFamilyList(groupName) + + # check the sliceType + sliceType = sliceType.lower() + if sliceType not in ["relative", "absolute"]: + raise Error("'sliceType' must be 'relative' or 'absolute'.") + + return sliceType, famList + def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer=None): """Add a specific integration surface for performing massflow-like computations. @@ -1023,8 +1014,7 @@ def addActuatorRegion( if relaxEnd is None and relaxStart is not None: raise Error("relaxEnd must be given is relaxStart is specified") - # Now continue to fortran were we setup the actual - # region. + # Now continue to fortran were we setup the actual actuator region. self.adflow.actuatorregion.addactuatorregion( pts.T, conn.T, axis1, axis2, familyName, famID, thrust, torque, heat, relaxStart, relaxEnd ) From e0a4ed71d20999b16f4b418e8e488c7b6d396ff3 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 12 Dec 2022 23:17:43 -0500 Subject: [PATCH 71/76] camelcase updates --- adflow/pyADflow.py | 136 ++++++++++++++--------------- doc/options.yaml | 22 ++--- tests/reg_tests/test_cavitation.py | 42 ++++----- 3 files changed, 100 insertions(+), 100 deletions(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 985579a31..2a2af4a94 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -316,45 +316,45 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # first, call the callback function with cgns zone name IDs. # this need to return us a dictionary with the surface mesh information, # as well as which blocks in the cgns mesh to include in the search - surf_dict = explicitSurfaceCallback(self.CGNSZoneNameIDs) + surfDict = explicitSurfaceCallback(self.CGNSZoneNameIDs) # loop over the surfaces - for surf in surf_dict: + for surf in surfDict: if self.comm.rank == 0: print(f"Explicitly blanking surface: {surf}") # this is the plot3d surface that defines the closed volume - surf_file = surf_dict[surf]["surf_file"] + surfFile = surfDict[surf]["surfFile"] # the indices of cgns blocks that we want to consider when blanking inside the surface - block_ids = surf_dict[surf]["block_ids"] + blockIDs = surfDict[surf]["blockIds"] # the fortran lookup expects this list in increasing order - block_ids.sort() + blockIDs.sort() - # check if there is a kmin provided - if "kmin" in surf_dict[surf]: - kmin = surf_dict[surf]["kmin"] + # check if there is a kMin provided + if "kMin" in surfDict[surf]: + kMin = surfDict[surf]["kMin"] else: - kmin = -1 + kMin = -1 # optional coordinate transformation to do general manipulation of the coordinates - if "coord_xfer" in surf_dict[surf]: - coord_xfer = surf_dict[surf]["coord_xfer"] + if "coordXfer" in surfDict[surf]: + coordXfer = surfDict[surf]["coordXfer"] else: - coord_xfer = None + coordXfer = None # read the plot3d surface - pts, conn = self._readPlot3DSurfFile(surf_file, convertToTris=False, coord_xfer=coord_xfer) + pts, conn = self._readPlot3DSurfFile(surfFile, convertToTris=False, coordXfer=coordXfer) # get a new flag array - surf_flag = numpy.zeros(n, "intc") + surfFlag = numpy.zeros(n, "intc") # call the fortran routine to determine if the cells are inside or outside. # this code is very similar to the actuator zone creation. - self.adflow.oversetapi.flagcellsinsurface(pts.T, conn.T, surf_flag, block_ids, kmin) + self.adflow.oversetapi.flagcellsinsurface(pts.T, conn.T, surfFlag, blockIDs, kMin) # update the flag array with the new info - flag = numpy.any([flag, surf_flag], axis=0) + flag = numpy.any([flag, surfFlag], axis=0) explicitSurfaceCutTime = time.time() @@ -607,8 +607,8 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): normal = [0.0, 0.0, 1.0] # for regular slices, we dont use the direction vector to pick a projection direction - slice_dir = [1.0, 0.0, 0.0] - use_dir = False + sliceDir = [1.0, 0.0, 0.0] + useDir = False for i in range(len(positions)): # It is important to ensure each slice get a unique @@ -617,13 +617,13 @@ def addSlices(self, direction, positions, sliceType="relative", groupName=None): sliceName = f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Regular {direction} = {positions[i]:.8f}" if sliceType == "relative": - self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, tmp[i], normal, sliceDir, useDir, famList) else: - self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, slice_dir, use_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, tmp[i], normal, sliceDir, useDir, famList) self.nSlice += N - def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None, slice_dir=None): + def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=None, sliceDir=None): """ Add slices that vary arbitrarily in space. This is a generalization of the :meth:`addSlices <.addSlices>` routine, where we have the user specify a list of "normals" @@ -632,14 +632,14 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No Parameters ---------- - normals : 3-d array or ndarray (n_slice, 3) + normals : 3-d array or ndarray (nSlice, 3) The normals of the slice directions. If an array of size 3 is passed, we use the same normal for all slices. if an array of multiple normals are passed, we use the individual normals for each point. in this case, the numbers of points and normals must match. - points : ndarray (n_slice, 3) + points : ndarray (nSlice, 3) Point coordinates that define a slicing plane along with the normals - slice_dir : ndarray (n_slice, 3) + sliceDir : ndarray (nSlice, 3) If this is provided, only the intersections that is in this direction starting from the normal is kept. This is useful if you are slicing a closed geometry and only want to keep one side of it. It is similar to @@ -660,31 +660,31 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No normals = numpy.atleast_2d(normals) points = numpy.atleast_2d(points) - n_slice = len(points) + nSlice = len(points) if len(normals) == 1: - tmp = numpy.zeros((n_slice, 3), self.dtype) + tmp = numpy.zeros((nSlice, 3), self.dtype) tmp[:] = normals normals = tmp - if slice_dir is None: + if sliceDir is None: # if we dont have a direction vector to pick a projection direction, we can just set this - # array to an arbitrary direction. Because the use_dir flag is false, the code won't actually + # array to an arbitrary direction. Because the useDir flag is false, the code won't actually # use this array - dummy_slice_dir = [1.0, 0.0, 0.0] - use_dir = False + dummySliceDir = [1.0, 0.0, 0.0] + useDir = False else: - use_dir = True + useDir = True - for i in range(n_slice): + for i in range(nSlice): # It is important to ensure each slice get a unique # name...so we will number sequentially from python j = self.nSlice + i + 1 - if use_dir: - direction = slice_dir[j] + if useDir: + direction = sliceDir[j] else: - direction = dummy_slice_dir + direction = dummySliceDir sliceName = ( f"Slice_{j:04d} {groupName} {sliceType.capitalize()} Arbitrary " @@ -692,14 +692,14 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No f"Normal = ({normals[i, 0]:.8f}, {normals[i, 1]:.8f}, {normals[i, 2]:.8f})" ) if sliceType == "relative": - self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], direction, use_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, points[i], normals[i], direction, useDir, famList) else: - self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], direction, use_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, points[i], normals[i], direction, useDir, famList) - self.nSlice += n_slice + self.nSlice += nSlice def addCylindricalSlices( - self, pt1, pt2, n_slice=180, slice_beg=0.0, slice_end=360.0, sliceType="relative", groupName=None + self, pt1, pt2, nSlice=180, sliceBeg=0.0, sliceEnd=360.0, sliceType="relative", groupName=None ): """ Add cylindrical projection slices. The cylindrical projection axis is defined @@ -716,11 +716,11 @@ def addCylindricalSlices( beginning point of the vector that defines the rotation axis pt2 : numpy array, length 3 end point of the vector that defines the rotation axis - n_slice : int + nSlice : int number of slices around a 360 degree full rotation. - slice_beg : float + sliceBeg : float beginning of the slices in the rotation direction in degrees - slice_end : float + sliceEnd : float end of the slices in the rotation direction in degrees sliceType : str {'relative', 'absolute'} Relative slices are 'sliced' at the beginning and then parametrically @@ -737,11 +737,11 @@ def addCylindricalSlices( sliceType, famList = self._preprocessSliceInput(sliceType, groupName) # get the angles that we are slicing in radians - angles = numpy.linspace(slice_beg, slice_end, n_slice) * numpy.pi / 180.0 + angles = numpy.linspace(sliceBeg, sliceEnd, nSlice) * numpy.pi / 180.0 # unit vector in the lift direction - lift_dir = numpy.zeros(3) - lift_dir[self.getOption("liftIndex") - 1] = 1.0 + liftDir = numpy.zeros(3) + liftDir[self.getOption("liftIndex") - 1] = 1.0 # the unit vector on the axis vec1 = pt2 - pt1 @@ -765,26 +765,26 @@ def addCylindricalSlices( ) # rotate the lift direction vector to get the slice direction - slice_dir = rot_mat.dot(lift_dir) + sliceDir = rot_mat.dot(liftDir) - # In general, the "slice_dir" does not need to be orthogonal to vec1, which is the center axis of the cylinder. So we make it orthogonal - slice_dir -= vec1.dot(slice_dir) * vec1 + # In general, the "sliceDir" does not need to be orthogonal to vec1, which is the center axis of the cylinder. So we make it orthogonal + sliceDir -= vec1.dot(sliceDir) * vec1 - # normalize slice_dir - slice_dir /= numpy.linalg.norm(slice_dir) + # normalize sliceDir + sliceDir /= numpy.linalg.norm(sliceDir) # cross product vec1 and vec2 to get the normal vector of this plane - slice_normal = numpy.cross(vec1, slice_dir) + sliceNormal = numpy.cross(vec1, sliceDir) # normalize for good measure - slice_normal /= numpy.linalg.norm(slice_normal) + sliceNormal /= numpy.linalg.norm(sliceNormal) - # we can now define a plane for the slice using p1 and slice_normal. + # we can now define a plane for the slice using p1 and sliceNormal. # in the cylindrical version, we also pick a "direction". This is which direction we are going # from the center axis. We will reject cells directly if their centroid are behind this - # direction (i.e. dot slice_dir is negative) and only use the cells that are in + # direction (i.e. dot sliceDir is negative) and only use the cells that are in # the same direction (i.e. dot product positive.) # this flag determines that we will use the direction vector as well to pick the slice dir. - use_dir = True + useDir = True # It is important to ensure each slice get a unique # name...so we will number sequentially from python @@ -793,16 +793,16 @@ def addCylindricalSlices( sliceName = ( f"Slice_{jj:04d} {groupName} {sliceType.capitalize()} Cylindrical " f"Point = ({pt1[0]:.8f}, {pt1[1]:.8f}, {pt1[2]:.8f}) " - f"Normal = ({slice_normal[0]:.8f}, {slice_normal[1]:.8f}, {slice_normal[2]:.8f}) " + f"Normal = ({sliceNormal[0]:.8f}, {sliceNormal[1]:.8f}, {sliceNormal[2]:.8f}) " f"Axis = ({vec1[0]:.8f}, {vec1[1]:.8f}, {vec1[2]:.8f}) " f"Theta = {angle * 180.0 / numpy.pi:.8f}" ) if sliceType == "relative": - self.adflow.tecplotio.addparaslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) + self.adflow.tecplotio.addparaslice(sliceName, pt1, sliceNormal, sliceDir, useDir, famList) else: - self.adflow.tecplotio.addabsslice(sliceName, pt1, slice_normal, slice_dir, use_dir, famList) + self.adflow.tecplotio.addabsslice(sliceName, pt1, sliceNormal, sliceDir, useDir, famList) - self.nSlice += n_slice + self.nSlice += nSlice def _preprocessSliceInput(self, sliceType, groupName): """ @@ -823,7 +823,7 @@ def _preprocessSliceInput(self, sliceType, groupName): return sliceType, famList - def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer=None): + def addIntegrationSurface(self, fileName, familyName, isInflow=True, coordXfer=None): """Add a specific integration surface for performing massflow-like computations. @@ -843,7 +843,7 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer= Flag to treat momentum forces as if it is an inflow or outflow face. Default is True - coord_xfer : function + coordXfer : function A callback function that performs a coordinate transformation between the original reference frame and any other reference frame relevant to the current CFD case. This allows user to apply @@ -872,7 +872,7 @@ def addIntegrationSurface(self, fileName, familyName, isInflow=True, coord_xfer= # of nodes/elements of the defined surface are sufficiently # small that we do not have to worry about parallelization. - pts, conn = self._readPlot3DSurfFile(fileName, coord_xfer=coord_xfer) + pts, conn = self._readPlot3DSurfFile(fileName, coordXfer=coordXfer) self.adflow.usersurfaceintegrations.addintegrationsurface(pts.T, conn.T, familyName, famID, isInflow) @@ -887,7 +887,7 @@ def addActuatorRegion( heat=0.0, relaxStart=None, relaxEnd=None, - coord_xfer=None, + coordXfer=None, ): """ Add an actuator disk zone defined by the supplied closed @@ -966,7 +966,7 @@ def addActuatorRegion( The end of the relaxation in terms of orders of magnitude of relative convergence - coord_xfer : function + coordXfer : function A callback function that performs a coordinate transformation between the original reference frame and any other reference frame relevant to the current CFD case. This allows user to apply @@ -979,7 +979,7 @@ def addActuatorRegion( raise Error("ActuatorRegions cannot be used in Time Spectral Mode.") # Load in the user supplied surface file. - pts, conn = self._readPlot3DSurfFile(fileName, convertToTris=False, coord_xfer=coord_xfer) + pts, conn = self._readPlot3DSurfFile(fileName, convertToTris=False, coordXfer=coordXfer) # We should do a topology check to ensure that the surface the # user supplied is actually closed. @@ -6173,7 +6173,7 @@ def _convertFortranStringArrayToList(self, fortArray): return strList - def _readPlot3DSurfFile(self, fileName, convertToTris=True, coord_xfer=None): + def _readPlot3DSurfFile(self, fileName, convertToTris=True, coordXfer=None): """Read a plot3d file and return the points and connectivity in an unstructured mesh format""" @@ -6221,11 +6221,11 @@ def _readPlot3DSurfFile(self, fileName, convertToTris=True, coord_xfer=None): # coordinate transformation for the coordinates if we have any. # this is where the user can rotate, translate, or generally manipulate # the coordinates coming from the plot3d file before they are used - if coord_xfer is not None: + if coordXfer is not None: # this callback function has the same call signature with the # method described in the DVGeometry addPointSet method: # https://github.com/mdolab/pygeo/blob/main/pygeo/parameterization/DVGeo.py - pts = coord_xfer(pts, mode="fwd", apply_displacement=True) + pts = coordXfer(pts, mode="fwd", applyDisplacement=True) # Update the conn newConn = numpy.zeros_like(conn) diff --git a/doc/options.yaml b/doc/options.yaml index 863057661..667c20bac 100644 --- a/doc/options.yaml +++ b/doc/options.yaml @@ -548,27 +548,27 @@ explicitSurfaceCallback: # obtain this surface file is to convert the surface # CGNS grid used to generate the mesh into the plot3d # format using the cgns2plot3d method in cgnsutils. - "surf_file": "wing_surface.x", + "surfFile": "wing_surface.x", # The block IDs we will search and blank using this surface. # Here, we only blank the fuselage cells that are inside the wing # and don't want to consider the background or collar meshes. - "block_ids": fuselage_blocks, + "blockIDs": fuselage_blocks, - # Optional entry: coord_xfer + # Optional entry: coordXfer # This is another callback function that performs a coordinate # transformation on the loaded plot3d mesh nodes. See the # addPointSet method in DVGeo.py at # https://github.com/mdolab/pygeo for the call signature. # We use this approach so that the users can have complete # control over the surface mesh nodes after they are loaded. - "coord_xfer": coord_xfer, + "coordXfer": coordXfer, }, # Similar entries for the fuselage. "fuselage": { - "surf_file": "fuselage_surface.x", - "block_ids": wing_blocks, + "surfFile": "fuselage_surface.x", + "blockIDs": wing_blocks, }, # We can have multiple entries with the same surface to blank different @@ -584,10 +584,10 @@ explicitSurfaceCallback: # they intersect the wing geometry itself somehow. E.g. very large splay. # However, we only want to blank cells that have a k-index that is # larger than 32 to avoid tagging cells near the wall. The - # optional "kmin" entry is used to achieve this. - "surf_file": "wing_surface.x", - "block_ids": wing_blocks, - "kmin": 32, + # optional "kMin" entry is used to achieve this. + "surfFile": "wing_surface.x", + "blockIDs": wing_blocks, + "kMin": 32, }, } @@ -595,7 +595,7 @@ explicitSurfaceCallback: # explicit blanking with the information provided. return surf_dict - The call signature of the ``coord_xfer`` option is documented in the DVGeometry's addPointset method: + The call signature of the ``coordXfer`` option is documented in the DVGeometry's addPointset method: :meth:`addPointset ` diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 1a103e4ea..6f38942b5 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -90,7 +90,7 @@ def test_cavitation_metrics_and_derivatives(self): self.handler.root_print("cavitation totals") self.handler.root_add_dict("cavitation totals", funcsSens, rtol=1e-10, atol=1e-10) - for func_name in evalFuncs: + for funcName in evalFuncs: ################## # GEOMETRIC TOTALS ################## @@ -101,8 +101,8 @@ def test_cavitation_metrics_and_derivatives(self): # Now that we have the adjoint solution for both functionals # also get a total derivative wrt a random spatial perturbation DV - psi = -self.CFDSolver.getAdjoint(func_name) - funcsBar = self.CFDSolver._getFuncsBar(func_name) + psi = -self.CFDSolver.getAdjoint(funcName) + funcsBar = self.CFDSolver._getFuncsBar(funcName) # this is the reverse seed up to the volume coordinates xVBar = self.CFDSolver.computeJacobianVectorProductBwd(resBar=psi, funcsBar=funcsBar, xVDeriv=True) @@ -113,7 +113,7 @@ def test_cavitation_metrics_and_derivatives(self): # by the processor count or architecture. We just have it here to have some test on the # cavitation functionals' derivatives w.r.t. spatial changes in a lazy way. self.handler.par_add_sum( - f"total {func_name} derivative wrt random volume perturbation", dotLocal, rtol=1e-3 + f"total {funcName} derivative wrt random volume perturbation", dotLocal, rtol=1e-3 ) ################## @@ -121,22 +121,22 @@ def test_cavitation_metrics_and_derivatives(self): ################## fDot_w = self.CFDSolver.computeJacobianVectorProductFwd(wDot=wDot, funcDeriv=True) fDot_xv = self.CFDSolver.computeJacobianVectorProductFwd(xVDot=xVDot, funcDeriv=True) - funcsBar = {func_name: 1.0} + funcsBar = {funcName: 1.0} wBar, xVBar = self.CFDSolver.computeJacobianVectorProductBwd(funcsBar=funcsBar, wDeriv=True, xVDeriv=True) # do the dot product. we test both state partials and volume coordinate partials # state dotLocal1 = np.dot(wDot, wBar) - dotLocal2 = fDot_w[func_name] / self.CFDSolver.comm.size + dotLocal2 = fDot_w[funcName] / self.CFDSolver.comm.size - self.handler.par_add_sum(f"Dot product test for w -> {func_name}", dotLocal1, rtol=1e-10) - self.handler.par_add_sum(f"Dot product test for w -> {func_name}", dotLocal2, rtol=1e-10, compare=True) + self.handler.par_add_sum(f"Dot product test for w -> {funcName}", dotLocal1, rtol=1e-10) + self.handler.par_add_sum(f"Dot product test for w -> {funcName}", dotLocal2, rtol=1e-10, compare=True) # volume coords dotLocal1 = np.dot(xVDot, xVBar) - dotLocal2 = fDot_xv[func_name] / self.CFDSolver.comm.size - self.handler.par_add_sum(f"Dot product test for xV -> {func_name}", dotLocal1, rtol=1e-10) - self.handler.par_add_sum(f"Dot product test for xV -> {func_name}", dotLocal2, rtol=1e-10, compare=True) + dotLocal2 = fDot_xv[funcName] / self.CFDSolver.comm.size + self.handler.par_add_sum(f"Dot product test for xV -> {funcName}", dotLocal1, rtol=1e-10) + self.handler.par_add_sum(f"Dot product test for xV -> {funcName}", dotLocal2, rtol=1e-10, compare=True) class CavitationCmplxTests(reg_test_classes.CmplxRegTest): @@ -214,13 +214,13 @@ def cmplx_test_cavitation_adjoints(self): self.ap.setDesignVars(aDV) elif dv == "vol_perturbation": xVDot = self.CFDSolver.getSpatialPerturbation(314) - # grid_save = np.zeros_like(xVDot) + # gridSave = np.zeros_like(xVDot) # get the original grid - grid_save = self.CFDSolver.adflow.warping.getgrid(self.CFDSolver.getSpatialSize()) + gridSave = self.CFDSolver.adflow.warping.getgrid(self.CFDSolver.getSpatialSize()) # perturb using the random seed # this is very intrusive but it works and its testing these functions sensitivities # wrt geometric DVs w/o actually having a mesh or dvgeo object - self.CFDSolver.adflow.warping.setgrid(grid_save + self.h * 1j * xVDot) + self.CFDSolver.adflow.warping.setgrid(gridSave + self.h * 1j * xVDot) self.CFDSolver.adflow.preprocessingapi.updatecoordinatesalllevels() self.CFDSolver.adflow.walldistance.updatewalldistancealllevels() self.CFDSolver.adflow.preprocessingapi.updatemetricsalllevels() @@ -251,7 +251,7 @@ def cmplx_test_cavitation_adjoints(self): self.ap.setDesignVars(aDV) elif dv == "vol_perturbation": # set the original grid back - self.CFDSolver.adflow.warping.setgrid(grid_save) + self.CFDSolver.adflow.warping.setgrid(gridSave) ################## # TEST DERIVATIVES @@ -261,15 +261,15 @@ def cmplx_test_cavitation_adjoints(self): # we treat the CS value as the truth, so if this test passes, # we assume the adjoint sensitivities are also true - for func_name in ["cavitation", "cpmin"]: + for funcName in ["cavitation", "cpmin"]: - full_name = f"naca0012_rans_2D_{func_name}" + fullName = f"naca0012_rans_2D_{funcName}" - ref_val = self.handler.db["cavitation totals"][full_name]["alpha"] - np.testing.assert_allclose(funcsSensCS["alpha"][full_name], ref_val, atol=1e-10, rtol=1e-10) + refVal = self.handler.db["cavitation totals"][fullName]["alpha"] + np.testing.assert_allclose(funcsSensCS["alpha"][fullName], refVal, atol=1e-10, rtol=1e-10) - ref_val = self.handler.db[f"total {func_name} derivative wrt random volume perturbation"] - np.testing.assert_allclose(funcsSensCS["vol_perturbation"][full_name], ref_val, rtol=1e-3) + refVal = self.handler.db[f"total {funcName} derivative wrt random volume perturbation"] + np.testing.assert_allclose(funcsSensCS["vol_perturbation"][fullName], refVal, rtol=1e-3) if __name__ == "__main__": From d6da220b751736c4dce870a7351c7476da0ed4bf Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Mon, 12 Dec 2022 23:31:11 -0500 Subject: [PATCH 72/76] rename cpmin_exact to cpmin_family --- .../outputForward/surfaceintegrations_d.f90 | 42 +++++++++---------- .../outputReverse/surfaceintegrations_b.f90 | 42 +++++++++---------- .../surfaceintegrations_fast_b.f90 | 20 ++++----- src/inputParam/inputParamRoutines.F90 | 2 +- src/modules/inputParam.F90 | 7 ++-- src/solver/surfaceIntegrations.F90 | 22 +++++----- 6 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 21ed50fec..fe5b8e71f 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -24,7 +24,7 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & +& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_family, & & cpmin_rho use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability @@ -235,7 +235,7 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin) - ovrnts& & *globalvalsd(icpmin, sps)/(globalvals(icpmin, sps)*cpmin_rho) funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_exact-log(globalvals(icpmin, sps))/cpmin_rho) +& cpmin_family-log(globalvals(icpmin, sps))/cpmin_rho) end if funcvaluesd(costfuncaxismoment) = funcvaluesd(costfuncaxismoment) & & + ovrnts*globalvalsd(iaxismoment, sps) @@ -560,7 +560,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_family, cpmin_rho use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_d, only : computetsderivatives @@ -675,7 +675,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & & sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, @@ -853,7 +853,7 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cpmin_exact, cpmin_rho, cavitationnumber +& cpmin_family, cpmin_rho, cavitationnumber use bcpointers_d implicit none ! input/output variables @@ -902,10 +902,10 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype) :: result1d real(kind=realtype) :: pwr1 real(kind=realtype) :: pwr1d - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1164,8 +1164,8 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_exact))) - ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) + ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_family))) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sumd = cpmin_ks_sumd + blk*ks_exponentd cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if @@ -1375,7 +1375,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber +& equations, momentaxis, cpmin_family, cpmin_rho, cavitationnumber use bcpointers_d implicit none ! input/output variables @@ -1406,10 +1406,10 @@ subroutine wallintegrationface(localvalues, mm) real(kind=realtype) :: arg1 real(kind=realtype) :: result1 real(kind=realtype) :: pwr1 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1563,7 +1563,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -1769,10 +1769,10 @@ subroutine flowintegrationface_d(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2141,10 +2141,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index 01fea2047..b530bdbd1 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -25,7 +25,7 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & trefd, lref, gammainf, pinf, pinfd, uref, urefd, uinf, uinfd use inputphysics, only : liftdirection, liftdirectiond, & & dragdirection, dragdirectiond, surfaceref, machcoef, machcoefd, & -& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_exact, & +& lengthref, alpha, alphad, beta, betad, liftindex, cpmin_family, & & cpmin_rho use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability @@ -187,7 +187,7 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & & sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, @@ -791,7 +791,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_family, cpmin_rho use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_b, only : computetsderivatives @@ -905,7 +905,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & & sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, @@ -1084,7 +1084,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) use inputcostfunctions use inputphysics, only : machcoef, machcoefd, pointref, pointrefd,& & veldirfreestream, veldirfreestreamd, equations, momentaxis, & -& cpmin_exact, cpmin_rho, cavitationnumber +& cpmin_family, cpmin_rho, cavitationnumber use bcpointers_b implicit none ! input/output variables @@ -1164,10 +1164,10 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: tempd16 real(kind=realtype) :: temp4 real(kind=realtype) :: tempd15 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1308,7 +1308,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -1631,7 +1631,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) & temp5)*sensor1d end if ks_exponentd = blk*cpmin_ks_sumd - cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(cpmin_exact-cp))*& + cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(cpmin_family-cp))*& & ks_exponentd tmpd = (plocal-pinf)*cpd plocald = tmp*cpd @@ -1815,7 +1815,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber +& equations, momentaxis, cpmin_family, cpmin_rho, cavitationnumber use bcpointers_b implicit none ! input/output variables @@ -1843,10 +1843,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1996,7 +1996,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -2212,10 +2212,10 @@ subroutine flowintegrationface_b(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2534,10 +2534,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index 86c7f7bb7..2622b5983 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -16,7 +16,7 @@ subroutine getcostfunctions(globalvals, funcvalues) use flowvarrefstate, only : pref, rhoref, tref, lref, gammainf, & & pinf, uref, uinf use inputphysics, only : liftdirection, dragdirection, surfaceref,& -& machcoef, lengthref, alpha, beta, liftindex, cpmin_exact, cpmin_rho +& machcoef, lengthref, alpha, beta, liftindex, cpmin_family, cpmin_rho use inputcostfunctions, only : computecavitation use inputtsstabderiv, only : tsstability use utils_fast_b, only : computetsderivatives @@ -130,7 +130,7 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_exact-log(globalvals(icpmin, & +& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & & sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, @@ -293,7 +293,7 @@ subroutine wallintegrationface(localvalues, mm) use flowvarrefstate use inputcostfunctions use inputphysics, only : machcoef, pointref, veldirfreestream, & -& equations, momentaxis, cpmin_exact, cpmin_rho, cavitationnumber +& equations, momentaxis, cpmin_family, cpmin_rho, cavitationnumber use bcpointers_fast_b implicit none ! input/output variables @@ -321,10 +321,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -474,7 +474,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_exact)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -644,10 +644,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/inputParam/inputParamRoutines.F90 b/src/inputParam/inputParamRoutines.F90 index f99dc1aa6..d2dc10baf 100644 --- a/src/inputParam/inputParamRoutines.F90 +++ b/src/inputParam/inputParamRoutines.F90 @@ -4042,7 +4042,7 @@ subroutine setDefaultValues usematrixfreedrdw = .False. sepSensorOffset = zero sepSensorSharpness = 10_realType - cpmin_exact = zero + cpmin_family = zero end subroutine setDefaultValues subroutine initializeIsoSurfaceVariables(values, nValues) diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 7d4cc9781..6c5c52137 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -560,9 +560,8 @@ module inputPhysics ! cavitationnumber Negative Cp value that triggers the traditional ! step-function based cavitation sensor. ! cpmin_rho The rho parameter used with the KS-based cavitation sensor. - ! cpmin_exact The "exact" cpmin for a given surface family that does not have - ! KS-aggregation. The "exact" wording refers to the fact that - ! we directly take the min. + ! cpmin_family The cpmin for a given surface family that does not use + ! KS-aggregation, but rather an exact min computation. integer(kind=intType) :: equations, equationMode, flowType @@ -589,7 +588,7 @@ module inputPhysics real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber real(kind=realType) :: cpmin_rho - real(kind=realType) :: cpmin_exact + real(kind=realType) :: cpmin_family #ifndef USE_TAPENADE real(kind=realType) :: alphad, betad diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 25cd6b665..1f755949f 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -8,7 +8,7 @@ subroutine getCostFunctions(globalVals, funcValues) use inputTimeSpectral, only : nTimeIntervalsSpectral use flowVarRefState, only : pRef, rhoRef, tRef, LRef, gammaInf, pInf, uRef, uInf use inputPhysics, only : liftDirection, dragDirection, surfaceRef, & - machCoef, lengthRef, alpha, beta, liftIndex, cpmin_exact, & + machCoef, lengthRef, alpha, beta, liftIndex, cpmin_family, & cpmin_rho use inputCostFunctions, only : computeCavitation use inputTSStabDeriv, only : TSstability @@ -114,7 +114,7 @@ subroutine getCostFunctions(globalVals, funcValues) ! If we are not computing cavitation, the iCpMin in globalVals will be zero, ! which doesn't play well with log. we just want to return zero here. funcValues(costfunccpmin) = funcValues(costfunccpmin) + ovrNTS * & - (cpmin_exact - log(globalVals(iCpMin, sps)) / cpmin_rho) + (cpmin_family - log(globalVals(iCpMin, sps)) / cpmin_rho) endif funcValues(costFuncAxisMoment) = funcValues(costFuncAxisMoment) + ovrNTS*globalVals(iAxisMoment, sps) @@ -323,7 +323,7 @@ subroutine wallIntegrationFace(localValues, mm) use flowVarRefState use inputCostFunctions use inputPhysics, only : MachCoef, pointRef, velDirFreeStream, & - equations, momentAxis, cpmin_exact, cpmin_rho, cavitationnumber + equations, momentAxis, cpmin_family, cpmin_rho, cavitationnumber use BCPointers implicit none @@ -523,7 +523,7 @@ subroutine wallIntegrationFace(localValues, mm) Cavitation = Cavitation + Sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho * (-Cp + cpmin_exact)) + ks_exponent = exp(cpmin_rho * (-Cp + cpmin_family)) cpmin_ks_sum = cpmin_ks_sum + ks_exponent * blk end if enddo @@ -983,7 +983,7 @@ subroutine getSolution(famLists, funcValues, globalValues) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCpMinExact(famList) + call computeCpMinFamily(famList) end if do sps=1, nTimeIntervalsSpectral @@ -1078,13 +1078,13 @@ subroutine integrateSurfaces(localValues, famList) end subroutine integrateSurfaces - subroutine computeCpMinExact(famList) + subroutine computeCpMinFamily(famList) use constants use inputTimeSpectral, only : nTimeIntervalsSpectral use communication, only : ADflow_comm_world, myID use blockPointers, only : nDom - use inputPhysics, only : cpmin_exact, MachCoef + use inputPhysics, only : cpmin_family, MachCoef use blockPointers use flowVarRefState use BCPointers @@ -1151,11 +1151,11 @@ subroutine computeCpMinExact(famList) end do ! finally communicate across all processors - call mpi_allreduce(cpmin_local, cpmin_exact, 1, MPI_DOUBLE, & + call mpi_allreduce(cpmin_local, cpmin_family, 1, MPI_DOUBLE, & MPI_MIN, adflow_comm_world, ierr) call EChk(ierr, __FILE__, __LINE__) - end subroutine computeCpMinExact + end subroutine computeCpMinFamily #ifndef USE_COMPLEX subroutine integrateSurfaces_d(localValues, localValuesd, famList) @@ -1287,7 +1287,7 @@ subroutine getSolution_d(famLists, funcValues, funcValuesd) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCpMinExact(famList) + call computeCpMinFamily(famList) end if localVal = zero @@ -1373,7 +1373,7 @@ subroutine getSolution_b(famLists, funcValues, funcValuesd) ! compute the current cp min value for the cavitation computation with KS aggregation if (computeCavitation) then - call computeCpMinExact(famList) + call computeCpMinFamily(famList) end if localVal = zero From 2b36dc849dddd04f897df7b1e9f5a9017120a1c9 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 13 Dec 2022 08:04:26 -0500 Subject: [PATCH 73/76] black fix and reran tapenade --- .../outputForward/surfaceintegrations_d.f90 | 27 ++++++++++--------- .../outputReverse/surfaceintegrations_b.f90 | 24 ++++++++--------- .../surfaceintegrations_fast_b.f90 | 12 ++++----- tests/reg_tests/test_cavitation.py | 4 +-- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index fe5b8e71f..5a99740be 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -902,10 +902,10 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) real(kind=realtype) :: result1d real(kind=realtype) :: pwr1 real(kind=realtype) :: pwr1d - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1164,7 +1164,8 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_family))) + ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_family))& +& ) ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) cpmin_ks_sumd = cpmin_ks_sumd + blk*ks_exponentd cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk @@ -1406,10 +1407,10 @@ subroutine wallintegrationface(localvalues, mm) real(kind=realtype) :: arg1 real(kind=realtype) :: result1 real(kind=realtype) :: pwr1 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1769,10 +1770,10 @@ subroutine flowintegrationface_d(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2141,10 +2142,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index b530bdbd1..2a3905a9c 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -1164,10 +1164,10 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) real(kind=realtype) :: tempd16 real(kind=realtype) :: temp4 real(kind=realtype) :: tempd15 - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -1843,10 +1843,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -2212,10 +2212,10 @@ subroutine flowintegrationface_b(isinflow, localvalues, localvaluesd, & ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows @@ -2534,10 +2534,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index 2622b5983..e5eb1f2c6 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -321,10 +321,10 @@ subroutine wallintegrationface(localvalues, mm) intrinsic max intrinsic sqrt intrinsic exp - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = -one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = one end select ! determine the reference point for the moment computation in @@ -644,10 +644,10 @@ subroutine flowintegrationface(isinflow, localvalues, mm) ! mass flow out of the domain. since the low faces have ssi ! vectors pointining into the domain, this is correct. the high ! end faces need to flip this. - select case (bcfaceid(mm)) - case (imin, jmin, kmin) + select case (bcfaceid(mm)) + case (imin, jmin, kmin) fact = one - case (imax, jmax, kmax) + case (imax, jmax, kmax) fact = -one end select ! the sign of momentum forces are flipped for internal flows diff --git a/tests/reg_tests/test_cavitation.py b/tests/reg_tests/test_cavitation.py index 6f38942b5..66f4152a2 100644 --- a/tests/reg_tests/test_cavitation.py +++ b/tests/reg_tests/test_cavitation.py @@ -112,9 +112,7 @@ def test_cavitation_metrics_and_derivatives(self): # this is not the best test out there; the final answer does get affected quite a bit # by the processor count or architecture. We just have it here to have some test on the # cavitation functionals' derivatives w.r.t. spatial changes in a lazy way. - self.handler.par_add_sum( - f"total {funcName} derivative wrt random volume perturbation", dotLocal, rtol=1e-3 - ) + self.handler.par_add_sum(f"total {funcName} derivative wrt random volume perturbation", dotLocal, rtol=1e-3) ################## # DOT PRODUCT TEST From 5c7ffa3326b9d90baa325c36cab048c759b48371 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 13 Dec 2022 09:03:19 -0500 Subject: [PATCH 74/76] fixed cpmin computation for TS cases --- .../outputForward/surfaceintegrations_d.f90 | 14 +++++------ .../outputReverse/surfaceintegrations_b.f90 | 16 ++++++------- .../surfaceintegrations_fast_b.f90 | 6 ++--- src/inputParam/inputParamRoutines.F90 | 12 +++++++++- src/modules/inputParam.F90 | 2 +- src/solver/surfaceIntegrations.F90 | 23 ++++++++----------- src/utils/utils.F90 | 5 ++++ 7 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/adjoint/outputForward/surfaceintegrations_d.f90 b/src/adjoint/outputForward/surfaceintegrations_d.f90 index 5a99740be..f79777320 100644 --- a/src/adjoint/outputForward/surfaceintegrations_d.f90 +++ b/src/adjoint/outputForward/surfaceintegrations_d.f90 @@ -235,7 +235,7 @@ subroutine getcostfunctions_d(globalvals, globalvalsd, funcvalues, & funcvaluesd(costfunccpmin) = funcvaluesd(costfunccpmin) - ovrnts& & *globalvalsd(icpmin, sps)/(globalvals(icpmin, sps)*cpmin_rho) funcvalues(costfunccpmin) = funcvalues(costfunccpmin) + ovrnts*(& -& cpmin_family-log(globalvals(icpmin, sps))/cpmin_rho) +& cpmin_family(sps)-log(globalvals(icpmin, sps))/cpmin_rho) end if funcvaluesd(costfuncaxismoment) = funcvaluesd(costfuncaxismoment) & & + ovrnts*globalvalsd(iaxismoment, sps) @@ -675,8 +675,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & -& sps))/cpmin_rho) +& costfunccpmin) + ovrnts*(cpmin_family(sps)-log(globalvals(& +& icpmin, sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, ! which doesn't play well with log. we just want to return zero here. @@ -1164,9 +1164,9 @@ subroutine wallintegrationface_d(localvalues, localvaluesd, mm) cavitationd = cavitationd + sensor1d cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_family))& -& ) - ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) + ks_exponentd = -(cpmin_rho*cpd*exp(cpmin_rho*(-cp+cpmin_family(& +& spectralsol)))) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family(spectralsol))) cpmin_ks_sumd = cpmin_ks_sumd + blk*ks_exponentd cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if @@ -1564,7 +1564,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family(spectralsol))) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/adjoint/outputReverse/surfaceintegrations_b.f90 b/src/adjoint/outputReverse/surfaceintegrations_b.f90 index 2a3905a9c..34bbfe92d 100644 --- a/src/adjoint/outputReverse/surfaceintegrations_b.f90 +++ b/src/adjoint/outputReverse/surfaceintegrations_b.f90 @@ -187,8 +187,8 @@ subroutine getcostfunctions_b(globalvals, globalvalsd, funcvalues, & & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & -& sps))/cpmin_rho) +& costfunccpmin) + ovrnts*(cpmin_family(sps)-log(globalvals(& +& icpmin, sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, ! which doesn't play well with log. we just want to return zero here. @@ -905,8 +905,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & -& sps))/cpmin_rho) +& costfunccpmin) + ovrnts*(cpmin_family(sps)-log(globalvals(& +& icpmin, sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, ! which doesn't play well with log. we just want to return zero here. @@ -1308,7 +1308,7 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family(spectralsol))) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do @@ -1631,8 +1631,8 @@ subroutine wallintegrationface_b(localvalues, localvaluesd, mm) & temp5)*sensor1d end if ks_exponentd = blk*cpmin_ks_sumd - cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(cpmin_family-cp))*& -& ks_exponentd + cpd = -sensor1d - cpmin_rho*exp(cpmin_rho*(cpmin_family(& +& spectralsol)-cp))*ks_exponentd tmpd = (plocal-pinf)*cpd plocald = tmp*cpd pinfd = pinfd - tmp*cpd @@ -1996,7 +1996,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family(spectralsol))) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 index e5eb1f2c6..295f1b108 100644 --- a/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 +++ b/src/adjoint/outputReverseFast/surfaceintegrations_fast_b.f90 @@ -130,8 +130,8 @@ subroutine getcostfunctions(globalvals, funcvalues) & ovrnts*globalvals(icavitation, sps) ! final part of the ks computation if (computecavitation) funcvalues(costfunccpmin) = funcvalues(& -& costfunccpmin) + ovrnts*(cpmin_family-log(globalvals(icpmin, & -& sps))/cpmin_rho) +& costfunccpmin) + ovrnts*(cpmin_family(sps)-log(globalvals(& +& icpmin, sps))/cpmin_rho) ! only calculate the log part if we are actually computing for cavitation. ! if we are not computing cavitation, the icpmin in globalvals will be zero, ! which doesn't play well with log. we just want to return zero here. @@ -474,7 +474,7 @@ subroutine wallintegrationface(localvalues, mm) sensor1 = sensor1*cellarea*blk cavitation = cavitation + sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho*(-cp+cpmin_family)) + ks_exponent = exp(cpmin_rho*(-cp+cpmin_family(spectralsol))) cpmin_ks_sum = cpmin_ks_sum + ks_exponent*blk end if end do diff --git a/src/inputParam/inputParamRoutines.F90 b/src/inputParam/inputParamRoutines.F90 index d2dc10baf..22c928e9f 100644 --- a/src/inputParam/inputParamRoutines.F90 +++ b/src/inputParam/inputParamRoutines.F90 @@ -3693,6 +3693,17 @@ subroutine checkInputParam sinCoefFourZRot = zero endif + ! Allocate the memory for cpmin_family. We had to wait until + ! nTimeIntervalsSpectral was set. + if(.not. allocated(cpmin_family) ) then + allocate(cpmin_family(nTimeIntervalsSpectral), stat=ierr) + if(ierr /= 0) & + call terminate("checkInputParam", & + "Memory allocation failure for & + &cpmin_family") + cpmin_family = zero + endif + end subroutine checkInputParam subroutine setDefaultValues ! @@ -4042,7 +4053,6 @@ subroutine setDefaultValues usematrixfreedrdw = .False. sepSensorOffset = zero sepSensorSharpness = 10_realType - cpmin_family = zero end subroutine setDefaultValues subroutine initializeIsoSurfaceVariables(values, nValues) diff --git a/src/modules/inputParam.F90 b/src/modules/inputParam.F90 index 6c5c52137..cff968c9c 100644 --- a/src/modules/inputParam.F90 +++ b/src/modules/inputParam.F90 @@ -588,7 +588,7 @@ module inputPhysics real(kind=realType) :: SSuthDim, muSuthDim, TSuthDim real(kind=realType) :: cavitationnumber real(kind=realType) :: cpmin_rho - real(kind=realType) :: cpmin_family + real(kind=realType), dimension(:), allocatable :: cpmin_family #ifndef USE_TAPENADE real(kind=realType) :: alphad, betad diff --git a/src/solver/surfaceIntegrations.F90 b/src/solver/surfaceIntegrations.F90 index 1f755949f..0aafa827c 100644 --- a/src/solver/surfaceIntegrations.F90 +++ b/src/solver/surfaceIntegrations.F90 @@ -114,7 +114,7 @@ subroutine getCostFunctions(globalVals, funcValues) ! If we are not computing cavitation, the iCpMin in globalVals will be zero, ! which doesn't play well with log. we just want to return zero here. funcValues(costfunccpmin) = funcValues(costfunccpmin) + ovrNTS * & - (cpmin_family - log(globalVals(iCpMin, sps)) / cpmin_rho) + (cpmin_family(sps) - log(globalVals(iCpMin, sps)) / cpmin_rho) endif funcValues(costFuncAxisMoment) = funcValues(costFuncAxisMoment) + ovrNTS*globalVals(iAxisMoment, sps) @@ -523,7 +523,7 @@ subroutine wallIntegrationFace(localValues, mm) Cavitation = Cavitation + Sensor1 ! also do the ks-based cpmin computation - ks_exponent = exp(cpmin_rho * (-Cp + cpmin_family)) + ks_exponent = exp(cpmin_rho * (-Cp + cpmin_family(spectralSol))) cpmin_ks_sum = cpmin_ks_sum + ks_exponent * blk end if enddo @@ -1102,14 +1102,12 @@ subroutine computeCpMinFamily(famList) ! and computes the true minimum Cp value. ! this is then used in the surface integration routine to compute ! the cpmin using KS aggregation. - ! the goal is to get a differentiable cpmin output + ! the goal is to get a differentiable cpmin output. - ! set the local cp min to a large value so that we get the actual min - cpmin_local = 10000.0_realType - - ! loop over the TS instances just because its the same convention everywhere. - ! in an actual TS computation, this wont work most likely. + ! loop over the TS instances and compute cpmin_family for each TS instance do sps=1, nTimeIntervalsSpectral + ! set the local cp min to a large value so that we get the actual min + cpmin_local = 10000.0_realType do nn=1, nDom call setPointers(nn, 1, sps) @@ -1148,13 +1146,12 @@ subroutine computeCpMinFamily(famList) end if famInclude end do bocos end do + ! finally communicate across all processors for this time spectral instance + call mpi_allreduce(cpmin_local, cpmin_family(sps), 1, MPI_DOUBLE, & + MPI_MIN, adflow_comm_world, ierr) + call EChk(ierr, __FILE__, __LINE__) end do - ! finally communicate across all processors - call mpi_allreduce(cpmin_local, cpmin_family, 1, MPI_DOUBLE, & - MPI_MIN, adflow_comm_world, ierr) - call EChk(ierr, __FILE__, __LINE__) - end subroutine computeCpMinFamily #ifndef USE_COMPLEX diff --git a/src/utils/utils.F90 b/src/utils/utils.F90 index 99b31ff69..e58595c60 100644 --- a/src/utils/utils.F90 +++ b/src/utils/utils.F90 @@ -4737,6 +4737,7 @@ subroutine releaseMemoryPart2 ! use block use inputTimeSpectral + use inputPhysics, only : cpmin_family use ADjointPETSc use cgnsGrid implicit none @@ -4764,6 +4765,10 @@ subroutine releaseMemoryPart2 ! Some more memory should be deallocated if this code is to ! be used in combination with adaptation. + ! deallocate the cpmin_family array allocated in inputParamRoutines + if (allocated(cpmin_family)) & + deallocate(cpmin_family) + ! Destroy variables allocated in preprocessingAdjoint if (adjointPETScPreProcVarsAllocated) then call vecDestroy(w_like1,PETScIerr) From 53514a8231f8522f94138245190f3991e095d7b3 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 13 Dec 2022 18:46:04 -0500 Subject: [PATCH 75/76] missed a capitalization --- adflow/pyADflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 2a2af4a94..4c7f19f2c 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -327,7 +327,7 @@ def __init__(self, comm=None, options=None, debug=False, dtype="d"): # this is the plot3d surface that defines the closed volume surfFile = surfDict[surf]["surfFile"] # the indices of cgns blocks that we want to consider when blanking inside the surface - blockIDs = surfDict[surf]["blockIds"] + blockIDs = surfDict[surf]["blockIDs"] # the fortran lookup expects this list in increasing order blockIDs.sort() From 4a9be757b626a67ddc2b7140c40a4b128b8f8383 Mon Sep 17 00:00:00 2001 From: Anil Yildirim Date: Tue, 13 Dec 2022 18:48:38 -0500 Subject: [PATCH 76/76] changed the number of default cylindrical slices --- adflow/pyADflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adflow/pyADflow.py b/adflow/pyADflow.py index 4c7f19f2c..22510d208 100644 --- a/adflow/pyADflow.py +++ b/adflow/pyADflow.py @@ -699,7 +699,7 @@ def addArbitrarySlices(self, normals, points, sliceType="relative", groupName=No self.nSlice += nSlice def addCylindricalSlices( - self, pt1, pt2, nSlice=180, sliceBeg=0.0, sliceEnd=360.0, sliceType="relative", groupName=None + self, pt1, pt2, nSlice=25, sliceBeg=0.0, sliceEnd=360.0, sliceType="relative", groupName=None ): """ Add cylindrical projection slices. The cylindrical projection axis is defined