! #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: EMISSION_DATA ! ! !DESCRIPTION: Provides general methods and fields needed for the emission ! routines. ! ! emission_vdist_by_sector : distribute vertically emissions according to source sector ! msg_emis : print formated emission total ! do_add_2d : add 2D emission to tracer mass array ! do_add_3d : add 3D emission to tracer mass array ! do_add_3d_cycle : add 3D emission to tracer mass array with a daily cycle ! scale_cycle : evaluate a daily cycle ! distribute_l44 : scale input field with NH (SH) fires distributed over JAS (JFM) !\\ !\\ ! !INTERFACE: ! MODULE EMISSION_DATA ! ! !USES: ! use GO, only : gol, goPr, goErr use Dims, only : nregions, lm use global_types, only : emis_data, d2_data, d23_data, d3_data #ifdef with_m7 use mo_aero_m7, only : nmod !use mo_aero, only : zom2oc use global_types, only : modal_emissions #endif #ifdef with_budgets use budget_global,only : budg_dat, nzon_vg #endif IMPLICIT NONE ! ! !PUBLIC DATA MEMBERS & TYPES: ! public :: emis_data, d2_data, d23_data ! type(emis_data), target :: plandr(nregions) ! Land fraction type(emis_data), target :: emis2D(nregions) ! 2D emiss prior vertical redistribution type(emis_data), target :: emis_temp(nregions) ! temp array to store emission #ifdef with_m7 type(modal_emissions), dimension(nregions,nmod), target :: emis_mass type(modal_emissions), dimension(nregions,nmod), target :: emis_number ! The value of 1.4 for the POM to OC mass ratio is an outdated estimate, ! see e.g. Turpin and Lim (Aerosol Sci. Technol., 2001) and ! Aiken et al. (Environ. Sci. Technol., 2008). ! Turpin and Lim estimate a ratio of 1.6 +- 0.2 for urban aerosol, ! and 2.1 +- 0.2 for aged (nonurban) aerosol; ! They also note that aerosols heavily impacted by woodsmoke can ! have an even higher ratio (2.2 to 2.6). ! According to Reid et al. (ACP, 2005), ! the POM to OC ratio in fresh biomass burning smoke is very uncertain, ! somewhere in between 1.4 and ~2. ! Aiken et al. measure ambient aerosol values ! between 1.25 for O/C = 0 to 2.44 for O/C = 1.0. ! For OA from biomass burning, they measure 1.56-1.70, ! lower than the estimates from Turpin and Lim (~2.0). ! They find the highest ratios for ! aged and freshly formed SOA (~2.4 and ~1.9, respectively) ! and lowest values for primary OA from urban combustion. ! Based on these studies, we apply different values ! for emissions from biomass burning versus other emissions, ! as is also done in some other models ! (see Table 1 in Tsigaridis et al., ACP, 2014), ! For SOA (seem emission_pom.F90) ! we apply a relatively high value valid for aged SOA. ! This compensates for the lack of SOA formation from isoprene, ! and improves the agreement with aerosol optical depth (AOD) ! derived from satellite observations (MODIS). ! ! We could go even further and apply different values for the ! water soluble and insoluble fractions (Turpin and Lim). ! ! It should be acknowledged that the representation of OA ! with a single tracer is very simplistic. ! In particular, increase in OA mass due to ageing ! is not properly accounted for. ! !real, parameter :: oc2pom = zom2oc !factor for conversion of OC mass to POM real, parameter :: oc2pom_ff = 1.6 real, parameter :: oc2pom_vg = 1.6 real, parameter :: oc2pom_soa = 2.4 #endif ! AR5 - EDGAR4 - RETRO - GFED3 - MACC - LPJ - HYMN - MEGAN logical :: LAR5, LAR5BMB, LEDGAR4, LRETROF, LGFED3, LMACC, LLPJ, LHYMN, LMACCITY, LMEGAN character(len=256) :: emis_input_dir character(len=256) :: emis_input_dir_ar5 character(len=256) :: emis_input_dir_megan character(len=256) :: emis_input_dir_ed4 character(len=256) :: emis_input_dir_mac integer :: emis_input_year character(len=256) :: emis_input_dir_gfed character(len=256) :: emis_input_dir_retro character(len=256) :: emis_input_dir_aerocom character(len=256) :: emis_input_dir_dms character(len=256) :: emis_input_dir_rn222 character(len=256) :: emis_input_dir_dust, emis_input_dust #ifdef with_ch4_emis character(len=256) :: emis_input_dir_natch4 #endif logical :: emis_ch4_single logical :: emis_ch4_fix3d real :: emis_ch4_fixed_ppb character(len=256) :: emis_zch4_fname ! biomass burning levels: integer, parameter :: bb_nlev = 5 integer, parameter :: bb_lm = lm(1) ! to be reduced to strip stratosphere! integer, parameter :: bl_lm = lm(1) ! to be reduced to the BL (around 8) real, parameter :: bb_hlow (0:bb_nlev) = (/ 0., 100., 500., 1000., 2000., 3000./) real, parameter :: bb_hhigh(0:bb_nlev) = (/ 100., 500., 1000., 2000., 3000., 6000./) ! biomass burning levels in tropics (-20 - 20):: integer, parameter :: bb_nlev_trop = 3 real, parameter :: bb_hlow_trop (0:bb_nlev_trop) = (/ 0., 100., 500., 1000./) real, parameter :: bb_hhigh_trop(0:bb_nlev_trop) = (/ 100., 500., 1000., 2000./) ! ----------------------------------------------------------------------------------- ! Biomassburning time splitting factors (now globally, instead of by constituent) logical :: emis_bb_trop_cycle type bb_cycle_data real, pointer :: scalef(:) end type bb_cycle_data type(bb_cycle_data), dimension(nregions), target :: bb_cycle ! ----------------------------------------------------------------------------------- ! Budgets #ifdef with_budgets real, dimension(nregions) :: sum_emission type budemi_data real,dimension(:,:,:,:),pointer :: emi ! [i, j, nbud_vg, ntracet] end type budemi_data type(budemi_data),dimension(nregions),target :: budemi_dat #endif logical :: use_tiedkte ! read from rc file, used to scale LiNOx ! ---------------------------------------------------- ! Vertical splitting : used now for all sectors, for biomassburning and other categories ! (tables in Dentener, 2006, ACP) ! ! ATTENTION: changes here have impact on the routine emission_vdist_by_sector (contained) ! Note: vdist_* variable could be hold private ! integer, parameter :: vd_class_name_len = 12 ! biomassburning integer, parameter :: vdist_bb_nlev = 6 real,dimension(vdist_bb_nlev),parameter :: vdist_bb_hlow = (/ 0., 100., 500., 1000., 2000., 3000./) real,dimension(vdist_bb_nlev),parameter :: vdist_bb_hhigh = (/ 100., 500., 1000., 2000., 3000., 6000./) ! other sources (related to surface) integer, parameter :: vdist_nn_nlev = 6 real,dimension(vdist_nn_nlev),parameter :: vdist_nn_hlow = (/ 0., 30. , 100., 300., 600., 1000. /) real,dimension(vdist_nn_nlev),parameter :: vdist_nn_hhigh = (/ 30., 100., 300., 600., 1000., 2000. /) ! ! !PRIVATE TYPES: ! character(len=*), parameter, private :: mname = 'emission_data' ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - adapted for AR5 ! 28 Jun 2012 - Ph. Le Sager - made everything public by default ! - adapted for lon-lat MPI domain decomposition ! !REMARKS: ! !EOP !------------------------------------------------------------------------ CONTAINS !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: EMISSION_VDIST_BY_SECTOR ! ! !DESCRIPTION: Return vertically distributed emissions depending on given ! sector and constituent. ! Distribution is done as 'compromise' between ! 1) Dentener et al., 2006, ACP, slightly modified for ! emissions supposed to enter the surface layer. ! 2) De Meij et al., ACP, 2006 ! 3) EMEP model (docu, model code, publications) ! 4) Bieser et al., GMDD, 2010 ! 5) Small updates to biomassburning following ! Huijnen et al., GMDD, 2010 !\\ !\\ ! !INTERFACE: ! SUBROUTINE EMISSION_VDIST_BY_SECTOR( splitname, constituent, region, emis2D, emis3D, status ) ! ! !USES: ! use toolbox, only : distribute_emis2D ! ! !INPUT PARAMETERS: ! character(len=vd_class_name_len), intent(in) :: splitname character(len=*), intent(in) :: constituent integer, intent(in) :: region type(emis_data), intent(in) :: emis2D ! ! !INPUT/OUTPUT PARAMETERS: ! type(d3_data), intent(out) :: emis3D ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: status ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - v0 ! ! !REMARKS: Splitting depending on constituent is still to code. ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/emission_vdist_by_sector' integer :: ilev character(len=2) :: splittype integer, parameter :: maxvdist_nlev = max(vdist_bb_nlev,vdist_nn_nlev) real, dimension(maxvdist_nlev) :: sfglobal, sfintrop, sfintemp ! --- begin -------------------------------------- ! control implicit settings here in this routine if( vdist_bb_nlev /= 6 .or. vdist_nn_nlev /= 6 ) then write(gol, '("ERROR: wrong number of layers: bb_nlev /= 6 or nn_lev /= 6")'); call goErr status=1; return end if ! initialise sfglobal = 0.0 sfintrop = 0.0 sfintemp = 0.0 emis3d%d3= 0.0 ! ------------------------------------------------- ! This here is selection by emission source sectors ! ------------------------------------------------- select case( trim(splitname) ) case( 'combenergy' ) ! Combustion from energy production and transformation, power-plants ! no zonal differences, no dependency on species ! -- ! assumed to be related to EMEP SNAP category [1] ! AEROCOM equivalent: power-plants ! -- splittype = 'nn' sfglobal = (/ 0.0, 0.1, 0.7, 0.2, 0.0, 0.0 /) case( 'combrescom' ) ! Residential and commercial combustion ! no zonal differences, no dependency on species ! -- ! assumed to be related to EMEP SNAP category [2] ! AEROCOM equivalent: domestic/industry ! -- splittype = 'nn' sfglobal = (/ 0.4, 0.4, 0.2, 0.0, 0.0, 0.0 /) case( 'industry' ) ! Industrial processes and combustion ! no zonal differences, no dependency on species ! -- ! assumed to be an aggregate of EMEP SNAP categories [3,4,5] ! AEROCOM equivalent: industry ! -- splittype = 'nn' sfglobal = (/ 0.1, 0.2, 0.6, 0.1, 0.0, 0.0 /) case( 'waste' ) ! Waste treatment and disposal ! no zonal differences, no dependency on species ! -- ! assumed to be related to EMEP SNAP category [9] ! AEROCOM equivalent: - ! -- splittype = 'nn' sfglobal = (/ 0.1, 0.2, 0.4, 0.3, 0.0, 0.0 /) case( 'nearsurface' ) ! Near surface emissions ! no zonal differences, no dependency on species ! -- ! AR5: solvent production and use, agricultural waste burning, & ! ships, grassland fire, mineral dust (AEROCOM or Tegen-Vignati) ! EMEP equivalents: SNAP categories [6,8] ! AEROCOM equivalents: ships, agricultural waste ! -- splittype = 'nn' sfglobal = (/ 0.8, 0.2, 0.0, 0.0, 0.0, 0.0 /) case( 'surface' ) ! Surface emissions ! no zonal differences, no dependency on species ! -- ! AR5: agriculture, transport, soil, oceanic, biogenic ! EMEP equivalents: SNAP categories [7,8,10] ! AEROCOM equivalents: surface emissions from road/off-road, ships, agricultural waste ! -- splittype = 'nn' sfglobal = (/ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 /) !!$ case ( 'mindust' ) !!$ ! Mineral dust emissions !!$ ! no zonal differences !!$ ! -- !!$ ! AR5: surface dust emissions from either from AEROCOM or Tegen-Vignati !!$ ! assumed to be slightly higher than near-surface !!$ splittype = 'nn' !!$ sfglobal = (/ 0.8, 0.2, 0.0, 0.0, 0.0, 0.0 /) case( 'volcanic' ) ! Volcanic emissions ! -- ! AR5: natural SOx emissions (from MACC repository) ! EMEP equivalents: SNAP categories [11] ! AEROCOM equivalents: continuous: 2/3 to 1 of height of volcano top ! explosive: 0.5 to 1.5 km above volcano top ! Since no data is available about volcano top levels, we assume here, that ! a volcano top is usually 200-1000 m higher than the grid's surrounding terrain ! height, thus emissions are distributed from 100 - 2000 m almost homogeneously ! -- splittype = 'nn' sfglobal = (/ 0.0, 0.0, 0.1, 0.3, 0.4, 0.2 /) case( 'forestfire' ) ! forest fires: 6 layer model, different splitting for different regions ! dont distinguish between boreal Europe and boreal Canada, use Europe globally ! Dentener et al., modified in tropics (up to 2 km) with respect to Huijnen et al., GMD 2010, \ ! who are citing Labonne et al., 2007 ofr new information based on satellite data. splittype = 'bb' sfglobal = (/ 0.1, 0.1, 0.2, 0.2, 0.4, 0.0 /) sfintemp = (/ 0.2, 0.2, 0.2, 0.4, 0.0, 0.0 /) sfintrop = (/ 0.2, 0.2, 0.2, 0.4, 0.0, 0.0 /) case default write(gol, '("ERROR: wrong specification of emission sector ",a,"in vdist_by_sector called for constituent ",a)') & trim(splitname), trim(constituent); call goErr status=1; return end select ! -------------------- ! Do the splitting - ! no need to skip cases of fraction (sfglobal, sfintemp, ..) being zero: ! distribute_emis2D is optimized for those and will return right away ! -------------------- select case( splittype ) case( 'nn' ) do ilev = 1, vdist_nn_nlev call distribute_emis2D( region, emis2D, emis3D, vdist_nn_hlow(ilev), vdist_nn_hhigh(ilev), status, sfglobal(ilev) ) IF_NOTOK_RETURN(status=1) end do case( 'bb' ) do ilev = 1, vdist_bb_nlev ! boreal call distribute_emis2D( region, emis2D, emis3D, vdist_bb_hlow(ilev), vdist_bb_hhigh(ilev), status, & sfglobal(ilev), -90.,-61.) IF_NOTOK_RETURN(status=1) call distribute_emis2D( region, emis2D, emis3D, vdist_bb_hlow(ilev), vdist_bb_hhigh(ilev), status, & sfglobal(ilev), 60., 90.) IF_NOTOK_RETURN(status=1) ! temperate call distribute_emis2D( region, emis2D, emis3D, vdist_bb_hlow(ilev), vdist_bb_hhigh(ilev), status, & sfintemp(ilev), -60.,-31.) IF_NOTOK_RETURN(status=1) call distribute_emis2D( region, emis2D, emis3D, vdist_bb_hlow(ilev), vdist_bb_hhigh(ilev), status, & sfintemp(ilev), 30., 59.) IF_NOTOK_RETURN(status=1) ! tropics call distribute_emis2D( region, emis2D, emis3D, vdist_bb_hlow(ilev), vdist_bb_hhigh(ilev), status, & sfintrop(ilev), -30., 29.) IF_NOTOK_RETURN(status=1) end do case default write(gol, '("ERROR: wrong specification of splitting type in vdist_by_sector.")'); call goErr status=1; return end select ! OK status=0 END SUBROUTINE EMISSION_VDIST_BY_SECTOR !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: MSG_EMIS ! ! !DESCRIPTION: Provide output to verify the amount of emissions ! entering the calculations !\\ !\\ ! !INTERFACE: ! SUBROUTINE MSG_EMIS(year_month, provider, sector, msg_comp, msg_mass, summed_emissions) ! ! !USES: ! use dims, only: idate ! ! !INPUT PARAMETERS: ! integer, intent(in) :: year_month ! 1: year, 2: monthly amount character(len=*), intent(in) :: provider, sector, msg_comp real, intent(in) :: msg_mass, summed_emissions ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - protex; increase space for output ! !EOP !------------------------------------------------------------------------ !BOC character(len=7),dimension(2), parameter:: ym=(/'Yearly ','Monthly'/) 1111 format(' EMISS-INFO - ',a7,' Emission from ',a8,' -> ',a18,1x,a6,' : mw=',f5.1,', month=',i2.2,', Sum [kg]=',1x,1pe11.4) 1112 format(' EMISS-INFO - ',a7,' Emission from ',a8,' -> ',a18,1x,a6,' : mw=',f5.1,', --------, Sum [kg]=',1x,1pe11.4) if (year_month==1) then write (gol,1112) ym(year_month), provider, sector, msg_comp, msg_mass, summed_emissions; call goPr else write (gol,1111) ym(year_month), provider, sector, msg_comp, msg_mass, idate(2), summed_emissions; call goPr endif END SUBROUTINE MSG_EMIS !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: SCALE_CYCLE ! ! !DESCRIPTION: Evaluates a daily cycle to be used for the biomass ! burning emissions. It is based on the isoprene daily ! cycle, except that the max peak is at 14:00h LT. ! Calculates factors to be multiplied with an ! emission field (e.g. co) in order to simulate a ! diurnal cycle in emissions (caused by solar dependency/ ! human activity), e.g. ! rm(i,j,1,isop) = rm(i,j,1,isop) + e_isop(i,j)*scalef(ipos,j)*dt ! with ipos depending on time and longitude. ! The scalefactor is calculated for -180 longitude and ! the mean value for ntim timesteps during a day is scaled ! to 1. ! The routine should be called only once, since ! the position relative to the sun is not relevant here. !\\ !\\ ! !INTERFACE: ! SUBROUTINE SCALE_CYCLE(ntim, scalef) ! ! !INPUT PARAMETERS: ! integer, intent(in) :: ntim ! ! !OUTPUT PARAMETERS: ! real, dimension(ntim), intent(out) :: scalef ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - added without_diurnal_emission_cycle ! (to be removed again :-( ) ! 19 Oct 2010 - Narcisa Banda - changed without_diurnal_emission_cycle to with_.... ! 31 Jan 2013 - Ph. Le Sager - get rid of with_diurnal_emission_cycle! ! ! !REMARKS: ! - This routine is called only once (see emission.F90), and only if ! emis_bb_trop_cycle is .true.. The later is set with the ! input.emis.bb.dailycycle in the rc file (chem.input.rc) ! !EOP !------------------------------------------------------------------------ !BOC real :: pi, piby, obliq, deday, delta, dt, lon, hr, lat, houra, smm, w, sig integer :: i ! The calling routine (emission_declare) defines NTIM as follows: ! dtime=float(ndyn_max)/(2*tref(region)) ! timestep emissions ! ntim=86400/nint(dtime) ! number of timesteps in 24 hours. pi = acos(-1.0) piby = pi/180.0 ! obliq = 23.45 * piby w = 0.2 sig = 2.0 dt = 24./ntim !timestep in hours lon = -180.0*piby !calculate for dateline hr = - 0.5*dt !shift half an interval back if (hr .gt. 12) hr = hr - 24 ! hr = hr - 2 !shift two hours. This means that Local-day-time maximum will be at 14:00 h LT. smm = 0.0 do i=1,ntim hr = hr + dt houra = lon - pi + hr * (2.*pi/24.) scalef(i) = w + (1-w)*24.0/(sig*sqrt(2*pi))*exp(-0.5*(((hr-1.5)/sig)**2)) ! scalef(i) = max(1+(cos(houra)),0.0) smm = smm+scalef(i)/ntim end do if ( smm > 1e-5 ) then scalef(1:ntim) = scalef(1:ntim)/smm else scalef(1:ntim) = 1.0 end if END SUBROUTINE SCALE_CYCLE !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DO_ADD_2D ! ! !DESCRIPTION: General routine to add a 2D emission field (given in kg ! /month) into tracer mass array. The mass increase is done ! at level L_LEVEL, and for tracer I_TRACER. ! ! Update accordingly the budget. !\\ !\\ ! !INTERFACE: ! SUBROUTINE DO_ADD_2D( region, i_tracer, l_level, is, js, emis_field, & mol_mass, mol_mass_e, status, xfrac ) ! ! !USES: ! use dims, only : CheckShape, tref, nsrce use dims, only : sec_month, im, jm, okdebug use global_data, only : mass_dat, region_dat use chem_param, only : ntracet, names use tm5_distgrid, only : get_distgrid, dgrid #ifdef with_budgets use budget_global, only : budg_dat, nzon_vg #endif ! ! !INPUT PARAMETERS: ! integer, intent(in) :: region integer, intent(in) :: i_tracer integer, intent(in) :: l_level integer, intent(in) :: is, js real, intent(in) :: emis_field(is:,js:) real, intent(in) :: mol_mass ! mol mass of tracer field real, intent(in) :: mol_mass_e ! mol mass of emission field (e.g. NOx emission ar in kgN/month) real, intent(in), optional :: xfrac ! partial addition ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: status ! ! !REVISION HISTORY: ! 27 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/do_add_2d' integer :: i, j, nzone, nzone_v, i1, i2, j1, j2 real :: x, efrac, dtime, month2dt real :: mbef, maft, sume ! mass BEFore, AFTer, SUM Emiss (debug) real, dimension(:,:,:,:), pointer :: rm, rzm ! --- begin -------------------------------------- call GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 ) call CheckShape( (/i2-i1+1,j2-j1+1/), shape(emis_field), status ) IF_NOTOK_RETURN(status=1) dtime=float(nsrce)/(2*tref(region)) ! timestep emissions month2dt=dtime/sec_month ! conversion to emission per timestep rm => mass_dat(region)%rm rzm => mass_dat(region)%rzm if(present(xfrac)) then efrac = xfrac else efrac = 1.0 endif if (okdebug) then write (gol, '("--------------------------------------------------------------")') ; call goPr write (gol, '(" DO ADD 2D debug in region:",i3) ' ) region ; call goPr write (gol, '(" itracer :",i3,a8)' ) i_tracer, ' :'//names(i_tracer) ; call goPr write (gol, '(" xfrac :",f6.1)' ) efrac ; call goPr write (gol, '(" mol_mass :",f6.1 ) ' ) mol_mass ; call goPr write (gol, '(" mol_mass_e :",f6.1 )' ) mol_mass_e ; call goPr write (gol, '(" emisfield :",2e12.4 )') minval(emis_field),maxval(emis_field) ; call goPr sume = sum(emis_field)*month2dt*(mol_mass/mol_mass_e)*efrac write (gol, '(" sum emmis :",e12.4 )' ) sume ; call goPr mbef = sum(rm(i1:i2,j1:j2,:,i_tracer)) endif do j=j1,j2 do i=i1,i2 x = emis_field(i,j)*month2dt*(mol_mass/mol_mass_e)*efrac rm(i,j,l_level,i_tracer) = rm(i,j,l_level,i_tracer) + x #ifdef slopes ! injection of emissions at surface, thus vertical slope more negative ! (keep concentration at top of layer the same as before emission) if ( i_tracer <= ntracet ) then rzm(i,j,l_level,i_tracer) = rzm(i,j,l_level,i_tracer) - x end if #endif #ifdef with_budgets nzone = budg_dat(region)%nzong(i,j) !global budget nzone_v = nzon_vg(l_level) budemi_dat(region)%emi(i,j,nzone_v,i_tracer) = & budemi_dat(region)%emi(i,j,nzone_v,i_tracer) + x/mol_mass*1e3 if(i_tracer == 1) sum_emission(region) = sum_emission(region) + x !in kg #endif enddo enddo if (okdebug) then maft = sum(rm(i1:i2,j1:j2,:,i_tracer)) write (gol, '(" Added amount :",e12.4 )' ) maft-mbef ; call goPr write (gol, '(" Added amount can be different when inner zoom is present!" )' ) ; call goPr if (maft-mbef-sume > 1e-8*sume) then write (gol, '(" Warning: error in emission ")' ) ; call goErr endif endif nullify(rm) nullify(rzm) status=0 END SUBROUTINE DO_ADD_2D !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DO_ADD_3D ! ! !DESCRIPTION: General routine to add a 3D emission field (given in kg ! /month) into tracer mass array. The mass increase is done ! for tracer I_TRACER. ! ! Update accordingly the budget. !\\ !\\ ! !INTERFACE: ! SUBROUTINE DO_ADD_3D( region, i_tracer, is, js, emis_field, mol_mass, mol_mass_e, status, xfrac) ! ! !USES: ! use dims, only : CheckShape, nsrce, tref use dims, only : sec_month, im, jm, lm, okdebug use global_data, only : mass_dat, region_dat use chem_param, only : ntracet, names use tm5_distgrid, only : get_distgrid, dgrid #ifdef with_budgets use budget_global, only : budg_dat, nzon_vg #endif ! ! !INPUT PARAMETERS: ! integer, intent(in) :: region ! region # integer, intent(in) :: i_tracer ! id of tracer to increase integer, intent(in) :: is, js real, intent(in) :: emis_field(is:,js:,:) real, intent(in) :: mol_mass, mol_mass_e real, intent(in), optional :: xfrac !partial addition ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: status ! ! !REVISION HISTORY: ! 27 Mar 2012 - P. Le Sager - adapted for lon-lat MPI domain decomposition ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/do_add_3d' integer :: i, j, l, nzone, nzone_v, i1,j1,i2,j2 integer, dimension(3) :: ubound_e real :: x, efrac, dtime, month2dt real, dimension(:,:,:,:), pointer :: rm real :: mbef, maft, sume ! debug ! --- begin -------------------------------------- call GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 ) status = 0 ! check arguments ubound_e = ubound(emis_field) if(ubound_e(1) /= i2) then write(gol,'(A)') 'do_add_3d: im emission not consistent' ; call goPr status = 1 endif if(ubound_e(2) /= j2) then write(gol,'(A)') 'do_add_3d: jm emission not consistent' ; call goPr status = 1 endif if(ubound_e(3) > lm(region)) then write(gol,'(A)') 'do_add_3d: lm emission not consistent' ; call goPr status = 1 endif IF_NOTOK_RETURN(status=1) rm => mass_dat(region)%rm dtime=float(nsrce)/(2*tref(region)) ! timestep emissions month2dt=dtime/sec_month ! conversion to emission per timestep if(present(xfrac)) then efrac = xfrac else efrac = 1.0 endif ! if (okdebug) then ! write (gol, '("--------------------------------------------------------------")') ; call goPr ! write (gol, '(" DO ADD 3D debug in region:",i3) ' ) region ; call goPr ! write (gol, '(" itracer :",i3,a8)' ) i_tracer, ' :'//names(i_tracer) ; call goPr ! write (gol, '(" xfrac :",f6.1)' ) efrac ; call goPr ! write (gol, '(" mol_mass :",f6.1 ) ' ) mol_mass ; call goPr ! write (gol, '(" mol_mass_e :",f6.1 )' ) mol_mass_e ; call goPr ! write (gol, '(" emisfield :",2e12.4 )') minval(emis_field), maxval(emis_field) ; call goPr ! write (gol, '(" ubound(3) :",i3 )' ) ubound_e(3) ; call goPr ! sume = sum(emis_field)*month2dt*(mol_mass/mol_mass_e)*efrac ! write (gol, '(" sume :", e12.4 )') sume ; call goPr ! mbef = sum(rm(i1:i2,j1:j2,:,i_tracer)) ! endif do l=1,ubound_e(3) do j=j1,j2 do i=i1,i2 x = emis_field(i,j,l)*month2dt*(mol_mass/mol_mass_e)*efrac rm(i,j,l,i_tracer) = rm(i,j,l,i_tracer) + x #ifdef with_budgets ! budget___ nzone=budg_dat(region)%nzong(i,j) !global budget nzone_v=nzon_vg(l) budemi_dat(region)%emi(i,j,nzone_v,i_tracer) = & budemi_dat(region)%emi(i,j,nzone_v,i_tracer) + x/mol_mass*1e3 if(i_tracer ==1) sum_emission(region) = sum_emission(region) + x !in kg #endif enddo enddo enddo !levels ! if (okdebug) then ! maft = sum(rm(i1:i2,j1:j2,:,i_tracer)) ! write (gol, '(" after-before :", e12.4 )' ) maft-mbef ; call goPr ! write (gol, '(" END debug output ")' ) ; call goPr ! endif nullify(rm) END SUBROUTINE DO_ADD_3D !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DO_ADD_3D_CYCLE ! ! !DESCRIPTION: Routine to add a 3D emission field (given in kg/month), ! scaled with a daily cycle. To be used for biomass burning ! emissions. !\\ !\\ ! !INTERFACE: ! SUBROUTINE DO_ADD_3D_CYCLE( region, i_tracer, is, js, emis_field, curr_cycle, mol_mass, mol_mass_e, status, xfrac) ! ! !USES: ! use dims, only : CheckShape, tref, nsrce, itaur use dims, only : sec_month, im,jm,lm, okdebug use dims, only : ndyn_max,dx, xref, xbeg,dy,yref,ybeg use global_data, only : mass_dat, region_dat use chem_param, only : ntracet, names use tm5_distgrid, only : get_distgrid, dgrid #ifdef with_budgets use budget_global, only : budg_dat, nzon_vg #endif use datetime, only : tau2date use toolbox, only : dumpfield ! ! !INPUT PARAMETERS: ! integer, intent(in) :: region integer, intent(in) :: i_tracer integer, intent(in) :: is, js real, intent(in) :: emis_field(is:,js:,:) real, dimension(:), intent(in) :: curr_cycle real, intent(in) :: mol_mass ! first is the mass of tracer field real, intent(in) :: mol_mass_e ! mass of emission field (e.g. NOx emission ar in kgN/month) real, intent(in), optional :: xfrac ! partial addition ! ! !OUTPUT PARAMETERS: ! integer, intent(out) :: status ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - v0 based on do_add_3d ! 20 Jun 2012 - Ph. Le Sager - adapted for lon-lat MPI domain decomposition ! ! !REMARKS: ! !EOP !------------------------------------------------------------------------ !BOC character(len=*), parameter :: rname = mname//'/do_add_3d_cycle' integer :: i, j, l, ipos, nzone, nzone_v integer,dimension(6) :: idater integer :: sec_in_day, ntim, itim, i1, j1, i2, j2 integer, dimension(3) :: ubound_e real :: x, xlon, xlat, efrac, dtime, month2dt, dtime2 real,dimension(:,:,:,:),pointer :: rm real :: mbef, maft, sume ! --- begin -------------------------------------- call GET_DISTGRID( dgrid(region), I_STRT=i1, I_STOP=i2, J_STRT=j1, J_STOP=j2 ) status = 0 ! check arguments ubound_e = ubound(emis_field) if(ubound_e(1) /= i2) then write(gol,'(A)') 'do_add_3d: im emission not consistent' ; call goPr status = 1 endif if(ubound_e(2) /= j2) then write(gol,'(A)') 'do_add_3d: jm emission not consistent' ; call goPr status = 1 endif if(ubound_e(3) > lm(region)) then write(gol,'(A)') 'do_add_3d: lm emission not consistent' ; call goPr status = 1 endif IF_NOTOK_RETURN(status=1) rm => mass_dat(region)%rm dtime = float(nsrce)/(2*tref(region)) !timestep emissions month2dt = dtime/sec_month ! conversion to emission per timestep dtime2 = float(ndyn_max)/(2*tref(region)) !timestep emissions based on non-CFL interference (CMK 05/2006) ntim = 86400/nint(dtime2) !number of timesteps in 24 hours based on non-CFL interference (CMK 05/2006) call tau2date(itaur(region),idater) sec_in_day = idater(4)*3600 + idater(5)*60 + idater(6) !elapsed seconds this day itim = sec_in_day/nint(dtime2)+1 !time interval if(present(xfrac)) then efrac = xfrac else efrac = 1.0 endif ! if (okdebug) then ! write (gol, '("--------------------------------------------------------------")') ; call goPr ! write (gol, '(" DO ADD 3D CYCLE debug in region:",i3) ' ) region ; call goPr ! write (gol, '(" itracer :",i3,a8)' ) i_tracer, ' :'//names(i_tracer) ; call goPr ! write (gol, '(" xfrac :",f6.1)' ) efrac ; call goPr ! write (gol, '(" mol_mass :",f6.1 ) ' ) mol_mass ; call goPr ! write (gol, '(" mol_mass_e :", f6.1 )' ) mol_mass_e ; call goPr ! write (gol, '(" emisfield :", 2e12.4 )') minval(emis_field),maxval(emis_field) ; call goPr ! write (gol, '(" ubound(3) :", i3 )' ) ubound_e(3) ; call goPr ! sume = sum(emis_field)*month2dt*(mol_mass/mol_mass_e)*efrac ! write (gol, '(" sume :", e12.4 )' ) sume ; call goPr ! mbef = sum(rm(i1:i2,j1:j2,:,i_tracer)) ! write (gol,*) 'lbounds:', is,i1,js,j1 ; call goPr ! endif do l=1,ubound_e(3) do j=j1,j2 do i=i1,i2 xlat = ybeg(region) + (j-0.5)*dy/yref(region) if (xlat .gt. -20 .and. xlat .lt. 20) then ! apply emission cycle in tropics only ! itim = 1 and lon = -180 --->position 1 ! itim = ntim ant lon = -180 --->position ntim, etc. ! itim = 1 and lon = 0 ---->position ntim/2 xlon = xbeg(region) + (i-0.5)*dx/xref(region) ipos = 1 + mod(int((xlon+180.)*ntim/360.) + (itim-1),ntim) !position in array depending on time and lon. x = emis_field(i,j,l)*month2dt*(mol_mass/mol_mass_e)*efrac*curr_cycle(ipos) else x = emis_field(i,j,l)*month2dt*(mol_mass/mol_mass_e)*efrac endif rm(i,j,l,i_tracer) = rm(i,j,l,i_tracer) + x #ifdef with_budgets ! budget___ ! if(region==nregions) then !sub budget finest region ! nzone=nzon(i,j) ! nzone_v=nzon_v(l) ! budemi(nzone,nzone_v,i_tracer)=budemi(nzone,nzone_v,i_tracer)+x/mol_mass*1e3 !mole ! endif nzone=budg_dat(region)%nzong(i,j) !global budget nzone_v=nzon_vg(l) budemi_dat(region)%emi(i,j,nzone_v,i_tracer) = & budemi_dat(region)%emi(i,j,nzone_v,i_tracer) + x/mol_mass*1e3 if(i_tracer ==1) sum_emission(region) = sum_emission(region) + x !in kg #endif enddo enddo enddo !levels ! if (okdebug) then ! maft = sum(rm(i1:i2,j1:j2,:,i_tracer)) ! write (gol, '(" after-before :", e12.4 )' ) maft-mbef ; call goPr ! !if ( sume > tiny(sume) ) then ! ! This is wrong... ! ! if ( (maft-mbef)/sume < 0.5) then ! ! write (gol, '(" spurious do_add_3d_cycle.... ")' ) ; call goPr ! ! call dumpfield(1, 'spurious.hdf', im(region), jm(region), ubound_e(3), 1, emis_field, names(i_tracer)) ! ! endif ! !endif ! write (gol, '(" END debug output ")' ) ; call goPr ! endif nullify(rm) end subroutine do_add_3d_cycle !EOC !-------------------------------------------------------------------------- ! TM5 ! !-------------------------------------------------------------------------- !BOP ! ! !IROUTINE: DISTRIBUTE_L44 ! ! !DESCRIPTION: Scales input field (field2d) such that ! 1) NH temperate vegetation fires are distributed over the ! months: july-august-september ! 2) SH temperate vegetation fires are distributed over the ! months: January-February-March !\\ !\\ ! !INTERFACE: ! SUBROUTINE DISTRIBUTE_L44(month, imdim, jmdim, field2d) ! ! !USES: ! use dims, only : okdebug ! ! !INPUT PARAMETERS: ! integer, intent(in) :: month ! month integer, intent(in) :: jmdim, imdim ! dimension of grid ! ! !REVISION HISTORY: ! 1 Oct 2010 - Achim Strunk - protex ! !EOP !------------------------------------------------------------------------ !BOC real,dimension(imdim,jmdim) :: field2d real :: bb_nh,bb_sh ! multiplication factor for yearly temperate fires integer :: j,i bb_nh=0. bb_sh=0. if (month==7.or.month==8.or.month==9) bb_nh=3./12. if (month==1.or.month==2.or.month==3) bb_sh=3./12. do i=1, imdim do j=1, jmdim/2 field2d(i,j)=field2d(i,j)*bb_sh enddo do j=jmdim/2+1,jmdim field2d(i,j)=field2d(i,j)*bb_nh enddo enddo if(okdebug) then write(gol,*) 'l44 is distributed' ; call goPr endif END SUBROUTINE DISTRIBUTE_L44 !EOC END MODULE EMISSION_DATA