diffusion.F90 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  1. !#################################################################
  2. !BOP
  3. !
  4. ! !MODULE: DIFFUSION
  5. !
  6. ! !DESCRIPTION:
  7. !
  8. ! Diffusion routines.
  9. !
  10. !
  11. ! !REVISION HISTORY: -----------------------------
  12. !
  13. ! ????-?? Bram Bregman.
  14. ! Adjusted for TM5 by
  15. !
  16. ! 2005-04 ??
  17. ! Adjoint version
  18. !
  19. ! 2010-08 Arjo Segers
  20. ! Debugged computation of u* over sea:
  21. ! abs. surface stress should be devided by air density.
  22. ! Set minimum value for u* to trap division by zero (MK).
  23. !
  24. ! 2012-01 Philippe Le Sager
  25. ! Adapted for Lat-Lon MPI domain decomposition
  26. !
  27. !EOP
  28. !#################################################################
  29. !
  30. ! global input fields:
  31. ! phlb(:,:,lm+1) ! half level pressure [Pa]
  32. ! gph(:,:,lm+1) ! height of half-levels [m] !CMK note gph starts NOW at 1!
  33. ! t ! temperature [K]
  34. ! q ! specific humidity [kg/kg]
  35. ! uwind ! mean wind W-E [m/s]
  36. ! vwind ! mean wind S-N [m/s]
  37. ! sshf ! surface sensible heat flux [W / m^2]
  38. ! slhf ! surface latent heat flux [W / m^2]
  39. ! ustar (ustar_loc) ! velocity scale
  40. !
  41. ! global output fields:
  42. ! kvh ! eddy diffusivity for heat at top [m^2/s]
  43. ! pblh ! boundary layer height[m]
  44. ! dkg ! vertical diffusion coefficient [ks s-1]
  45. !
  46. !### macro's #####################################################
  47. !
  48. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  49. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  50. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  51. !
  52. #include "tm5.inc"
  53. !
  54. !#################################################################
  55. MODULE DIFFUSION
  56. use GO, only : gol, goPr, goErr
  57. use dims, only : nregions
  58. use global_types, only : emis_data
  59. implicit none
  60. private
  61. ! methods
  62. public :: Diffusion_Init, Diffusion_Done
  63. public :: Calc_Kzz, Read_Diffusion, Write_Diffusion
  64. ! flag
  65. public :: diffusion_write
  66. ! --- const --------------------------------------
  67. character(len=*), parameter :: mname = 'diffusion'
  68. logical :: diffusion_write = .false.
  69. character(len=2000) :: diffusion_dir = ''
  70. ! --- local ------------------------------------
  71. type(emis_data), dimension(nregions), target :: ustar_loc, sr_mix
  72. CONTAINS
  73. ! ================================================================
  74. subroutine Diffusion_Init( status )
  75. use global_data, only : rcfile
  76. use MeteoData, only : Set
  77. use MeteoData, only : pu_dat, pv_dat
  78. use MeteoData, only : temper_dat, humid_dat, gph_dat
  79. use MeteoData, only : oro_dat, lsmask_dat
  80. use MeteoData, only : sr_ecm_dat, sr_ols_dat
  81. use MeteoData, only : u10m_dat, v10m_dat
  82. use MeteoData, only : slhf_dat, sshf_dat
  83. use MeteoData, only : ewss_dat, nsss_dat
  84. use GO, only : TrcFile, Init, Done, ReadRc
  85. ! --- in/out --------------------------------
  86. integer, intent(out) :: status
  87. ! --- const ------------------------------
  88. character(len=*), parameter :: rname = mname//'/Diffusion_Init'
  89. ! --- local -------------------------------------
  90. integer :: region
  91. type(TrcFile) :: rcF
  92. ! --- begin --------------------------------
  93. ! loop over all (zoom) regions:
  94. do region = 1, nregions
  95. ! meteo used by diffusion
  96. call Set( pu_dat(region), status, used=.true. )
  97. call Set( pv_dat(region), status, used=.true. )
  98. call Set( temper_dat(region), status, used=.true. )
  99. call Set( humid_dat(region), status, used=.true. )
  100. call Set( gph_dat(region), status, used=.true. )
  101. call Set( oro_dat(region), status, used=.true. )
  102. call Set( lsmask_dat(region), status, used=.true. )
  103. call Set( sr_ecm_dat(region), status, used=.true. )
  104. call Set( sr_ols_dat(region), status, used=.true. )
  105. call Set( u10m_dat(region), status, used=.true. )
  106. call Set( v10m_dat(region), status, used=.true. )
  107. call Set( sshf_dat(region), status, used=.true. )
  108. call Set( slhf_dat(region), status, used=.true. )
  109. call Set( ewss_dat(region), status, used=.true. )
  110. call Set( nsss_dat(region), status, used=.true. )
  111. end do
  112. call Init( rcF, rcfile , status)
  113. IF_NOTOK_RETURN(status=1)
  114. call ReadRc(rcF, 'diffusion.write', diffusion_write, status, default=.false.)
  115. IF_ERROR_RETURN(status=1)
  116. if (diffusion_write) then
  117. call ReadRc(rcF, 'diffusion.dir', diffusion_dir, status)
  118. IF_NOTOK_RETURN(status=1)
  119. endif
  120. call Done(rcF, status)
  121. IF_NOTOK_RETURN(status=1)
  122. ! ok
  123. status = 0
  124. end subroutine Diffusion_Init
  125. ! ***
  126. subroutine Diffusion_Done( status )
  127. ! --- in/out --------------------------------
  128. integer, intent(out) :: status
  129. ! --- const ------------------------------
  130. character(len=*), parameter :: rname = mname//'/Diffusion_Done'
  131. ! --- begin --------------------------------
  132. ! nothing to be done
  133. ! ok
  134. status = 0
  135. end subroutine Diffusion_Done
  136. ! ================================================================
  137. !------------------------------------
  138. !
  139. ! Purpose:
  140. ! -------
  141. ! this subroutine reads and prepares all fields needed for the calculation of kzz
  142. !
  143. ! External
  144. ! --------
  145. ! dd_get_3_hourly_surface_fields
  146. ! dd_calc_ustar_raero_rb
  147. ! dd_coarsen_fields
  148. !
  149. ! Reference
  150. ! ---------
  151. ! Ganzeveld and Lelieveld (1996) and references therein.
  152. ! Adjusted for TM5, Bram Bregman, August 2003
  153. !
  154. !
  155. subroutine calc_kzz( status )
  156. use binas, only : grav
  157. use dims, only : im, jm, lmax_conv, idate, lm, okdebug
  158. use dims, only : nread, ndyn, tref, at, bt
  159. use dims, only : revert
  160. use global_data, only : mass_dat, wind_dat, region_dat
  161. #ifndef without_convection
  162. #ifndef without_diffusion
  163. use global_data, only : conv_dat
  164. #endif
  165. #endif
  166. use meteoData, only : spm_dat, pu_dat, pv_dat, m_dat
  167. use meteoData, only : temper_dat, humid_dat, gph_dat
  168. use tm5_distgrid, only : dgrid, Get_DistGrid, update_halo, dist_arr_stat
  169. integer, intent(out) :: status
  170. ! --- local ------------------------------
  171. character(len=10) :: c_time
  172. real,dimension(:,:,:),pointer :: phlb,gph,t,q,m,pu,pv
  173. real,dimension(:,:,:),pointer :: am,bm,cm ! fluxes in kg/timestep(region)
  174. #ifndef without_convection
  175. #ifndef without_diffusion
  176. real,dimension(:,:,:),pointer :: dkg !vert diff (ks/s)
  177. #endif
  178. #endif
  179. real,dimension(:),pointer :: dxyp
  180. integer,parameter :: avg_field=1, nlon360=360, nlat180=180
  181. integer :: i,region, nsend, ntimes
  182. real, dimension(:,:,:),allocatable,target :: m_adj, phlb_adj
  183. real, dimension(:,:),allocatable :: p_adj
  184. integer :: imr, jmr, lmr, j,l
  185. real, allocatable, target :: phlb_t(:,:,:)
  186. real, allocatable, target :: m_t(:,:,:)
  187. integer :: i1, i2, j1, j2
  188. character(len=*), parameter :: rname = mname//'/Calc_kzz'
  189. ! --- begin ----------------------------------
  190. if (okdebug) write(*,*) 'start of calc_kzz'
  191. ! Allocate work arrays, and fill ghost cells
  192. DO region = 1, nregions
  193. CALL GET_DISTGRID( DGRID(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  194. ALLOCATE(ustar_loc(region)%surf( i1:i2, j1:j2))
  195. ALLOCATE( sr_mix(region)%surf( i1:i2, j1:j2))
  196. CALL UPDATE_HALO( dgrid(region), wind_dat(region)%am, wind_dat(region)%halo, status)
  197. IF_NOTOK_RETURN(status=1)
  198. CALL UPDATE_HALO( dgrid(region), wind_dat(region)%bm, wind_dat(region)%halo, status)
  199. IF_NOTOK_RETURN(status=1)
  200. CALL UPDATE_HALO( dgrid(region), wind_dat(region)%cm, wind_dat(region)%halo, status)
  201. IF_NOTOK_RETURN(status=1)
  202. CALL UPDATE_HALO( dgrid(region), pu_dat(region)%data, pu_dat(region)%halo, status)
  203. IF_NOTOK_RETURN(status=1)
  204. CALL UPDATE_HALO( dgrid(region), pv_dat(region)%data, pv_dat(region)%halo, status)
  205. IF_NOTOK_RETURN(status=1)
  206. ENDDO
  207. ! -- for output of time header on debug fields
  208. write(c_time,'(i4,3(i2))') idate(1:4) !CMK corrected
  209. do i=1,10
  210. if (c_time(i:i)==' ') c_time(i:i)='0'
  211. enddo
  212. !
  213. ! Surface data sets may have the following characteristics
  214. ! 1. instanteneous. The time written in the file is valid from t-1.5 to t+1.5
  215. ! 2. Accumulated. The time written in the file is valid from t to t+3
  216. ! 3. Daily averaged. The time on the file is always 00 hours, and valid until t+24
  217. !
  218. ! *** It is essential to understand this timing when reading and applying these sets.
  219. !
  220. !
  221. ! fd2mk it has to be decided to 'save' fields like vgrat_low and daily average surface fields
  222. ! for later use, or to read it every 3 hours time step
  223. REG: do region = 1,nregions
  224. ! local grid sizes
  225. lmr=lm(region)
  226. call Get_DistGrid( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
  227. if (revert == -1) then
  228. !mkadj
  229. !mass and pressure are at t=t+dt in adjoint
  230. !these should be brought back to t to get
  231. !exactly the same diffusion as in forward run
  232. allocate ( m_adj (i1:i2, j1:j2, lmr ) )
  233. allocate ( phlb_adj(i1:i2, j1:j2, lmr+1) )
  234. allocate ( p_adj (i1:i2, j1:j2 ) )
  235. am => wind_dat(region)%am
  236. bm => wind_dat(region)%bm
  237. cm => wind_dat(region)%cm
  238. dxyp => region_dat(region)%dxyp
  239. ntimes = (nread/(ndyn))*tref(region)
  240. m_adj = m_dat(region)%data(i1:i2, j1:j2, 1:lmr)
  241. do i=1,ntimes
  242. m_adj = m_adj + revert*am(i1-1:i2-1, j1 :j2 , 1:lmr ) & !east
  243. - revert*am(i1 :i2 , j1 :j2 , 1:lmr ) & !west
  244. + revert*bm(i1 :i2 , j1 :j2 , 1:lmr ) & !south
  245. - revert*bm(i1 :i2 , j1+1:j2+1, 1:lmr ) & !north
  246. + revert*cm(i1 :i2 , j1 :j2 , 0:lmr-1) & !lower
  247. - revert*cm(i1 :i2 , j1 :j2 , 1:lmr ) !upper
  248. enddo
  249. p_adj(:,:) = 0.0
  250. do l=1,lmr
  251. ! note that on the EDGES masses are coarse>
  252. ! diffusion iis applied only on core zoom>
  253. do j = j1, j2
  254. do i = i1, i2
  255. p_adj(i,j) = p_adj(i,j) + m_adj(i,j,l)*grav/dxyp(j)
  256. end do
  257. end do
  258. end do
  259. do l=1,lmr+1
  260. do j = j1, j2
  261. do i = i1, i2
  262. phlb_adj(i,j,l) = at(l)+bt(l)*p_adj(i,j)
  263. end do
  264. end do
  265. end do
  266. deallocate(p_adj)
  267. nullify(am)
  268. nullify(bm)
  269. nullify(cm)
  270. nullify(dxyp)
  271. phlb => phlb_adj
  272. m => m_adj
  273. else
  274. ! Bug fix 2006-09-21 (AJS)
  275. ! The two half level pressure arrays phbl_t and phlb_k
  276. ! are sometimes not updated together when running in parallel
  277. ! with zoom regions. To avoid problems, pressure and mass
  278. ! are computed here given the surface pressure in the middle
  279. ! of the current time interval, stored in spm_dat.
  280. !--
  281. !phlb => mass_dat(region)%phlb_t
  282. !m => mass_dat(region)%m_t
  283. !--
  284. allocate( phlb_t(i1:i2, j1:j2, 1:lmr+1) )
  285. do l = 1, lmr+1
  286. phlb_t(:,:,l) = at(l) + bt(l)*spm_dat(region)%data(i1:i2, j1:j2, 1)
  287. end do
  288. allocate( m_t(i1-2:i2+2, j1-2:j2+2, 1:lmr) )
  289. m_t = 0.0
  290. do l = 1, lmr
  291. do j = j1, j2
  292. m_t(i1:i2,j,l) = ( phlb_t(:,j,l) - phlb_t(:,j,l+1) )*region_dat(region)%dxyp(j)/grav
  293. end do
  294. end do
  295. phlb => phlb_t
  296. m => m_t
  297. !--
  298. endif
  299. pu => pu_dat(region)%data
  300. pv => pv_dat(region)%data
  301. gph => gph_dat(region)%data
  302. t => temper_dat(region)%data
  303. q => humid_dat(region)%data
  304. #ifndef without_convection
  305. #ifndef without_diffusion
  306. dkg => conv_dat(region)%dkg
  307. #endif
  308. #endif
  309. ! ustar_loc
  310. call dd_calc_ustar(region, i1, i2, j1, j2)
  311. if (okdebug) then
  312. ! call dd_field_statistics(region, 'ustar_loc', ustar_loc(region)%surf, i1, j1, status)
  313. call dist_arr_stat(dgrid(region), 'ustar_loc', ustar_loc(region)%surf, 0, status)
  314. end if
  315. #ifndef without_convection
  316. #ifndef without_diffusion
  317. ! calculate kzz
  318. call bldiff( region, phlb, m, i1, i2, j1, j2 )
  319. #endif
  320. #endif
  321. nullify(phlb)
  322. nullify(m)
  323. !--
  324. deallocate( phlb_t )
  325. deallocate( m_t )
  326. !--
  327. nullify(pu)
  328. nullify(pv)
  329. #ifndef without_convection
  330. #ifndef without_diffusion
  331. nullify(dkg)
  332. #endif
  333. #endif
  334. nullify(t)
  335. nullify(q)
  336. nullify(gph)
  337. if(revert == -1) then
  338. deallocate(m_adj)
  339. deallocate(phlb_adj)
  340. endif
  341. end do REG
  342. ! Done
  343. do region = 1,nregions
  344. deallocate(sr_mix(region)%surf)
  345. deallocate(ustar_loc(region)%surf)
  346. end do
  347. if (okdebug) write(*,*) 'end of calc_kzz'
  348. end subroutine calc_kzz
  349. !------------------------------------------------------------------------------
  350. ! TM5 !
  351. !------------------------------------------------------------------------------
  352. !BOP
  353. !
  354. ! !IROUTINE: dd_calc_ustar
  355. !
  356. ! !DESCRIPTION:
  357. !
  358. ! Calculate friction velocity (ustar)
  359. !
  360. ! Uses the log normal wind profile information stored by ECMWF in 10 meter wind
  361. ! to estimate a local ustar over land
  362. ! uses Charnock equation over sea to estimate ustar
  363. ! aerodynamic resistance is calculated from heat fluxes and ustar using a constant reference height
  364. ! sub laminar resistance from ustar
  365. !
  366. ! Reference:
  367. ! o M.Z. Jacobson, "Fundamentals of Atmospheric Modeling", sections 8.3-8.4
  368. !
  369. ! !REVISION HISTORY:
  370. !
  371. ! 2003 ??; Ge Verver (personal communication, 2003)
  372. !
  373. ! 2010-08 Arjo Segers
  374. ! Debugged computation of u* over sea:
  375. ! abs. surface stress should be devided by air density.
  376. ! Set minum value for u* to trap division by zero (MK).
  377. !
  378. ! 2012-01 P. Le Sager
  379. ! adapted for lon-lat MPI domain decomposition
  380. !------------------------
  381. subroutine dd_calc_ustar(region, i1, i2, j1, j2)
  382. use binas, only : grav, vKarman
  383. use dims, only : okdebug
  384. use meteoData, only : lsmask_dat, sr_ecm_dat, sr_ols_dat
  385. use meteoData, only : u10m_dat, v10m_dat
  386. use meteoData, only : slhf_dat, sshf_dat
  387. use meteoData, only : ewss_dat, nsss_dat
  388. !--- in/out ------------------------------------
  389. integer,intent(in) :: region, i1, i2, j1, j2
  390. ! --- const -------------------------------------
  391. ! Garret relation:
  392. real,parameter :: alfa_garret = 0.11
  393. ! air density at seal level and 293 K :
  394. real, parameter :: rho_air = 1.2 ! kg/m3
  395. ! Charnock relation:
  396. real,parameter :: alfa_charnock = 0.018
  397. ! kinematic viscosity of air at about 300 K :
  398. real,parameter :: nu_air = 1.5e-5 ! m2/s
  399. real, parameter :: Href=30. ! constant reference height for calculations of raero
  400. ! some constants specific to calculation of ustar and raero
  401. real,parameter :: rhoCp = 1231.0
  402. real,parameter :: rhoLv = 3013000.0
  403. real, parameter :: rz0 =2.0
  404. !--- local -------------------------------------
  405. integer :: i,j
  406. real :: tau_z_abs
  407. real :: ustar_sea,ustar_land,xland,sr_sea,sr_land,sr_help,wind10m
  408. ! --- begin ----------------------------------
  409. do j=j1, j2
  410. do i=i1, i2
  411. xland=lsmask_dat(region)%data(i,j,1)/100. ! 0-1
  412. ! SEA:
  413. !
  414. ! From M.Z. Jacobson, "Fundamentals of Atmospheric Modeling",
  415. ! section "8.3 Friction velocity" :
  416. ! The friction velocity :
  417. ! u* = sqrt( |tau_z|/rho_a ) [m/s]
  418. ! where:
  419. ! tau_z = (ewss,nsss) surface stress [N/m2=kg/m/s2]
  420. ! rho_air air density [kg/m3] ; about 1.2 at sea level and 293 K
  421. !
  422. tau_z_abs = sqrt(ewss_dat(region)%data(i,j,1)**2+&
  423. nsss_dat(region)%data(i,j,1)**2 ) ! N/m2
  424. ustar_sea = sqrt(tau_z_abs/rho_air) ! m/s
  425. !
  426. ! limitation to avoid division by zero:
  427. ustar_sea = max( 0.001, ustar_sea ) ! m/s ; minium of 1 mm/s
  428. !
  429. ! From M.Z. Jacobson, "Fundamentals of Atmospheric Modeling",
  430. ! section "8.4 Surface roughness lengths" :
  431. ! "For smooth surfaces, such as over a smooth ocean with low wind speeds (Garret):
  432. ! z0m = 0.11 nu_a / u*
  433. ! where nu_a is the kinematic viscosity of air.
  434. ! Over a rough ocean with high wind speeds:
  435. ! z0m = alpha_c (u*)**2 / grav
  436. ! which is the 'Charnock relation',
  437. ! where alpha_c ~ 0.016 is the 'Charnock constant'."
  438. !
  439. ! Here the sum of these two parameterizations is used,
  440. ! where the first part is dominant for u*<0.1 and the second for u*>0.1 ;
  441. ! minimum value for u* prevents division by zero:
  442. !
  443. sr_sea = alfa_garret * nu_air / ustar_sea + &
  444. alfa_charnock * ustar_sea**2 / grav
  445. !
  446. ! LAND
  447. ! calculate the 'local' surface roughness for momentum that is consistent with 10 m wind
  448. ! and the Olsson data base, we assume that the windspeed at 75 m is independent of
  449. ! surface roughness
  450. !
  451. wind10m = sqrt( u10m_dat(region)%data(i,j,1)**2 + v10m_dat(region)%data(i,j,1)**2 )
  452. if ( xland > 0.0 ) then
  453. !>>> TvN
  454. ! Over land, the friction velocity ustar
  455. ! is calculated from the 10 m wind speed, u10.
  456. ! In IFS u10 is a diagnostic variable, calculated to be
  457. ! compatible with "open-terrain" wind speed observations.
  458. ! Over rough or inhomogeneous terrain (z0M > 0.03 m),
  459. ! it is calculated using an aerodynamic roughness
  460. ! length typical for open terrain with grassland (0.03 m)
  461. ! (see IFS cy31r1 documentation, p. 46).
  462. ! In the expressions applied in TM5,
  463. ! the stability profile functions Psi_M have disappeared,
  464. ! and only the logarithmic terms are kept.
  465. ! Apart from this, the expression for ustar was incorrect:
  466. ! 10./sr_land should be 75./sr_land.
  467. ! This has now been corrected.
  468. ! Moreover, over islands and near coast lines,
  469. ! zeros can occur in sr_ols_dat,
  470. ! which have to be removed.
  471. ! However, a lower bound of 1e-2 m = 1 cm
  472. ! seems too high for smooth surfaces,
  473. ! like deserts and ice caps.
  474. ! The minimum positive value in sr_ols_dat
  475. ! is 2.5e-4 m = 0.025 cm,
  476. ! which is obtained in parts of Antarctica.
  477. ! This is likely the result of regridding of
  478. ! a field with minimum value of 0.1 cm
  479. ! from 0.5x0.5 to 1x1 degrees.
  480. ! Please note that with the introduction of CY31R1,
  481. ! the orographic contribution to the aerodynamic roughness length
  482. ! in IFS has been replaced by an explicit specification of stress
  483. ! on model levels due to turbulent orographic form drag,
  484. ! and the climatological variable previously used
  485. ! has been replaced by a prognostic variable.
  486. ! In TM5, the climatological variable is still used,
  487. ! but it would be better to use the prognostic variable instead.
  488. ! Note also that the same calculation
  489. ! is done in dry_deposition.F90.
  490. !sr_land=max(1e-2,sr_ols_dat(region)%data(i,j,1)) ! occurs at Islands, etc.
  491. sr_land=max(1e-3,sr_ols_dat(region)%data(i,j,1))
  492. sr_help=min(sr_ecm_dat(region)%data(i,j,1),0.03)
  493. !fd ustar_land=vKarman*wind10m(i,j)/alog(10./sr_help) !ustar consistent with 'clipped' large scale roughness
  494. !ustar_land=vKarman*wind10m/&
  495. ! alog(10./sr_help)*alog(75./sr_help)/alog(10./sr_land)
  496. ustar_land=vKarman*wind10m/&
  497. alog(10./sr_help)*alog(75./sr_help)/alog(75./sr_land)
  498. ! <<< TvN
  499. else
  500. sr_land = 0.0
  501. ustar_land = 0.0
  502. endif
  503. ! interpolate between land and sea for mixed pixels:
  504. ustar_loc(region)%surf(i,j) = xland*ustar_land+(1-xland)*ustar_sea
  505. sr_mix (region)%surf(i,j) = xland* sr_land+(1-xland)* sr_sea
  506. end do !i
  507. end do !j
  508. if (okdebug) write(*,*) 'end calc_ustar'
  509. end subroutine dd_calc_ustar
  510. ! ***
  511. #ifndef without_convection
  512. #ifndef without_diffusion
  513. !------------------------------------------------------------------
  514. ! Procedure:
  515. ! (1) calc_Kv: Diffusion coefficients full atmosphere from shear
  516. ! (2) pblhght: Determine the boundary layer height
  517. ! (3) difcoef: Replace diffusion coefficients in the boundary layer
  518. !------------------------------------------------------------------
  519. ! subroutine adjusted for TM5, Bram Bregman, August 2003.
  520. !-------------------------IO---------------------------------------
  521. subroutine bldiff( region, phlb, m, i1, i2, j1, j2 )
  522. use binas, only: ae, cp_air, Rgas, grav, Lvap
  523. use binas, only: xmair
  524. use binas, only: vkarman
  525. use dims, only: im, jm, lm, lmax_conv
  526. use dims, only: okdebug
  527. use dims, only: gtor, dx, dy, ybeg, xref, yref
  528. use dims, only: isr, ier, jsr, jer
  529. use toolbox, only: dumpfield
  530. use global_data, only : conv_dat
  531. use meteodata , only : slhf_dat, sshf_dat, pu_dat, pv_dat, gph_dat, temper_dat, humid_dat
  532. ! --- in/out ----------------------------------------------
  533. integer,intent(in) :: region, i1, i2, j1, j2
  534. real,dimension(:,:,:),pointer :: phlb, gph, t, q, m, pu, pv, dkg
  535. ! --- const ----------------------------------
  536. ! minimum value diffusion coefficient
  537. real, parameter :: ckmin = 1.e-15
  538. real, parameter :: sffrac= 0.1
  539. real, parameter :: onet = 1./3.
  540. real, parameter :: rair = Rgas*1.e3/xmair
  541. real, parameter :: ccpq = 1869.46/cp_air -1.
  542. real, parameter :: epsilo = rair/461.51
  543. real, parameter :: apzero = 100000. ! reference pressure (usually 1000 hPa)
  544. real, parameter :: ccon = sffrac*vkarman
  545. real, parameter :: betam=15.,betah=15.
  546. real, parameter :: binm = betam*sffrac
  547. real, parameter :: binh = betah*sffrac
  548. real, parameter :: fr_excess = 1.
  549. real, parameter :: fak = fr_excess * 8.5
  550. real, parameter :: fakn = fr_excess * 7.2
  551. real, parameter :: zkappa = rair / cp_air
  552. real, parameter :: zcrdq = 1.0/epsilo - 1.0
  553. real, parameter :: tiny = 1.e-9 ! bound wind**2 to avoid dividing by 0
  554. real, parameter :: zacb = 100. !factor in ustr-shearproduction term
  555. real, parameter :: ricr = 0.3 ! critical richardson number
  556. real, parameter :: ssfrac=0.1
  557. ! --- local ------------------------------------
  558. real, dimension(:,:,:), allocatable:: wkvf,& ! outer layer Kv (at the top of each layer)
  559. zdup2,& ! vertical shear squared
  560. zrinub,& ! Richardson number
  561. wthm,& ! potential temperature
  562. zthvk,& ! virtual potential temperature
  563. pf,& ! full level pressure
  564. whm, & ! height of layer centers
  565. uwind,vwind,& ! wind velocities [m s-1]
  566. kvh !
  567. real, dimension(:,:), allocatable :: ustr,& ! velocity scale
  568. wheat,& ! surface sensible heat flux [K m/s]
  569. wqflx,& ! surface latent heat flux [kg m/ (kg s)]
  570. wobkl,& ! Monin Obukhov length
  571. wheatv,& ! surface virtual heat flux [K m/s]
  572. wtseff ! theta_v at lowest level [K]
  573. integer :: i, j, l
  574. real :: intfac !cmk BUG was integer!
  575. ! variables for the calculation of free atmosphere vertical diffusion coefficients wkvf
  576. real :: cml2,zlambdac,arg,zdz,zthva,zfunst, zfstabh,zsstab,zkvn,dyy
  577. real, dimension(j1:j2) :: dxx, lat
  578. integer :: jq! jqif function
  579. ! variabales for the calculation of the boundary layer height
  580. real :: wrino ! Richardson number
  581. real :: thvparc ! parcel virtual potential temperature
  582. real :: fmt,wsc,tkv,zrino,vvk,dtkv,zexcess
  583. integer :: jwork
  584. real,dimension(:,:),pointer :: pblh ! planetary boundary layer height [m]
  585. ! variables to calculate difusion coefficient in the boundary layer
  586. !real :: wsc,cml2
  587. real :: z,zwstr,zkvh,kvhmin,zm,zp,zslask,zsl1, &
  588. zh,zzh,zl,pr,zpblk,zfstabh1,zfstabh2,&
  589. term1,term2,term3,obukov
  590. integer :: jq1,jq2,jq3,jq4,jq5,jck,jqq, jq6, jq7
  591. real :: yres
  592. real :: xres
  593. real :: thvgrad, kvhentr
  594. ! --- begin ------------------------------------------
  595. if (okdebug) write(*,*) 'start of bldiff'
  596. allocate(wkvf ( i1:i2, j1:j2, lm(region)))
  597. allocate(zdup2 ( i1:i2, j1:j2, lm(region)))
  598. allocate(zrinub( i1:i2, j1:j2, lm(region)))
  599. allocate(wthm ( i1:i2, j1:j2, lm(region)))
  600. allocate(zthvk ( i1:i2, j1:j2, lm(region)))
  601. allocate(pf ( i1:i2, j1:j2, lm(region)))
  602. allocate(whm ( i1:i2, j1:j2, lm(region)))
  603. allocate(uwind ( i1:i2, j1:j2, lm(region)))
  604. allocate(vwind ( i1:i2, j1:j2, lm(region)))
  605. allocate(kvh ( i1:i2, j1:j2, lm(region)))
  606. allocate(ustr ( i1:i2, j1:j2 ))
  607. allocate(wheat ( i1:i2, j1:j2 ))
  608. allocate(wqflx ( i1:i2, j1:j2 ))
  609. allocate(wobkl ( i1:i2, j1:j2 ))
  610. allocate(wheatv( i1:i2, j1:j2 ))
  611. allocate(wtseff( i1:i2, j1:j2 ))
  612. pblh => conv_dat(region)%blh
  613. pu => pu_dat(region)%data
  614. pv => pv_dat(region)%data
  615. gph => gph_dat(region)%data
  616. t => temper_dat(region)%data
  617. q => humid_dat(region)%data
  618. dkg => conv_dat(region)%dkg
  619. ! mid-layer pressure levels
  620. ! potential temperature field
  621. ! virtual potential temperature field
  622. !
  623. !PLS $OMP PARALLEL &
  624. !PLS $OMP default (none) &
  625. !PLS $OMP shared (lm, jsr, jer, isr, ier, region, pf, phlb, t, q, wthm, &
  626. !PLS $OMP zthvk, whm, gph) &
  627. !PLS $OMP private (i, j, l, jss, jee, intfac)
  628. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  629. do l=1,lm(region)
  630. do j=j1,j2
  631. do i=i1,i2
  632. pf(i,j,l) = (phlb(i,j,l) + phlb(i,j,l+1) )*0.5
  633. wthm(i,j,l) = t(i,j,l) * ( apzero/pf(i,j,l) )**zkappa
  634. zthvk(i,j,l) = wthm(i,j,l) * (1.0 + zcrdq*q(i,j,l))
  635. ! mid-layer heights (note: gph array is for levels 1:lm+1)
  636. intfac = (phlb(i,j,l)-pf(i,j,l)) / (phlb(i,j,l)-phlb(i,j,l+1))
  637. ! cmk: intfac is now real!
  638. whm(i,j,l) = (gph(i,j,l)-gph(i,j,1)) * (1.0-intfac) + (gph(i,j,l+1) -gph(i,j,1)) * intfac
  639. ! cmk bug corrected:
  640. ! cmk old: whm(i,j,l) = (gph(i,j,l+1)-gph(i,j,1)) * (1.0-intfac) + (gph(i,j,l+1) -gph(i,j,1)) * intfac
  641. end do
  642. end do
  643. end do
  644. !PLS $OMP END PARALLEL
  645. ! convert units of sensible and latent heat fluxes
  646. ! sshf: W/m2 / (J/kg/K) / (kg/m3) = J/s/m2 /J kg K /kg m3 = K m/s
  647. ! slhf: W/m2 / (J/kg) / (kg/m3) = J/s/m2 /J kg /kg m3 = m/s
  648. ! ustr is local velocity scale, NOT from ECMWF surface stresses
  649. !
  650. !PLS $OMP PARALLEL &
  651. !PLS $OMP default (none) &
  652. !PLS $OMP shared (jm, im, region, wheat, sshf_dat, gph, phlb, slhf_dat, &
  653. !PLS $OMP wqflx, ustr, ustar_loc) &
  654. !PLS $OMP private (i, j, js, je)
  655. ! call my_omp_domain (1, jm(region), js, je)
  656. do j = j1,j2
  657. do i = i1,i2
  658. wheat(i,j) = -sshf_dat(region)%data(i,j,1) * (gph(i,j,2) - &
  659. gph(i,j,1)) * grav / (phlb(i,j,1) - &
  660. phlb(i,j,2)) / cp_air
  661. wqflx(i,j) = -slhf_dat(region)%data(i,j,1) * (gph(i,j,2) - &
  662. gph(i,j,1)) * grav / (phlb(i,j,1) - &
  663. phlb(i,j,2)) / lvap
  664. ustr(i,j) = max (ustar_loc(region)%surf(i,j), 0.01)
  665. end do
  666. end do
  667. !PLS $OMP END PARALLEL
  668. !
  669. !-----------------------------------------------------------------
  670. ! compute the free atmosphere vertical diffusion coefficients wkvf
  671. ! height-dependent asymptotic mixing length implemented
  672. ! Holtslag and Boville, 1993, J. Climate, 6, 1825-1842.
  673. !------------------------------------------------------------------
  674. ! first calculate wind velocities [m s-1] from the mass fluxes
  675. yres = dy/yref(region)
  676. xres = dx/xref(region)
  677. do j = j1,j2
  678. lat(j) = ybeg(region) + 0.5 * yres + yres * (j-1)
  679. enddo
  680. dxx(j1:j2) = ae * xres * gtor * cos(lat(j1:j2)*gtor)
  681. dyy = ae * yres * gtor
  682. !PLS $OMP PARALLEL &
  683. !PLS $OMP default (none) &
  684. !PLS $OMP shared (lm, jsr, jer, isr, ier, region, dxx, dyy, pu, pv, m, &
  685. !PLS $OMP uwind, vwind) &
  686. !PLS $OMP private (i, j, l, jss, jee)
  687. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  688. do l=1,lm(region)
  689. do j=j1,j2
  690. do i=i1,i2
  691. uwind(i,j,l) = dxx(j)*(pu(i,j,l) + pu(i-1,j,l))*0.5 / m(i,j,l)
  692. vwind(i,j,l) = dyy *(pv(i,j,l) + pv(i,j+1,l))*0.5 / m(i,j,l)
  693. enddo
  694. enddo
  695. enddo
  696. !PLS $OMP END PARALLEL
  697. !
  698. ! Initialize gradient Richardson number and free tropospheric k values
  699. !
  700. if (okdebug) write(*,*) ' Richardson number'
  701. !PLS $OMP PARALLEL &
  702. !PLS $OMP default (none) &
  703. !PLS $OMP shared (lm, jsr, jer, isr, ier, region, gph, zdup2, uwind, &
  704. !PLS $OMP vwind, whm, phlb, pf, zthvk, zrinub, wkvf) &
  705. !PLS $OMP private (i, j, l, jss, jee, jq, zlambdac, cml2, zdz, arg, &
  706. !PLS $OMP zthva, zsstab, zfunst, zfstabh, zkvn)
  707. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  708. do l=1,lm(region)-1
  709. do j=j1,j2
  710. do i=i1,i2
  711. !
  712. ! if (delta gph < 1000) then jq=1
  713. jq = jqif( 1000.0, (gph(i,j,l+1)-gph(i,j,1)) )
  714. zlambdac=jq*300.+(1-jq)*(30. + 270. * exp (1.-(gph(i,j,l+1)-gph(i,j,1))/1000.))
  715. cml2=(1./( 1./zlambdac + 1./(vkarman*(gph(i,j,l+1)-gph(i,j,1))) ))**2.
  716. !
  717. ! vertical shear squared,
  718. ! min value of (delta v)**2 prevents zero shear
  719. !
  720. zdup2(i,j,l) = (uwind(i,j,l+1)-uwind(i,j,l))**2 + &
  721. (vwind(i,j,l+1)-vwind(i,j,l))**2
  722. zdup2(i,j,l) = max(zdup2(i,j,l),1.e-10)
  723. zdz = whm(i,j,l+1) - whm(i,j,l)
  724. zdup2(i,j,l) = zdup2(i,j,l)/(zdz**2)
  725. !
  726. ! static stability (use virtual potential temperature)
  727. ! dv now calculated at interface height (lineair in pressure)
  728. !
  729. arg=(log(phlb(i,j,l+1))-log(pf(i,j,l)))/(log(pf(i,j,l+1))-log(pf(i,j,l)))
  730. zthva = zthvk(i,j,l) + arg * (zthvk(i,j,l+1)-zthvk(i,j,l))
  731. zsstab = grav/zthva*(zthvk(i,j,l+1) - zthvk(i,j,l))/zdz
  732. !
  733. ! gradient Richardson number
  734. !
  735. zrinub(i,j,l) = zsstab/zdup2(i,j,l)
  736. !
  737. ! stability functions
  738. !
  739. zfunst = max(1. - 18.*zrinub(i,j,l),0.)
  740. zfunst = sqrt(zfunst)
  741. !
  742. zfstabh = 1.0 / (1.0 + 10.0*zrinub(i,j,l)*(1.0+8.0*zrinub(i,j,l)))
  743. !
  744. ! neutral diffusion coefficient
  745. !
  746. zkvn = cml2 * sqrt(zdup2(i,j,l))
  747. !
  748. ! correction with stability functions
  749. !
  750. jq = jqif( zrinub(i,j,l),0.0 ) ! thus: if (zrinub>0) then jq=1
  751. wkvf(i,j,l)=jq*(max(ckmin,zkvn*zfstabh))+(1-jq)*(max(ckmin,zkvn*zfunst))
  752. end do
  753. end do
  754. end do
  755. !PLS $OMP END PARALLEL
  756. !
  757. ! Determine the boundary layer height
  758. !--------------------------------------------------------------------------------
  759. ! based on: Vogelezang and Holtslag, 1996, Bound. Layer Meteorol., 81, 245-269.
  760. !--------------------------------------------------------------------------------
  761. if (okdebug) write(*,*) ' boundary layer height'
  762. !PLS $OMP PARALLEL &
  763. !PLS $OMP default (none) &
  764. !PLS $OMP shared (lm, jsr, jer, isr, ier, region, wtseff, wthm, q, &
  765. !PLS $OMP wheatv, wheat, wqflx, wobkl, ustr, pblh, uwind, vwind, &
  766. !PLS $OMP whm ) &
  767. !PLS $OMP private (i, j, l, jss, jee, jwork, wrino, vvk, tkv, dtkv, &
  768. !PLS $OMP zrino, jq, fmt, wsc, zexcess, thvparc )
  769. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  770. do j=j1,j2
  771. do i=i1,i2
  772. ! compute bottom level virtual temperature and heat flux and Monin-Obukhov Length
  773. wtseff(i,j) = wthm(i,j,1)*(1. + zcrdq*q(i,j,1))
  774. wheatv(i,j) = wheat(i,j) + zcrdq*wthm(i,j,1)*wqflx(i,j)
  775. wobkl(i,j) = -wtseff(i,j)*ustr(i,j)**3 / (grav*vkarman*(wheatv(i,j)+sign(1.e-10,wheatv(i,j))) )
  776. ! initialize
  777. pblh(i,j) = 0.0
  778. jwork = 1
  779. wrino = 0.0
  780. do l=1,lm(region)
  781. vvk = (uwind(i,j,l)-uwind(i,j,1))**2 + (vwind(i,j,l)-vwind(i,j,1))**2 + &
  782. zacb*ustr(i,j)*ustr(i,j)
  783. vvk = max(vvk,tiny)
  784. tkv = wthm(i,j,l)*(1. + zcrdq*q(i,j,l))
  785. dtkv = tkv-wtseff(i,j)
  786. !
  787. ! Bulk Richardson number
  788. !
  789. zrino = grav*dtkv * (whm(i,j,l)-whm(i,j,1)) / (wtseff(i,j)*vvk)
  790. zrino = zrino+sign(1.e-10,zrino) ! prevent zrino becoming zero
  791. zrino = jwork*zrino
  792. jq = jqif(ricr,zrino) ! thus: if (zrino < ricr) then jq=1
  793. !
  794. ! calculate pblh from linear interpolation in Ri(bulk)
  795. !
  796. if ( l == 1 ) then
  797. pblh(i,j) = jq*pblh(i,j) + (1-jq) * &
  798. ( (ricr-wrino)/(zrino-wrino)*(whm(i,j,l) ) )
  799. else
  800. pblh(i,j) = jq*pblh(i,j) + (1-jq) * &
  801. ( whm(i,j,l-1) + (ricr-wrino)/(zrino-wrino)*(whm(i,j,l)-whm(i,j,l-1)) )
  802. end if
  803. !
  804. ! first time zrino > ricr we set jwork to zero, thus all further times zrino=0
  805. ! and pblh does not change anymore
  806. !
  807. jwork = jq*jwork
  808. !
  809. ! if pblh is found already avoid dividing by zero next level by a faked value
  810. ! of wrino (jwork=0 already)
  811. !
  812. wrino = zrino+(1-jwork)*0.1
  813. end do
  814. pblh(i,j) = (1-jwork)*pblh(i,j) + whm(i,j,lm(region))*jwork
  815. !
  816. ! second calculation of pblh including excess surface temperature using
  817. ! a convective velocity scale wsc (wm, not equal to w*!!!), using result
  818. ! of the first calculation of pblh
  819. !
  820. jq = jqif(wheatv(i,j),0.) ! thus: if (wheatv(i,j) > 0.) then jq=1
  821. jwork = jq
  822. fmt = ( jq*(1.0 - binm*pblh(i,j)/wobkl(i,j)) + (1.0-jq) )**onet
  823. wsc = ustr(i,j)*fmt
  824. zexcess = wheatv(i,j)*fak/wsc
  825. !
  826. ! improve pblh estimate under convective conditions using
  827. ! convective temperature excess (zexcess)
  828. !
  829. thvparc = wtseff(i,j)+jq*zexcess
  830. !
  831. jwork = 1
  832. wrino = 0.0
  833. !
  834. do l=2,lm(region)
  835. !
  836. ! Bulk Richardson number:
  837. ! if stable corrected with extra shear term
  838. ! if unstable now also corrected for temperature excess
  839. !
  840. vvk = (uwind(i,j,l)-uwind(i,j,1))**2 + (vwind(i,j,l)-vwind(i,j,1))**2 + &
  841. zacb*ustr(i,j)*ustr(i,j)
  842. vvk = max(vvk,tiny)
  843. tkv = wthm(i,j,l)*(1. + zcrdq*q(i,j,l))
  844. zrino = grav*(tkv-thvparc) * (whm(i,j,l)-whm(i,j,1))/(vvk*wtseff(i,j))
  845. zrino = zrino+sign(1.e-10,zrino) ! prevent zrino becoming zero
  846. zrino = zrino*jwork
  847. jq = jqif(ricr,zrino) ! thus: if (zrino < ricr) then jq=0
  848. !
  849. ! calculate pblh from linear interpolation in Ri(bulk)
  850. !
  851. pblh(i,j) = jq*pblh(i,j)+(1-jq)* (whm(i,j,l-1)+(ricr-wrino)/ &
  852. (zrino-wrino)*(whm(i,j,l)-whm(i,j,l-1)))
  853. !
  854. ! first time zrino > ricr we set jwork to zero, thus all further times zrino=0
  855. ! and pblh does not change anymore
  856. !
  857. jwork = jq*jwork
  858. !
  859. ! if pblh is found already avoid dividing by zero next level by a faked value
  860. ! of wrino (jwork=0 already)
  861. !
  862. wrino = zrino+(1-jwork)*0.1
  863. end do
  864. pblh(i,j) = (1-jwork)*pblh(i,j) + jwork*whm(i,j,lm(region))
  865. pblh(i,j) = max(pblh(i,j), 100.0) ! set minimum value for pblh
  866. end do
  867. end do
  868. !PLS $OMP END PARALLEL
  869. !
  870. ! Diffusion coefficients in the surface layer
  871. !
  872. !--------------------------------------------------------------------------------
  873. ! the revised LTG scheme (Beljaars and Viterbo, 1998)
  874. ! Modification - April 1, 1999: prevent zpblk to become too small in very stable conditions
  875. !--------------------------------------------------------------------------------
  876. if (okdebug) write(*,*) ' diffusion coeff'
  877. ! initialize output array with minimum value
  878. kvhmin = 0.1
  879. !
  880. ! Loop to calculate the diffusivity
  881. !
  882. !PLS $OMP PARALLEL &
  883. !PLS $OMP default (none) &
  884. !PLS $OMP shared (lm, jsr, jer, isr, ier, region, pblh, gph, wobkl, &
  885. !PLS $OMP wheatv, whm, zrinub, zdup2, kvhmin, wkvf, ustr, &
  886. !PLS $OMP wtseff, kvh, zthvk) &
  887. !PLS $OMP private (i, j, l, jss, jee, jq, z, zh, zl, zzh, jq1, jq2, jq3, &
  888. !PLS $OMP jq4, jq5, jq6, jq7, jqq, cml2, zfstabh, zpblk, zkvh, &
  889. !PLS $OMP zslask, fmt, wsc, zwstr, obukov, term1, term2, term3, &
  890. !PLS $OMP pr, thvgrad, kvhentr)
  891. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  892. do l=1,lm(region)-1
  893. do j=j1,j2
  894. do i=i1,i2
  895. jq = jqif(pblh(i,j),(gph(i,j,l+1)-gph(i,j,1))) ! if top of level hh < pblh jq=1 inside BL
  896. z = gph(i,j,l+1)-gph(i,j,1)
  897. zh = jq*z/pblh(i,j) ! only defined in BL (jq=1)
  898. ! zl must not be zero
  899. zl = jq*z/wobkl(i,j)+(1-jq) ! z/L outside BL = 1
  900. zzh = jq*(1.-zh)**2 ! (1-z/h)^2 only in BL
  901. jq1 = jqif(wheatv(i,j),0.) ! jq1 is 1 in unstable case
  902. jq2 = jq*(1-jq1) ! jq2 is 1 in stable BL
  903. jq3 = jq*jq1 ! jq3 is 1 in unstable BL
  904. jq6 = jqif(pblh(i,j), whm(i,j,l))
  905. jq7 = jqif(whm(i,j,l+1), pblh(i,j))
  906. jq6 = jq1*jq6*jq7 ! jq6 is 1 at at the kvh-level that is located between the
  907. ! mid-levels that surround pblh
  908. jq1 = jqif(sffrac,zh) ! jq1 is 1 in surface layer
  909. jq4 = jq3*jq1 ! jq4 is 1 in unstable surface layer
  910. jq5 = jq3*(1-jq1) ! jq5 is 1 outside unstable surface layer
  911. !
  912. ! calculate coefficients for momentum, the values for heat are obtained by dividing by Prantl number
  913. !
  914. ! stable and neutral:
  915. !
  916. cml2 = (1./( 1./(vkarman*z) + 1./450. ))**2.
  917. jqq = jqif(zrinub(i,j,l),0.)
  918. !
  919. ! stability function for momentum
  920. !
  921. zfstabh = jqq/(1.+10.*zrinub(i,j,l)*sqrt(1.+jqq*zrinub(i,j,l))) + (1-jqq)
  922. zpblk = cml2 * sqrt(zdup2(i,j,l))*zfstabh
  923. zkvh = jq2*max(zpblk,kvhmin)+(1-jq2)*wkvf(i,j,l) ! take free troposp. values outside BL
  924. !
  925. ! unstable case in surface layer
  926. !
  927. zslask = 1.-betah*zl
  928. zslask = jq4*zslask+(1-jq4)
  929. zpblk = (1-jq4)*zkvh+jq4*(ustr(i,j)*vkarman*z*zzh*zslask**(1./3.))
  930. !
  931. ! unstable case above surface layer
  932. !
  933. ! evaluate stability function for momentum at height z = 0.1*pblh (top of surface layer)
  934. !
  935. zslask = 1.-ssfrac*betah*pblh(i,j)/wobkl(i,j)
  936. zslask = jq5*zslask+(1-jq5)
  937. fmt = zslask**(1./3.)
  938. !
  939. ! use surface layer definition for w_m
  940. wsc = ustr(i,j)*fmt
  941. zpblk = (1-jq5)*zpblk + jq5*wsc*vkarman*z*zzh
  942. !
  943. ! Determine Prandt Number
  944. !
  945. ! Pr-number is assumed to be constant throughout the CBL, i.e. in surface and mixed layer
  946. ! NOTE: this is different from the original formulation
  947. ! zwstr not used if wheatv<0.
  948. !
  949. zwstr = (abs(wheatv(i,j))*grav*pblh(i,j)/wtseff(i,j))**(1./3.) ! bh
  950. obukov = jq3*wobkl(i,j)-(1-jq3)
  951. term1 = (1.-ssfrac*betah*pblh(i,j)/obukov)**(1./3.)
  952. term2 = sqrt(1.-ssfrac*betah*pblh(i,j)/obukov)
  953. term3 = ccon*fakn*zwstr/(ustr(i,j)*(1.-ssfrac*betah*pblh(i,j)/obukov)**(1./3.))
  954. pr = jq3*(term1/term2+term3)+(1-jq3)
  955. !
  956. ! NOTE that kvh applies to the top of the level
  957. !
  958. kvh(i,j,l) = jq3*max(zpblk/pr,kvhmin)+(1-jq3)*zkvh
  959. ! if in the entrainment zone, override with prescribed entrainment
  960. thvgrad = (zthvk(i,j,l+1)-zthvk(i,j,l))/(whm(i,j,l+1)-whm(i,j,l))
  961. kvhentr = 0.2*wheatv(i,j)/thvgrad
  962. kvh(i,j,l) = jq6*kvhentr + (1-jq6)*kvh(i,j,l)
  963. end do
  964. end do
  965. end do
  966. !PLS $OMP END PARALLEl
  967. ! calculate vertical diffusion
  968. !PLS $OMP PARALLEL &
  969. !PLS $OMP default (none) &
  970. !PLS $OMP shared (jsr, jer, isr, ier, region, dkg, kvh, m, gph) &
  971. !PLS $OMP private (i, j, l, jss, jee)
  972. ! call my_omp_domain (jsr(region), jer(region), jss, jee)
  973. do l=1,lmax_conv-1
  974. do j=j1,j2
  975. do i=i1, i2
  976. dkg(i,j,l)=max(0.,kvh(i,j,l))*2.*(m(i,j,l+1)+m(i,j,l))/(gph(i,j,l+2)-gph(i,j,l))**2
  977. ! CMK dec 2002 ----> gph changed to 1--->lm+1 boundaries
  978. enddo
  979. enddo
  980. enddo
  981. dkg(i1:i2,j1:j2,lmax_conv) = 0.0
  982. !PLS $OMP END PARALLEL
  983. deallocate(wkvf)
  984. deallocate(zdup2)
  985. deallocate(zrinub)
  986. deallocate(wthm)
  987. deallocate(zthvk)
  988. deallocate(pf)
  989. deallocate(whm)
  990. deallocate(ustr)
  991. deallocate(wheat)
  992. deallocate(wqflx)
  993. deallocate(wobkl)
  994. deallocate(wheatv)
  995. deallocate(wtseff)
  996. deallocate(uwind)
  997. deallocate(vwind)
  998. deallocate(kvh)
  999. nullify(pblh)
  1000. if (okdebug) write(*,*) 'end of bldiff'
  1001. end subroutine bldiff
  1002. #endif /* diffusion */
  1003. #endif /* convection */
  1004. !
  1005. ! define vectorizable 'if' function
  1006. ! if xxxz>yyyz jqif=1 else jqif=0
  1007. !
  1008. INTEGER FUNCTION JQIF( xxxz, yyyz )
  1009. ! --- in/out ---------------------------
  1010. real, intent(in) :: xxxz, yyyz
  1011. ! --- begin ----------------------------
  1012. !
  1013. !jqif = nint( 0.5 - sign( 0.5, -dim(xxxz,yyyz)) )
  1014. !
  1015. jqif = nint( 0.5 + sign( 0.5, xxxz-yyyz ) )
  1016. end function jqif
  1017. !=====================================================================================================
  1018. !=====================================================================================================
  1019. subroutine read_diffusion( status )
  1020. !
  1021. ! Read vertical diffusion from file and store in conv_dat%dkg
  1022. !
  1023. ! Output:
  1024. ! o status 0 = ok
  1025. ! -1 = file not available for at least one region
  1026. ! 1 = read error
  1027. !
  1028. ! 19 Dec 2012 - P. Le Sager - TM5-MP version, using MDF
  1029. ! --- modules ------------------------------
  1030. use dims, only : itau, revert, region_name, lm, okdebug
  1031. use global_data, only : conv_dat
  1032. use datetime, only : tau2date
  1033. use MDF, only : MDF_OPEN, MDF_HDF4, MDF_Inq_VarID, MDF_Get_Var, MDF_Close, MDF_READ
  1034. use Partools, only : isRoot
  1035. use meteodata, only : global_lli
  1036. use tm5_distgrid, only : dgrid, scatter
  1037. ! --- in/out ----------------------------------------------
  1038. integer, intent(out) :: status
  1039. ! --- const -----------------------------------------------
  1040. character(len=*), parameter :: rname = mname//', read_diffusion'
  1041. ! --- local -----------------------------------------------
  1042. character(len=1000) :: fname
  1043. integer :: region, fid, varid, imr, jmr, sz(3)
  1044. integer, dimension(6) :: idater
  1045. logical :: exist
  1046. real, allocatable :: global_arr(:,:,:)
  1047. ! --- begin -----------------------------------------------
  1048. if ( revert == 1 ) then
  1049. call tau2date( itau, idater )
  1050. else
  1051. ! read field from 3 hours before
  1052. call tau2date( itau - 3600*3, idater )
  1053. end if
  1054. do region = 1, nregions
  1055. ! entire region grid size
  1056. imr = global_lli(region)%nlon
  1057. jmr = global_lli(region)%nlat
  1058. ! for gathering
  1059. sz = shape(conv_dat(region)%dkg) ! to get 3rd dimension
  1060. if(isRoot)then
  1061. allocate(global_arr(imr,jmr,sz(3)))
  1062. else
  1063. allocate(global_arr(1,1,1))
  1064. end if
  1065. if (isRoot) then
  1066. ! Create file name
  1067. write(fname,'(2a,i4.4,a,i2.2,a,i2.2,3a,i2,a,i4,5i2.2,a)') trim(diffusion_dir), &
  1068. '/',idater(1),'/',idater(2),'/dkg/',idater(3),'/dkg_', &
  1069. trim(region_name(region)), '_z', lm(region), '_', idater, '.hdf'
  1070. inquire( file=fname, exist=exist )
  1071. if ( .not. exist ) then
  1072. write(*,'(a,": dkg file not found for region",i2)') rname, region
  1073. status = -1
  1074. TRACEBACK; return
  1075. end if
  1076. ! Open file
  1077. ! This is a bit too verbose, leading to long output files.
  1078. ! write(*,'(a,": reading ", a)') rname, trim(fname)
  1079. call MDF_OPEN(TRIM(fname), MDF_HDF4, MDF_READ, fid, status )
  1080. IF_NOTOK_RETURN(status=1)
  1081. ! Read dkg
  1082. CALL MDF_Inq_VarID( fid, 'dkg', varid, status )
  1083. IF_ERROR_RETURN(status=1)
  1084. CALL MDF_Get_Var( fid, varid, global_arr, status )
  1085. IF_NOTOK_RETURN(status=1)
  1086. end if
  1087. call scatter( dgrid(region), conv_dat(region)%dkg, global_arr, 0, status)
  1088. IF_NOTOK_RETURN(status=1)
  1089. if(isRoot) then
  1090. ! Read blh
  1091. CALL MDF_Inq_VarID( fid, 'blh', varid, status )
  1092. IF_ERROR_RETURN(status=1)
  1093. CALL MDF_Get_Var( fid, varid, global_arr(:,:,1), status )
  1094. IF_NOTOK_RETURN(status=1)
  1095. end if
  1096. call scatter( dgrid(region), conv_dat(region)%blh, global_arr(:,:,1), 0, status)
  1097. IF_NOTOK_RETURN(status=1)
  1098. ! Close file
  1099. if (isRoot) then
  1100. call MDF_Close( fid, status )
  1101. IF_NOTOK_RETURN(status=1)
  1102. end if
  1103. deallocate(global_arr)
  1104. end do
  1105. status = 0
  1106. end subroutine read_diffusion
  1107. !=====================================================================================================
  1108. !=====================================================================================================
  1109. subroutine write_diffusion( status )
  1110. !
  1111. ! Write vertical diffusion to files (for all regions)
  1112. !
  1113. ! Output:
  1114. ! o status 0 = ok, else not ok
  1115. !
  1116. ! 19 Dec 2012 - P. Le Sager - made a TM5-MP version , that works using MDF
  1117. ! --- modules ------------------------------
  1118. use dims, only : itau, revert, region_name, lm, okdebug
  1119. use global_data, only : conv_dat
  1120. use datetime, only : tau2date
  1121. use MDF, only : MDF_CREATE, MDF_HDF4, MDF_Def_Dim, MDF_Def_Var, MDF_Close
  1122. use MDF, only : MDF_DOUBLE, MDF_WRITE, MDF_Put_Var, MDF_EndDef
  1123. use Partools, only : isRoot
  1124. use meteodata, only : global_lli
  1125. use tm5_distgrid, only : dgrid, gather
  1126. ! --- in/out ----------------------------------------------
  1127. integer, intent(out) :: status
  1128. ! --- const -----------------------------------------------
  1129. character(len=*), parameter :: rname = mname//'write_diffusion'
  1130. ! --- local -----------------------------------------------
  1131. character(len=1000) :: fname, targetdir
  1132. integer :: region, fid, dkgid, blhid, dimlon, dimlat, dimlev, imr, jmr, sz(3)
  1133. integer, dimension(6) :: idater
  1134. real, allocatable :: global_arr(:,:,:)
  1135. ! --- begin -----------------------------------------------
  1136. if ( revert == 1 ) then
  1137. call tau2date( itau, idater )
  1138. else
  1139. ! read field from 3 hours before
  1140. call tau2date( itau - 3600*3, idater )
  1141. end if
  1142. status=0
  1143. do region = 1, nregions
  1144. ! entire region grid size
  1145. imr = global_lli(region)%nlon
  1146. jmr = global_lli(region)%nlat
  1147. ! for gathering
  1148. sz = shape(conv_dat(region)%dkg) ! to get 3rd dimension
  1149. if(isRoot)then
  1150. allocate(global_arr(imr,jmr,sz(3)))
  1151. else
  1152. allocate(global_arr(1,1,1))
  1153. end if
  1154. ! Create and define
  1155. if(isRoot) then
  1156. ! Create file name
  1157. write(fname,'(2a,i4.4,a,i2.2,a,i2.2,3a,i2,a,i4,5i2.2,a)') trim(diffusion_dir), &
  1158. '/',idater(1),'/',idater(2),'/dkg/',idater(3),'/dkg_', &
  1159. trim(region_name(region)), '_z', lm(region), '_', idater, '.hdf'
  1160. ! Create directory if necessary
  1161. write(targetdir,'(2a,i4.4,a,i2.2,a,i2.2)') trim(diffusion_dir), &
  1162. '/',idater(1),'/',idater(2),'/dkg/',idater(3)
  1163. call system('mkdir -p ' // targetdir)
  1164. if(okdebug) then
  1165. write(gol,'(a,": creating ", a)') rname, trim(fname); call goPr
  1166. end if
  1167. call MDF_CREATE(TRIM(fname), MDF_HDF4, MDF_WRITE, fid, status )
  1168. IF_NOTOK_RETURN(status=1)
  1169. call MDF_Def_Dim( fid, 'lon', imr, dimlon, status )
  1170. call MDF_Def_Dim( fid, 'lat', jmr, dimlat, status )
  1171. call MDF_Def_Dim( fid, 'levels', sz(3), dimlev, status )
  1172. call MDF_Def_Var( fid, 'dkg', MDF_DOUBLE, (/dimlon,dimlat,dimlev/), dkgid, status)
  1173. call MDF_Def_Var( fid, 'blh', MDF_DOUBLE, (/dimlon,dimlat/), blhid, status)
  1174. call MDF_EndDef(fid, status)
  1175. end if
  1176. ! gather and write dkg/blh
  1177. call gather( dgrid(region), conv_dat(region)%dkg, global_arr, 0, status)
  1178. IF_NOTOK_RETURN(status=1)
  1179. if (isRoot) then
  1180. call MDF_Put_Var( fid, dkgid, global_arr, status)
  1181. IF_NOTOK_RETURN(status=1)
  1182. end if
  1183. call gather( dgrid(region), conv_dat(region)%blh, global_arr(:,:,1), 0, status)
  1184. IF_NOTOK_RETURN(status=1)
  1185. if(isRoot) then
  1186. call MDF_Put_Var( fid, blhid, global_arr(:,:,1), status)
  1187. IF_NOTOK_RETURN(status=1)
  1188. ! Close file
  1189. call MDF_CLOSE( fid, status )
  1190. IF_NOTOK_RETURN(status=1)
  1191. end if
  1192. deallocate(global_arr)
  1193. end do
  1194. status = 0
  1195. end subroutine write_diffusion
  1196. !=====================================================================================================
  1197. !=====================================================================================================
  1198. END MODULE DIFFUSION