1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480 |
- !
- #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
- #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
- #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
- !
- #include "tm5.inc"
- !
- !-------------------------------------------------------------------------
- ! TM5 !
- !-------------------------------------------------------------------------
- !BOP
- !
- ! !MODULE: TOOLBOX
- !
- ! !DESCRIPTION: General tools for chemistry/emission treatment.
- !\\
- !\\
- ! !INTERFACE:
- !
- MODULE TOOLBOX
- !
- ! !USES:
- !
- use GO, only : gol, goErr, goPr, goLabel, goBug
- use dims, only : okdebug
-
- IMPLICIT NONE
- PRIVATE
- !
- ! !PUBLIC MEMBER FUNCTIONS:
- !
- public :: zfarr ! calculation of Arrhenius expression for rate constants
- public :: ltropo ! find tropopause level from T gradient
- public :: lvlpress ! return index of highest level below a pressure value
- public :: dumpfield ! write 4D field (real) to file (debug tool)
- public :: dumpfieldi ! write 4D field (real) to file (debug tool)
- public :: coarsen_emission ! convert GLOBAL field to each region
- public :: escape_tm ! error handler
- public :: distribute_emis2D ! distribute vertically 2D field [work on MPI tiles]
- public :: distribute1x1 ! distribute vertically GLOBAL 1x1 2D field
- public :: distribute1x1b ! alternate distribute1x1
- public :: tropospheric_columns ! integrate tropospheric ozone
- !
- ! !PRIVATE DATA MEMBERS:
- !
- character(len=*), parameter :: mname = 'toolbox'
- !
- ! !INTERFACE:
- !
- interface coarsen_emission
- module procedure coarsen_emission_1d
- module procedure coarsen_emission_2d
- module procedure coarsen_emission_3d
- module procedure coarsen_emission_d23
- end interface
- !
- ! !REVISION HISTORY:
- ! 16 Jul 2010 - Achim Strunk - optional input to distribute_emis2D; protex
- ! 24 Jan 2012 - P. Le Sager - fixed coarsen_emission_2d and 3d for lon-lat MPI domain decomposition
- !
- ! !REMARKS:
- !
- !EOP
- !-----------------------------------------------------------------------
- CONTAINS
-
- !-----------------------------------------------------------------------
- ! TM5 !
- !-----------------------------------------------------------------------
- !BOP
- !
- ! !FUNCTION: ltropo
- !
- ! !DESCRIPTION: determine tropopause level from temperature gradient
- ! reference: WMO /Bram Bregman
- !\\
- !\\
- ! !INTERFACE:
- !
- integer function ltropo(region,tx,gphx,lmx)
- !
- ! !INPUT PARAMETERS:
- !
- integer,intent(in) :: region
- integer,intent(in) :: lmx
- real,dimension(lmx),intent(in) :: tx
- real,dimension(lmx+1),intent(in) :: gphx
- !
- ! !REVISION HISTORY:
- ! programmed by fd 01-11-1996
- ! changed to function fd 12-07-2002
- ! 16 Jul 2010 - Achim Strunk -
- !
- ! !REMARKS:
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- integer :: ltmin,ltmax,l
- real :: dz,dt
- ! ltropo is highest tropospheric level
- ! above is defined as stratosphere
- ! min tropopause level 450 hPa (ca. 8 km)
- ltmin=lvlpress(region,45000.,98400.)
- ! max tropopause level 70 hPa (ca. 20 km)
- ltmax=lvlpress(region,7000.,98400.)
- ltropo=ltmin
- do l=ltmin,ltmax
- dz=(gphx(l)-gphx(l-2))/2.
- dt=(tx(l)-tx(l-1))/dz
- if ( dt < -0.002) ltropo=l !wmo 85 criterium for stratosphere
- ! increase upper tropospheric level
- end do !l
- end function ltropo
- !EOC
-
- !---------------------------------------------------------------------------
- ! TM5 !
- !---------------------------------------------------------------------------
- !BOP
- !
- ! !FUNCTION: lvlpress
- !
- ! !DESCRIPTION: lvlpress determines the index of the level with a pressure
- ! greater than press i.e. in height below press
- ! determines level independent of vertical resolution lm
- ! uses hybrid level coefficients to determine lvlpress
- !\\
- !\\
- ! !INTERFACE:
- !
- integer function lvlpress(region,press,press0)
- !
- ! !USES:
- !
- use dims, only: at, bt, lm
- !
- ! !INPUT PARAMETERS:
- !
- integer, intent(in) :: region
- real, intent(in) :: press
- real, intent(in) :: press0
- !
- ! !REVISION HISTORY:
- ! programmed by Peter van Velthoven, 6-november-2000
- ! 16 Jul 2010 - Achim Strunk -
- !
- ! !REMARKS:
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- real :: zpress0, zpress
- integer :: l,lvl
- if ( press0 == 0.0 ) then
- zpress0 = 98400.
- else
- zpress0 = press0
- endif
- lvl = 1
- ! l increases from bottom (l=1) to top (l=lm)
- do l = 1, lm(region)
- zpress = (at(l)+at(l+1) + (bt(l)+bt(l+1))*zpress0)*0.5
- if ( press < zpress ) then
- lvl = l
- endif
- end do
- lvlpress = lvl
- end function lvlpress
- !EOC
-
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !FUNCTION: zfarr
- !
- ! !DESCRIPTION: ZFARR calculation of Arrhenius expression for rate constants
- !\\
- !\\
- ! !INTERFACE:
- !
- real function zfarr(rx1,er,ztrec)
- !
- ! !INPUT PARAMETERS:
- !
- real,intent(in) :: rx1,er,ztrec
- !
- ! !REVISION HISTORY:
- ! 16 Jul 2010 - Achim Strunk -
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- zfarr=rx1*exp(er*ztrec)
- end function zfarr
- !EOC
-
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: DumpField
- !
- ! !DESCRIPTION: Write 4D field (type real) to HDF file
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine dumpfield(flag,fname,im,jm,lm,nt,field,namfield)
- !
- ! !USES:
- !
- use io_hdf, only : DFACC_CREATE, DFACC_WRITE, io_write
- !
- ! !INPUT PARAMETERS:
- !
- integer, intent(in) :: im, jm, lm, nt
- integer, intent(in) :: flag
- real, dimension(im,jm,lm,nt), intent(in) :: field ! 4D field
- character(len=*), intent(in) :: fname ! file name
- character(len=*), intent(in) :: namfield ! field name
- !
- ! !REVISION HISTORY:
- ! 16 Jul 2010 - Achim Strunk - protex
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- integer :: sfstart, io, sfend
- if ( flag==0 ) then
- io = sfstart(fname,DFACC_CREATE)
- else
- io = sfstart(fname,DFACC_WRITE)
- if ( io == -1 ) io = sfstart(fname,DFACC_CREATE)
- end if
- call io_write(io,im,'X',jm,'Y',lm,'Z',nt,'N',field,namfield)
- io = sfend(io)
- end subroutine dumpfield
- !EOC
-
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: dumpfieldi
- !
- ! !DESCRIPTION: Write 4D field (type integer) to HDF file
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine dumpfieldi(flag,fname,im,jm,lm,nt,field,namfield)
- !
- ! !USES:
- !
- use io_hdf, only : DFACC_CREATE, DFACC_WRITE, io_write
- !
- ! !INPUT PARAMETERS:
- !
- integer,intent(in) :: im, jm, lm, nt
- integer,intent(in) :: flag
- integer,dimension(im,jm,lm,nt),intent(in) :: field ! 4D field
- character(len=*),intent(in) :: fname ! file name
- character(len=*),intent(in) :: namfield ! field name
- !
- ! !REVISION HISTORY:
- ! 16 Jul 2010 - Achim Strunk - protex
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- integer :: sfstart,io,sfend
- if ( flag == 0 ) then
- io = sfstart(fname,DFACC_CREATE)
- else
- io = sfstart(fname,DFACC_WRITE)
- if (io==-1) io = sfstart(fname,DFACC_CREATE)
- end if
- call io_write(io,im,'X',jm,'Y',lm,'Z',nt,'N',field,namfield)
- io = sfend(io)
- end subroutine dumpfieldi
- !EOC
-
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: coarsen_emission_1d
- !
- ! !DESCRIPTION: Transform the 1D field available on e.g. 1 degree resolution
- ! to the desired zoom geometry
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine coarsen_emission_1d( name_field, jm_emis, field_in, field, avg, status)
- !
- ! name_field : name, only for printing reasons
- ! jm_emis : the dimension of the input field
- ! field_in : the input field
- ! field : type d2_data (defined in chem_param)
- ! avg : flags the mode: avg = 1 means that a surface area
- ! weighted area is calulated (e.g. land fraction)
- ! avg = 0 means that the sum of the underlying field
- ! is taken (e.g. emissions in kg/month).
- !
- ! !USES:
- !
- use dims, only: nregions, dy, yref, ybeg, jm, dxy11, idate
- use global_types, only: d2_data
- implicit none
- !
- ! !INPUT PARAMETERS:
- !
- character(len=*), intent(in) :: name_field
- integer, intent(in) :: avg ! 0=no 1=yes
- integer, intent(in) :: jm_emis
- real, dimension(jm_emis), intent(in) :: field_in
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- type(d2_data), dimension(nregions), target :: field
- !
- ! !OUTPUT PARAMETERS:
- !
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 19 Jun 2012 - P. Le Sager - got rid of escape_tm
- !
- ! !REMARKS:
- ! (1) FIXME : should work as is for lon-lat MPI domain decomposition, but
- ! not tested.
- ! (2) This is limited to a 1 degree zonal global input [-90,+90]
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- character(len=*), parameter :: rname = mname//'/coarsen_emission_1d'
- real, dimension(:), pointer :: coarse_field
- integer :: region
- real :: scale,w,wtot
- integer :: ystart
- integer :: yres
- integer :: j,j_index,jj
- integer :: jm_start
- ! start
-
- do region=1,nregions ! main loop over regions
- yres=dy/yref(region)
- if ( yres < 1 ) then
- write (gol,'("1 degree minimum resolution in emissions")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
-
- if ( jm_emis /= 180 ) then
- write (gol,'("input resolution should be 1 degree")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- !WP! find index of southmost gridpoint based on 1x1 degree
- jm_start=ybeg(region)+91
- if ( jm_start <= -1 ) then
- write (gol,'("requested emission fields outside valid region")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- coarse_field => field(region)%d2
- do j=1,jm(region)
- !cycle through 1x1 grid with steps for this region
- j_index=jm_start+(j-1)*yres
- coarse_field(j) = 0.0
- wtot = 0.0
- do jj=0,yres-1
- if(avg==1) then
- w = dxy11(j_index+jj)
- wtot = wtot + w
- coarse_field(j)=coarse_field(j) + field_in(j_index+jj)*w
- else
- coarse_field(j)=coarse_field(j) + field_in(j_index+jj)
- end if
- end do
- if ( avg == 1 ) coarse_field(j) = coarse_field(j)/wtot
- end do
- !if ( avg == 0 ) then
- ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
- ! ' coarsen_emission_1d: region ',region,name_field, &
- ! ' Field coarsened month :',idate(2),'total:',&
- ! sum(coarse_field) ; call goPr
- !else
- ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
- ! ' coarsen_emission_1d: region:',region,name_field, &
- ! ' Field averaged month :',idate(2) ; call goPr
- !end if
- nullify(coarse_field)
- end do ! loop over regions....
- end subroutine coarsen_emission_1d
- !EOC
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: COARSEN_EMISSION_2D
- !
- ! !DESCRIPTION: Transform a 2D *global* emissions, at a given resolution,
- ! to the geometry of all model regions.
- !\\
- !\\
- ! !INTERFACE:
- !
- SUBROUTINE COARSEN_EMISSION_2D(name_field, im_emis, jm_emis, field_in, field, avg, status)
- !
- ! !USES:
- !
- use GO, only : gol, goPr, goErr
- use Grid, only : TllGridInfo, Init, Done, FillGrid
- use dims, only : nregions
- use global_types, only : emis_data
- use meteodata, only : global_lli
- !
- ! !INPUT PARAMETERS:
- !
- character(len=*), intent(in) :: name_field ! name, only for printing reasons
- integer, intent(in) :: im_emis, jm_emis ! grid size of global input field
- real, intent(in) :: field_in(im_emis,jm_emis) ! input field
- integer, intent(in) :: avg ! avg = 1 means that a surface area
- ! weighted area is calulated (e.g. land fraction)
- ! avg = 0 means that the sum of the underlying field
- ! is taken (e.g. emissions in kg/month).
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- type(emis_data), target :: field(nregions) ! per region, %surf(im,jm)
- !
- ! !OUTPUT PARAMETERS:
- !
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 28 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/coarsen_emission_2d'
- integer :: region
- type(TllGridInfo) :: lli_in
- character(len=32) :: combkey
- ! --- begin ---------------------------------------
- ! define input grid
- call Init( lli_in, -180.0+0.5*360.0/im_emis, 360.0/im_emis, im_emis, &
- -90.0+0.5*180.0/jm_emis, 180.0/jm_emis, jm_emis, status )
- IF_NOTOK_RETURN(status=1)
- ! sum or average
- status=0
- select case ( avg )
- case ( 0 ) ; combkey = 'sum'
- case ( 1 ) ; combkey = 'area-aver'
- case default
- write (gol,'("ERROR - unsupported avg = ",i6)') avg; call goErr
- status=1
- end select
- IF_NOTOK_RETURN(status=1)
- ! main loop over regions
- do region = 1, nregions
- ! convert grid:
- call FillGrid( global_lli(region), 'n', field(region)%surf, &
- lli_in, 'n', field_in, trim(combkey), status)
- IF_NOTOK_RETURN(status=1)
- end do
- ! done
- call Done( lli_in, status )
- IF_NOTOK_RETURN(status=1)
- END SUBROUTINE COARSEN_EMISSION_2D
- !EOC
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: COARSEN_EMISSION_3D
- !
- ! !DESCRIPTION: Transform a 3D *global* emissions, at a given resolution,
- ! to the geometry of all model regions.
- !\\
- !\\
- ! !INTERFACE:
- !
- SUBROUTINE COARSEN_EMISSION_3D( name_field, im_emis, jm_emis, lm_emis, &
- field_in, field, avg, status )
- !
- ! !USES:
- !
- use GO, only : gol, goPr, goErr
- use Grid, only : TllGridInfo, Init, Done, FillGrid
- use dims, only : nregions
- use global_types, only : d3_data
- use meteodata, only : global_lli
- !
- ! !INPUT PARAMETERS:
- !
- character(len=*), intent(in) :: name_field
- integer, intent(in) :: avg
- integer, intent(in) :: im_emis, jm_emis, lm_emis
- real, intent(in) :: field_in(im_emis,jm_emis,lm_emis)
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- type(d3_data), target :: field(nregions) ! contains, per region, 3d field %d3(im,jm,lm)
- !
- ! !OUTPUT PARAMETERS:
- !
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 28 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/coarsen_emission_3d'
-
- integer :: region
- integer :: l
- type(TllGridInfo) :: lli_in
- character(len=32) :: combkey
- ! --- begin ---------------------------------------
- ! define input grid
- call Init( lli_in, -180.0+0.5*360.0/im_emis, 360.0/im_emis, im_emis, &
- -90.0+0.5*180.0/jm_emis, 180.0/jm_emis, jm_emis, status )
- IF_NOTOK_RETURN(status=1)
-
- ! sum or average
- status=0
- select case ( avg )
- case ( 0 ) ; combkey = 'sum'
- case ( 1 ) ; combkey = 'area-aver'
- case default
- write (gol,'("ERROR - unsupported avg = ",i6)') avg; call goErr
- status=1
- end select
- IF_NOTOK_RETURN(status=1)
-
- ! main loop over regions
- do region = 1, nregions
- ! convert grid:
- do l = 1, lm_emis
- call FillGrid( global_lli(region), 'n', field(region)%d3(:,:,l), &
- lli_in, 'n', field_in(:,:,l), trim(combkey), status)
- IF_NOTOK_RETURN(status=1)
- end do
-
- !! info ...
- !select case ( combkey )
- ! case ( 'aver', 'area-aver' )
- ! write (gol,'("coarsen_emission : region ",i1," ",a," field averaged")') &
- ! region, trim(name_field); call goPr
- ! case ( 'sum' )
- ! write (gol,'("coarsen_emission : region ",i1," ",a," field coarsened/distr.; total ",es12.3)') &
- ! region, trim(name_field), sum(field(region)%d3); call goPr
- ! case default
- ! write (gol,'("coarsen_emission : region ",i1," ",a," field coarsened/distributed")') &
- ! region, trim(name_field); call goPr
- !end select
- end do ! regions
-
- ! done
- call Done( lli_in, status )
- IF_NOTOK_RETURN(status=1)
- ! ok
- status = 0
- END SUBROUTINE COARSEN_EMISSION_3D
- !EOC
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: COARSEN_EMISSION_D23
- !
- ! !DESCRIPTION: Transform the 2D emissions available on lat-pressure resolution
- ! to the desired zoom geometry
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine coarsen_emission_d23( name_field, jm_emis, lm_emis, &
- field_in, field, avg, status )
- !
- ! name_field : name, only for printing reasons
- ! jm_emis : the y-dimension of the input field
- ! lm_emis : the z-dimension of the input field
- ! field_in : the input field
- ! field : type d23_data (defined in chem_param)
- ! avg : flags the mode: avg = 1 means that a surface area
- ! weighted area is calulated (e.g. land fraction)
- ! avg = 0 means that the sum of the underlying field
- ! is taken (e.g. emissions in kg/month).
- !
- ! !USES:
- !
- use dims, only : nregions, dy, yref, ybeg, jm, lm, dxy11, idate
- use global_types, only : d23_data
- !
- ! !INPUT PARAMETERS:
- !
- character(len=*),intent(in) :: name_field
- integer,intent(in) :: avg !0=no 1=yes
- integer,intent(in) :: jm_emis,lm_emis
- real,dimension(jm_emis,lm_emis),intent(in) :: field_in
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- type(d23_data),dimension(nregions),target :: field ! contains, per region, field %d23(jm,lm)
- !
- ! !OUTPUT PARAMETERS:
- !
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 19 Jun 2012 - P. Le Sager - got rid of escape_tm
- !
- ! !REMARKS:
- ! (1) FIXME : should work as is for lon-lat MPI domain decomposition, but
- ! not tested.
- ! (2) First dimension of input is limited to a 1 degree global [-90,+90]
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/coarsen_emission_d23'
-
- real, dimension(:,:), pointer :: coarse_field
- integer :: region
- real :: scale,w,wtot
- integer :: ystart
- integer :: yres
- integer :: j,j_index,jj,l
- integer :: jm_start
- ! start
- do region=1,nregions ! main loop over regions
- yres=dy/yref(region)
- if ( yres < 1 ) then
- write (gol,'("1 degree minimum resolution in emissions")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- if ( jm_emis /= 180 ) then
- write (gol,'("input resolution should be 1 degree")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- !WP! find index of southmost gridpoint based on 1x1 degree
- jm_start=ybeg(region)+91
- if ( jm_start <= -1 ) then
- write (gol,'("requested emission fields outside valid region")'); call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- coarse_field => field(region)%d23
- do l=1,lm(region)
- do j=1,jm(region)
- !cycle through 1x1 grid with steps for this region
- j_index=jm_start+(j-1)*yres
- coarse_field(j,l) = 0.0
- wtot = 0.0
- do jj=0,yres-1
- if(avg==1) then
- w = dxy11(j_index+jj)
- wtot = wtot + w
- coarse_field(j,l)=coarse_field(j,l) + &
- field_in(j_index+jj,l)*w
- else
- coarse_field(j,l)=coarse_field(j,l) + &
- field_in(j_index+jj,l)
- end if
- end do
- if ( avg == 1 ) coarse_field(j,l) = coarse_field(j,l)/wtot
- end do !j
- end do !l
- !if ( avg == 0 ) then
- !
- ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
- ! ' coarsen_emission_d23: region ',region,name_field// &
- ! ' Field coarsened month ',idate(2),' total ',&
- ! sum(coarse_field); call goPr
- !else
- ! write(gol,'(a,i1,x,a12,a,i2,a,1pe14.3)') &
- ! ' coarsen_emission_d23: region ',region,name_field// &
- ! ' Field averaged month ',idate(2); call goPr
- !end if
- nullify(coarse_field)
- end do ! loop over regions....
- end subroutine coarsen_emission_d23
- !EOC
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: ESCAPE_TM
- !
- ! !DESCRIPTION: abnormal termination of a model run
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine escape_tm( msg )
- !
- ! !USES:
- !
- use GO, only : GO_Print_Done
- use dims, only : okdebug, kmain, itau
- use datetime, only : wrtgol_tstamp
- use partools, only : Par_StopMPI
- #ifdef with_prism
- #ifdef oasis3
- use mod_oasis
- #endif
- use TM5_Prism, only : comp_id
- #endif
- !
- ! !INPUT PARAMETERS:
- !
- character(len=*), intent(in) :: msg ! character string to be printed on unit gol
- !
- ! !REVISION HISTORY:
- ! 19 Jun 2012 - P. Le Sager - use par_stopmpi instead of stop; protex
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/escape_tm'
- integer :: status
- ! --- begin ---------------------------
- write (gol,'(1x,39("--"))'); call goErr
- write (gol,'(1x,39("--"))'); call goErr
- call wrtgol_tstamp(itau,'ERROR - ESCAPE_TM'); call goErr
- write (gol,'(1x,a)') trim(msg); call goErr
- write (gol,'(1x,39("--"))'); call goErr
- write (gol,'(1x,39("--"))'); call goErr
- ! try to display at least the messages in a proper way ...
- call GO_Print_Done( status )
- if (status/=0) write (*,'("ERROR status from GO_Print_Done : ",i6)') status
- #ifdef with_prism
- #ifdef oasis3
- call oasis_abort( comp_id, rname, 'called prism_abort' )
- #endif
- #endif
- call Par_StopMPI
- end subroutine escape_tm
- !EOC
- !-----------------------------------------------------------------------
- ! TM5 !
- !-----------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: DISTRIBUTE_EMIS2D
- !
- ! !DESCRIPTION: subroutine to distribute the emissions given as a TM5 2D field
- ! into a TM5 3D emission field. Hlow and Hhigh are the bounds of
- ! the 2D emission fields. They give the height RELATIVE to oro
- ! From that the distribution is calculated
- ! employing the geopotential height (relative to oro)
- !\\
- !\\
- ! !INTERFACE:
- !
- SUBROUTINE DISTRIBUTE_EMIS2D( region, emis2D, emis3D, hlow, hhigh, status, xfrac, lat_start, lat_end)
- !
- ! !USES:
- !
- use tm5_distgrid, only : Get_DistGrid, dgrid
- use dims, only : lm, im, jm, dy, yref, ybeg
- use meteodata, only : gph_dat
- use global_types, only : d3_data, emis_data
- !
- ! !INPUT PARAMETERS:
- !
- integer, intent(in) :: region
- type(emis_data), intent(in), target :: emis2D ! 2D emission field (kg/gridbox/month)
- type(d3_data), intent(inout), target :: emis3D ! 3D emission field (kg/gridbox/month)
- real, intent(in) :: hlow ! lowest level (m)
- real, intent(in) :: hhigh ! highest level (m)
- !
- ! !OUTPUT PARAMETERS:
- !
- integer, intent(out) :: status
- real, intent(in), optional :: xfrac ! fraction of emissions to put b/w HLOW and HHIGH (default=1)
- real, intent(in), optional :: lat_start ! lower limit (default=-90) of application domain
- real, intent(in), optional :: lat_end ! upper limit (default=+90) of application domain
- !
- ! !REVISION HISTORY:
- ! 16 Jul 2010 - Achim Strunk - Added Lat_start and lat_end optional inputs.
- ! 27 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !----------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/distribute_emis2D'
- real, dimension(:,:,:),pointer :: gph ! geopotential height (m)
- real, dimension(:,:,:),pointer :: e3d ! 3D emissions
- real, dimension(:,:),pointer :: e2d ! 2D emissions
- integer :: i,j,l,j_st,j_end
- real, dimension(lm(1)+1) :: height
- real, dimension(lm(1)) :: dz
- real :: dy1,dze
- real :: totw, f, tot2d, tot3db, tot3da, fraction
- integer, dimension(3) :: ubound_e3d
- integer :: lmmax
- real :: hhighb
- real :: lat_low,lat_high
- integer :: i1, i2, j1, j2
- real :: l_status, g_status
- ! --- begin ---------------------------------------------
-
- status = 0
-
- if (present(xfrac)) then
- fraction = xfrac
- else
- fraction = 1.0
- endif
- if (fraction < spacing(fraction)) return ! degenerated cases
- if (present(lat_start)) then
- lat_low = lat_start
- else
- lat_low = -90.
- endif
- if (present(lat_end)) then
- lat_high = lat_end
- else
- lat_high = 90.
- endif
- CALL GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 )
- ! get indices of application-region
- dy1=dy/yref(region)
- j_st = floor((lat_low - ybeg(region))/dy1) + 1
- j_end = floor((lat_high - ybeg(region))/dy1) + 1
- ! is tile in appl. region?
- if ((j_end .lt. j1 ) .or. (j_st .gt. j2) ) then
- return
- end if
- ! limit range
- if (j_end .gt. j2 ) j_end = j2
- if (j_st .lt. j1 ) j_st = j1
- ! check inputs
- dze = hhigh - hlow
- if ( (hhigh <= 0.0) .or. (hlow < 0.0) .or. (dze < 0.0) ) then
- write (gol,'("found strange emission heights:")'); call goErr
- write (gol,'(" hhigh (> 0.0 ?) : ",es12.4)') hhigh; call goErr
- write (gol,'(" hlow (>= 0.0 ?) : ",es12.4)') hlow; call goErr
- write (gol,'(" hhigh-hlow (> 0.0 ?) : ",es12.4)') dze; call goErr
- TRACEBACK; status=1; return
- end if
- ! init
- nullify(gph)
- nullify(e2d)
- nullify(e3d)
- gph => gph_dat(region)%data
- e2d => emis2d%surf
- e3d => emis3d%d3
- ! get highest possible level
- ubound_e3d = ubound(e3d)
- lmmax = ubound_e3d(3)
- ! total of to-be-redistributed before redistribution
- tot2d = sum(e2d(:,j_st:j_end)*fraction)
- ! total of target array before adding redistributed data
- tot3db = sum(e3d(:,j_st:j_end,:))
-
-
- ! do work
- jlo: do j=j_st,j_end
- do i=i1, i2
- ! zero based height:
- height(1) = 0.0
- do l=1, lm(region)
- dz(l) = gph(i,j,l+1) - gph(i,j,l)
- height(l+1) = height(l) + dz(l)
- enddo
- totw = 0.0
- if( hhigh > height(lmmax+1) ) then
- write (gol,'("try to put emissions higher than array allows:")') ; call goErr
- write (gol,'(" hhigh : ",es12.4)') hhigh ; call goErr
- write (gol,'(" height(lmmax+1) : ",es12.4)') height(lmmax+1) ; call goErr
- write (gol,'(" at i/j=",i3,1x,i3)') i,j ; call goErr
- do l = 1, size(height)
- write (gol,*) 'height : ', l, height(l); call goErr
- end do
- do l = 1, size(gph,3)
- write (gol,*) 'gph : ', l, gph(i,j,l); call goErr
- end do
- TRACEBACK; status=1
- exit jlo
- endif
- zz: do l=1, lmmax
- if (hhigh > height(l+1)) then
- if ( hlow < height(l) ) then
- f = dz(l)/dze
- totw = totw + f
- e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
- else if( hlow < height(l+1)) then
- f = (height(l+1)-hlow)/dze
- totw = totw + f
- e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
- endif
- else
- if ( hlow < height(l)) then
- f = (hhigh - height(l))/dze
- totw = totw + f
- e3d(i,j,l) = e3d(i,j,l) + f*fraction*e2d(i,j)
- else
- totw = totw + 1.0
- e3d(i,j,l) = e3d(i,j,l) + fraction*e2d(i,j)
- endif
- exit zz
- endif
- enddo zz
- if ( abs(totw-1.0) > 1e-14 ) then
- write (gol,'("sum weight /= 1 : ",es12.4)') totw-1.0; call goErr
- TRACEBACK; status=1
- exit jlo
- end if
-
- enddo !i
- enddo jlo !j
- IF_NOTOK_RETURN(status=1)
- ! Total of target array after adding redistributed data, and check
-
- ! DO NOT FIXME ?? : the following test will fail if tot2d << tot3da (strictly: if
- ! tot2d is less than the last significant digit of tot3da). However this
- ! is good, since we actually expect that tot3da to be 0 (as used in
- ! chemistry): so we can catch some bad initialization.
- tot3da = sum(e3d(:,j_st:j_end,:))
- if (abs((tot3da-tot3db)-tot2d) > 1e-8*abs(tot2d) ) then
- write (gol,'("emissions have not been distributed mass-conserving")'); call goErr
- write(gol,*)"totals to add : ", tot2d, tot3db ; call goErr
- write(gol,*)"total after : ", tot3da ; call goErr
- write(gol,*)"with bounds : ", j1, j2, j_st, j_end; call goErr
- write(gol,*)"shapes e3d",shape(e3d) ; call goErr
- write(gol,*)"lbound e3d",lbound(e3d); call goErr
- write(gol,*)"ubound e3d",ubound(e3d); call goErr
- write(gol,*)"minmax e3d",minval(e3d), maxval(e3d); call goErr
- write(gol,*)"shapes e2d",shape(e2d) ; call goErr
- write(gol,*)"lbound e2d",lbound(e2d); call goErr
- write(gol,*)"ubound e2d",ubound(e2d); call goErr
- write(gol,*)"minmax e2d",minval(e2d), maxval(e2d); call goErr
- TRACEBACK; status=1; return
- end if
- ! done
- nullify(gph)
- nullify(e2d)
- nullify(e3d)
- END SUBROUTINE DISTRIBUTE_EMIS2D
- !EOC
- !---------------------------------------------------------------------------
- ! TM5 !
- !---------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: distribute1x1
- !
- ! !DESCRIPTION: subroutine to distribute 1x1 emissions linearly between
- ! hlow and hhigh. The vertical level is determined by
- ! the orography which is read from the surface file...
- ! A simple scale height vertical structure is assumed.
- !
- ! To be called by one processor, with a global 2D oro input
- !\\
- !\\
- ! !INTERFACE:
- !
- SUBROUTINE DISTRIBUTE1X1( emi1x1, hlow, hhigh, emis3d, oro, status, xfrac)
- !
- ! !USES:
- !
- use Binas, only : grav
- use dims, only : nlon360, nlat180, lm, itau, staggered, at, bt
- !
- ! !INPUT PARAMETERS:
- !
- real, dimension(nlon360,nlat180), intent(in) :: emi1x1 ! (kg/1x1 gridbox) 2D field of emissions
- real, dimension(nlon360,nlat180), intent(in) :: hlow ! (m) lower bound of emission
- real, dimension(nlon360,nlat180), intent(in) :: hhigh ! (m) higher bound of emission
- real, dimension(nlon360,nlat180), intent(in) :: oro ! (m m/s2)
- real, intent(in), optional :: xfrac ! fraction of emissions to put
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- real, dimension(nlon360,nlat180,lm(1)), intent(inout) :: emis3d ! (kg/box) distributed in height
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 8 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
-
- character(len=*), parameter :: rname = mname//'/distribute1x1'
-
- real, parameter :: scalh = 8000.0
- real :: p0, pt
- real, dimension(lm(1)) :: height, dz
- integer :: i,j,l
- real :: hh,hl,dze,totw,f,e3da,e3db, fract
-
- ! --- begin -----------------------------------
- if (present(xfrac)) then
- fract = xfrac
- else
- fract = 1.0
- endif
-
- e3db = sum(emis3d)
- do j=1,nlat180
- do i=1,nlon360
- if (fract*emi1x1(i,j) > 1e-14) then
- height(1) = oro(i,j)/grav
- p0 = 1e5*exp(-height(1)/scalh)
- do l=1,lm(1)-1 ! bug reported by FD: alog(0) crashes!
- pt = at(l+1) + bt(l+1)*p0
- height(l+1) = height(1)-scalh*alog(pt/p0)
- dz(l) = height(l+1)-height(l)
- enddo
- hl = max(height(1),hlow(i,j))
- hh = max(hhigh(i,j),height(1))
- dze = hh-hl
- if(dze < 0.0) then
- status=1
- IF_NOTOK_RETURN(status=1)
- else if ( dze == 0.0) then ! this somehow happens!
- hh = height(1)+1.0
- hl = height(1)
- endif
- totw = 0.0
- zz: do l=1, lm(1)
- if (hh > height(l+1)) then
- if ( hl < height(l) ) then
- f = dz(l)/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- else if( hl < height(l+1)) then
- f = (height(l+1)-hl)/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- endif
- else
- if ( hl < height(l)) then
- f = (hh - height(l))/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- else
- totw = totw + 1.0
- emis3d(i,j,l) = emis3d(i,j,l) + fract*emi1x1(i,j)
- endif
- exit zz
- endif
- enddo zz
- if ( abs(totw-1.0) > 1e-14 ) then
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
-
- endif
- enddo
- enddo
- e3da = sum(emis3d)
- if (abs(e3da-e3db-sum(fract*emi1x1)) > e3da*1e-8 ) then
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- status=0
-
- END SUBROUTINE DISTRIBUTE1X1
- !EOC
-
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: DISTRIBUTE1X1B
- !
- ! !DESCRIPTION: same as DISTRIBUTE1X1, but with scalar for HLOW and HHIGH
- !
- ! Is it still used ????
- !
- ! subroutine to distribute 1x1 emissions linearly between
- ! hlow and hhigh. The vertical level is determined by
- ! the orography which is read from the surface file...
- ! A simple scale height vertical structure is assumed.
- ! same as distribute1x1 but hlow, hhigh now scalar
- ! ALSO: the height is now defined relative to the orography!
- !\\
- !\\
- ! !INTERFACE:
- !
- SUBROUTINE DISTRIBUTE1X1B( emi1x1, hlow, hhigh, emis3d, oro, status, xfrac)
- !
- ! !USES:
- !
- use Binas, only : grav
- use dims, only : nlon360, nlat180, lm, itau, staggered, at, bt
- !
- ! !INPUT PARAMETERS:
- !
- real, dimension(nlon360,nlat180), intent(in) :: emi1x1 ! (kg/1x1 gridbox) 2D field of emissions
- real, intent(in) :: hlow ! (m) lower bound of emission
- real, intent(in) :: hhigh ! (m) higher bound of emission
- real, dimension(nlon360,nlat180), intent(in) :: oro ! (m m/s2)
- real, intent(in), optional :: xfrac ! fraction of emissions to put
- !
- ! !INPUT/OUTPUT PARAMETERS:
- !
- real, dimension(nlon360,nlat180,lm(1)), intent(inout) :: emis3d ! (kg/box) distributed in height
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 8 May 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/distribute1x1b'
- real, parameter :: scalh = 8000.0
- real :: p0, pt
- real, dimension(lm(1)) :: height, dz
- integer :: i,j,l
- real :: hh,hl,dze,totw,f,e3da,e3db, fract, hlow_oro, hhigh_oro
- ! --- begin -----------------------------------
- if (present(xfrac)) then
- fract = xfrac
- else
- fract = 1.0
- endif
- e3db = sum(emis3d)
- do j=1,nlat180
- do i=1,nlon360
- if (fract*emi1x1(i,j) > 1e-14) then
- height(1) = oro(i,j)/grav
- hlow_oro = hlow + height(1)
- hhigh_oro = hhigh + height(1)
- p0 = 1e5*exp(-height(1)/scalh)
- do l=1,lm(1)-1 ! bug reported by FD: alog(0) crashes!
- pt = at(l+1) + bt(l+1)*p0
- height(l+1) = height(1)-scalh*alog(pt/p0)
- dz(l) = height(l+1)-height(l)
- enddo
- hl = max(height(1),hlow_oro)
- hh = max(hhigh_oro,height(1))
- dze = hh-hl
- if(dze < 0.0) then
- status=1
- IF_NOTOK_RETURN(status=1)
- else if ( dze == 0.0) then ! this somehow happens!
- hh = height(1)+1.0
- hl = height(1)
- endif
- totw = 0.0
- zz: do l=1, lm(1)
- if (hh > height(l+1)) then
- if ( hl < height(l) ) then
- f = dz(l)/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- else if( hl < height(l+1)) then
- f = (height(l+1)-hl)/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- endif
- else
- if ( hl < height(l)) then
- f = (hh - height(l))/dze
- totw = totw + f
- emis3d(i,j,l) = emis3d(i,j,l) + f*fract*emi1x1(i,j)
- else
- totw = totw + 1.0
- emis3d(i,j,l) = emis3d(i,j,l) + fract*emi1x1(i,j)
- endif
- exit zz
- endif
- enddo zz
- if ( abs(totw-1.0) > 1e-14 ) then
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
-
- endif
- enddo
- enddo
-
- e3da = sum(emis3d)
- if (abs(e3da-e3db-sum(fract*emi1x1)) > e3da*1e-8 ) then
- status=1
- IF_NOTOK_RETURN(status=1)
- end if
- status=0
- END SUBROUTINE DISTRIBUTE1X1B
- !EOC
- !--------------------------------------------------------------------------
- ! TM5 !
- !--------------------------------------------------------------------------
- !BOP
- !
- ! !IROUTINE: TROPOSPHERIC_COLUMNS
- !
- ! !DESCRIPTION: Routine to integrate tropospheric (ozone)
- ! note: routine is now written for Ozone, but may be changed
- ! to be more general. The definition of tropopause is critical for ozone.
- ! here, the slope is used in the interpolation.
- ! multiple tropopause values are ignored, but are known to
- ! occur. The lowest crossing of thres is used.
- ! In the lower atmosphere > 600 hPa, values > thres are ignored.
- !\\
- !\\
- ! !INTERFACE:
- !
- subroutine tropospheric_columns(region, field, slope, column, thres, xmo3, status)
- !
- ! !USES:
- !
- use binas, only : Dobs, xmair, Avog
- use global_data, only : region_dat
- use meteodata, only : phlb_dat, m_dat
- use Dims, only : lm, isr, ier, jsr, jer, CheckShape, im, jm
- !
- ! !INPUT PARAMETERS:
- !
- integer, intent(in) :: region ! region in the TM5 zoom definition
- real, dimension(:,:,:), intent(in) :: field ! 3D field of tracer (O3)
- real, dimension(:,:,:), intent(in) :: slope ! 3D field of tracer z -slope (O3)
- !
- ! !OUTPUT PARAMETERS:
- !
- real, dimension(:,:),intent(out) :: column ! output: tropospheric column in DU
- real, intent(in) :: thres ! ppb threshold for tropospheric column
- real, intent(in) :: xmo3 ! mol mass tracer
- integer, intent(out) :: status
- !
- ! !REVISION HISTORY:
- ! 19 Jun 2012 - P. Le Sager - fix calls to CheckShape
- !
- ! !REMARKS:
- ! (1) FIXME : must be adapted for lon-lat MPI domain decomposition
- !
- !EOP
- !------------------------------------------------------------------------
- !BOC
- character(len=*), parameter :: rname = mname//'/tropospheric_columns'
-
- #ifdef with_zoom
- integer,dimension(:,:),pointer :: zoomed
- #endif
- real,dimension(:,:,:),pointer :: m
- real,dimension(:,:,:),pointer :: phlb
- real,dimension(:),pointer :: dxyp
- real, dimension(2*lm(1)+1) :: o3a
- real :: o3mm, o3mmu, o3mml, o3trop, o3ml, o3mu, frac
- integer :: i,j,l,ip
- ! FIXME
- write (gol,'("ERROR - routine not converted to TM5-MP")') ; call goErr
- status=1
- IF_NOTOK_RETURN(status=1)
-
- ! start
- call CheckShape( (/im(region),jm(region)/), shape(column), status )
- call CheckShape( (/im(region),jm(region), lm(region)/), shape(field), status )
- call CheckShape( (/im(region),jm(region), lm(region)/), shape(slope), status )
- dxyp=> region_dat(region)%dxyp
- #ifdef with_zoom
- zoomed => region_dat(region)%zoomed
- #endif
- phlb => phlb_dat(region)%data
- m => m_dat(region)%data
- ! collect ozone on mid levels and at boundaries
- ! average the estimates from upper/lower gridboxes
- ! except for bottom and top.
- !
- column(:,:) = 0.0
- do j=jsr(region), jer(region)
- do i=isr(region), ier(region)
- #ifdef with_zoom
- if(zoomed(i,j)/=region) cycle
- #endif
- do l=1,lm (region)
- ip = 2*l-1
- o3mm = xmair/xmo3*1e9*field(i,j,l)/m(i,j,l) ! level
- o3mmu = xmair/xmo3*1e9*(field(i,j,l)+slope(i,j,l))/m(i,j,l) ! top
- o3mml = xmair/xmo3*1e9*(field(i,j,l)-slope(i,j,l))/m(i,j,l) ! bottom
- if(l == 1) then
- o3a(ip) = o3mml
- else
- o3a(ip) = o3a(ip) + 0.5*o3mml
- endif
- o3a(ip+1) = o3mm
- if(l == lm(region)) then
- o3a(ip+2) = o3mmu
- else
- o3a(ip+2) = 0.5*o3mmu
- endif
- enddo
- o3trop = 0.0
- height: do l=1,lm (region)
- ip = 2*l-1
- ! split gridbox in upper and lower part
- ! for more accurate interpolation
- o3ml = 0.5*field(i,j,l) - 0.25*slope(i,j,l)
- o3mu = 0.5*field(i,j,l) + 0.25*slope(i,j,l)
- if (phlb(i,j,l) > 60000.0) then ! avoid surface o3>150ppb
- o3trop = o3trop + field(i,j,l)
- cycle height
- endif
- if (phlb(i,j,l+1) < 7000.0) exit height ! now about time 70 hPa at top
- if(o3a(ip) < thres) then ! bottom value less than thres
- if(o3a(ip+1) >= thres) then ! but central value is not
- frac = (thres - o3a(ip))/(o3a(ip+1)-o3a(ip))
- o3trop = o3trop + frac*o3ml
- exit height
- else if (o3a(ip+2) >= thres) then ! but upper is not
- frac = (thres - o3a(ip+1))/(o3a(ip+2)-o3a(ip+1))
- o3trop = o3trop + o3ml + frac*o3mu
- exit height
- else ! entire layer is not
- o3trop = o3trop + field(i,j,l)
- endif
- else
- exit height
- endif
- enddo height
- column(i,j) = o3trop*1e3/xmo3*Avog*1e-4/dxyp(j)/Dobs ! kg ->dobs
- enddo ! i
- enddo !j
- call dumpfield(0,'dump.hdf', im(region), jm(region), lm(region), 1, field, 'o3')
- call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region), 1, slope, 'o3slope')
- call dumpfield(1,'dump.hdf', im(region), jm(region), 1, 1, column, 'o3column')
- call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region)+1, 1, phlb, 'phlb')
- call dumpfield(1,'dump.hdf', im(region), jm(region), lm(region), 1, m, 'm')
- call dumpfield(1,'dump.hdf', jm(region),1, 1, 1, dxyp, 'dxyp')
- nullify(dxyp)
- #ifdef with_zoom
- nullify(zoomed)
- #endif
- nullify(phlb)
- nullify(m)
- end subroutine tropospheric_columns
- !EOC
- END MODULE TOOLBOX
|