This document describes the programming guidelines to be used during NPARC Alliance software development projects. [Since much of the NPARC Alliance software has been developed over several years, some of the programming guidelines described in this document will not necessarily be followed throughout the final product. They should, however, be followed for any new code that is written.] It deals exclusively with Fortran 90, since most new NPARC Alliance software is written in that language. [Throughout this document, the term "Fortran" should be understood to mean Fortran 90.]
The guidelines are intended to enhance the following aspects of the final product, listed in decreasing order of importance:
Much of this material has been taken, sometimes verbatim, from the following documents:
Items in this section are fairly general and fundamental in nature. They impact all three of the items listed above - maintainability, portability, and efficiency.
Use ANSI standard Fortran 90 exclusively, with the following exceptions:
Items in this section are fairly specific, and primarily impact the readability, and thus the maintainability, of the final product. It is recognized that rules for "good coding style" are somewhat subjective. [The guidelines in this document no doubt reflect some of my own biases.] Some flexibility for personal preference should be acceptable. However, these guidelines should be followed at least in spirit throughout the program.
y1 = (-b + Sqrt(b**2 - 4.*a*c))/(2.*a)is easier to read than this:
y1=(-b+Sqrt(b**2-4.*a*c))/(2.*a)or this:
y1 = ( - b + Sqrt ( b ** 2 - 4. * a * c ) ) / ( 2. * a )
dum1 = Sqrt((fr (i,j) - fr ( 1, j))**2 + &
(fth(i,j) - fth( 1, j))**2)
dum2 = Sqrt((fr (i,j) - fr (n1, j))**2 + &
(fth(i,j) - fth(n1, j))**2)
dum3 = Sqrt((fr (i,j) - fr ( i, 1))**2 + &
(fth(i,j) - fth( i, 1))**2)
dum4 = Sqrt((fr (i,j) - fr ( i,n2))**2 + &
(fth(i,j) - fth( i,n2))**2)
is easier to read than this:
dum1 = Sqrt((fr(i,j) - fr(1,j))**2 + (fth(i,j) - & fth(1,j))**2) dum2 = Sqrt((fr(i,j) - fr(n1,j))**2 + (fth(i,j) - & fth(n1,j))**2) dum3 = Sqrt((fr(i,j) - fr(i,1))**2 + (fth(i,j) - & fth(i,1))**2) dum4 = Sqrt((fr(i,j) - fr(i,n2))**2 + (fth(i,j) - & fth(i,n2))**2)
Subroutine sub (c) Character*(*) c
If ( bccode == 13 ) then
[Lines and lines of code]
Do i = 1,nzones
If ( zondim(1,i) > 0 ) then
[More lines and lines of code]
End if ! If ( zondim(1,i) > 0 ) then
End do ! Do i = 1,nzones
End if ! If ( bccode == 13 ) then
For do loops, another method is using a Fortran 77 style loop,
ending with a labeled Continue statement.
!-----Get the turbulent viscosity using Baldwin-Lomax model
Call turbbw
is more meaningful than this:
!-----Call turbbw
Call turbbw
The following Fortran features are either formally declared as obsolete, or widely considered to be poor programming practice, and should not be used:
The following is an example illustrating the use of the guidelines in this document for one of the subprograms in Wind-US. First, here's an include file named mxdim.par that's needed:
Integer MXDIM ! Max grid points in any direction Parameter (MXDIM = 1023)And here's another named test.inc:
Common /test/ itest Integer itest(200) ! Test options Save /test/
And here's the subprogram itself, named blomax.f90:
Subroutine blomax (jedge,re,yy,rh,uu,vo,vi,tauw,tv)
!
!-----Purpose: This subroutine computes the turbulent viscosity
! coefficient using the Baldwin-Lomax model.
!
!-----Use modules
Use data_types ! kind parameters
!-----Require explicit typing of variables
Implicit none
!-----Parameter statements
Include 'mxdim.par'
!-----Common blocks
Include 'test.inc'
!-----Input arguments
Integer(kindInt), intent(in) :: jedge ! Index of bl edge
Real(kindSingle), intent(in) :: re ! Reference Reynolds number
Real(kindSingle), intent(in) :: yy(MXDIM) ! Distance from wall
Real(kindSingle), intent(in) :: rh(MXDIM) ! Static density
Real(kindSingle), intent(in) :: uu(jedge) ! Velocity
Real(kindSingle), intent(in) :: vo(MXDIM) ! Vorticity
Real(kindSingle), intent(in) :: vi(MXDIM) ! Laminar viscosity coeff
Real(kindSingle), intent(in) :: tauw ! Shear stress at the wall
!-----Output arguments
Real(kindSingle), intent(out) :: tv(jedge) ! Turbulent viscosity coeff
!-----Local variables
Integer(kindInt) icross ! Flag for inner/outer region
Integer(kindInt) j ! Do loop index
Integer(kindInt) jedg ! Index limit for Fmax search
Real(kindSingle) al ! Mixing length
Real(kindSingle) aplus ! Van Driest damping constant
Real(kindSingle) bigk ! Clauser constant
Real(kindSingle) ccp ! Constant in outer region model
Real(kindSingle) ckleb ! Constant in Klebanoff intermittency factor
Real(kindSingle) cwk ! Constant in outer region model
Real(kindSingle) fkleb ! Klebanoff intermittency factor
Real(kindSingle) fl ! Baldwin-Lomax F parameter
Real(kindSingle) fmax ! Baldwin-Lomax Fmax parameter
Real(kindSingle) frac ! Fractional decrease in F req'd for peak
Real(kindSingle) fwake ! Baldwin-Lomax Fwake parameter
Real(kindSingle) rdum ! Ratio of distance from wall to ymax
Real(kindSingle) smlk ! Von Karman constant
Real(kindSingle) tvi ! Inner region turbulent viscosity coeff
Real(kindSingle) tvo ! Outer region turbulent viscosity coeff
Real(kindSingle) udif ! Max velocity difference
Real(kindSingle) umax ! Max velocity
Real(kindSingle) umin ! Min velocity
Real(kindSingle) ymax ! Distance from wall to location of Fmax
Real(kindSingle) yp ! y+
Real(kindSingle) ypcon ! Coeff term for y+, based on wall values
Real(kindSingle) ypconl ! Coeff term for y+
Real(kindSingle) yyj ! Distance from wall
!-----Set constants
aplus = 26.
ccp = 1.6
ckleb = 0.3
cwk = 0.25
smlk = 0.4
bigk = 0.0168
If (itest(126) == 1) bigk = 0.0180 ! Comp. correction (cfl3de)
!-----Compute stuff needed in model
!-----Get coefficient term for y+
If (itest(25) == 1) then ! Using wall vorticity as in cfl3de
ypcon = Sqrt(re*rh(1)*vo(1)/vi(1))
Else ! Using wall shear stress
If (tauw <= 1.e-9) tauw = 1.e-9
ypcon = Sqrt(re*rh(1)*tauw)/vi(1)
End if
!-----Set index limit for Fmax search, and fractional decrease needed to
!----- qualify as first peak
jedg = jedge
frac = .70
If (itest(163) > 0) then ! User-spec. frac. decrease
frac = Real(itest(163))/1000.
Else if (itest(163) < 0) then ! Reset search range, use max
jedg = Min(jedge,-itest(163)) ! value, not first peak
frac = 0.0
Endif
!-----Get max velocity and max velocity difference
umin = 0.
umax = 0.
Do j = 2,jedge
umax = Max(umax,uu(j))
umin = Min(umin,uu(j))
End do
udif = umax - umin
!-----Get Fmax by searching for first peak in F
ymax = 0.
fmax = 0.
ypconl = ypcon
Do j = 2,jedg
yyj = yy(j)
If (itest(26) == 1) then ! Use local values in y+
ypconl = ypcon*Sqrt(rh(j)/rh(1))*vi(1)/vi(j)
End if
yp = ypconl*yyj ! y+
fl = yyj*vo(j)*(1. - Exp(-yp/aplus)) ! B-L F parameter
If (fl > fmax) then ! Set new Fmax
fmax = fl
ymax = yyj
Else if (fl > frac*fmax) then ! Keep searching
Cycle
Else ! Found Fmax, so get out
Exit
End if
End do
!-----Reset ymax and Fmax if necessary, to avoid overflows
If (ymax < 1.e-6) ymax = 5.e-5
If (fmax < 1.e-6) fmax = 5.e-5
!-----Compute turbulent viscosity
icross = 0
ypconl = ypcon
Do j = 2,jedge
yyj = yy(j)
tvi = 1.e10
!--------Inner region value, if we're still there
If (icross == 0) then
If (itest(26) == 1) then ! Use local values in y+
ypconl = ypcon*Sqrt(rh(j)/rh(1))*vi(1)/vi(j)
End if
yp = ypconl*yyj ! y+
al = smlk*yyj*(1. - Exp(-yp/aplus)) ! Mixing length
tvi = rh(j)*al*al*vo(j)
End if
!--------Outer region value
rdum = yyj/ymax
If (rdum >= 1.e5) then ! Prevent overflow
fkleb = 0.0
Else ! Klebanoff intermittency factor
fkleb = 1./(1. + 5.5*(ckleb*rdum)**6)
End if
fwake = Min(ymax*fmax,cwk*ymax*udif*udif/fmax)
tvo = bigk*ccp*rh(j)*fwake*fkleb
!--------Set turbulent viscosity, plus flag if we're in outer region
tv(j) = tvi
If (tvo < tvi) then
icross = 1
tv(j) = tvo
End if
!--------Non-dimensionalize
tv(j) = re*tv(j)
End do ! Do j = 2,jedge
!-----Zero out turbulent viscosity at wall
tv(1) = 0.0
Return
End
Last updated 22 Apr 2004