module nst_module ! ! The module of diurnal thermocline layer model ! USE MACHINE , ONLY : kind_phys use module_nst_parameters, only: z_w_max,z_w_min,z_w_ini,eps_z_w,eps_conv, & eps_sfs,niter_z_w,niter_conv,niter_sfs,Ri_c, & Ri_g,omg_m,omg_sh, kw => tc_w,visw,t0K,cp_w, & z_c_max,z_c_ini,ustar_a_min,delz,exp_const, & rad2deg,const_rot,tw_max,sst_max USE module_nst_water_prop, ONLY: sw_rad_skin,sw_ps_9b,sw_ps_9b_Aw implicit none contains subroutine dtm_1p(kdt,timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,Hl_Ts,rho, & alpha,beta,alon,sinlat,soltim,grav,Le,d_conv, & xt,xs,xu,xv,xz,xzts,xtts) integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,& Hl_Ts,rho,alpha,beta,alon,sinlat,soltim,& grav,Le,d_conv real(kind=kind_phys), intent(inout) :: xt,xs,xu,xv,xz,xzts,xtts ! local variables real(kind=kind_phys) :: xt0,xs0,xu0,xv0,xz0,xzts0,xtts0 real(kind=kind_phys) :: fac,t0,tau ! ! input variables ! ! timestep: integration time step in seconds ! rich : critical Ri (flow dependent) ! tox : x wind stress (N*M^-2 or KG/M/S^2) ! toy : y wind stress (N*M^-2 or KG/M/S^2) ! I0 : solar radiation flux at the surface (WM^-2) ! Q : non-solar heat flux at the surface (WM^-2) ! sss : Salinity (ppt) ! sep : Sr(E-P) (ppt*M/S) ! Q_Ts : d(Q)/d(Ts) : Q = the sum of non-solar heat fluxes ! Hl_Ts : d(Hl)/d(Ts) ! rho : sea water density (KG*M^-3) ! alpha : thermal expansion coefficient (1/K) ! beta : saline contraction coefficient (1/ppt) ! sinlat : sine (lat) ! grav : gravity accelleration ! Le : Le=(2.501-.00237*tsea)*1e6 ! d-conv : FCL thickness ! ! inout variables ! ! xt : DTL heat content (M*K) ! xs : DTL salinity content (M*ppt) ! xu : DTL x current content (M*M/S) ! xv : DTL y current content (M*M/S) ! xz : DTL thickness (M) ! xzts : d(xz)/d(ts) (M/K ) ! xtts : d(xt)/d(ts) (M) ! ! logical lprnt ! if (lprnt) print *,' first xt=',xt if ( xt <= 0.0 ) then ! dtl doesn't exist yet call dtm_onset(kdt,timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,Hl_Ts,rho,alpha,& beta,alon,sinlat,soltim,grav,Le,xt,xs,xu,xv,xz,xzts,xtts) elseif ( xt > 0.0 ) then ! dtl already exists ! ! forward the system one time step ! call Eulerm(kdt,timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,Hl_Ts,rho,alpha, & beta,alon,sinlat,soltim,grav,Le,d_conv, & xt,xs,xu,xv,xz,xzts,xtts) endif ! if ( xt == 0 ) then end subroutine dtm_1p subroutine Eulerm(kdt,timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,Hl_Ts,rho,alpha,& beta,alon,sinlat,soltim,grav,Le,d_conv, & xt,xs,xu,xv,xz,xzts,xtts) ! ! subroutine Eulerm: integrate one time step with Modified Euler method ! integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,& Hl_Ts,rho,alpha,beta,alon,sinlat,soltim,& grav,Le,d_conv real(kind=kind_phys), intent(inout) :: xt,xs,xu,xv,xz,xzts,xtts ! local variables real(kind=kind_phys) :: xt0,xs0,xu0,xv0,xz0,xzts0,xtts0 real(kind=kind_phys) :: fw,Aw,Q_warm real(kind=kind_phys) :: xt1,xs1,xu1,xv1,xz1,xzts1,xtts1 real(kind=kind_phys) :: xt2,xs2,xu2,xv2,xz2,xzts2,xtts2 real(kind=kind_phys) :: dzw,drho,fc,t_fcl,ttop,dz real(kind=kind_phys) :: alat,t0,te,tau,speed ! logical lprnt ! ! input variables ! ! timestep: integration time step in seconds ! rich : critial Ri (flow/mass dependent) ! tox : x wind stress (N*M^-2 or KG/M/S^2) ! toy : y wind stress (N*M^-2 or KG/M/S^2) ! I0 : solar radiation flux at the surface (WM^-2) ! Q : non-solar heat flux at the surface (WM^-2) ! sss : Salinity (ppt) ! sep : Sr(E-P) (ppt*M/S) ! Q_Ts : d(Q)/d(Ts) : Q = the sum of non-solar heat fluxes ! Hl_Ts : d(Hl)/d(Ts) ! rho : sea water density (KG*M^-3) ! alpha : thermal expansion coefficient (1/K) ! beta : saline contraction coefficient (1/ppt) ! alon : longitude (DEG) ! sinlat : sine (lat) ! soltim : solar time ! grav : gravity accelleration ! Le : Le=(2.501-.00237*tsea)*1e6 ! d_conv : FCL thickness (M) ! ! inout variables ! ! xt : DTL heat content (M*K) ! xs : DTL salinity content (M*ppt) ! xu : DTL x current content (M*M/S) ! xv : DTL y current content (M*M/S) ! xz : DTL thickness (M) ! xzts : d(xz)/d(ts) (M/K ) ! xtts : d(xt)/d(ts) (M) xt0 = xt xs0 = xs xu0 = xu xv0 = xv xz0 = xz xtts0 = xtts xzts0 = xzts speed = max(1.0e-8,xu0*xu0 + xv0*xv0) alat=asin(sinlat)*rad2deg fc = const_rot*sinlat call sw_ps_9b(xz0,fw) q_warm = fw*I0-Q !total heat abs in warm layer call sw_ps_9b_Aw(xz0,Aw) drho = -alpha*q_warm/(rho*cp_w) + omg_m*beta*sep ! dzw = xz0*(tox*xu0+toy*xv0) / (rho*(xu0*xu0+xv0*xv0)) & ! + xz0*xz0*xz0*drho*grav / (4.0*rich*(xu0*xu0+xv0*xv0)) dzw = xz0 * ((tox*xu0+toy*xv0) / (rho*speed) & + xz0*xz0*drho*grav / (4.0*rich*speed)) xt1 = xt0 + timestep*q_warm/(rho*cp_w) xs1 = xs0 + timestep*sep xu1 = xu0 + timestep*(fc*xv0+tox/rho) xv1 = xv0 + timestep*(-fc*xu0+toy/rho) xz1 = xz0 + timestep*dzw ! if (lprnt) print *,' xt1=',xt1,' xz1=',xz1,' xz0=',xz0,' dzw=',dzw, & ! 'timestep=',timestep,tox,toy,xu0,xv0,rho,drho,grav,rich if ( xt1 <= 0.0 .or. xz1 <= 0.0 .or. xz1 > z_w_max ) then call dtl_reset(xt,xs,xu,xv,xz,xzts,xtts) go to 100 endif ! call dtm_1p_zwa(kdt,timestep,I0,Q,rho,d_conv,xt1,xs1,xu1,xv1,xz1,tr_mda,tr_fca,tr_tla,tr_mwa) xzts1 = xzts0 + timestep*((1.0/(xu0*xu0+xv0*xv0)) * & ( (alpha*Q_Ts/cp_w+omg_m*beta*sss*Hl_Ts/Le)*grav*xz0**3/(4.0*rich*rho)& +( (tox*xu0+toy*xv0)/rho+(3.0*drho-alpha*I0*Aw*xz0/(rho*cp_w)) & *grav*xz0*xz0/(4.0*rich) )*xzts0 )) xtts1 = xtts0 + timestep*(I0*Aw*xzts0-Q_Ts)/(rho*cp_w) ! if ( 2.0*xt1/xz1 > 0.001 ) then ! write(*,'(a,I5,2F8.3,4F8.2,F10.6,10F8.4)') 'Eulerm_01 : ',kdt,alat,alon,soltim/3600.,I0,Q,Q_warm,sep,& ! 2.0*xt1/xz1,2.0*xs1/xz1,2.0*xu1/xz1,2.0*xv1/xz1,xz1,xtts1,xzts1,d_conv,t_fcl,te ! endif call sw_ps_9b(xz1,fw) q_warm = fw*I0-Q !total heat abs in warm layer call sw_ps_9b_Aw(xz1,Aw) drho = -alpha*q_warm/(rho*cp_w) + omg_m*beta*sep dzw = xz1*(tox*xu1+toy*xv1) / (rho*(xu1*xu1+xv1*xv1)) & + xz1*xz1*xz1*drho*grav / (4.0*rich*(xu1*xu1+xv1*xv1)) xt2 = xt0 + timestep*q_warm/(rho*cp_w) xs2 = xs0 + timestep*sep xu2 = xu0 + timestep*(fc*xv1+tox/rho) xv2 = xv0 + timestep*(-fc*xu1+toy/rho) xz2 = xz0 + timestep*dzw ! if (lprnt) print *,' xt2=',xt2,' xz2=',xz2 if ( xt2 <= 0.0 .or. xz2 <= 0.0 .or. xz2 > z_w_max ) then call dtl_reset(xt,xs,xu,xv,xz,xzts,xtts) go to 100 endif xzts2 = xzts0 + timestep*((1.0/(xu1*xu1+xv1*xv1)) * & ( (alpha*Q_Ts/cp_w+omg_m*beta*sss*Hl_Ts/Le)*grav*xz1**3/(4.0*rich*rho)& +( (tox*xu1+toy*xv1)/rho+(3.0*drho-alpha*I0*Aw*xz1/(rho*cp_w))* & grav*xz1*xz1/(4.0*rich) )*xzts1 )) xtts2 = xtts0 + timestep*(I0*Aw*xzts1-Q_Ts)/(rho*cp_w) xt = 0.5*(xt1 + xt2) xs = 0.5*(xs1 + xs2) xu = 0.5*(xu1 + xu2) xv = 0.5*(xv1 + xv2) xz = 0.5*(xz1 + xz2) xzts = 0.5*(xzts1 + xzts2) xtts = 0.5*(xtts1 + xtts2) if ( xt <= 0.0 .or. xz < 0.0 .or. xz > z_w_max ) then call dtl_reset(xt,xs,xu,xv,xz,xzts,xtts) endif ! if (lprnt) print *,' xt=',xt,' xz=',xz ! if ( 2.0*xt/xz > 0.001 ) then ! write(*,'(a,I5,2F8.3,4F8.2,F10.6,10F8.4)') 'Eulerm_02 : ',kdt,alat,alon,soltim/3600.,I0,Q,Q_warm,sep,& ! 2.0*xt/xz,2.0*xs/xz,2.0*xu/xz,2.0*xv/xz,xz,xtts,xzts,d_conv,t_fcl,te ! endif 100 continue end subroutine Eulerm subroutine dtm_1p_zwa(kdt,timestep,I0,Q,rho,d_conv,xt,xs,xu,xv,xz,tr_mda,tr_fca,tr_tla,tr_mwa) ! apply xz adjustment: Minimum Depth Adjustment (MDA) ! Free Convection Adjustment (FCA); ! Top Layer Adjustment (TLA); ! Maximum Warming Adjustment (MWA) ! integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,I0,Q,rho,d_conv real(kind=kind_phys), intent(inout) :: xt,xs,xu,xv,xz real(kind=kind_phys), intent(out) :: tr_mda,tr_fca,tr_tla,tr_mwa ! local variables real(kind=kind_phys) :: dz,t0,ttop0,ttop,fw,Q_warm real(kind=kind_phys) :: xz_fca,xz_tla,xz_mwa real(kind=kind_phys) :: xz_mda tr_mda = 0.0; tr_fca = 0.0; tr_tla = 0.0; tr_mwa = 0.0 ! Apply MDA if ( z_w_min > xz ) then xz_mda = z_w_min endif ! Apply FCA if ( d_conv > 0.0 ) then xz_fca = 2.0*xt/((2.0*xt/xz)*(1.0-d_conv/(2.0*xz))) tr_fca = 1.0 if ( xz_fca >= z_w_max ) then call dtl_reset_cv(xt,xs,xu,xv,xz) go to 10 endif endif ! Apply TLA dz = min(xz,max(d_conv,delz)) call sw_ps_9b(dz,fw) Q_warm=fw*I0-Q !total heat abs in warm layer if ( Q_warm > 0.0 ) then call cal_ttop(kdt,timestep,Q_warm,rho,dz,xt,xz,ttop0) ! ttop = (2.0*xt/xz)*(1.0-dz/(2.0*xz)) ttop = ((xt+xt)/xz)*(1.0-dz/(xz+xz)) if ( ttop > ttop0 ) then xz_tla = (xt+sqrt(xt*(xt-delz*ttop0)))/ttop0 tr_tla = 1.0 if ( xz_tla >= z_w_max ) then call dtl_reset_cv(xt,xs,xu,xv,xz) go to 10 endif endif endif ! Apply MWA t0 = 2.0*xt/xz if ( t0 > tw_max ) then if ( xz >= z_w_max ) then call dtl_reset_cv(xt,xs,xu,xv,xz) go to 10 endif endif xz = max(xz_mda,xz_fca,xz_tla,xz_mwa) 10 continue end subroutine dtm_1p_zwa subroutine dtm_1p_fca(d_conv,xt,xtts,xz,xzts) ! apply xz adjustment: Free Convection Adjustment (FCA); ! real(kind=kind_phys), intent(in) :: d_conv,xt,xtts real(kind=kind_phys), intent(inout) :: xz,xzts ! local variables real(kind=kind_phys) :: t_fcl,t0,xz0,dxz ! t0 = 2.0*xt/xz t_fcl = t0*(1.0-d_conv/(2.0*xz)) xz = 2.0*xt/t_fcl ! xzts = 2.0*xtts/t_fcl end subroutine dtm_1p_fca subroutine dtm_1p_tla(dz,te,xt,xtts,xz,xzts) ! apply xz adjustment: Top Layer Adjustment (TLA); ! real(kind=kind_phys), intent(in) :: dz,te,xt,xtts real(kind=kind_phys), intent(inout) :: xz,xzts ! local variables real(kind=kind_phys) tem ! tem = xt*(xt-dz*te) if (tem > 0.0) then xz = (xt+sqrt(xt*(xt-dz*te)))/te else xz = z_w_max endif ! xzts = xtts*(1.0+0.5*(2.0*xt-dz*te)/sqrt(xt*(xt-dz*te)))/te end subroutine dtm_1p_tla subroutine dtm_1p_mwa(xt,xtts,xz,xzts) ! apply xz adjustment: Maximum Warming Adjustment (MWA) ! real(kind=kind_phys), intent(in) :: xt,xtts real(kind=kind_phys), intent(inout) :: xz,xzts ! local variables ! xz = 2.0*xt/tw_max ! xzts = 2.0*xtts/tw_max end subroutine dtm_1p_mwa subroutine dtm_1p_mda(xt,xtts,xz,xzts) ! apply xz adjustment: Minimum Depth Adjustment (MDA) ! real(kind=kind_phys), intent(in) :: xt,xtts real(kind=kind_phys), intent(inout) :: xz,xzts ! local variables real(kind=kind_phys) :: ta ! xz = max(z_w_min,xz) ta = 2.0*xt/xz ! xzts = 2.0*xtts/ta end subroutine dtm_1p_mda subroutine dtm_1p_mta(dta,xt,xtts,xz,xzts) ! apply xz adjustment: Maximum Temperature Adjustment (MTA) ! real(kind=kind_phys), intent(in) :: dta,xt,xtts real(kind=kind_phys), intent(inout) :: xz,xzts ! local variables real(kind=kind_phys) :: ta ! ta = max(0.0,2.0*xt/xz-dta) if ( ta > 0.0 ) then xz = 2.0*xt/ta else xz = z_w_max endif ! xzts = 2.0*xtts/ta end subroutine dtm_1p_mta subroutine convdepth(kdt,timestep,I0,Q,sss,sep,rho,alpha,beta,xt,xs,xz,d_conv) ! ! calculate depth for convective adjustment ! integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,I0,Q,sss,sep,rho,alpha,beta real(kind=kind_phys), intent(in) :: xt,xs,xz real(kind=kind_phys), intent(out) :: d_conv real(kind=kind_phys) :: t,s,d_conv_ini,d_conv2,fxp,Aw,s1,s2,fac1,fac2 integer :: n ! ! input variables ! ! timestep: time step in seconds ! I0 : solar radiation flux at the surface (WM^-2) ! Q : non-solar heat flux at the surface (WM^-2) ! sss : Salinity (ppt) ! sep : Sr(E-P) (ppt*M/S) ! rho : sea water density (KG*M^-3) ! alpha : thermal expansion coefficient (1/K) ! beta : saline contraction coefficient (1/ppt) ! xt : initial heat content (K*M) ! xs : initial salinity content (ppt*M) ! xz : initial DTL thickness (M) ! ! output variables ! ! d_conv : Free convection depth (m) ! t : initial diurnal warming T (K) ! s : initial diurnal warming S (ppt) n = 0 t = 2.0*xt/xz s = 2.0*xs/xz s1 = alpha*rho*t-omg_m*beta*rho*s if ( s1 == 0.0 ) then d_conv = 0.0 else fac1 = alpha*Q/cp_w+omg_m*beta*rho*sep if ( I0 <= 0.0 ) then d_conv2=(2.0*xz*timestep/s1)*fac1 if ( d_conv2 > 0.0 ) then d_conv = sqrt(d_conv2) else d_conv = 0.0 endif elseif ( I0 > 0.0 ) then d_conv_ini = 0.0 iter_conv: do n = 1, niter_conv call sw_ps_9b(d_conv_ini,fxp) call sw_ps_9b_Aw(d_conv_ini,Aw) s2 = alpha*(Q-(fxp-Aw*d_conv_ini)*I0)/cp_w+omg_m*beta*rho*sep d_conv2=(2.0*xz*timestep/s1)*s2 if ( d_conv2 < 0.0 ) then d_conv = 0.0 exit iter_conv endif d_conv = sqrt(d_conv2) if ( abs(d_conv-d_conv_ini) < eps_conv .and. n <= niter_conv ) exit iter_conv d_conv_ini = d_conv enddo iter_conv d_conv = max(0.0,min(d_conv,z_w_max)) endif ! if ( I0 <= 0.0 ) then endif ! if ( s1 == 0.0 ) then ! if ( d_conv > 0.01 ) then ! write(*,'(a,I4,I3,10F9.3,3F10.6,F10.1,F6.2)') ' d_conv : ',kdt,n,d_conv,d_conv_ini,Q,I0,rho,cp_w,timestep,xt,xs,xz,sep, & ! s1,s2,d_conv2,Aw ! endif end subroutine convdepth subroutine dtm_onset(kdt,timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,Hl_Ts,rho, & alpha,beta,alon,sinlat,soltim,grav,Le,xt,xs,xu,xv,xz,xzts,xtts) ! ! determine xz iteratively (starting wit fw = 0.5) and then update the other 6 variables ! integer,intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,rich,tox,toy,I0,Q,sss,sep,Q_Ts,& Hl_Ts,rho,alpha,beta,alon,sinlat,soltim,grav,Le real(kind=kind_phys), intent(out) :: xt,xs,xu,xv,xz,xzts,xtts real(kind=kind_phys) :: xt0,xs0,xu0,xv0,xz0 real(kind=kind_phys) :: xt1,xs1,xu1,xv1,xz1 real(kind=kind_phys) :: fw,Aw,Q_warm,ft0,fs0,fu0,fv0,fz0,ft1,fs1,fu1,fv1,fz1 real(kind=kind_phys) :: coeff1,coeff2,ftime,z_w,z_w_tmp,fc,warml,alat integer :: n ! ! input variables ! ! timestep: time step in seconds ! tox : x wind stress (N*M^-2 or KG/M/S^2) ! toy : y wind stress (N*M^-2 or KG/M/S^2) ! I0 : solar radiation flux at the surface (WM^-2) ! Q : non-solar heat flux at the surface (WM^-2) ! sss : Salinity (ppt) ! sep : Sr(E-P) (ppt*M/S) ! rho : sea water density (KG*M^-3) ! alpha : thermal expansion coefficient (1/K) ! beta : saline contraction coefficient (1/ppt) ! alon : longitude ! sinlat : sine(latitude) ! grav : gravity accelleration ! Le : Le=(2.501-.00237*tsea)*1e6 ! ! output variables ! ! xt : onset T content in DTL ! xs : onset S content in DTL ! xu : onset u content in DTL ! xv : onset v content in DTL ! xz : onset DTL thickness (M) ! xzts : onset d(xz)/d(ts) (M/K ) ! xtts : onset d(xt)/d(ts) (M) fc=1.46/10000.0/2.0*sinlat alat = asin(sinlat) ! ! initializing DTL (just before the onset) ! xt0 = 0.0 xs0 = 0.0 xu0 = 0.0 xv0 = 0.0 z_w_tmp=z_w_ini call sw_ps_9b(z_w_tmp,fw) ! fw=0.5 ! Q_warm=fw*I0-Q !total heat abs in warm layer if ( abs(alat) > 1.0 ) then ftime=sqrt((2.0-2.0*cos(fc*timestep))/(fc*fc*timestep)) else ftime=timestep endif coeff1=alpha*grav/cp_w coeff2=omg_m*beta*grav*rho warml = coeff1*Q_warm-coeff2*sep if ( warml > 0.0 .and. Q_warm > 0.0) then iters_z_w: do n = 1,niter_z_w if ( warml > 0.0 .and. Q_warm > 0.0 ) THEN z_w=sqrt(2.0*rich*ftime/rho)*sqrt(tox**2+toy**2)/sqrt(warml) else z_w = z_w_max exit iters_z_w endif ! write(*,'(a,I4,I4,10F9.3,F9.6,F3.0)') ' z_w = ',kdt,n,z_w,z_w_tmp,timestep,Q_warm,Q,I0,fw,tox,toy,sep,warml,omg_m if (ABS(z_w - z_w_tmp) < eps_z_w .AND. z_w/=z_w_max .AND. n < niter_z_w) exit iters_z_w z_w_tmp=z_w call sw_ps_9b(z_w_tmp,fw) Q_warm = fw*I0-Q warml = coeff1*Q_warm-coeff2*sep end do iters_z_w else z_w=z_w_max endif xz0 = max(z_w,z_w_min) ! ! Update xt, xs, xu, xv ! if ( z_w < z_w_max .and. Q_warm > 0.0) then call sw_ps_9b(z_w,fw) q_warm=fw*I0-Q !total heat abs in warm layer ft0 = q_warm/(rho*cp_w) fs0 = sep fu0 = fc*xv0+tox/rho fv0 = -fc*xu0+toy/rho xt1 = xt0 + timestep*ft0 xs1 = xs0 + timestep*fs0 xu1 = xu0 + timestep*fu0 xv1 = xv0 + timestep*fv0 fz0 = xz0*((tox*xu1+toy*xv1)/rho+omg_m*beta*grav*sep*xz0*xz0/(4.0*rich) & -alpha*grav*Q_warm*xz0*xz0/(4.0*rich*cp_w*rho))/(xu1*xu1+xv1*xv1) xz1 = xz0 + timestep*fz0 xz1 = max(xz1,z_w_min) if ( xt1 < 0.0 .or. xz1 > z_w_max ) then call dtl_reset(xt,xs,xu,xv,xz,xtts,xzts) go to 100 endif call sw_ps_9b(xz1,fw) Q_warm=fw*I0-Q !total heat abs in warm layer ft1 = Q_warm/(rho*cp_w) fs1 = sep fu1 = fc*xv1+tox/rho fv1 = -fc*xu1+toy/rho fz1 = xz1*((tox*xu1+toy*xv1)/rho+omg_m*beta*grav*sep*xz1*xz1/(4.0*rich) & -alpha*grav*Q_warm*xz1*xz1/(4.0*rich*cp_w*rho))/(xu1*xu1+xv1*xv1) xt = xt0+0.5*timestep*(ft0+ft1) xs = xs0+0.5*timestep*(fs0+fs1) xu = xu0+0.5*timestep*(fu0+fu1) xv = xv0+0.5*timestep*(fv0+fv1) xz = xz0+0.5*timestep*(fz0+fz1) xz = max(xz,z_w_min) call sw_ps_9b_Aw(xz,Aw) ! xzts = (Q_Ts+(cp_w*omg_m*beta*sss/(Le*alpha))*Hl_Ts)*xz/(I0*xz*Aw+2.0*q_warm-2.0*(rho*cp_w*omg_m*beta*sss/alpha)*(sep/sss)) xzts = (Q_Ts+omg_m*rho*cp_w*beta*sss*Hl_Ts*xz/(Le*alpha))/(I0*xz*Aw+2.0*q_warm-2.0*omg_m*rho*cp_w*beta*sss*sep/(Le*alpha)) xtts = timestep*(I0*Aw*xzts-Q_Ts)/(rho*cp_w) endif if ( xt < 0.0 .or. xz > z_w_max ) then call dtl_reset(xt,xs,xu,xv,xz,xtts,xzts) endif 100 continue end subroutine dtm_onset subroutine cal_w(kdt,xz,xt,xzts,xtts,w_0,w_d) ! ! abstract: calculate w_0,w_d ! ! input variables ! ! kdt : the number of time step ! xt : DTL heat content ! xz : DTL depth ! xzts : d(zw)/d(ts) ! xtts : d(xt)/d(ts) ! ! output variables ! ! w_0 : coefficint 1 to calculate d(Tw)/d(Ts) ! w_d : coefficint 2 to calculate d(Tw)/d(Ts) integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: xz,xt,xzts,xtts real(kind=kind_phys), intent(out) :: w_0,w_d w_0 = 2.0*(xtts-xt*xzts/xz)/xz w_d = (2.0*xt*xzts/xz**2-w_0)/xz ! if ( 2.0*xt/xz > 1.0 ) then ! write(*,'(a,I4,2F9.3,4F10.4))') ' cal_w : ',kdt,xz,xt,w_0,w_d,xzts,xtts ! endif end subroutine cal_w subroutine cal_ttop(kdt,timestep,Q_warm,rho,dz,xt,xz,ttop) ! ! abstract: calculate ! ! input variables ! ! kdt : the number of record ! timestep : the number of record ! Q_warm : total heat abs in layer dz ! rho : sea water density ! dz : dz = max(delz,d_conv) top layer thickness defined to adjust xz ! xt : heat content in DTL at previous time ! xz : DTL thickness at previous time ! ! output variables ! ! ttop : the diurnal warming amount at the top layer with thickness of delz integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: timestep,Q_warm,rho,dz,xt,xz real(kind=kind_phys), intent(out) :: ttop real(kind=kind_phys) :: dt_warm,t0 dt_warm = (xt+xt)/xz t0 = dt_warm*(1.0-dz/(xz+xz)) ttop = t0 + Q_warm*timestep/(rho*cp_w*dz) end subroutine cal_ttop subroutine app_sfs(kdt,xt,xs,xu,xv,alpha,beta,grav,d_1p,xz) ! ! abstract: adjust dtm-1p DTL thickness by applying Shear Flow Stability with assumed exponetial profile ! ! input variables ! ! kdt : the number of record ! xt : heat content in DTL ! xs : salinity content in DTL ! xu : u-current content in DTL ! xv : v-current content in DTL ! alpha ! beta ! grav ! d_1p : DTL depth before SFS applied ! ! output variables ! ! xz : DTL depth integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: xt,xs,xu,xv,alpha,beta,grav,d_1p real(kind=kind_phys), intent(out) :: xz ! real(kind=kind_phys) :: ze,cc,xz0,L,d_sfs, tem real(kind=kind_phys) :: cc,xz0,L,d_sfs,t_sfs, tem real(kind=kind_phys), parameter :: a2 = 0.2294, c2 = 0.3782 integer :: n cc = Ri_g/(grav*c2) tem = alpha*xt - beta*xs if (tem > 0.0) then d_sfs = sqrt(2.0*cc*(xu*xu+xv*xv)/tem) else d_sfs = 0.0 endif ! xz0 = d_1p ! iter_sfs: do n = 1, niter_sfs ! L = Int_epn(0.0,xz0,0.0,xz0,2) ! d_sfs = cc*(xu*xu+xv*xv)/((alpha*xt-beta*xs)*L) ! write(*,'(a,I6,I3,4F9.4))') ' app_sfs_iter : ',kdt,n,cc,L,xz0,d_sfs ! if ( abs(d_sfs-xz0) < eps_sfs .and. n <= niter_sfs ) exit iter_sfs ! xz0 = d_sfs ! enddo iter_sfs ! ze = a2*d_sfs ! not used! L = Int_epn(0.0,d_sfs,0.0,d_sfs,2) ! t_sfs = xt/L ! xz = (xt+xt) / t_sfs xz = L + L ! write(*,'(a,I6,6F9.4))') ' app_sfs : ',kdt,xz0,d_sfs,d_1p,xz,2.0*xt/d_1p,t_sfs end subroutine app_sfs subroutine cal_tztr(kdt,xt,c_0,c_d,w_0,w_d,zc,zw,z,tztr) ! ! abstract: calculate d(Tz)/d(Ts) ! ! input variables ! ! kdt : the number of record ! xt : heat content in DTL ! xz : DTL depth (M) ! c_0 : coefficint 1 to calculate d(Tc)/d(Ts) ! c_d : coefficint 2 to calculate d(Tc)/d(Ts) ! w_0 : coefficint 1 to calculate d(Tw)/d(Ts) ! w_d : coefficint 2 to calculate d(Tw)/d(Ts) ! ! output variables ! ! tztr : d(Tz)/d(Tr) integer, intent(in) :: kdt real(kind=kind_phys), intent(in) :: xt,c_0,c_d,w_0,w_d,zc,zw,z real(kind=kind_phys), intent(out) :: tztr real(kind=kind_phys) :: tem if ( xt > 0.0 ) then if ( z <= zc ) then ! tztr = 1.0/(1.0-w_0+c_0)+z*(w_d-c_d)/(1.0-w_0+c_0) tztr = (1.0+z*(w_d-c_d))/(1.0-w_0+c_0) elseif ( z > zc .and. z < zw ) then ! tztr = (1.0+c_0)/(1.0-w_0+c_0)+z*w_d/(1.0-w_0+c_0) tztr = (1.0+c_0+z*w_d)/(1.0-w_0+c_0) elseif ( z >= zw ) then tztr = 1.0 endif elseif ( xt == 0.0 ) then if ( z <= zc ) then ! tztr = 1.0/(1.0+c_0)-z*c_d/(1.0+c_0) tztr = (1.0-z*c_d)/(1.0+c_0) else tztr = 1.0 endif else tztr = 1.0 endif ! write(*,'(a,I4,9F9.4))') ' cal_tztr : ',kdt,xt,c_0,c_d,w_0,w_d,zc,zw,z,tztr end subroutine cal_tztr subroutine cool_skin(ustar_a,F_nsol,F_sol_0,evap,sss,alpha,beta,rho_w,rho_a,Ts,Q_Ts,Hl_Ts,grav,Le,deltaT_c,z_c,c_0,c_d) ! ! Upper ocean cool-skin parameterizaion, Fairall et al, 1996. ! ! INPUT: ! ustar_a : atmosphreic friction velocity at the air-sea interface (m/s) ! F_nsol : the "nonsolar" part of the surface heat flux (W/m^s) ! F_sol_0 : solar radiation at the ocean surface (W/m^2) ! evap : latent heat flux (W/M^2) ! sss : ocean upper mixed layer salinity (ppu) ! alpha : thermal expansion coefficient ! beta : saline contraction coefficient ! rho_w : oceanic density ! rho_a : atmospheric density ! Ts : oceanic surface temperature ! Q_Ts : d(Q)/d(Ts) : Q = the sum of non-solar heat fluxes ! Hl_Ts : d(Hl)/d(Ts) ! grav : gravity ! Le : ! ! OUTPUT: ! deltaT_c: cool-skin temperature correction (degrees K) ! z_c : molecular sublayer (cool-skin) thickness (m) ! c_0 : coefficient1 to calculate d(Tz)/d(Ts) ! c_d : coefficient2 to calculate d(Tz)/d(Ts) ! real(kind=kind_phys), intent(in) :: ustar_a,F_nsol,F_sol_0,evap,sss,alpha,beta,rho_w,rho_a,Ts,Q_Ts,Hl_Ts,grav,Le real(kind=kind_phys), intent(out):: deltaT_c,z_c,c_0,c_d ! declare local variables real(kind=kind_phys) :: a1,a2,a3,a4,A_c,B_c,zc_ts,bc1,bc2 real(kind=kind_phys) :: xi,Hb,ustar1_a,bigc,deltaF,fxp real(kind=kind_phys) :: tcw,cc1,cc2,cc3,qcol,dtemp,corioli,A_w,dwat,dtmp,alfac,wetc tcw = 0.6 z_c=z_c_ini ! initial quess ustar1_a=max(ustar_a,ustar_a_min) CALL sw_rad_skin(z_c,fxp) deltaF=F_sol_0*fxp Hb=alpha*(F_nsol-DeltaF)+beta*sss*cp_w*evap/Le bigc=16*grav*cp_w*(rho_w*visw)**3/(rho_a*rho_a*kw*kw) if ( Hb > 0 ) then xi=6./(1+(bigc*Hb/ustar1_a**4)**0.75)**0.3333333 else xi=6.0 endif z_c=min(z_c_max,xi*visw/(SQRT(rho_a/rho_w)*ustar1_a )) CALL sw_rad_skin(z_c,fxp) deltaF=F_sol_0*fxp deltaF=F_nsol - deltaF if ( deltaF > 0 ) then deltaT_c= deltaF * z_c / kw else deltaT_c=0. z_c=0. endif ! ! calculate c_0 & c_d ! if ( z_c > 0.0 ) then cc1 = 6.0*visw/(tcw*ustar1_a*(rho_a/rho_w)**0.5) cc2 = bigc*alpha/max(ustar_a,ustar_a_min)**4 cc3 = beta*sss*cp_w/(alpha*Le) A_c = a2+a3/z_c**2-(a3/(a4*z_c)+a3/z_c**2)*exp(-z_c/a4) if ( Hb > 0.0 ) then bc1 = z_c**2*(Q_Ts+cc3*Hl_Ts) bc2 = z_c**2*F_sol_0*A_c-4.0*(cc1*tcw)**3*(Hb/alpha)**0.25/(cc2**0.75*z_c**2) zc_ts = bc1/bc2 ! B_c = z_c**2*(Q_Ts+cc3*Hl_Ts)/(z_c**2*F_sol_0*A_c-4.0*(cc1*tcw)**3*(Hb/alpha)**0.25/(cc2**0.75*z_c**2)) ! d(z_c)/d(Ts) B_c = (Q_Ts+cc3*Hl_Ts)/(F_sol_0*A_c-4.0*(cc1*tcw)**3*(Hb/alpha)**0.25/(cc2**0.75*z_c**4)) ! d(z_c)/d(Ts) c_0 = (z_c*Q_Ts+(F_nsol-DeltaF-F_sol_0*A_c*z_c)*B_c)/tcw c_d = (F_sol_0*A_c*z_c*B_c-Q_Ts)/tcw else B_c = 0.0 zc_ts = 0.0 c_0 = z_c*Q_Ts/tcw c_d = -Q_Ts/tcw endif ! if ( c_0 < 0.0 ) then ! write(*,'(a,2F12.6,10F10.6)') ' c_0, c_d = ',c_0,c_d,B_c,zc_ts,Hb,bc1,bc2,z_c,cc1,cc2,cc3,z_c**2 ! endif ! c_0 = z_c*Q_Ts/tcw ! c_d = -Q_Ts/tcw else c_0 = 0.0 c_d = 0.0 endif ! if ( z_c > 0.0 ) then end subroutine cool_skin ! !====================== ! real function Int_epn(z1,z2,zmx,ztr,n) ! ! abstract: calculate a definitive integral of an exponetial curve (power of 2) ! real(kind_phys) :: z1,z2,zmx,ztr,zi real(kind_phys) :: fa,fb,fi,Int integer :: m,i,n m = nint((z2-z1)/delz) fa = exp(-exp_const*((z1-zmx)/(ztr-zmx))**n) fb = exp(-exp_const*((z2-zmx)/(ztr-zmx))**n) Int = 0.0 do i = 1, m-1 zi = z1 + delz*float(i) fi = exp(-exp_const*((zi-zmx)/(ztr-zmx))**n) Int = Int + fi enddo Int_epn = delz*((fa+fb)/2.0 + Int) end function Int_epn subroutine dtl_reset_cv(xt,xs,xu,xv,xz) real(kind=kind_phys), intent(inout) :: xt,xs,xu,xv,xz xt = 0.0 xs = 0.0 xu = 0.0 xv = 0.0 xz = z_w_max end subroutine dtl_reset_cv subroutine dtl_reset(xt,xs,xu,xv,xz,xzts,xtts) real(kind=kind_phys), intent(inout) :: xt,xs,xu,xv,xz,xzts,xtts xt = 0.0 xs = 0.0 xu = 0.0 xv = 0.0 xz = z_w_max xtts = 0.0 xzts = 0.0 end subroutine dtl_reset end module nst_module