! +-======-+ ! Copyright (c) 2003-2007 United States Government as represented by ! the Admistrator of the National Aeronautics and Space Administration. ! All Rights Reserved. ! ! THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE, ! REPRODUCTION, DISTRIBUTION, MODIFICATION AND REDISTRIBUTION OF CERTAIN ! COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE UNITED STATES GOVERNMENT AS ! REPRESENTED BY THE GOVERNMENT AGENCY LISTED BELOW ("GOVERNMENT AGENCY"). ! THE UNITED STATES GOVERNMENT, AS REPRESENTED BY GOVERNMENT AGENCY, IS AN ! INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT DISTRIBUTIONS OR ! REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, ! DISTRIBUTES, MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED ! HEREIN, OR ANY PART THEREOF, IS, BY THAT ACTION, ACCEPTING IN FULL THE ! RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT. ! ! Government Agency: National Aeronautics and Space Administration ! Government Agency Original Software Designation: GSC-15354-1 ! Government Agency Original Software Title: GEOS-5 GCM Modeling Software ! User Registration Requested. Please Visit http://opensource.gsfc.nasa.gov ! Government Agency Point of Contact for Original Software: ! Dale Hithon, SRA Assistant, (301) 286-2691 ! ! +-======-+ ! $Id: surfacelayer.F90,v 1.2.4.1.10.3.22.1.2.6.2.1.2.1.2.1.2.5.6.4 2015-06-18 13:42:30 atrayano Exp $ ! $Name: Heracles-5_1 $ module sfclayer ! !USES: use MAPL_Mod use DragCoefficientsMod implicit none private PUBLIC louissurface,z0sea,helfsurface,psi,phi,linadj,zcsub contains !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !IROUTINE: louissurface ! !INTERFACE: subroutine louissurface(ISTYPE,N,UU,WW,PS,TA,TS,QA,QS,PCU,LAI, & Z0,DZ,CM,CN,RI,ZT,ZQ,CH,CQ,UUU,UCN,RE,DCH,DCQ) integer, intent(IN ) :: N integer, intent(IN ) :: ISTYPE real, intent(IN) :: UU (:) real, intent(IN) :: WW (:,:) real, intent(IN) :: PS (:) real, intent(IN) :: TA (:) real, intent(IN) :: TS (:,:) real, intent(IN) :: QA (:) real, intent(IN) :: QS (:,:) real, intent(IN) :: PCU(:) real, intent(IN) :: LAI(:) real, intent(INOUT) :: Z0 (:,:) real, intent(IN) :: DZ (:) real, intent(INOUT) :: CM (:,:) real, intent(OUT) :: CN (:) real, intent(OUT) :: RI (:) real, intent(OUT) :: ZT (:) real, intent(OUT) :: ZQ (:) real, intent(OUT) :: CH (:,:) real, intent(OUT) :: CQ (:,:) real, intent(OUT) :: UUU (:) real, intent(OUT) :: UCN (:) real, intent(OUT) :: RE (:) real, optional, intent(OUT) :: DCH (:,:) real, optional, intent(OUT) :: DCQ (:,:) real, parameter :: OCEANICEZ0 = 1.0e-3 real, parameter :: LAKEZ0 = 1.0E-5 real, parameter :: LAKEICEZ0 = 0.01 real, parameter :: LANDICEZ0 = 0.002 integer, parameter :: ICE = 1 integer, parameter :: WATER = 2 integer,parameter :: FSNW=4 ! Snowcover subtile integer :: irun real, allocatable :: UST(:) real, allocatable :: TVS(:) real, allocatable :: URA(:) real, allocatable :: TVA(:) real :: LAICRT irun = size(UU,1) LAICRT = 0.3 allocate( UST(1:irun) ) allocate( TVS(1:irun) ) allocate( URA(1:irun) ) allocate( TVA(1:irun) ) if(ISTYPE==1 .or. ISTYPE==3) then UCN = PCU*8640. ! cm/day UCN = ((19.8*UCN*UCN)/(1.5 + UCN + UCN*UCN))**0.4 ! REDELSPERGER et al. (2000) UCN = UCN*UCN ! UCN = 0.0 ! Remove Redelsperger endif ! TVA = TA*( 1.0 + MAPL_VIREPS*QA) if(ISTYPE==3)TVA = TA*(1+MAPL_VIREPS*QA) ! if(ISTYPE==1 .or. ISTYPE==3) then UUU = max( sqrt(UU*UU + WW(:,N) + UCN), MAPL_USMIN ) elseif (ISTYPE==2 .or. ISTYPE==4) then UUU = max(UU,MAPL_USMIN) endif if(ISTYPE==1) then URA = UUU*( PS/(MAPL_RGAS*TVA) ) elseif (ISTYPE==2 .or. ISTYPE==3 .or. ISTYPE==4) then URA = UUU*PS/(MAPL_RGAS*TVA) endif TVS = TS(:,N)*(1+MAPL_VIREPS*QS(:,N)) ! Estimate of friction velocity from previous step's drag coefficient !--------------------------------------------------------------------- UST = UUU*sqrt(CM(:,N)/URA) UST = min( max(UST,1.e-6) , 5.0 ) ! Iterate for aerodynamic roughness, based on previous step's stability !----------------------------------------------------------------------- if(ISTYPE==1) then if (N==WATER) then call Z0SEA (Z0(:,N),UST,DZ) else Z0(:,N) = OCEANICEZ0 end if elseif (ISTYPE==2) then if(N==ICE) then Z0(:,N) = LAKEICEZ0 else Z0(:,N) = LAKEZ0 end if elseif (ISTYPE==4) then Z0(:,N) = LANDICEZ0 end if ! Get a new drag coefficient for the updated roughness !----------------------------------------------------- call GETCDM(TVA,UUU,DZ,TVS,Z0(:,N), CM(:,N),CN,RI) if(ISTYPE==1) UST = UUU*sqrt(CM(:,N)) ! Reynolds number at the top of the viscous sublayer !---------------------------------------------------- if(ISTYPE==1) then RE = max(min(Z0(:,N)*UST/MAPL_NUAIR, 50.),0.1) elseif (ISTYPE==3) then RE = max(min(Z0(:,N)*(sqrt(CM(:,N))*UUU) / MAPL_NUAIR, 1000.),0.4) elseif (ISTYPE==2 .or. ISTYPE==4) then RE = min(Z0(:,N) * (sqrt(CM(:,N))*UUU) / MAPL_NUAIR, 1000.) end if ! Calculate scalar roughnesses !------------------------------ if(ISTYPE==1) then if(N==WATER) then ! This is based on Zilitinkevich et al. ! ZT = Z0(:,N) * exp(MAPL_KARMAN*(3.2 - 4.0*sqrt(max(RE,0.1)))) ! This is based on Garrett 1992 ! ZT = Z0(:,N) * exp(2.0 - 2.48*RE**.25) ! This is as used in ecmwf model, based on: ! Beljaars, A. C. M., 1994: ! The parametrization of surface fluxes in large-scale models under ! free convection. Q. J. R. Meteorol. Soc., 121, 255-270. ! ZT = Z0(:,N) * (0.4/RE) else ! This is used over snow and bare soil in CSM ZT = Z0(:,N) * exp(-0.13*sqrt(RE)) end if elseif (ISTYPE==2) then if(N==ICE) then ZT = Z0(:,N) * exp(-0.13*sqrt(RE)) else ZT = Z0(:,N) * (0.4/RE) end if elseif (ISTYPE==3) then ! Viscous sub-layer effects on Z0 vanish as the surface ! becomes very vegetated (LAI -> infinity), assuming they are handled ! in the vegetation resistance to heat and moisture fluxes. !!! Note: Comment out special code for SNOW condition to alleviate excessive night-time cooling !!! ------------------------------------------------------------------------------------------- !!! if (N==FSNW) then !!! ZT = Z0(:,N)*exp( -0.13 * sqrt(RE) ) !!! ZQ = ZT !!! else ZT = 1.0 - (1.0-exp(-0.13*sqrt(RE)))*exp(-max(LAI,LAICRT)) where(LAI 1.0 ! DO 9006 I = 1,IRUN IF ( IWATER(I).EQ.1) THEN VAZ0(I) = 1. / VZ1(I) VG(I) = VDZSEA(I) * VAZ0(I) VG0(I) = VX0PSIM(I) * VG(I) VR1MG0(I) = 1. / ( 1. - VG0(I) ) VDZ0(I) = ( VZ2(I) - VZ1(I) ) * VR1MG0(I) ENDIF 9006 CONTINUE ENDIF ! IF ( LWATER .AND. (ITYPE.GE.3) ) THEN DO 9008 I = 1,IRUN IF (IWATER(I).EQ.1) VDZ0(I) = VDZ0(I) * VAZ0(I) 9008 CONTINUE ENDIF ! ! COMPUTE NUM1,NUM2,NUM3, DEN ! IF (ITYPE.GE.3) THEN DO 9010 I = 1,IRUN VXNUM1(I) = 0. IF (VRIB1(I).EQ.0.) THEN INTRIB(I) = 1 ELSE INTRIB(I) = 0 ENDIF IF ( INTRIB(I).EQ.0 ) VXNUM1(I) = 1. / VRIB1(I) VPSIGB2(I) = 0. if(vpsig(i).gt.0.)VPSIGB2(I) = & 0.5 * ( vpsig(i)*vpsig(i) + b2uhs(i) ) / vpsig(i) VDX(I) = VX(I) - VX0(I) VDXPSIM(I) = VDX(I) * VAPSIM(I) VDY(I) = VY(I) - VY0(I) VXNUM3(I) = - VPSIGB2(I) ! IF ( LWATER ) THEN IF (IWATER(I).EQ.1) THEN VDXPSIM(I) = VDXPSIM(I) * VR1MG0(I) VXNUM3(I) = VXNUM3(I) + VG(I) * ( VY0(I) - VPSIGB2(I) ) VXNUM2(I) = VY0(I) - VPSIGB2(I) - VX0PSIM(I) * VPSIGB2(I) VXNUM2(I) = (VXNUM2(I) * VAPSIHG(I)) - 2. * VX0PSIM(I) VXNUM2(I) = VXNUM2(I) * VDZ0(I) ENDIF ENDIF ! VDEN(I) = VDY(I) + VDXPSIM(I) * VXNUM3(I) VDEN(I) = ( 1. + VDEN(I) * VAPSIHG(I) ) - 2. * VDXPSIM(I) 9010 CONTINUE ENDIF ! IF (ITYPE.EQ.5) THEN DO 9012 I = 1,IRUN VAWS1(I) = VR1MG0(I) / VWS1(I) VXNUM3(I) = VXNUM3(I) * VAPSIHG(I) ! IF ( LWATER ) THEN IF(IWATER(I).EQ.1) THEN VXNUM3(I) = VXNUM3(I) - 2. * VG0(I) VXNUM3(I) = VAWS1(I) * VXNUM3(I) ENDIF ENDIF 9012 CONTINUE ENDIF ! ! COMPUTE D LOG ZETA ! IF (ITYPE.GE.3) THEN DO 9014 I = 1,IRUN VXNUM(I) = VRIB2(I) - VRIB1(I) IF( (VX0(I).GT.XX0MAX).AND.(VXNUM(I).GE.0.) )VXNUM(I) = 0. VXNUM(I) = VXNUM1(I) * VXNUM(I) 9014 CONTINUE ! DO 9018 I = 1,IRUN VDZETA1(I) = VXNUM(I) IF(LWATER.AND.(IWATER(I).EQ.1)) VXNUM(I) = VXNUM(I) + VXNUM2(I) IF ( VDEN(I) .LT.0.1 ) VDEN(I) = 0.1 9018 CONTINUE ! DO 9020 I = 1,IRUN VDZETA(I) = VXNUM(I) / VDEN(I) 9020 CONTINUE DO 9022 I = 1,IRUN IF((VRIB2(I).EQ.0.).OR.(VDZETA(I).LE.-1.))VDZETA(I) = VDZETA1(I) 9022 CONTINUE ENDIF ! ! COMPUTE D LOG Z0 ! IF ( LWATER .AND. (ITYPE.GE.3) )THEN DO 9026 I = 1,IRUN IF( IWATER(I).EQ.1 ) THEN VZCOEF2(I) = VG(I) * VDXPSIM(I) VDZ0(I) = VDZ0(I) - VZCOEF2(I) * VDZETA(I) ENDIF 9026 CONTINUE ENDIF ! IF ( LWATER .AND. (ITYPE.EQ.5) ) THEN DO 9028 I = 1,IRUN IF(IWATER(I).EQ.1) VZCOEF1(I) = VG(I) * VAWS1(I) 9028 CONTINUE ENDIF ! ! CALCULATE D PSIM AND D PSIH ! IF ( (ITYPE.EQ.1) .AND. LWATER ) THEN DO 9032 I = 1,IRUN IF (IWATER(I).EQ.1) THEN VDPSIM(I) = - VDZ0(I) * VAZ0(I) VDPSIH(I) = VDPSIM(I) ENDIF 9032 CONTINUE ENDIF ! IF (ITYPE.GE.3) THEN DO 9034 I = 1,IRUN VDPSIM(I) = VDX(I) * VDZETA(I) VDPSIH(I) = VDY(I) * VDZETA(I) IF ( LWATER ) THEN IF (IWATER(I).EQ.1 ) THEN VDPSIM(I) = VDPSIM(I) - VX0(I) * VDZ0(I) VDPSIH(I) = VDPSIH(I) - VY0(I) * VDZ0(I) ENDIF ENDIF 9034 CONTINUE ENDIF ! ! PREVENT OVERCORRECTION OF PSIM OR PSIH FOR UNSTABLE CASE ! IF (ITYPE.GE.4) THEN DO 9036 I = 1,IRUN VDPSIMC(I) = -0.9 - VDPSIM(I) * VAPSIM(I) VDPSIHC(I) = -0.9 * VPSIH(I) - VDPSIH(I) IF ( VDPSIMC(I).GT.0. ) THEN VINT1(I) = 1 ELSE VINT1(I) = 0 ENDIF IF ( VDPSIHC(I).GT.0. ) THEN VINT2(I) = 1 ELSE VINT2(I) = 0 ENDIF VDZETA1(I) = 0. IF(VINT1(I).EQ.1) VDZETA1(I) = VDPSIMC(I) / VDXPSIM(I) IF((VINT1(I).EQ.1).OR.(VINT2(I).EQ.1)) VTEMPLIN(I) = & VDY(I) + VY0(I) * VG(I) * VDXPSIM(I) IF (VINT2(I).EQ.1) then VDZETA2(I) = VDPSIHC(I) / VTEMPLIN(I) IF ( VDZETA2(I).LT.VDZETA1(I) ) VDZETA1(I) = VDZETA2(I) endif IF((VINT1(I).EQ.1).OR.(VINT2(I).EQ.1)) THEN VDZETA(I) = VDZETA1(I) + VDZETA(I) VDPSIM(I) = VDPSIM(I) + VDX(I) * VR1MG0(I) * VDZETA1(I) VDPSIH(I) = VDPSIH(I) + VTEMPLIN(I) * VDZETA1(I) IF ( IWATER(I).EQ.1 ) & VDZ0(I) = VDZ0(I) - VG(I) * VDXPSIM(I) * VDZETA1(I) ENDIF 9036 CONTINUE ENDIF ! end subroutine linadj !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !IROUTINE: zcsub ! !INTERFACE: SUBROUTINE ZCSUB (VUSTAR,VDZSEA,IWATER,LDZSEA,IRUN,VZSEA,CHOOSEZ0) !********************************************************************** ! FUNCTION ZSEA ! PURPOSE ! COMPUTES Z0 AS A FUNCTION OF USTAR OVER WATER SURFACES ! USAGE ! CALLED BY helfsurface ! DESCRIPTION OF PARAMETERS ! USTAR - INPUTED VALUE OF SURFACE-STRESS VELOCITY ! DZSEA - OUTPUTED VALUE OF DERIVATIVE D(ZSEA)/D(USTAR) ! WATER - INPUTED BIT VECTOR TO DETERMINE WATER POINTS ! LDZSEA - LOGICAL FLAG TO DETERMINE IF DZSEA SHOULD BE COMPUTED ! ZSEA - OUTPUTED VALUE OF ROUGHNESS LENGTH ! CHOOSEZ0 - INTEGER FLAG: 0 - L&P Z0, no high wind limit ! 1 - Edson Z0 for mom. and heat, high wind limit ! 2 - L&P Z0, high wind limit ! 3 - Edson Z0 for mom. only, high wind limit ! SUBPROGRAMS NEEDED ! NONE ! RECORD OF MODIFICATIONS ! Molod 6/8/2011 - Implement new choozez0 options (expand from 0,1 choice) ! REMARKS: ! COMPUTE ROUGHNESS LENGTH FOR OCEAN POINTS ! BASED ON FUNCTIONS OF LARGE AND POND ! AND OF KONDO --- DESIGNED FOR K = .4 ! ********************************************************************* implicit none ! Argument List Delcarations integer irun, CHOOSEZ0 real VZSEA(:),VUSTAR(:),VDZSEA(:) integer IWATER(:) LOGICAL LDZSEA ! Local Variables real USTMX1_OLD,USTMX2_OLD real USTMX1_NEW,USTMX2_NEW real USTMX1,USTMX2,USTMX3 PARAMETER ( USTMX1_NEW = 0.80 ) PARAMETER ( USTMX2_NEW = 0.80 ) PARAMETER ( USTMX1_OLD = 1.1 ) PARAMETER ( USTMX2_OLD = 0.381844 ) PARAMETER ( USTMX3 = 0.0632456) real AA(IRUN,5),TEMP(IRUN) integer INT2(IRUN),INT3(IRUN),INT4(IRUN) integer i,k real ustloc(irun) real AA1(5),AA2(5),AA3(5),AA4(5) real AA2_NEW(5),AA3_NEW(5),AA4_NEW(5) real AA2_OLD(5),AA3_OLD(5),AA4_OLD(5) DATA AA1/.2030325E-5,0.0,0.0,0.0,0.0/ DATA AA2_NEW/-1.102451E-08,0.1593E-04,0.1E-03,2.918E-03, & 0.695649E-04/ DATA AA3_NEW/-1.102451E-08,0.12E-04,0.1E-03,2.918E-03, & 1.5649E-04/ DATA AA4_NEW/0.085E-03,1.5E-03,-0.210E-03,0.215E-02, & -0.0/ DATA AA2_OLD/-0.402451E-08,0.239597E-04,0.117484E-03,0.191918E-03, & 0.395649E-04/ DATA AA3_OLD/-0.237910E-04,0.228221E-03,-0.860810E-03,0.176543E-02, & 0.784260E-04/ DATA AA4_OLD/-0.343228E-04,0.552305E-03,-0.167541E-02,0.250208E-02, & -0.153259E-03/ if( CHOOSEZ0.eq.0 .OR. CHOOSEZ0.eq.2) then USTMX1 = USTMX1_OLD USTMX2 = USTMX2_OLD AA2 = AA2_OLD AA3 = AA3_OLD AA4 = AA4_OLD else USTMX1 = USTMX1_NEW USTMX2 = USTMX2_NEW AA2 = AA2_NEW AA3 = AA3_NEW AA4 = AA4_NEW endif ! !********************************************************************** !***** LOWER CUTOFF CONDITION FOR USTAR *** !********************************************************************** ! DO 9000 I = 1,IRUN IF(VUSTAR(I) .LT. 1.e-6)THEN INT3(I) = 1 ELSE INT3(I) = 0 ENDIF 9000 CONTINUE DO 9002 I = 1,IRUN IF(INT3(I).EQ.1) VUSTAR(I) = 1.e-6 9002 CONTINUE ustloc = vustar ! !*********************************** !***** LOAD THE ARRAY A(I,K) ***** !*********************************** ! DO 9004 I = 1,IRUN IF( (ustloc(I) .GT. USTMX1) .AND. (IWATER(I).EQ.1) ) THEN if( CHOOSEZ0.gt.0 ) ustloc(i) = ustmx1 INT4(I) = 1 ELSE INT4(I) = 0 ENDIF 9004 CONTINUE DO 9006 I = 1,IRUN IF(ustloc(I) .GT. USTMX2) THEN INT3(I) = 1 ELSE INT3(I) = 0 ENDIF 9006 CONTINUE DO 9008 I = 1,IRUN IF(ustloc(I) .GE. USTMX3) THEN INT2(I) = 1 ELSE INT2(I) = 0 ENDIF 9008 CONTINUE ! DO 100 K=1,5 DO 9010 I = 1,IRUN AA(I,K) = AA1(K) IF( INT2(I).EQ.1 ) AA(I,K) = AA2(K) IF( INT3(I).EQ.1 ) AA(I,K) = AA3(K) IF( INT4(I).EQ.1 ) AA(I,K) = AA4(K) 9010 CONTINUE 100 CONTINUE ! !******************************************************** !***** EVALUATE THE ENHANCED POLYNOMIAL FOR ZSEA ***** !******************************************************** ! DO 9012 I = 1,IRUN VDZSEA(I) = ( AA(I,4) + AA(I,5) * ustloc(I) ) * ustloc(I) VZSEA(I) = AA(I,2) + ( AA(I,3) + VDZSEA(I) ) * ustloc(I) TEMP(I) = AA(I,1) / ustloc(I) VZSEA(I) = VZSEA(I) + TEMP(I) 9012 CONTINUE ! !********************************************************************** !***** EVALUATE THE DERIVATIVE DZSEA IF LDZSEA IS TRUE *** !********************************************************************** ! IF( LDZSEA ) THEN DO 9014 I = 1,IRUN VDZSEA(I) = 3. * VDZSEA(I) -(AA(I,4)*ustloc(I) - AA(I,3)) VDZSEA(I) = VDZSEA(I) * ustloc(I) - TEMP(I) 9014 CONTINUE ENDIF ! end subroutine zcsub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! end module sfclayer