chemistry_cariolle.F90 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. #define TRACEBACK write (gol,'("in ",a," (",a,i6,")")') rname, __FILE__, __LINE__ ; call goErr
  2. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  3. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  4. !
  5. #include "tm5.inc"
  6. !
  7. !#################################################################
  8. !
  9. ! Parameterized ozone chemistry:
  10. ! o Cariolle, Cold Tracer
  11. ! o relaxation to climatology
  12. !
  13. ! Relaxation time scale is altitude depended:
  14. !
  15. ! | ------ 0
  16. ! | ------ ^
  17. ! | ^ |
  18. ! | | ColdTracer |
  19. ! | | |Cariolle
  20. ! | v |
  21. ! | ------ |
  22. ! | v
  23. ! | * ------ cariolle_plev (230 hPa)
  24. ! | o
  25. ! | * ------ tropo_plev (500 hPa)
  26. ! | o
  27. ! | o
  28. ! ----------+--------------+------> tau
  29. ! tropo_tau_lower tropo_tau_upper
  30. ! (weeks) (months)
  31. !
  32. !
  33. ! 22 Jun 2011 - P. Le Sager - Bug fix in O3 overhead. Plus added two
  34. ! checks on negative mixing ratio from Vincent.
  35. !
  36. !### macro's #####################################################
  37. !
  38. module Chemistry_Cariolle
  39. use GO , only : gol, goPr, goErr, goLabel
  40. use dims , only : nregions
  41. use global_types, only : chem_data
  42. use Climat , only : TClimat
  43. #ifdef with_budgets
  44. use budget_global,only : nbudg, nbud_vg
  45. use chem_param, only : ncar
  46. #endif
  47. implicit none
  48. ! --- in/out ----------------------------
  49. private
  50. public :: Cariolle_Init, Cariolle_Done, Cariolle_Chemie
  51. public :: o3clim_vmr, l_cariolle, with_trop_force
  52. ! --- const -----------------------------
  53. character(len=*), parameter :: mname = 'cariolle'
  54. !
  55. ! overhead fields
  56. !
  57. ! 3d fields with total column ABOVE each level !
  58. !
  59. ! rm_ovh(:,:,lm ,iovh(k)) = 0.0
  60. ! rm_ovh(:,:,lm-1,iovh(k)) = rm(:,:,lm,k)
  61. ! :
  62. ! rm_ovh(:,:,l ,iovh(k)) = sum( rm(:,:,l+1:lm,k) , 3 )
  63. !
  64. ! Total column is thus :
  65. !
  66. ! rm(:,:,1,k) + rm_ovh(:,:,1,iovh(k))
  67. !
  68. ! number of overhead fields:
  69. integer, parameter :: novh = 1
  70. ! indices:
  71. integer, parameter :: iovh_o3 = 1
  72. ! --- var ------------------------------
  73. ! overhead fields (4d arrays, parallel over layers)
  74. type(chem_data) :: ovh_dat(nregions)
  75. ! ozone climatology
  76. character(len=256) :: climat_fname
  77. type(TClimat),save :: o3clim_vmr(nregions)
  78. ! cariolle or linoz coefficients
  79. character(len=256) :: cariolle_fname
  80. type(TClimat),save :: o3coef(nregions)
  81. type(TClimat),save :: o3coefp(nregions)
  82. integer, parameter :: nc = 7
  83. ! with cold tracer
  84. logical :: with_cold_tracer
  85. ! with forcing troposphere to climatology
  86. logical :: with_trop_force
  87. ! compute temper climat from model temperatures ?
  88. logical :: apply_taver
  89. ! minimum time scale for slower chemistry:
  90. real :: cariolle_tau_min
  91. ! pressure range over which Cariolle is applied:
  92. real :: cariolle_plev
  93. ! lowest model level for Cariolle chemistry:
  94. integer :: l_cariolle(nregions)
  95. ! Pressure range over which cold tracer is active:
  96. ! o production of cold tracer
  97. ! o hetrochem
  98. ! Loss of cold tracer is applied everywhere ...
  99. real :: coldtracer_plevs(2) ! 35.0e2,228.0e2 Pa
  100. ! tropospheric forcing to climatology:
  101. real :: tropo_plev ! Pa
  102. real :: tropo_tau ! sec
  103. #ifdef with_budgets
  104. real,dimension(nbudg, nbud_vg, ncar ),public :: budcarg
  105. #endif
  106. contains
  107. subroutine Cariolle_Init( status )
  108. use GO , only : TrcFile, Init, Done, ReadRc
  109. use dims , only : im, jm, lm
  110. use global_data , only : rcfile
  111. use Climat , only : Init
  112. use file_cariolle, only : Cariolle_Info
  113. use toolbox , only : lvlpress
  114. ! --- in/out --------------------------------
  115. integer, intent(out) :: status
  116. ! --- const ------------------------------
  117. character(len=*), parameter :: rname = mname//'/Cariolle_Init'
  118. ! --- local ------------------------------
  119. type(TrcFile) :: rcF
  120. integer :: region
  121. integer :: imr, jmr, lmr
  122. real :: tau_day, plev_hPa
  123. integer :: nlevs
  124. ! --- begin --------------------------------
  125. !
  126. ! read settings
  127. !
  128. call Init( rcF, rcfile, status )
  129. IF_NOTOK_RETURN(status=1)
  130. call ReadRc( rcF, 'chem.o3tracer.climat', climat_fname, status )
  131. IF_NOTOK_RETURN(status=1)
  132. call ReadRc( rcF, 'chem.o3tracer.cariolle.coeff', cariolle_fname, status )
  133. IF_NOTOK_RETURN(status=1)
  134. call ReadRc( rcF, 'chem.o3tracer.cariolle.taver', apply_taver, status )
  135. IF_NOTOK_RETURN(status=1)
  136. ! pressure level below which Cariolle is applied:
  137. call ReadRc( rcF, 'chem.o3tracer.cariolle.strato.plev', plev_hPa, status )
  138. IF_NOTOK_RETURN(status=1)
  139. cariolle_plev = plev_hPa * 1e2 ! Pa
  140. call ReadRc( rcF, 'chem.o3tracer.cariolle.strato.tau_min', tau_day, status )
  141. IF_NOTOK_RETURN(status=1)
  142. cariolle_tau_min = tau_day * 24.0 * 3600.0 ! sec
  143. ! with cold tracer?
  144. call ReadRc( rcF, 'chem.o3tracer.coldtracer', with_cold_tracer, status )
  145. IF_NOTOK_RETURN(status=1)
  146. ! pressure levels between which cold tracer scheme is applied:
  147. call ReadRc( rcF, 'chem.o3tracer.coldtracer.plevtop', coldtracer_plevs(1), status ) ! hPa
  148. IF_NOTOK_RETURN(status=1)
  149. call ReadRc( rcF, 'chem.o3tracer.coldtracer.plevbottom', coldtracer_plevs(2), status ) ! hPa
  150. IF_NOTOK_RETURN(status=1)
  151. coldtracer_plevs = coldtracer_plevs * 1.0e2 ! Pa
  152. call ReadRc( rcF, 'chem.o3tracer.tropforce', with_trop_force, status )
  153. IF_NOTOK_RETURN(status=1)
  154. ! tropospheric forcing to climatology:
  155. ! on and below plev0 (hPa), use relax timescale tau0 (days)
  156. ! between plev0 and plev1 (hPa), linear interpol between tau0 and tau1
  157. !
  158. call ReadRc( rcF, 'chem.o3tracer.cariolle.tropo.plev', plev_hPa, status )
  159. IF_NOTOK_RETURN(status=1)
  160. tropo_plev = plev_hPa * 1e2 ! Pa
  161. call ReadRc( rcF, 'chem.o3tracer.cariolle.tropo.tau', tau_day, status )
  162. IF_NOTOK_RETURN(status=1)
  163. tropo_tau = tau_day * 24.0 * 3600.0 ! sec
  164. call Done( rcF, status )
  165. IF_NOTOK_RETURN(status=1)
  166. !
  167. ! other
  168. !
  169. ! loop over regions:
  170. do region = 1, nregions
  171. ! regional grid sizes:
  172. imr = im(region)
  173. jmr = jm(region)
  174. lmr = lm(region)
  175. ! setup climatology; linear time interpolation
  176. call Init( o3clim_vmr(region), 'O3', 'ppv', 'linear', 1, jmr, lmr, status )
  177. IF_NOTOK_RETURN(status=1)
  178. ! setup cariole coeff and pressure; constant within month
  179. ! grid sizes:
  180. call Cariolle_Info( status, nlevs=nlevs )
  181. IF_NOTOK_RETURN(status=1)
  182. call Init( o3coef(region), 'coeff', 'unit', 'constant', nc, jmr, nlevs, status )
  183. IF_NOTOK_RETURN(status=1)
  184. call Init( o3coefp(region), 'pressure', 'Pa', 'constant', 1, jmr, nlevs, status )
  185. IF_NOTOK_RETURN(status=1)
  186. ! overhead fields (concentration arrays, thus 2 halo cells):
  187. allocate( ovh_dat(region)%rm_k(-1:imr+2,-1:jmr+2,lmr,novh) )
  188. ! lowest model level for Cariolle chemistry
  189. ! the use of 1013.25 hPa allows reading full level pressures from ECMWF tables
  190. l_cariolle=lvlpress(region,cariolle_plev, 101325.)
  191. end do ! regions
  192. ! ok
  193. status = 0
  194. end subroutine Cariolle_Init
  195. ! ***
  196. subroutine Cariolle_Done( status )
  197. use Climat, only : Done
  198. ! --- in/out --------------------------------
  199. integer, intent(out) :: status
  200. ! --- const ------------------------------
  201. character(len=*), parameter :: rname = mname//'/Cariolle_Done'
  202. ! --- var ----------------------------------
  203. integer :: region
  204. ! --- begin --------------------------------
  205. ! loop over regions:
  206. do region = 1, nregions
  207. ! clear climatology:
  208. call Done( o3clim_vmr(region), status )
  209. IF_NOTOK_RETURN(status=1)
  210. ! clear cariolle coeff:
  211. call Done( o3coef(region), status )
  212. IF_NOTOK_RETURN(status=1)
  213. call Done( o3coefp(region), status )
  214. IF_NOTOK_RETURN(status=1)
  215. ! overhead fields:
  216. deallocate( ovh_dat(region)%rm_k )
  217. end do ! regions
  218. ! ok
  219. status = 0
  220. end subroutine Cariolle_Done
  221. ! ================================================================
  222. subroutine Cariolle_Chemie( region, tr, status )
  223. use binas , only : Avog, xm_o3,xmair
  224. use GO , only : TDate, Get, DayNumber, rTotal, wrtgol
  225. use GO , only : operator(+), operator(-), operator(/)
  226. use toolbox , only : dumpfield,escape_tm
  227. use Num , only : Interp_Lin
  228. use Grid , only : AreaOper
  229. use Phys , only : cos_sza
  230. use dims , only : im, jm, lm
  231. use dims , only : isr, ier, jsr, jer
  232. use chem_param , only : fscale, io3, ipsc,xmo3
  233. use global_data , only : mass_dat, region_dat
  234. use tracer_data , only : AdjustTracer
  235. use meteodata , only : phlb_dat, m_dat
  236. use meteo , only : lli, levi
  237. use meteo , only : temper_dat
  238. use chemistry_0d, only : Cariolle_0d, ColdTracer_0d
  239. use ParTools , only : tracer_active, lmloc, offsetl
  240. use ParTools , only : which_par, previous_par, myid
  241. use photolysis_data, only : phot_dat
  242. use mpi_comm , only : dump_field3d
  243. use boundary , only : use_o3du
  244. #ifdef with_budgets
  245. use budget_global,only : budg_dat,nzon_vg
  246. use chem_param , only : ra
  247. #endif
  248. !use file_hdf , only : TTimeSeriesHDF, Init, Done, AddRecord
  249. implicit none
  250. ! --- in/out -----------------------------
  251. integer, intent(in) :: region
  252. type(TDate), intent(in) :: tr(2)
  253. integer, intent(out) :: status
  254. ! --- const ------------------------------
  255. character(len=*), parameter :: rname = mname//'/Chemie'
  256. ! real, parameter :: conv = 0.1*Avog/xm_o3 ! from kg/m2 --> #/cm2
  257. real, parameter :: conv = 0.1*Avog/xmo3 ! from kg/m2 --> #/cm2
  258. real, parameter :: todu = 3.767e-17 ! from #/cm2 --> du
  259. ! --- local -------------------------------
  260. type(TDate) :: tmid
  261. integer :: imr, jmr, lmr
  262. integer :: i, j, l, ll, lll
  263. integer :: level, lglob
  264. #ifdef with_budgets
  265. integer :: nzone,nzone_v
  266. #endif
  267. real, pointer :: rm(:,:,:,:)
  268. real, pointer :: vo3(:,:,:)
  269. real, pointer :: ozone_klimtop(:)
  270. real, pointer :: phlb(:,:,:)
  271. real, pointer :: m(:,:,:)
  272. real, pointer :: temper(:,:,:)
  273. #ifdef with_zoom
  274. integer, pointer :: zoomed(:,:)
  275. #endif
  276. real, pointer :: area(:) ! cell area (m2) for each lat band
  277. real, allocatable :: Tclim(:,:)
  278. ! real,allocatable :: o3_overhead(:,:,:) ! in mlc/cm2
  279. real,allocatable :: o3_overhead(:,:) ! in mlc/cm2
  280. real :: lon, lat
  281. integer :: daynr, hour, minu, sec
  282. real :: csza
  283. real :: pf ! full level pressure (Pa)
  284. real :: dt_sec
  285. real :: o3_vmr ! ozone mixing ratio (ppv)
  286. real :: o3_ohc ! overhead column (mlc/cm2)
  287. real :: o3_ohc_fac
  288. real :: o3c_vmr ! ozone mixing ratio (ppv)
  289. real :: o3c_ohc ! overhead column (mlc/cm2)
  290. real :: kg_TO_mlc_m2
  291. real :: Xpsc, dXpsc, kXpsc
  292. real :: do3_vmr, do3
  293. real :: cc(nc)
  294. integer :: ilast
  295. real :: k_h
  296. real :: rm_new,A,B,sgn,timesc
  297. !type(TTimeSeriesHDF) :: F
  298. ! --- begin ---------------------------------
  299. if ( lmloc == 0 ) then
  300. status=0; return
  301. end if
  302. #ifdef MPI
  303. which_par = previous_par(region)
  304. if (which_par == 'tracers') &
  305. call escape_tm('Model should be parallel over levels in Cariolle chemistry')
  306. #endif
  307. call goLabel( rname )
  308. if (myid == 0) then
  309. call wrtgol( 'ozone parchem : ', tr(1), ' - ', tr(2) ); call goPr
  310. if ( with_cold_tracer ) then
  311. write (gol,*) 'ozone parchem with cold tracer' ; call goPr
  312. else
  313. write (gol,*) 'ozone parchem without cold tracer' ; call goPr
  314. endif
  315. if ( with_trop_force ) then
  316. write (gol,*) 'ozone parchem with nudged tropospheric climatology' ; call goPr
  317. else
  318. write (gol,*) 'ozone parchem without nudged tropospheric climatology' ; call goPr
  319. endif
  320. end if
  321. ! regional grid sizes:
  322. imr = im(region)
  323. jmr = jm(region)
  324. lmr = lm(region)
  325. ! set pointers
  326. #ifdef MPI
  327. rm => mass_dat(region)%rm_k ! kg tracer, parallel over levels
  328. #else
  329. rm => mass_dat(region)%rm_t ! kg tracer, parallel over tracers
  330. #endif
  331. m => m_dat(region)%data ! kg air
  332. phlb => phlb_dat(region)%data ! air pressure at boundaries (1:lm+1)
  333. vo3 => phot_dat(region)%vo3 ! overhead O3, #/cm2, parallel over levels
  334. ozone_klimtop => phot_dat(region)%o3klim_top ! top layers overhead O3, #/cm2
  335. temper => temper_dat(region)%data ! K
  336. area => region_dat(region)%dxyp ! m2
  337. #ifdef with_zoom
  338. zoomed => region_dat(region)%zoomed
  339. #endif
  340. allocate(o3_overhead(jmr,lmr)) ; o3_overhead = 0.0
  341. ! mid of interval:
  342. tmid = tr(1) + (tr(2)-tr(1))/2
  343. !
  344. ! ** setup climatology
  345. !
  346. ! interpolate to this time, eventually read new fields:
  347. call Setup_O3Clim( lli(region), levi, O3clim_vmr(region), tmid, status )
  348. IF_NOTOK_RETURN(status=1)
  349. if (use_o3du) then
  350. ! overhead ozone column for model top is calculated (in photolysis routine)
  351. ! based on Fortuin-Kelder climatology scaled by observations
  352. ! same should be done here for climatological overhead column
  353. do j=1,jmr
  354. o3_overhead(j,lmr) = ozone_klimtop(j)
  355. enddo
  356. else
  357. ! convert climatology from ppv to mlc/cm2 using standard airmass/m2 (p=1e5 Pa)
  358. !PRIOR
  359. ! o3_overhead(:,:,lmr) = 0.5 * O3clim_vmr(region)%data(:,:,lmr)*levi%m0(lmr) * conv / fscale(io3)
  360. !NOW
  361. o3_overhead(:,lmr) = 0.5 * O3clim_vmr(region)%data(1,:,lmr)*levi%m0(lmr) * conv / fscale(io3)
  362. endif
  363. do l = lmr-1,1,-1
  364. ! convert climatology from ppv to mlc/cm2 using standard airmass/m2 (p=1e5 Pa)
  365. !PRIOR
  366. ! o3_overhead(:,:,l) = o3_overhead(:,:,l+1) + &
  367. ! 0.5 * ( O3clim_vmr(region)%data(:,:,l)*levi%m0(l) + &
  368. ! O3clim_vmr(region)%data(:,:,l+1)*levi%m0(l+1) ) * conv / fscale(io3)
  369. !NOW
  370. o3_overhead(:,l) = o3_overhead(:,l+1) + &
  371. 0.5 * ( O3clim_vmr(region)%data(1,:,l)*levi%m0(l) + &
  372. O3clim_vmr(region)%data(1,:,l+1)*levi%m0(l+1) ) * conv / fscale(io3)
  373. end do
  374. !
  375. ! ** setup coefficients
  376. !
  377. ! tables:
  378. ! bsf15k:/usr/people/eskes/fdscia/input/cariolle/OZONE_64x26.ASCII
  379. ! linoz/linoz_coeff.dat
  380. ! input routines:
  381. ! /usr/people/segers/work/tm/TM5/proj/chem/ozone.bak/src/chem_ozonepar.F90
  382. ! check if current coeff are valid for this month,
  383. ! eventually (re)load:
  384. call Setup_Cariolle( lli(region), o3coef(region), o3coefp(region), tmid, status )
  385. IF_NOTOK_RETURN(status=1)
  386. !
  387. ! zonal average temperature
  388. !
  389. ! compute smoothed temperature climatology ?
  390. if ( apply_taver ) then
  391. ! setup zonal field:
  392. allocate( Tclim(jmr,lmr) )
  393. ! fill smoothed temperature:
  394. call Setup_Tclim( lli(region), temper, Tclim, status )
  395. IF_NOTOK_RETURN(status=1)
  396. end if
  397. !
  398. ! apply chemistry
  399. !
  400. ! time step
  401. dt_sec = rTotal( tr(2) - tr(1), 'sec' )
  402. ! loop over all grid cells:
  403. do j = jsr(region), jer(region)
  404. do i = isr(region), ier(region)
  405. ! skip if this cell is calculated in an overlying zoom region:
  406. #ifdef with_zoom
  407. if ( region_dat(region)%zoomed(i,j) /= region ) cycle
  408. #endif
  409. ! grid cell location:
  410. lon = lli(region)%lon_deg(i) ! deg
  411. lat = lli(region)%lat_deg(j) ! deg
  412. ! compute cos(solar_zenith_angle)
  413. daynr = DayNumber( tmid )
  414. call Get( tmid, hour=hour, min=minu, sec=sec )
  415. csza = cos_sza( daynr, hour, minu, sec, lon, lat )
  416. ! conversion from (kg o3) to (mlc o3/m2) :
  417. ! ( kg O3 / m2 ) / (kg o3 / mol) * (mlc/mol) * (1e-4 m2/cm2) = mlc/cm2
  418. kg_TO_mlc_m2 = 1.0 / area(j) / xm_o3 * Avog * 1.0e-4
  419. ! loop over levels
  420. ilast = 1
  421. do level = 1,lmloc
  422. lglob = offsetl + level
  423. ! Cariolle chemistry not applied below l_cariolle
  424. ! except when tropospheric nudging is active
  425. if ( (.not.with_trop_force) .and. (lglob .lt. l_cariolle(region)) ) exit
  426. ! full level pressure:
  427. pf = ( phlb(i,j,lglob) + phlb(i,j,lglob+1) )/2.0 ! Pa
  428. ! ozone volume mixing ratios:
  429. o3_vmr = fscale(io3) * rm(i,j,level,io3) / m(i,j,lglob) ! ppv
  430. o3_vmr = max(o3_vmr,0.0) ! can become negative...
  431. o3c_vmr = o3clim_vmr(region)%data(1,j,lglob)
  432. ! overhead column (including contribution of upper-half of current layer):
  433. o3_ohc = vo3(i,j,level) ! mlc/cm2
  434. o3c_ohc = o3_overhead(j,lglob) ! mlc/cm2
  435. o3_ohc_fac = 0.5*kg_TO_mlc_m2 / fscale(io3) * m(i,j,lglob)
  436. o3_ohc_fac = max(o3_ohc_fac,0.0)
  437. !if (i.eq.10.and.j.eq.10)then
  438. ! write(*,'a15,3i3,5e10.2')'DEBUG CARIOLLE',i,j,lglob,o3_ohc*todu,o3c_ohc*todu,o3_vmr*o3_ohc_fac*todu,o3_vmr,o3_ohc_fac
  439. !endif
  440. ! ** cold tracer scheme
  441. ! standard put values to zero, overwritten if with_cold_tracer = T
  442. Xpsc = 0.
  443. ! convert to mass again:
  444. dXpsc = 0.
  445. ! hetero chem (might be zero):
  446. k_h = 0. !kXpsc
  447. if ( with_cold_tracer ) then
  448. ! cold tracer (marked air mass)
  449. Xpsc = rm(i,j,level,ipsc) / m(i,j,lglob) ! ~ 0-1
  450. Xpsc = min( max( 0.0, Xpsc ), 1.0 ) ! 0-1
  451. ! hetrogeneous chemistry (cold tracer);
  452. ! fills kXpsc to be used as hetrochem reaction rate in Cariolle scheme:
  453. call ColdTracer_0d( Xpsc, pf, coldtracer_plevs, &
  454. temper(i,j,lglob), csza, lat, dt_sec, &
  455. dXpsc, kXpsc, status )
  456. IF_NOTOK_RETURN(status=1)
  457. ! convert to mass again:
  458. dXpsc = dXpsc * m(i,j,lglob) ! kg
  459. ! add tracer mass changes:
  460. if (dXpsc .gt. 0.) then
  461. call AdjustTracer( dXpsc, region, i, j, level, ipsc, status )
  462. IF_NOTOK_RETURN(status=1)
  463. end if
  464. #ifdef with_budgets
  465. nzone=budg_dat(region)%nzong(i,j) ! global budget
  466. nzone_v=nzon_vg(lglob)
  467. budcarg(nzone,nzone_v,2)=budcarg(nzone,nzone_v,2)+ dXpsc*1000./ra(ipsc) ! mol psc per cell
  468. #endif
  469. ! hetero chem (might be zero):
  470. k_h = kXpsc
  471. end if
  472. ! ** end applying cold tracer
  473. ! ** Cariolle scheme
  474. ! interpolate to pressure level:
  475. call Interp_Lin( o3coefp(region)%data(1,j,:), &
  476. o3coef(region)%data(:,j,:), pf, cc, ilast, status )
  477. IF_NOTOK_RETURN(status=1)
  478. ! replace some coeffs by climatological data
  479. ! (have no impact if corresponding reaction rates are zero)
  480. cc(3) = o3c_vmr ! zonal aver ozone mixing ratio
  481. cc(7) = o3c_ohc ! zonal aver ozone overhead column
  482. ! use zonal aver temperature ?
  483. ! (has no impact if corresponding reaction rate is zero)
  484. if ( apply_taver ) cc(5) = Tclim(j,lglob)
  485. ! apply parameterized ozone chemistry for current cell:
  486. call Cariolle_0d( o3_vmr, o3_ohc, o3_ohc_fac, temper(i,j,lglob), &
  487. cc, k_h, cariolle_tau_min, dt_sec, do3_vmr )
  488. IF_NOTOK_RETURN(status=1)
  489. ! if (i.eq.5.and. (j.eq.1 .or. j.eq.11 .or. j.eq. 80 .or. j.eq.90))then
  490. ! write(*,'a18,i3,i3,8e11.3')'DEBUG CARIOLLE cc',lglob,j,cc,dt_sec
  491. ! write(*,'a18,i3,i3,7e11.3')'DEBUG CARIOLLE o3',lglob,j,o3_vmr,o3_ohc,o3_ohc_fac,temper(i,j,lglob),pf,k_h,do3_vmr
  492. !
  493. ! write(*,'a18,i3,i3,7e11.3')'DEBUG CAR timesc', lglob, j, 1./abs(cc(2) + cc(6)*o3_ohc_fac - k_h)
  494. ! endif
  495. ! ozone mass change:
  496. do3 = do3_vmr * m(i,j,lglob) / fscale(io3) ! kg
  497. ! add tracer mass changes:
  498. call AdjustTracer( do3, region, i, j, level, io3, status )
  499. IF_NOTOK_RETURN(status=1)
  500. #ifdef with_budgets
  501. nzone=budg_dat(region)%nzong(i,j) ! global budget
  502. nzone_v=nzon_vg(lglob)
  503. budcarg(nzone,nzone_v,1)=budcarg(nzone,nzone_v,1)+do3*1000./ra(io3) ! mol o3 per cell
  504. #endif
  505. end do ! levels
  506. end do ! i
  507. end do ! j
  508. !
  509. ! done
  510. !
  511. nullify( rm )
  512. nullify( m )
  513. nullify( phlb )
  514. nullify( vo3 )
  515. nullify( ozone_klimtop )
  516. nullify( temper )
  517. #ifdef with_zoom
  518. nullify( zoomed )
  519. #endif
  520. nullify( area )
  521. #ifdef MPI
  522. rm => mass_dat(region)%rm_k ! kg tracer, parallel over levels
  523. #else
  524. rm => mass_dat(region)%rm_t ! kg tracer, parallel over tracers
  525. #endif
  526. m => m_dat(region)%data ! kg air
  527. nullify( rm )
  528. nullify( m )
  529. if ( apply_taver ) deallocate( Tclim )
  530. deallocate (o3_overhead)
  531. ! ok
  532. call goLabel(); status=0
  533. end subroutine Cariolle_Chemie
  534. ! ================================================================
  535. subroutine Setup_Cariolle( lli, carcoef, carcoefp, t, status )
  536. use Binas , only : p0 ! standard pressure (1e5 Pa)
  537. use GO , only : TDate, Get, NewDate
  538. use Num , only : Interp_Lin
  539. use Grid , only : TllGridInfo
  540. use Climat , only : TClimat, Set, Setup
  541. use file_cariolle, only : Cariolle_Info, CARIOLLE_READ
  542. ! --- in/out --------------------------------
  543. type(TllGridInfo), intent(in) :: lli
  544. type(TClimat), intent(inout) :: carcoef ! 1-7
  545. type(TClimat), intent(inout) :: carcoefp ! Pa
  546. type(TDate), intent(in) :: t
  547. integer, intent(out) :: status
  548. ! --- const ------------------------------
  549. character(len=*), parameter :: rname = mname//'/Setup_Cariolle'
  550. ! --- local ------------------------------
  551. integer :: year, month
  552. integer :: nlats, nlevs
  553. real, allocatable :: lats(:)
  554. real, allocatable :: pp(:,:)
  555. real, allocatable :: ppX(:,:,:)
  556. real, allocatable :: cc(:,:,:)
  557. real, allocatable :: ccX(:,:,:)
  558. type(TDate) :: tr_in(2)
  559. integer :: j, l, ic
  560. ! --- begin ------------------------------
  561. ! try to setup for requested time;
  562. ! return status=-1 if not filled yet or filled for wrong time:
  563. call Setup( carcoef, t, status )
  564. if (status==0) return
  565. ! data needs to be (re)setup ...
  566. ! grid sizes:
  567. call Cariolle_Info( status, nlats=nlats, nlevs=nlevs )
  568. IF_NOTOK_RETURN(status=1)
  569. ! setup storage:
  570. allocate( lats(nlats) )
  571. allocate( pp(nlats,nlevs) )
  572. allocate( ppX(1,lli%nlat,nlevs) )
  573. allocate( cc(nlats,nlevs,nc) )
  574. allocate( ccX(nc,lli%nlat,nlevs) )
  575. ! extract month:
  576. call Get( t, year=year, month=month )
  577. ! load coeff for this month (ppmv)
  578. call Cariolle_Read( trim(cariolle_fname), month, lats, pp, cc, status )
  579. IF_NOTOK_RETURN(status=1)
  580. ! interpolate pressure field to latitudes
  581. do l = 1, nlevs
  582. call Interp_Lin( lats, pp(:,l), lli%lat_deg, ppX(1,:,l), status )
  583. IF_NOTOK_RETURN(status=1)
  584. end do
  585. ! spatial interpolation;
  586. ! loop over coeffs:
  587. do ic = 1, nc
  588. ! interpolate to latitudes
  589. do l = 1, nlevs
  590. call Interp_Lin( lats, cc(:,l,ic), lli%lat_deg, ccX(ic,:,l), status )
  591. IF_NOTOK_RETURN(status=1)
  592. end do
  593. !! interpolate to standard pressures
  594. !do j = 1, lli%nlat
  595. ! ! Cariolle coefs from top->surf, thus no negation required:
  596. ! call Interp_Lin( ppX(j,:), ccX(j,:), levi%fp0, cc_in(ic,j,:) )
  597. !end do
  598. end do ! coeff loop
  599. ! set time range for which this data is valid:
  600. ! o begin of current month:
  601. tr_in(1) = NewDate( year, month, 01, 00, 00 )
  602. ! o begin of next month:
  603. month = month + 1
  604. if ( month > 12 ) then
  605. year = year + 1
  606. month = 1
  607. end if
  608. tr_in(2) = NewDate( year, month, 01, 00, 00 )
  609. ! store:
  610. call Set( carcoef, status, data=ccX, tr=tr_in )
  611. IF_NOTOK_RETURN(status=1)
  612. call Set( carcoefp, status, data=ppX, tr=tr_in )
  613. IF_NOTOK_RETURN(status=1)
  614. ! set coeff such that in troposphere only relaxation to climatology remains:
  615. if ( with_trop_force ) then
  616. call Setup_TropForce( carcoef, carcoefp, status )
  617. IF_NOTOK_RETURN(status=1)
  618. end if
  619. ! clear storage:
  620. deallocate( lats )
  621. deallocate( pp )
  622. deallocate( ppX )
  623. deallocate( cc )
  624. deallocate( ccX )
  625. ! ok
  626. status = 0
  627. end subroutine Setup_Cariolle
  628. ! ================================================================
  629. subroutine Setup_TropForce( carcoef, carcoefp, status )
  630. ! --- in/out --------------------------------
  631. type(TClimat), intent(inout) :: carcoef ! c1-c7
  632. type(TClimat), intent(inout) :: carcoefp ! Pa
  633. integer, intent(out) :: status
  634. ! --- const ------------------------------
  635. character(len=*), parameter :: rname = mname//'/Setup_TropForce'
  636. ! --- local ------------------------------
  637. integer :: nlat, nlev
  638. integer :: j, l
  639. integer :: ilev0
  640. real :: plev0, tau0
  641. real :: plev, tau
  642. real :: cc(7)
  643. real :: alfa
  644. ! --- begin ------------------------------
  645. ! grid size
  646. nlat = size(carcoefp%data,2)
  647. nlev = size(carcoefp%data,3)
  648. ! loop over latitudes
  649. do j = 1, nlat
  650. ! first level above troposphere:
  651. if ( carcoefp%data(1,j,1) > carcoefp%data(1,j,nlev) ) then
  652. ! upwards
  653. ilev0 = nlev ! model top
  654. do l = 1, nlev
  655. if ( carcoefp%data(1,j,l) <= cariolle_plev ) then
  656. ilev0 = l
  657. exit
  658. end if
  659. end do
  660. else
  661. ! downwards
  662. ilev0 = 1 ! model top
  663. do l = nlev, 1, -1
  664. if ( carcoefp%data(1,j,l) <= cariolle_plev ) then
  665. ilev0 = l
  666. exit
  667. end if
  668. end do
  669. end if
  670. ! pressure in lowest cariolle level:
  671. plev0 = carcoefp%data(1,j,ilev0) ! Pa
  672. tau0 = - 1.0/carcoef%data(2,j,ilev0) ! sec
  673. ! loop over levels
  674. do l = 1, nlev
  675. ! current pressure and coeffs:
  676. cc = carcoef%data(:,j,l)
  677. plev = carcoefp%data(1,j,l)
  678. ! different pressure ranges:
  679. if ( plev >= tropo_plev ) then
  680. ! ~~ relaxation to climatology, slow
  681. ! relaxation towards climatology via Cariolle coeff:
  682. cc = 0.0
  683. cc(2) = -1.0/tropo_tau
  684. else if ( plev >= cariolle_plev ) then
  685. ! ~~ relaxation to climatology, slower downwards
  686. ! interpolate tau between lower constant value and cariolle value:
  687. alfa = ( plev - plev0 ) / ( tropo_plev - plev0 )
  688. tau = tau0 * (1.0-alfa ) + tropo_tau * alfa
  689. ! relaxation towards climatology via Cariolle coeff:
  690. cc = 0.0
  691. cc(2) = -1.0/tau
  692. end if
  693. ! restore:
  694. carcoef%data(:,j,l) = cc
  695. end do ! levs
  696. end do ! lats
  697. ! ok
  698. status = 0
  699. end subroutine Setup_TropForce
  700. ! ================================================================
  701. subroutine Setup_O3clim( lli, levi, o3c, t, status )
  702. use GO , only : TDate, Get, NewDate
  703. use Num , only : Interp_Lin
  704. use Grid , only : TllGridInfo, TLevelInfo
  705. use Climat , only : TClimat, Set, Setup
  706. use file_fortkeld, only : FortuinKelder_Info, FortuinKelder_Read
  707. ! --- in/out --------------------------------
  708. type(TllGridInfo), intent(in) :: lli
  709. type(TLevelInfo), intent(in) :: levi
  710. type(TClimat), intent(inout) :: o3c
  711. type(TDate), intent(in) :: t
  712. integer, intent(out) :: status
  713. ! --- const ------------------------------
  714. character(len=*), parameter :: rname = mname//'/Setup_O3clim'
  715. ! --- local ------------------------------
  716. integer :: year, month, day
  717. type(TDate) :: t_in(2)
  718. integer :: it
  719. integer :: nlats, nlevs
  720. real, allocatable :: lats_deg(:)
  721. real, allocatable :: pres_Pa(:)
  722. real, allocatable :: o3_ppv(:,:)
  723. real, allocatable :: o3X(:,:)
  724. real, allocatable :: sp(:)
  725. real, allocatable :: o3_in(:,:,:)
  726. integer :: j, l
  727. ! --- begin ------------------------------
  728. ! try to interpolate in time to t;
  729. ! return status=-1 if not filled yet or filled for wrong time:
  730. call Setup( o3c, t, status )
  731. if (status==0) return
  732. ! data needs to be (re)setup ...
  733. ! extract grid sizes:
  734. call FortuinKelder_Info( status, nlats=nlats, nlevs=nlevs )
  735. IF_NOTOK_RETURN(status=1)
  736. ! setup arrays:
  737. allocate( lats_deg(nlats) )
  738. allocate( pres_Pa(nlevs) )
  739. allocate( o3_ppv(nlats,nlevs) )
  740. allocate( o3X(lli%nlat,nlevs) )
  741. allocate( sp(lli%nlat) )
  742. allocate( o3_in(1,lli%nlat,levi%nlev) )
  743. ! loop over interpolation times:
  744. do it = 1, 2
  745. ! set times to 16th 00:00
  746. call Get( t, year=year, month=month, day=day )
  747. if ( it == 1 ) then
  748. ! previous mid of month
  749. if ( day <= 15 ) then
  750. ! mid of previous month
  751. month = month - 1
  752. if ( month < 1 ) then
  753. year = year - 1
  754. month = 12
  755. end if
  756. end if
  757. else
  758. ! next mid of month
  759. if ( day >= 16 ) then
  760. ! mid of next month
  761. month = month + 1
  762. if ( month > 12 ) then
  763. year = year + 1
  764. month = 1
  765. end if
  766. end if
  767. end if
  768. ! load climatology for this month (ppmv)
  769. call FortuinKelder_Read( trim(climat_fname), month, &
  770. lats_deg, pres_Pa, o3_ppv, status )
  771. IF_NOTOK_RETURN(status=1)
  772. ! convert from ppmv to ppv:
  773. o3_ppv = o3_ppv * 1.0e-6
  774. ! interpolate to latitudes
  775. do l = 1, nlevs
  776. call Interp_Lin( lats_deg, o3_ppv(:,l), lli%lat_deg, o3X(:,l), status )
  777. IF_NOTOK_RETURN(status=1)
  778. end do
  779. ! interpolate to standard pressures
  780. do j = 1, lli%nlat
  781. ! negate pressure ax; should be increasing ...
  782. call Interp_Lin( -pres_Pa, o3X(j,:), -levi%fp0, o3_in(1,j,:), status )
  783. IF_NOTOK_RETURN(status=1)
  784. end do
  785. ! time is mid of month:
  786. t_in(it) = NewDate( year, month, 16, 00, 00 )
  787. ! store:
  788. call Set( o3c, status, t_in=t_in(it), data_in=o3_in, it_in=it )
  789. IF_NOTOK_RETURN(status=1)
  790. end do ! times
  791. ! clear:
  792. deallocate( lats_deg )
  793. deallocate( pres_Pa )
  794. deallocate( o3_ppv )
  795. deallocate( o3X )
  796. deallocate( sp )
  797. deallocate( o3_in )
  798. ! set time range for which data could be interpolated:
  799. call Set( o3c, status, tr=t_in )
  800. IF_NOTOK_RETURN(status=1)
  801. ! apply interpolation: should succeed now:
  802. call Setup( o3c, t, status )
  803. if ( status < 0 ) then
  804. write (gol,'("time interpolation failed, while data has just been read.")'); call goErr
  805. write (gol,'("in ",a)') rname; call goErr; status=1; return
  806. else if ( status > 0 ) then
  807. write (gol,'("in ",a)') rname; call goErr; status=1; return
  808. end if
  809. ! ok
  810. status = 0
  811. end subroutine Setup_O3clim
  812. ! ================================================================
  813. subroutine Setup_Tclim( lli, T, Taver, status )
  814. use Grid, only : TllGridInfo
  815. ! --- in/out --------------------------------
  816. type(TllGridInfo), intent(in) :: lli
  817. real, intent(in) :: T(:,:,:)
  818. real, intent(out) :: Taver(:,:)
  819. integer, intent(out) :: status
  820. ! --- const ------------------------------
  821. character(len=*), parameter :: rname = mname//'/Setup_Tclim'
  822. ! latitude range for model temperature average
  823. real, parameter :: latrange = 6.2
  824. ! --- local ------------------------------
  825. integer :: im, jm, lm
  826. integer :: i, j, l, k
  827. integer :: kmin, kmax
  828. real :: wk
  829. real :: taccu, waccu
  830. ! --- begin ------------------------------
  831. im = size(T,1)
  832. jm = size(T,2)
  833. lm = size(T,3)
  834. do l = 1, lm
  835. do j = 1, jm
  836. taccu = 0.0
  837. waccu = 0.0
  838. ! cells within lat+[-latrange,+latrange]
  839. kmin = max(j-int(latrange/lli%dlat_deg),1)
  840. kmax = min(j+int(latrange/lli%dlat_deg),jm)
  841. ! loop over smoothing cells:
  842. do k = kmin, kmax
  843. ! weight decreasing with distance:
  844. wk = 1.0 - abs(real(k-j))*lli%dlat_deg/latrange
  845. if ( wk <= 0.0 ) then
  846. write (gol,'("internal error : wk = ",es12.4)') wk
  847. write (gol,'("in ",a)') rname; call goErr; status=1; return
  848. end if
  849. ! accumulate
  850. do i = 1, im
  851. taccu = taccu + wk * T(i,k,l)
  852. waccu = waccu + wk
  853. end do ! lon
  854. end do ! smoothing lats
  855. ! average:
  856. Taver(j,l) = taccu / waccu
  857. end do ! lats
  858. end do ! levs
  859. ! ok
  860. status = 0
  861. end subroutine Setup_Tclim
  862. end module Chemistry_Cariolle