chemistry_cariolle.F90 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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. implicit none
  249. ! --- in/out -----------------------------
  250. integer, intent(in) :: region
  251. type(TDate), intent(in) :: tr(2)
  252. integer, intent(out) :: status
  253. ! --- const ------------------------------
  254. character(len=*), parameter :: rname = mname//'/Chemie'
  255. ! real, parameter :: conv = 0.1*Avog/xm_o3 ! from kg/m2 --> #/cm2
  256. real, parameter :: conv = 0.1*Avog/xmo3 ! from kg/m2 --> #/cm2
  257. real, parameter :: todu = 3.767e-17 ! from #/cm2 --> du
  258. ! --- local -------------------------------
  259. type(TDate) :: tmid
  260. integer :: imr, jmr, lmr
  261. integer :: i, j, l, ll, lll
  262. integer :: level, lglob
  263. #ifdef with_budgets
  264. integer :: nzone,nzone_v
  265. #endif
  266. real, pointer :: rm(:,:,:,:)
  267. real, pointer :: vo3(:,:,:)
  268. real, pointer :: ozone_klimtop(:)
  269. real, pointer :: phlb(:,:,:)
  270. real, pointer :: m(:,:,:)
  271. real, pointer :: temper(:,:,:)
  272. #ifdef with_zoom
  273. integer, pointer :: zoomed(:,:)
  274. #endif
  275. real, pointer :: area(:) ! cell area (m2) for each lat band
  276. real, allocatable :: Tclim(:,:)
  277. ! real,allocatable :: o3_overhead(:,:,:) ! in mlc/cm2
  278. real,allocatable :: o3_overhead(:,:) ! in mlc/cm2
  279. real :: lon, lat
  280. integer :: daynr, hour, minu, sec
  281. real :: csza
  282. real :: pf ! full level pressure (Pa)
  283. real :: dt_sec
  284. real :: o3_vmr ! ozone mixing ratio (ppv)
  285. real :: o3_ohc ! overhead column (mlc/cm2)
  286. real :: o3_ohc_fac
  287. real :: o3c_vmr ! ozone mixing ratio (ppv)
  288. real :: o3c_ohc ! overhead column (mlc/cm2)
  289. real :: kg_TO_mlc_m2
  290. real :: Xpsc, dXpsc, kXpsc
  291. real :: do3_vmr, do3
  292. real :: cc(nc)
  293. integer :: ilast
  294. real :: k_h
  295. real :: rm_new,A,B,sgn,timesc
  296. !type(TTimeSeriesHDF) :: F
  297. ! --- begin ---------------------------------
  298. if ( lmloc == 0 ) then
  299. status=0; return
  300. end if
  301. #ifdef MPI
  302. which_par = previous_par(region)
  303. if (which_par == 'tracers') &
  304. call escape_tm('Model should be parallel over levels in Cariolle chemistry')
  305. #endif
  306. call goLabel( rname )
  307. if (myid == 0) then
  308. call wrtgol( 'ozone parchem : ', tr(1), ' - ', tr(2) ); call goPr
  309. if ( with_cold_tracer ) then
  310. write (gol,*) 'ozone parchem with cold tracer' ; call goPr
  311. else
  312. write (gol,*) 'ozone parchem without cold tracer' ; call goPr
  313. endif
  314. if ( with_trop_force ) then
  315. write (gol,*) 'ozone parchem with nudged tropospheric climatology' ; call goPr
  316. else
  317. write (gol,*) 'ozone parchem without nudged tropospheric climatology' ; call goPr
  318. endif
  319. end if
  320. ! regional grid sizes:
  321. imr = im(region)
  322. jmr = jm(region)
  323. lmr = lm(region)
  324. ! set pointers
  325. #ifdef MPI
  326. rm => mass_dat(region)%rm_k ! kg tracer, parallel over levels
  327. #else
  328. rm => mass_dat(region)%rm_t ! kg tracer, parallel over tracers
  329. #endif
  330. m => m_dat(region)%data ! kg air
  331. phlb => phlb_dat(region)%data ! air pressure at boundaries (1:lm+1)
  332. vo3 => phot_dat(region)%vo3 ! overhead O3, #/cm2, parallel over levels
  333. ozone_klimtop => phot_dat(region)%o3klim_top ! top layers overhead O3, #/cm2
  334. temper => temper_dat(region)%data ! K
  335. area => region_dat(region)%dxyp ! m2
  336. #ifdef with_zoom
  337. zoomed => region_dat(region)%zoomed
  338. #endif
  339. allocate(o3_overhead(jmr,lmr)) ; o3_overhead = 0.0
  340. ! mid of interval:
  341. tmid = tr(1) + (tr(2)-tr(1))/2
  342. !
  343. ! ** setup climatology
  344. !
  345. ! interpolate to this time, eventually read new fields:
  346. call Setup_O3Clim( lli(region), levi, O3clim_vmr(region), tmid, status )
  347. IF_NOTOK_RETURN(status=1)
  348. if (use_o3du) then
  349. ! overhead ozone column for model top is calculated (in photolysis routine)
  350. ! based on Fortuin-Kelder climatology scaled by observations
  351. ! same should be done here for climatological overhead column
  352. do j=1,jmr
  353. o3_overhead(j,lmr) = ozone_klimtop(j)
  354. enddo
  355. else
  356. ! convert climatology from ppv to mlc/cm2 using standard airmass/m2 (p=1e5 Pa)
  357. !PRIOR
  358. ! o3_overhead(:,:,lmr) = 0.5 * O3clim_vmr(region)%data(:,:,lmr)*levi%m0(lmr) * conv / fscale(io3)
  359. !NOW
  360. o3_overhead(:,lmr) = 0.5 * O3clim_vmr(region)%data(1,:,lmr)*levi%m0(lmr) * conv / fscale(io3)
  361. endif
  362. do l = lmr-1,1,-1
  363. ! convert climatology from ppv to mlc/cm2 using standard airmass/m2 (p=1e5 Pa)
  364. !PRIOR
  365. ! o3_overhead(:,:,l) = o3_overhead(:,:,l+1) + &
  366. ! 0.5 * ( O3clim_vmr(region)%data(:,:,l)*levi%m0(l) + &
  367. ! O3clim_vmr(region)%data(:,:,l+1)*levi%m0(l+1) ) * conv / fscale(io3)
  368. !NOW
  369. o3_overhead(:,l) = o3_overhead(:,l+1) + &
  370. 0.5 * ( O3clim_vmr(region)%data(1,:,l)*levi%m0(l) + &
  371. O3clim_vmr(region)%data(1,:,l+1)*levi%m0(l+1) ) * conv / fscale(io3)
  372. end do
  373. !
  374. ! ** setup coefficients
  375. !
  376. ! tables:
  377. ! bsf15k:/usr/people/eskes/fdscia/input/cariolle/OZONE_64x26.ASCII
  378. ! linoz/linoz_coeff.dat
  379. ! input routines:
  380. ! /usr/people/segers/work/tm/TM5/proj/chem/ozone.bak/src/chem_ozonepar.F90
  381. ! check if current coeff are valid for this month,
  382. ! eventually (re)load:
  383. call Setup_Cariolle( lli(region), o3coef(region), o3coefp(region), tmid, status )
  384. IF_NOTOK_RETURN(status=1)
  385. !
  386. ! zonal average temperature
  387. !
  388. ! compute smoothed temperature climatology ?
  389. if ( apply_taver ) then
  390. ! setup zonal field:
  391. allocate( Tclim(jmr,lmr) )
  392. ! fill smoothed temperature:
  393. call Setup_Tclim( lli(region), temper, Tclim, status )
  394. IF_NOTOK_RETURN(status=1)
  395. end if
  396. !
  397. ! apply chemistry
  398. !
  399. ! time step
  400. dt_sec = rTotal( tr(2) - tr(1), 'sec' )
  401. ! loop over all grid cells:
  402. do j = jsr(region), jer(region)
  403. do i = isr(region), ier(region)
  404. ! skip if this cell is calculated in an overlying zoom region:
  405. #ifdef with_zoom
  406. if ( region_dat(region)%zoomed(i,j) /= region ) cycle
  407. #endif
  408. ! grid cell location:
  409. lon = lli(region)%lon_deg(i) ! deg
  410. lat = lli(region)%lat_deg(j) ! deg
  411. ! compute cos(solar_zenith_angle)
  412. daynr = DayNumber( tmid )
  413. call Get( tmid, hour=hour, min=minu, sec=sec )
  414. csza = cos_sza( daynr, hour, minu, sec, lon, lat )
  415. ! conversion from (kg o3) to (mlc o3/m2) :
  416. ! ( kg O3 / m2 ) / (kg o3 / mol) * (mlc/mol) * (1e-4 m2/cm2) = mlc/cm2
  417. kg_TO_mlc_m2 = 1.0 / area(j) / xm_o3 * Avog * 1.0e-4
  418. ! loop over levels
  419. ilast = 1
  420. do level = 1,lmloc
  421. lglob = offsetl + level
  422. ! Cariolle chemistry not applied below l_cariolle
  423. ! except when tropospheric nudging is active
  424. if ( (.not.with_trop_force) .and. (lglob .lt. l_cariolle(region)) ) exit
  425. ! full level pressure:
  426. pf = ( phlb(i,j,lglob) + phlb(i,j,lglob+1) )/2.0 ! Pa
  427. ! ozone volume mixing ratios:
  428. o3_vmr = fscale(io3) * rm(i,j,level,io3) / m(i,j,lglob) ! ppv
  429. o3_vmr = max(o3_vmr,0.0) ! can become negative...
  430. o3c_vmr = o3clim_vmr(region)%data(1,j,lglob)
  431. ! overhead column (including contribution of upper-half of current layer):
  432. o3_ohc = vo3(i,j,level) ! mlc/cm2
  433. o3c_ohc = o3_overhead(j,lglob) ! mlc/cm2
  434. o3_ohc_fac = 0.5*kg_TO_mlc_m2 / fscale(io3) * m(i,j,lglob)
  435. o3_ohc_fac = max(o3_ohc_fac,0.0)
  436. !if (i.eq.10.and.j.eq.10)then
  437. ! 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
  438. !endif
  439. ! ** cold tracer scheme
  440. ! standard put values to zero, overwritten if with_cold_tracer = T
  441. Xpsc = 0.
  442. ! convert to mass again:
  443. dXpsc = 0.
  444. ! hetero chem (might be zero):
  445. k_h = 0. !kXpsc
  446. if ( with_cold_tracer ) then
  447. ! cold tracer (marked air mass)
  448. Xpsc = rm(i,j,level,ipsc) / m(i,j,lglob) ! ~ 0-1
  449. Xpsc = min( max( 0.0, Xpsc ), 1.0 ) ! 0-1
  450. ! hetrogeneous chemistry (cold tracer);
  451. ! fills kXpsc to be used as hetrochem reaction rate in Cariolle scheme:
  452. call ColdTracer_0d( Xpsc, pf, coldtracer_plevs, &
  453. temper(i,j,lglob), csza, lat, dt_sec, &
  454. dXpsc, kXpsc, status )
  455. IF_NOTOK_RETURN(status=1)
  456. ! convert to mass again:
  457. dXpsc = dXpsc * m(i,j,lglob) ! kg
  458. ! add tracer mass changes:
  459. if (dXpsc .gt. 0.) then
  460. call AdjustTracer( dXpsc, region, i, j, level, ipsc, status )
  461. IF_NOTOK_RETURN(status=1)
  462. end if
  463. #ifdef with_budgets
  464. nzone=budg_dat(region)%nzong(i,j) ! global budget
  465. nzone_v=nzon_vg(lglob)
  466. budcarg(nzone,nzone_v,2)=budcarg(nzone,nzone_v,2)+ dXpsc*1000./ra(ipsc) ! mol psc per cell
  467. #endif
  468. ! hetero chem (might be zero):
  469. k_h = kXpsc
  470. end if
  471. ! ** end applying cold tracer
  472. ! ** Cariolle scheme
  473. ! interpolate to pressure level:
  474. call Interp_Lin( o3coefp(region)%data(1,j,:), &
  475. o3coef(region)%data(:,j,:), pf, cc, ilast, status )
  476. IF_NOTOK_RETURN(status=1)
  477. ! replace some coeffs by climatological data
  478. ! (have no impact if corresponding reaction rates are zero)
  479. cc(3) = o3c_vmr ! zonal aver ozone mixing ratio
  480. cc(7) = o3c_ohc ! zonal aver ozone overhead column
  481. ! use zonal aver temperature ?
  482. ! (has no impact if corresponding reaction rate is zero)
  483. if ( apply_taver ) cc(5) = Tclim(j,lglob)
  484. ! apply parameterized ozone chemistry for current cell:
  485. call Cariolle_0d( o3_vmr, o3_ohc, o3_ohc_fac, temper(i,j,lglob), &
  486. cc, k_h, cariolle_tau_min, dt_sec, do3_vmr )
  487. IF_NOTOK_RETURN(status=1)
  488. ! if (i.eq.5.and. (j.eq.1 .or. j.eq.11 .or. j.eq. 80 .or. j.eq.90))then
  489. ! write(*,'a18,i3,i3,8e11.3')'DEBUG CARIOLLE cc',lglob,j,cc,dt_sec
  490. ! 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
  491. !
  492. ! write(*,'a18,i3,i3,7e11.3')'DEBUG CAR timesc', lglob, j, 1./abs(cc(2) + cc(6)*o3_ohc_fac - k_h)
  493. ! endif
  494. ! ozone mass change:
  495. do3 = do3_vmr * m(i,j,lglob) / fscale(io3) ! kg
  496. ! add tracer mass changes:
  497. call AdjustTracer( do3, region, i, j, level, io3, status )
  498. IF_NOTOK_RETURN(status=1)
  499. #ifdef with_budgets
  500. nzone=budg_dat(region)%nzong(i,j) ! global budget
  501. nzone_v=nzon_vg(lglob)
  502. budcarg(nzone,nzone_v,1)=budcarg(nzone,nzone_v,1)+do3*1000./ra(io3) ! mol o3 per cell
  503. #endif
  504. end do ! levels
  505. end do ! i
  506. end do ! j
  507. !
  508. ! done
  509. !
  510. nullify( rm )
  511. nullify( m )
  512. nullify( phlb )
  513. nullify( vo3 )
  514. nullify( ozone_klimtop )
  515. nullify( temper )
  516. #ifdef with_zoom
  517. nullify( zoomed )
  518. #endif
  519. nullify( area )
  520. #ifdef MPI
  521. rm => mass_dat(region)%rm_k ! kg tracer, parallel over levels
  522. #else
  523. rm => mass_dat(region)%rm_t ! kg tracer, parallel over tracers
  524. #endif
  525. m => m_dat(region)%data ! kg air
  526. nullify( rm )
  527. nullify( m )
  528. if ( apply_taver ) deallocate( Tclim )
  529. deallocate (o3_overhead)
  530. ! ok
  531. call goLabel(); status=0
  532. end subroutine Cariolle_Chemie
  533. ! ================================================================
  534. subroutine Setup_Cariolle( lli, carcoef, carcoefp, t, status )
  535. use Binas , only : p0 ! standard pressure (1e5 Pa)
  536. use GO , only : TDate, Get, NewDate
  537. use Num , only : Interp_Lin
  538. use Grid , only : TllGridInfo
  539. use Climat , only : TClimat, Set, Setup
  540. use file_cariolle, only : Cariolle_Info, CARIOLLE_READ
  541. ! --- in/out --------------------------------
  542. type(TllGridInfo), intent(in) :: lli
  543. type(TClimat), intent(inout) :: carcoef ! 1-7
  544. type(TClimat), intent(inout) :: carcoefp ! Pa
  545. type(TDate), intent(in) :: t
  546. integer, intent(out) :: status
  547. ! --- const ------------------------------
  548. character(len=*), parameter :: rname = mname//'/Setup_Cariolle'
  549. ! --- local ------------------------------
  550. integer :: year, month
  551. integer :: nlats, nlevs
  552. real, allocatable :: lats(:)
  553. real, allocatable :: pp(:,:)
  554. real, allocatable :: ppX(:,:,:)
  555. real, allocatable :: cc(:,:,:)
  556. real, allocatable :: ccX(:,:,:)
  557. type(TDate) :: tr_in(2)
  558. integer :: j, l, ic
  559. ! --- begin ------------------------------
  560. ! try to setup for requested time;
  561. ! return status=-1 if not filled yet or filled for wrong time:
  562. call Setup( carcoef, t, status )
  563. if (status==0) return
  564. ! data needs to be (re)setup ...
  565. ! grid sizes:
  566. call Cariolle_Info( status, nlats=nlats, nlevs=nlevs )
  567. IF_NOTOK_RETURN(status=1)
  568. ! setup storage:
  569. allocate( lats(nlats) )
  570. allocate( pp(nlats,nlevs) )
  571. allocate( ppX(1,lli%nlat,nlevs) )
  572. allocate( cc(nlats,nlevs,nc) )
  573. allocate( ccX(nc,lli%nlat,nlevs) )
  574. ! extract month:
  575. call Get( t, year=year, month=month )
  576. ! load coeff for this month (ppmv)
  577. call Cariolle_Read( trim(cariolle_fname), month, lats, pp, cc, status )
  578. IF_NOTOK_RETURN(status=1)
  579. ! interpolate pressure field to latitudes
  580. do l = 1, nlevs
  581. call Interp_Lin( lats, pp(:,l), lli%lat_deg, ppX(1,:,l), status )
  582. IF_NOTOK_RETURN(status=1)
  583. end do
  584. ! spatial interpolation;
  585. ! loop over coeffs:
  586. do ic = 1, nc
  587. ! interpolate to latitudes
  588. do l = 1, nlevs
  589. call Interp_Lin( lats, cc(:,l,ic), lli%lat_deg, ccX(ic,:,l), status )
  590. IF_NOTOK_RETURN(status=1)
  591. end do
  592. !! interpolate to standard pressures
  593. !do j = 1, lli%nlat
  594. ! ! Cariolle coefs from top->surf, thus no negation required:
  595. ! call Interp_Lin( ppX(j,:), ccX(j,:), levi%fp0, cc_in(ic,j,:) )
  596. !end do
  597. end do ! coeff loop
  598. ! set time range for which this data is valid:
  599. ! o begin of current month:
  600. tr_in(1) = NewDate( year, month, 01, 00, 00 )
  601. ! o begin of next month:
  602. month = month + 1
  603. if ( month > 12 ) then
  604. year = year + 1
  605. month = 1
  606. end if
  607. tr_in(2) = NewDate( year, month, 01, 00, 00 )
  608. ! store:
  609. call Set( carcoef, status, data=ccX, tr=tr_in )
  610. IF_NOTOK_RETURN(status=1)
  611. call Set( carcoefp, status, data=ppX, tr=tr_in )
  612. IF_NOTOK_RETURN(status=1)
  613. ! set coeff such that in troposphere only relaxation to climatology remains:
  614. if ( with_trop_force ) then
  615. call Setup_TropForce( carcoef, carcoefp, status )
  616. IF_NOTOK_RETURN(status=1)
  617. end if
  618. ! clear storage:
  619. deallocate( lats )
  620. deallocate( pp )
  621. deallocate( ppX )
  622. deallocate( cc )
  623. deallocate( ccX )
  624. ! ok
  625. status = 0
  626. end subroutine Setup_Cariolle
  627. ! ================================================================
  628. subroutine Setup_TropForce( carcoef, carcoefp, status )
  629. ! --- in/out --------------------------------
  630. type(TClimat), intent(inout) :: carcoef ! c1-c7
  631. type(TClimat), intent(inout) :: carcoefp ! Pa
  632. integer, intent(out) :: status
  633. ! --- const ------------------------------
  634. character(len=*), parameter :: rname = mname//'/Setup_TropForce'
  635. ! --- local ------------------------------
  636. integer :: nlat, nlev
  637. integer :: j, l
  638. integer :: ilev0
  639. real :: plev0, tau0
  640. real :: plev, tau
  641. real :: cc(7)
  642. real :: alfa
  643. ! --- begin ------------------------------
  644. ! grid size
  645. nlat = size(carcoefp%data,2)
  646. nlev = size(carcoefp%data,3)
  647. ! loop over latitudes
  648. do j = 1, nlat
  649. ! first level above troposphere:
  650. if ( carcoefp%data(1,j,1) > carcoefp%data(1,j,nlev) ) then
  651. ! upwards
  652. ilev0 = nlev ! model top
  653. do l = 1, nlev
  654. if ( carcoefp%data(1,j,l) <= cariolle_plev ) then
  655. ilev0 = l
  656. exit
  657. end if
  658. end do
  659. else
  660. ! downwards
  661. ilev0 = 1 ! model top
  662. do l = nlev, 1, -1
  663. if ( carcoefp%data(1,j,l) <= cariolle_plev ) then
  664. ilev0 = l
  665. exit
  666. end if
  667. end do
  668. end if
  669. ! pressure in lowest cariolle level:
  670. plev0 = carcoefp%data(1,j,ilev0) ! Pa
  671. tau0 = - 1.0/carcoef%data(2,j,ilev0) ! sec
  672. ! loop over levels
  673. do l = 1, nlev
  674. ! current pressure and coeffs:
  675. cc = carcoef%data(:,j,l)
  676. plev = carcoefp%data(1,j,l)
  677. ! different pressure ranges:
  678. if ( plev >= tropo_plev ) then
  679. ! ~~ relaxation to climatology, slow
  680. ! relaxation towards climatology via Cariolle coeff:
  681. cc = 0.0
  682. cc(2) = -1.0/tropo_tau
  683. else if ( plev >= cariolle_plev ) then
  684. ! ~~ relaxation to climatology, slower downwards
  685. ! interpolate tau between lower constant value and cariolle value:
  686. alfa = ( plev - plev0 ) / ( tropo_plev - plev0 )
  687. tau = tau0 * (1.0-alfa ) + tropo_tau * alfa
  688. ! relaxation towards climatology via Cariolle coeff:
  689. cc = 0.0
  690. cc(2) = -1.0/tau
  691. end if
  692. ! restore:
  693. carcoef%data(:,j,l) = cc
  694. end do ! levs
  695. end do ! lats
  696. ! ok
  697. status = 0
  698. end subroutine Setup_TropForce
  699. ! ================================================================
  700. subroutine Setup_O3clim( lli, levi, o3c, t, status )
  701. use GO , only : TDate, Get, NewDate
  702. use Num , only : Interp_Lin
  703. use Grid , only : TllGridInfo, TLevelInfo
  704. use Climat , only : TClimat, Set, Setup
  705. use file_fortkeld, only : FortuinKelder_Info, FortuinKelder_Read
  706. ! --- in/out --------------------------------
  707. type(TllGridInfo), intent(in) :: lli
  708. type(TLevelInfo), intent(in) :: levi
  709. type(TClimat), intent(inout) :: o3c
  710. type(TDate), intent(in) :: t
  711. integer, intent(out) :: status
  712. ! --- const ------------------------------
  713. character(len=*), parameter :: rname = mname//'/Setup_O3clim'
  714. ! --- local ------------------------------
  715. integer :: year, month, day
  716. type(TDate) :: t_in(2)
  717. integer :: it
  718. integer :: nlats, nlevs
  719. real, allocatable :: lats_deg(:)
  720. real, allocatable :: pres_Pa(:)
  721. real, allocatable :: o3_ppv(:,:)
  722. real, allocatable :: o3X(:,:)
  723. real, allocatable :: sp(:)
  724. real, allocatable :: o3_in(:,:,:)
  725. integer :: j, l
  726. ! --- begin ------------------------------
  727. ! try to interpolate in time to t;
  728. ! return status=-1 if not filled yet or filled for wrong time:
  729. call Setup( o3c, t, status )
  730. if (status==0) return
  731. ! data needs to be (re)setup ...
  732. ! extract grid sizes:
  733. call FortuinKelder_Info( status, nlats=nlats, nlevs=nlevs )
  734. IF_NOTOK_RETURN(status=1)
  735. ! setup arrays:
  736. allocate( lats_deg(nlats) )
  737. allocate( pres_Pa(nlevs) )
  738. allocate( o3_ppv(nlats,nlevs) )
  739. allocate( o3X(lli%nlat,nlevs) )
  740. allocate( sp(lli%nlat) )
  741. allocate( o3_in(1,lli%nlat,levi%nlev) )
  742. ! loop over interpolation times:
  743. do it = 1, 2
  744. ! set times to 16th 00:00
  745. call Get( t, year=year, month=month, day=day )
  746. if ( it == 1 ) then
  747. ! previous mid of month
  748. if ( day <= 15 ) then
  749. ! mid of previous month
  750. month = month - 1
  751. if ( month < 1 ) then
  752. year = year - 1
  753. month = 12
  754. end if
  755. end if
  756. else
  757. ! next mid of month
  758. if ( day >= 16 ) then
  759. ! mid of next month
  760. month = month + 1
  761. if ( month > 12 ) then
  762. year = year + 1
  763. month = 1
  764. end if
  765. end if
  766. end if
  767. ! load climatology for this month (ppmv)
  768. call FortuinKelder_Read( trim(climat_fname), month, &
  769. lats_deg, pres_Pa, o3_ppv, status )
  770. IF_NOTOK_RETURN(status=1)
  771. ! convert from ppmv to ppv:
  772. o3_ppv = o3_ppv * 1.0e-6
  773. ! interpolate to latitudes
  774. do l = 1, nlevs
  775. call Interp_Lin( lats_deg, o3_ppv(:,l), lli%lat_deg, o3X(:,l), status )
  776. IF_NOTOK_RETURN(status=1)
  777. end do
  778. ! interpolate to standard pressures
  779. do j = 1, lli%nlat
  780. ! negate pressure ax; should be increasing ...
  781. call Interp_Lin( -pres_Pa, o3X(j,:), -levi%fp0, o3_in(1,j,:), status )
  782. IF_NOTOK_RETURN(status=1)
  783. end do
  784. ! time is mid of month:
  785. t_in(it) = NewDate( year, month, 16, 00, 00 )
  786. ! store:
  787. call Set( o3c, status, t_in=t_in(it), data_in=o3_in, it_in=it )
  788. IF_NOTOK_RETURN(status=1)
  789. end do ! times
  790. ! clear:
  791. deallocate( lats_deg )
  792. deallocate( pres_Pa )
  793. deallocate( o3_ppv )
  794. deallocate( o3X )
  795. deallocate( sp )
  796. deallocate( o3_in )
  797. ! set time range for which data could be interpolated:
  798. call Set( o3c, status, tr=t_in )
  799. IF_NOTOK_RETURN(status=1)
  800. ! apply interpolation: should succeed now:
  801. call Setup( o3c, t, status )
  802. if ( status < 0 ) then
  803. write (gol,'("time interpolation failed, while data has just been read.")'); call goErr
  804. write (gol,'("in ",a)') rname; call goErr; status=1; return
  805. else if ( status > 0 ) then
  806. write (gol,'("in ",a)') rname; call goErr; status=1; return
  807. end if
  808. ! ok
  809. status = 0
  810. end subroutine Setup_O3clim
  811. ! ================================================================
  812. subroutine Setup_Tclim( lli, T, Taver, status )
  813. use Grid, only : TllGridInfo
  814. ! --- in/out --------------------------------
  815. type(TllGridInfo), intent(in) :: lli
  816. real, intent(in) :: T(:,:,:)
  817. real, intent(out) :: Taver(:,:)
  818. integer, intent(out) :: status
  819. ! --- const ------------------------------
  820. character(len=*), parameter :: rname = mname//'/Setup_Tclim'
  821. ! latitude range for model temperature average
  822. real, parameter :: latrange = 6.2
  823. ! --- local ------------------------------
  824. integer :: im, jm, lm
  825. integer :: i, j, l, k
  826. integer :: kmin, kmax
  827. real :: wk
  828. real :: taccu, waccu
  829. ! --- begin ------------------------------
  830. im = size(T,1)
  831. jm = size(T,2)
  832. lm = size(T,3)
  833. do l = 1, lm
  834. do j = 1, jm
  835. taccu = 0.0
  836. waccu = 0.0
  837. ! cells within lat+[-latrange,+latrange]
  838. kmin = max(j-int(latrange/lli%dlat_deg),1)
  839. kmax = min(j+int(latrange/lli%dlat_deg),jm)
  840. ! loop over smoothing cells:
  841. do k = kmin, kmax
  842. ! weight decreasing with distance:
  843. wk = 1.0 - abs(real(k-j))*lli%dlat_deg/latrange
  844. if ( wk <= 0.0 ) then
  845. write (gol,'("internal error : wk = ",es12.4)') wk
  846. write (gol,'("in ",a)') rname; call goErr; status=1; return
  847. end if
  848. ! accumulate
  849. do i = 1, im
  850. taccu = taccu + wk * T(i,k,l)
  851. waccu = waccu + wk
  852. end do ! lon
  853. end do ! smoothing lats
  854. ! average:
  855. Taver(j,l) = taccu / waccu
  856. end do ! lats
  857. end do ! levs
  858. ! ok
  859. status = 0
  860. end subroutine Setup_Tclim
  861. end module Chemistry_Cariolle