9117 lines
343 KiB
Fortran
9117 lines
343 KiB
Fortran
! $Id: sulfate_mod.f,v 1.8 2012/04/25 22:46:23 nicolas Exp $
|
|
MODULE SULFATE_MOD
|
|
!
|
|
!******************************************************************************
|
|
! Module SULFATE_MOD contains arrays and routines for performing either a
|
|
! coupled chemistry/aerosol run or an offline sulfate aerosol simulation.
|
|
! Original code taken from Mian Chin's GOCART model and modified accordingly.
|
|
! (rjp, bdf, bmy, 6/22/00, 10/31/08)
|
|
!
|
|
! Module Variables:
|
|
! ============================================================================
|
|
! (1 ) XNUMOL_OH (REAL*8 ) : Molecules OH per kg OH [molec/kg]
|
|
! (2 ) XNUMOL_O3 (REAL*8 ) : Molecules O3 per kg O3 [molec/kg]
|
|
! (3 ) XNUMOL_NO3 (REAL*8 ) : Molecules NO3 per kg NO3 [molec/kg]
|
|
! (4 ) TCVV_S (REAL*8 ) : Ratio: Molwt air / Molwt S [unitless]
|
|
! (5 ) DMSo (REAL*8 ) : DMS oceanic emissions [v/v/timestep]
|
|
! (6 ) DRYH2O2 (INTEGER) : Pointer to H2O2 in DEPVEL array [unitless]
|
|
! (7 ) DRYSO2 (INTEGER) : Pointer to SO2 in DEPVEL array [unitless]
|
|
! (8 ) DRYSO4 (INTEGER) : Pointer to SO4 in DEPVEL array [unitless]
|
|
! (9 ) DRYSO4s (INTEGER) : Pointer to SO4s in DEPVEL array [unitless]
|
|
! (10) DRYMSA (INTEGER) : Pointer to MSA in DEPVEL array [unitless]
|
|
! (11) DRYNH3 (INTEGER) : Pointer to NH3 in DEPVEL array [unitless]
|
|
! (12) DRYNH4 (INTEGER) : Pointer to NH4 in DEPVEL array [unitless]
|
|
! (13) DRYNIT (INTEGER) : Pointer to NIT in DEPVEL array [unitless]
|
|
! (14) DRYNITs (INTEGER) : Pointer to NITs in DEPVEL array [unitless]
|
|
! (15) DRYSO4aq (INTEGER) : Pointer to SO4aq in DEPVEL array [unitless]
|
|
! (16) DRYAS (INTEGER) : Pointer to AS in DEPVEL array [unitless]
|
|
! (17) DRYAHS (INTEGER) : Pointer to AHS in DEPVEL array [unitless]
|
|
! (18) DRYLET (INTEGER) : Pointer to LET in DEPVEL array [unitless]
|
|
! (19) DRYNH4aq (INTEGER) : Pointer to NH4aq in DEPVEL array [unitless]
|
|
! (20) ENH3_an (REAL*8 ) : NH3 anthropogenic emissions [kg NH3/box/s]
|
|
! (21) ENH3_bb (REAL*8 ) : NH3 biomass emissions [kg NH3/box/s]
|
|
! (22) ENH3_bf (REAL*8 ) : NH3 biofuel emissions [kg NH3/box/s]
|
|
! (23) ENH3_na (REAL*8 ) : NH73 natural source emissions [kg NH3/box/s]
|
|
! (24) ESO2_ac (REAL*8 ) : SO2 aircraft emissions [kg SO2/box/s]
|
|
! (25) ESO2_an (REAL*8 ) : SO2 anthropogenic emissions [kg SO2/box/s]
|
|
! (26) ESO2_ev (REAL*8 ) : SO2 eruptive volcanic em. [kg SO2/box/s]
|
|
! (27) ESO2_nv (REAL*8 ) : SO2 non-eruptive volcanic em. [kg SO2/box/s]
|
|
! (28) ESO2_bb (REAL*8 ) : SO2 biomass burning emissions [kg SO2/box/s]
|
|
! (29) ESO2_bf (REAL*8 ) : SO2 biofuel burning emissions [kg SO2/box/s]
|
|
! (30) ESO2_sh (REAL*8 ) : SO2 ship emissions [kg SO2/box/s]
|
|
! (31) ESO4_an (REAL*8 ) : SO4 anthropogenic emissions [kg SO4/box/s]
|
|
! (32) JH2O2 (REAL*8 ) : Monthly mean J(H2O2) values [s-1]
|
|
! (33) O3m (REAL*8 ) : Monthly mean O3 concentration [v/v]
|
|
! (34) PH2O2m (REAL*8 ) : Monthly mean P(H2O2) [molec/cm3/s]
|
|
! (35) PMSA_DMS (REAL*8 ) : P(MSA) from DMS [v/v/timestep]
|
|
! (36) PSO2_DMS (REAL*8 ) : P(SO2) from DMS [v/v/timestep]
|
|
! (37) PSO4_SO2 (REAL*8 ) : P(SO4) from SO2 [v/v/timestep]
|
|
! (38) SSTEMP (REAL*8 ) : Sea surface temperatures [K]
|
|
! (39) VCLDF (REAL*8 ) : Volume cloud frac. for SO2 aq. [unitless]
|
|
! (40) NEV (INTEGER) : Max # of eruptive volcanoes [unitless]
|
|
! (41) IEV (INTEGER) : Longitudes of eruptive volcanoes [degrees]
|
|
! (42) JEV (INTEGER) : Latitudes of eruptive volcanoes [degrees ]
|
|
! (43) IHGHT (INTEGER) : Height of eruptive volcano plume [m]
|
|
! (44) IELVe (INTEGER) : Elevation of eruptive volcanoes [m]
|
|
! (45) Eev (REAL*8 ) : SO2 em. from eruptive volcanoes [kg SO2/box/s]
|
|
! (46) NNV (INTEGER) : Max # of non-eruptive volcanoes [unitless]
|
|
! (47) NNVOL (INTEGER) : Number of non-eruptive volcanoes [unitless]
|
|
! (48) INV (INTEGER) : Longitude of non-erup volcanoes [degrees]
|
|
! (49) JNV (INTEGER) : Latitude of non-erup volcanoes [degrees]
|
|
! (50) IELVn (INTEGER) : Elevation of non-erup volcanoes [m]
|
|
! (51) Env (INTEGER) : SO2 em. from non-erup volcanoes [kg SO2/box/s]
|
|
! (52) TCOSZ (REAL*8 ) : Sum of cos(SZA) for offline run [unitless]
|
|
! (53) TTDAY (REAL*8 ) : Total daylight length at (I,J) [minutes]
|
|
! (54) SMALLNUM (REAL*8 ) : Small number - prevent underflow [unitless]
|
|
! (55) COSZM (REAL*8 ) : Array for MAX(cos(SZA)) at (I,J) [unitless]
|
|
!
|
|
! Module Routines:
|
|
! ===========================================================================
|
|
! (1 ) GET_VCLDF : Computes volume cloud fraction for SO2 chemistry
|
|
! (2 ) GET_LWC : Computes liquid water content as a function of T
|
|
! (3 ) CHEMSULFATE : Driver routine for sulfate/aerosol chemistry
|
|
! (4 ) GRAV_SETTLING : Routine to compute settling of SO4s and NITs
|
|
! (5 ) CHEM_DMS : Chemistry routine for DMS tracer
|
|
! (6 ) CHEM_H2O2 : Chemistry routine for H2O2 tracer
|
|
! (7 ) CHEM_SO2 : Chemistry routine for SO2 tracer
|
|
! (8 ) SEASALT_CHEM : Computes SO2->SO4 and HNO3->nitrate w/in seasalt
|
|
! (9 ) AQCHEM_SO2 : Computes reaction rates for aqueous SO2 chemistry
|
|
! (10) CHEM_SO4 : Chemistry routine for SO4 tracer
|
|
! (11) PHASE_SO4 : Computes phase transition for crystalline tracers
|
|
! (12) PHASE_RADIATIVE : Computes radiative forcing for crystalline tracers
|
|
! (13) CHEM_MSA : Chemistry routine for MSA tracer
|
|
! (14) CHEM_NH3 : Chemistry routine for ammonia tracer
|
|
! (15) CHEM_NH4 : Chemistry routine for ammonium tracer
|
|
! (16) CHEM_NIT : Chemistry routine for nitrates tracer
|
|
! (17) EMISSSULFATE : Driver routine for sulfate/aerosol emissions
|
|
! (18) SRCDMS : Emission routine for DMS tracer
|
|
! (19) SRCSO2 : Emission routine for SO2 tracer
|
|
! (20) SRCSO4 : Emission routine for SO4 tracer
|
|
! (21) SRCNH3 : Emission routine for NH3 tracer
|
|
! (22) GET_OH : Returns OH for coupled or offline simulations
|
|
! (23) SET_OH : Resets modified OH in SMVGEAR's CSPEC array
|
|
! (24) GET_NO3 : Returns NO3 for coupled or offline simulations
|
|
! (25) SET_NO3 : Resets modified OH in SMVGEAR's CSPEC array
|
|
! (26) GET_O3 : Returns O3 for coupled or offline simulations
|
|
! (27) READ_NONERUP_VOLC : Reads SO2 emissions from non-eruptive volcanoes
|
|
! (28) READ_ERUP_VOLC : Reads SO2 emissions from eruptive volcanoes
|
|
! (29) READ_ANTHRO_SOx : Reads anthropogenic SO2 and SO4 emissions
|
|
! (30) READ_OCEAN_DMS : Reads biogenic DMS emissions from oceans
|
|
! (31) READ_SST : Reads monthly mean sea-surface temperatures
|
|
! (32) READ_BIOFUEL_SO2 : Reads SO2 emissions from biomass burning
|
|
! (33) READ_AIRCRAFT_SO2 : Reads SO2 emissions from aircraft exhaust
|
|
! (34) READ_SHIP_SO2 : Reads SO2 emissions from ship exhaust
|
|
! (35) READ_ANTHRO_NH3 : Reads NH3 emissions from anthropogenic sources
|
|
! (36) READ_NATURAL_NH3 : Reads NH3 emissions from natural sources
|
|
! (37) READ_BIOMASS_NH3 : Reads NH3 biomass burning emissions
|
|
! (38) READ_OXIDANT : Reads monthly mean O3 and H2O2 for offline run
|
|
! (39) OHNO3TIME : Computes time arrays for scaling offline OH, NO3
|
|
! (40) INIT_SULFATE : Allocates & zeroes module arrays
|
|
! (41) CLEANUP_SULFATE : Deallocates module arrays
|
|
!
|
|
! GEOS-CHEM modules referenced by sulfate_mod.f
|
|
! ============================================================================
|
|
! (1 ) biomass_mod.f : Module w/ routines for biomass burning
|
|
! (2 ) bpch2_mod.f : Module w/ routines for binary pch file I/O
|
|
! (3 ) bravo_mod.f : Module w/ routines to read BRAVO emissions
|
|
! (4 ) comode_mod.f : Module w/ SMVGEAR allocatable arrays
|
|
! (5 ) dao_mod.f : Module w/ DAO met field arrays
|
|
! (6 ) diag_mod.f : Module w/ GEOS-Chem diagnostic arrays
|
|
! (7 ) directory_mod.f : Module w/ GEOS-Chem data & met field dirs
|
|
! (8 ) drydep_mod.f : Module w/ GEOS-Chem dry deposition routines
|
|
! (9 ) epa_nei_mod.f : Module w/ routines to read EPA/NEI99 data
|
|
! (10) error_mod.f : Module w/ NaN, other error check routines
|
|
! (11) file_mod.f : Module w/ file unit numbers & error checks
|
|
! (12) future_emissions_mod.f : Module w/ routines for IPCC future emissions
|
|
! (13) grid_mod.f : Module w/ horizontal grid information
|
|
! (14) global_no3_mod.f : Module w/ routines to read 3-D NO3 field
|
|
! (15) global_oh_mod.f : Module w/ routines to read 3-D OH field
|
|
! (16) isoropiaii_adj_mod.f : Module w/ ISORROPIAII routines for aer thermo eq
|
|
! (17) logical_mod.f : Module w/ GEOS-Chem logical switches
|
|
! (18) pbl_mix_mod.f : Module w/ routines for PBL height & mixing
|
|
! (19) pressure_mod.f : Module w/ routines to compute P(I,J,L)
|
|
! (20) seasalt_mod.f : Module w/ routines for seasalt chemistry
|
|
! (21) streets_anthro_mod.f : Module w/ routines for David Streets' emiss
|
|
! (22) time_mod.f : Module w/ routines to compute time & date
|
|
! (23) tracer_mod.f : Module w/ GEOS-Chem tracer array STT etc.
|
|
! (24) tracerid_mod.f : Module w/ pointers to tracers & emissions
|
|
! (25) transfer_mod.f : Module w/ routines to cast & resize arrays
|
|
! (26) tropopause_mod.f : Module w/ routines to read ann mean tropopause
|
|
! (27) uvalbedo_mod.f : Module w/ UV albedo array and reader
|
|
! (28) wetscav_mod.f : Module w/ routines for wetdep & scavenging
|
|
!
|
|
! References:
|
|
! ============================================================================
|
|
! (1 ) Andreae, M.O. & P. Merlet, "Emission of trace gases and aerosols from
|
|
! biomass burning", Global Biogeochem. Cycles, 15, 955-966, 2001.
|
|
! (2 ) Nightingale et al [2000a], J. Geophys. Res, 14, 373-387
|
|
! (3 ) Nightingale et al [2000b], Geophys. Res. Lett, 27, 2117-2120
|
|
! (4 ) Wanninkhof, R., "Relation between wind speed and gas exchange over
|
|
! the ocean", J. Geophys. Res, 97, 7373-7382, 1992.
|
|
!
|
|
! NOTES:
|
|
! (1 ) All module variables are declared PRIVATE (i.e., they can only
|
|
! be seen from within this module (bmy, 6/2/00)
|
|
! (2 ) The routines in "sulfate_mod.f" assume that we are doing chemistry
|
|
! over the global region (e.g. IIPAR=IGLOB, JJPAR=JGLOB). (bmy, 6/8/00)
|
|
! (3 ) Removed obsolete code from DRYDEP_SULFATE (bmy, 12/21/00)
|
|
! (4 ) Removed obsolete commented-out code from module routines (bmy, 4/23/01)
|
|
! (5 ) Now read data files from DATA_DIR/sulfate_sim_200106/ (bmy, 6/19/01)
|
|
! (6 ) Updated comments (bmy, 9/4/01)
|
|
! (7 ) XTRA2(IREF,JREF,5) is now XTRA2(I,J). Now reference COSSZA from
|
|
! "dao_mod.f". (bmy, 9/27/01)
|
|
! (8 ) Removed obsolete commented out code from 9/01 (bmy, 10/24/01)
|
|
! (9 ) Minor fixes to facilitate compilation on ALPHA (bmy, 11/15/01)
|
|
! (11) Now divide module header into MODULE PRIVATE, MODULE VARIABLES, and
|
|
! MODULE ROUTINES sections. Updated comments (bmy, 5/28/02)
|
|
! (12) Replaced all instances of IM with IIPAR and JM with JJPAR, in order
|
|
! to prevent namespace confusion for the new TPCORE (bmy, 6/25/02)
|
|
! (13) Now reference "file_mod.f" (bmy, 6/27/02)
|
|
! (14) Now references GET_PEDGE from "pressure_mod.f", which computes P at
|
|
! the bottom edge of grid box (I,J,L). Also deleted obsolete,
|
|
! commented-out code. (dsa, bdf, bmy, 8/21/02)
|
|
! (15) Added updated code from Rokjin Park and Brendan Field, in order to
|
|
! perform coupled chemistry-aerosol simulations. Also added parallel
|
|
! DO-loops in several subroutines. Updated comments, cosmetic
|
|
! changes. Now reference "error_mod.f" and "wetscav_mod.f".
|
|
! Now only do chemistry below the tropopause. (rjp, bdf, bmy, 12/6/02)
|
|
! (16) Added ENH3_na array to hold natural source NH3 emissions. Also now
|
|
! facilitate passing DMS, SO2, SO4, NH3 to SMVGEAR for fullchem
|
|
! simulations. Added subroutine READ_NATURAL_NH3. (rjp, bmy, 3/23/03)
|
|
! (17) Now references "grid_mod.f" and "time_mod.f". Also made other minor
|
|
! cosmetic changes. (bmy, 3/27/03)
|
|
! (18) Updated chemistry routines to apply drydep losses throughout the
|
|
! entire PBL. (rjp, bmy, 8/1/03)
|
|
! (19) Now accounts for GEOS-4 PBL being in meters (bmy, 1/15/04)
|
|
! (20) Fix ND44 diag so that we get same results for sp or mp (bmy, 3/24/04)
|
|
! (21) Added COSZM array. Now use diurnal varying JH2O2 in CHEM_H2O2.
|
|
! (rjp, bmy, 3/39/04)
|
|
! (22) Added more parallel DO-loops (bmy, 4/14/04)
|
|
! (23) Now add SO2 from ships (bec, bmy, 5/20/04)
|
|
! (24) Now references "directory_mod.f", "logical_mod.f" and "tracer_mod.f".
|
|
! Now removed IJSURF. (bmy, 7/20/04)
|
|
! (25) Can overwrite USA with EPA/NEI99 emissions (rjp, rch, bmy, 11/16/04)
|
|
! (26) Modified for AS, AHS, LET, SO4aq, NH4aq (cas, bmy, 1/11/05)
|
|
! (27) Now also references "pbl_mix_mod.f". NOTE: Comment out phase
|
|
! transition code for now since it is still under development and
|
|
! will take a while to be rewritten. (bmy, 3/15/05)
|
|
! (28) Modified for SO4s, NITs chemistry (bec, 4/13/05)
|
|
! (29) Now reads updated files for SST and offline chemistry. Now read data
|
|
! for both GCAP and GEOS grids. Now references "tropopause_mod.f".
|
|
! (bmy, 8/22/05)
|
|
! (30) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (31) Now references XNUMOL & XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (32) Now read int'annual SST data on GEOS 1x1 grid (bmy, 11/17/05)
|
|
! (33) Bug fix for offline aerosol sim in SEASALT_CHEM (bec, bmy, 3/29/06)
|
|
! (34) Bug fix in INIT_DRYDEP (bmy, 5/23/06)
|
|
! (35) Now references "bravo_mod.f" (rjp, kfb, bmy, 6/26/06)
|
|
! (36) Now references "streets_anthro_mod.f" (yxw, bmy, 8/17/06)
|
|
! (37) Now references "biomass_mod.f" (bmy, 9/27/06)
|
|
! (38) Now prevent seg fault error in READ_BIOFUEL_SO2 (bmy, 11/3/06)
|
|
! (39) Bug fix in SEASALT_CHEM (havala, bec, bmy, 12/8/06)
|
|
! (40) Extra error check for low RH in GRAV_SETTLING (phs, 6/11/08)
|
|
! (41) Now references "cac_anthro_mod.f". And apply SO2 yearly scale factor
|
|
! to SO2 from GEIA (amv, phs, 3/11/08)
|
|
! (41) Bug fixes in reading EDGAR data w/ the right tracer number,
|
|
! when we are doing offline or nonstd simulations (dkh, 10/31/08)
|
|
! (42) Bug fix for AD13_SO2_sh in SRCSO2 (phs, 2/27/09)
|
|
! (43) Bug fix: need to add CAC_AN to PRIVATE statements (bmy, 5/27/09)
|
|
! (44) (adj_group: haven't implemented yet as haven't implemented LNLPBL)
|
|
!
|
|
! (45) Last year of SST data is now 2008 (see READ_SST) (bmy, 7/13/09)
|
|
! 07 Sep 2011 - P. Kasibathla - Modified to include GFED3
|
|
!******************************************************************************
|
|
!
|
|
IMPLICIT NONE
|
|
|
|
!=================================================================
|
|
! MODULE PRIVATE DECLARATIONS -- keep certain internal variables
|
|
! and routines from being seen outside "sulfate_mod.f"
|
|
!=================================================================
|
|
|
|
! Make everything PRIVATE ...
|
|
PRIVATE
|
|
|
|
! ... except these routines
|
|
PUBLIC :: CHEMSULFATE
|
|
PUBLIC :: EMISSSULFATE
|
|
PUBLIC :: CLEANUP_SULFATE
|
|
|
|
! adj_group: ... and these needed for adjoint (dkh, 11/04/09)
|
|
PUBLIC :: ENH3_an
|
|
PUBLIC :: ENH3_na
|
|
PUBLIC :: ENH3_bf
|
|
PUBLIC :: ENH3_bb
|
|
PUBLIC :: ESO2_an
|
|
PUBLIC :: ESO2_bf
|
|
PUBLIC :: ESO2_bb
|
|
PUBLIC :: ESO2_sh
|
|
|
|
!=================================================================
|
|
! MODULE VARIABLES (see descriptions listed above)
|
|
!=================================================================
|
|
|
|
! Time variable
|
|
INTEGER :: ELAPSED_SEC
|
|
|
|
! Logical Flags
|
|
LOGICAL, PARAMETER :: LENV = .TRUE.
|
|
LOGICAL, PARAMETER :: LEEV = .TRUE.
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: XNUMOL_OH = 6.022d23 / 17d-3
|
|
REAL*8, PARAMETER :: XNUMOL_O3 = 6.022d23 / 48d-3
|
|
REAL*8, PARAMETER :: XNUMOL_NO3 = 6.022d23 / 62d-3
|
|
REAL*8, PARAMETER :: TCVV_S = 28.97d0 / 32d0
|
|
REAL*8, PARAMETER :: SMALLNUM = 1d-20
|
|
|
|
! Allocatable arrays
|
|
REAL*8, ALLOCATABLE :: DMSo(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_an(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_bb(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_bf(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_na(:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_ac(:,:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_an(:,:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_bb(:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_bf(:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_ev(:,:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_nv(:,:,:)
|
|
REAL*8, ALLOCATABLE :: ESO2_sh(:,:)
|
|
REAL*8, ALLOCATABLE :: ESO4_an(:,:,:)
|
|
REAL*8, ALLOCATABLE :: JH2O2(:,:,:)
|
|
REAL*8, ALLOCATABLE :: LSO2_AQ(:,:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_wl(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_hu(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_fe(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_ls(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_ns(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_oc(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_id(:,:)
|
|
REAL*8, ALLOCATABLE :: ENH3_ff(:,:)
|
|
REAL*8, ALLOCATABLE :: O3m(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PH2O2m(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PMSA_DMS(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PSO2_DMS(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PSO4_SO2(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PSO4_SS(:,:,:)
|
|
REAL*8, ALLOCATABLE :: PNITs(:,:,:)
|
|
REAL*4, ALLOCATABLE :: SOx_SCALE(:,:)
|
|
REAL*8, ALLOCATABLE :: SSTEMP(:,:)
|
|
REAL*8, ALLOCATABLE :: TCOSZ(:,:)
|
|
REAL*8, ALLOCATABLE :: TTDAY(:,:)
|
|
REAL*8, ALLOCATABLE :: VCLDF(:,:,:)
|
|
REAL*8, ALLOCATABLE :: COSZM(:,:)
|
|
|
|
! Eruptive volcanoes
|
|
INTEGER, PARAMETER :: NEV=50
|
|
INTEGER :: NEVOL
|
|
INTEGER, ALLOCATABLE :: IEV(:), JEV(:)
|
|
INTEGER, ALLOCATABLE :: IDAYs(:), IDAYe(:)
|
|
INTEGER, ALLOCATABLE :: IHGHT(:), IELVe(:)
|
|
REAL*8, ALLOCATABLE :: EEV(:)
|
|
|
|
! Non-eruptive volcanoes
|
|
INTEGER, PARAMETER :: NNV=50
|
|
INTEGER :: NNVOL
|
|
INTEGER, ALLOCATABLE :: INV(:), JNV(:), IELVn(:)
|
|
REAL*8, ALLOCATABLE :: ENV(:)
|
|
|
|
! Pointers to drydep species w/in DEPSAV
|
|
INTEGER :: DRYSO2, DRYSO4, DRYMSA, DRYNH3
|
|
INTEGER :: DRYNH4, DRYNIT, DRYSO4s, DRYNITs
|
|
INTEGER :: DRYH2O2, DRYSO4aq, DRYAS, DRYAHS
|
|
INTEGER :: DRYLET, DRYNH4aq
|
|
|
|
!=================================================================
|
|
! MODULE ROUTINES -- follow below the "CONTAINS" statement
|
|
!=================================================================
|
|
CONTAINS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE GET_VCLDF
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_VCLDF computes the volume cloud fraction for SO2 chemistry.
|
|
! (rjp, bdf, bmy, 9/23/02)
|
|
!
|
|
! References:
|
|
! ============================================================================
|
|
! (1) Sundqvist et al. [1989]
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : RH
|
|
USE PRESSURE_MOD, ONLY : GET_PCENTER, GET_PEDGE
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L
|
|
REAL*8 :: PRES, PSFC, RH2, R0, B0
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: ZRT = 0.60d0, ZRS = 0.99d0
|
|
|
|
!=================================================================
|
|
! GET_VCLDF begins here!
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, PSFC, PRES, RH2, R0, B0 )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Surface pressure
|
|
PSFC = GET_PEDGE(I,J,1)
|
|
|
|
! Pressure at the center of the grid box
|
|
PRES = GET_PCENTER(I,J,L)
|
|
|
|
! RH (from "dao_mod.f") is relative humidity [%]
|
|
! Convert to fraction and store in RH2
|
|
RH2 = RH(I,J,L) * 1.0d-2
|
|
|
|
! Terms from Sundqvist ???
|
|
R0 = ZRT + ( ZRS - ZRT ) * EXP( 1d0 - ( PSFC / PRES )**2.5 )
|
|
B0 = ( RH2 - R0 ) / ( 1d0 - R0 )
|
|
|
|
! Force B0 into the range 0-1
|
|
IF ( RH2 < R0 ) B0 = 0d0
|
|
IF ( B0 > 1d0 ) B0 = 1d0
|
|
|
|
! Volume cloud fraction
|
|
VCLDF(I,J,L) = 1d0 - SQRT( 1d0 - B0 )
|
|
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE GET_VCLDF
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_LWC( T ) RESULT( LWC )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_LWC returns the cloud liquid water content at a GEOS-CHEM
|
|
! grid box as a function of temperature. (rjp, bmy, 10/31/02, 1/14/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) T (REAL*8) : Temperature value at a GEOS-CHEM grid box [K]
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: T
|
|
|
|
! Function value
|
|
REAL*8 :: LWC
|
|
|
|
!=================================================================
|
|
! GET_LWC begins here!
|
|
!=================================================================
|
|
|
|
! Compute Liquid water content in [g/m3]
|
|
IF ( T > 293d0 ) THEN
|
|
LWC = 0.2d0
|
|
|
|
ELSE IF ( T >= 280.d0 .AND. T <= 293.d0 ) THEN
|
|
LWC = 0.32d0 - 0.0060d0 * ( T - 273.D0 )
|
|
|
|
ELSE IF ( T >= 248.d0 .AND. T < 280.d0 ) THEN
|
|
LWC = 0.23d0 + 0.0065d0 * ( T - 273.D0 )
|
|
|
|
ELSE IF ( T < 248.d0 ) THEN
|
|
LWC = 0.07d0
|
|
|
|
ENDIF
|
|
|
|
! Convert from [g/m3] to [m3/m3]
|
|
LWC = LWC * 1.D-6
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_LWC
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEMSULFATE
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEMSULFATE is the interface between the GEOS-CHEM main program
|
|
! and the sulfate chemistry routines. The user has the option of running
|
|
! a coupled chemistry-aerosols simulation or an offline aerosol simulation.
|
|
! (rjp, bdf, bmy, 5/31/00, 3/16/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference all arguments except FIRSTCHEM and RH from either F90
|
|
! modules or from common block header files. Updated comments,
|
|
! cosmetic changes. Added NH3, NH4, NITRATE chemistry routines.
|
|
! Also call MAKE_RH and CONVERT_UNITS from "dao_mod.f". Now references
|
|
! IDTDMS, IDTSO2 etc. from "tracerid_mod.f". Now make FIRSTCHEM a
|
|
! local SAVEd variable. Now reference DEPSAV from "drydep_mod.f".
|
|
! Also get rid of extraneous dimensions of DEPSAV. Added NTIME,
|
|
! NHMSb arrays for OHNO3TIME. (rjp, bdf, bmy, 12/16/02)
|
|
! (2 ) CHEM_DMS is now only called for offline sulfate simulations.
|
|
! (rjp, bmy, 3/23/03)
|
|
! (3 ) Now remove NTIME, NHMSb from the arg list and call to OHNO3TIME.
|
|
! Now references functions GET_MONTH, GET_TS_CHEM, and GET_ELAPSED_SEC
|
|
! from the new "time_mod.f". (bmy, 3/27/03)
|
|
! (4 ) Now reference STT, TCVV, N_TRACERS, ITS_AN_AEROSOL_SIM from
|
|
! "tracer_mod.f". Now reference ITS_A_NEW_MONTH from "time_mod.f".
|
|
! Now references LPRT from "logical_mod.f". (bmy, 7/20/04)
|
|
! (5 ) Updated for AS, AHS, LET, SO4aq, NH4aq. Now references LCRYST from
|
|
! logical_mod.f. Now locate species in the DEPSAV array w/in
|
|
! INIT_SULFATE. (bmy, 12/21/04)
|
|
! (6 ) Now handle gravitational settling of SO4s, NITs (bec, bmy, 4/13/05)
|
|
! (7 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (8 ) Remove reference to MAKE_RH, it's not needed here (bmy, 3/16/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD, AIRDEN, CLDF
|
|
USE DAO_MOD, ONLY : SUNCOS, CONVERT_UNITS
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE ERROR_MOD, ONLY : DEBUG_MSG
|
|
USE GLOBAL_OH_MOD, ONLY : GET_GLOBAL_OH
|
|
USE GLOBAL_NO3_MOD, ONLY : GET_GLOBAL_NO3
|
|
USE LOGICAL_MOD, ONLY : LCRYST, LPRT
|
|
USE TIME_MOD, ONLY : GET_MONTH, GET_TS_CHEM
|
|
USE TIME_MOD, ONLY : GET_ELAPSED_SEC, ITS_A_NEW_MONTH
|
|
USE TRACER_MOD, ONLY : STT, TCVV
|
|
USE TRACER_MOD, ONLY : N_TRACERS, ITS_AN_AEROSOL_SIM
|
|
USE TRACERID_MOD, ONLY : IDTNITs, IDTSO4s
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
LOGICAL, SAVE :: FIRSTCHEM = .TRUE.
|
|
INTEGER, SAVE :: LASTMONTH = -99
|
|
INTEGER :: I, J, L, N, MONTH
|
|
REAL*8 :: DTCHEM
|
|
|
|
! External functions
|
|
REAL*8, EXTERNAL :: BOXVL
|
|
|
|
!=================================================================
|
|
! CHEMSULFATE begins here!
|
|
!=================================================================
|
|
|
|
! Get current month
|
|
MONTH = GET_MONTH()
|
|
|
|
! Establish indices w/in DEPSAV array
|
|
IF ( FIRSTCHEM ) THEN
|
|
|
|
! Initialize arrays (if not already done before)
|
|
CALL INIT_SULFATE
|
|
|
|
! Reset first-time flag
|
|
FIRSTCHEM = .FALSE.
|
|
ENDIF
|
|
|
|
! If it's an offline simulation ...
|
|
IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
! Then read monthly data files ...
|
|
IF ( ITS_A_NEW_MONTH() ) THEN
|
|
CALL GET_GLOBAL_OH( MONTH )
|
|
CALL GET_GLOBAL_NO3( MONTH )
|
|
ENDIF
|
|
|
|
! And compute time scaling arrays for offline OH, NO3
|
|
CALL OHNO3TIME
|
|
|
|
ENDIF
|
|
|
|
! Store NTIME in a shadow variable
|
|
ELAPSED_SEC = GET_ELAPSED_SEC()
|
|
|
|
! DTCHEM is the chemistry timestep in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Initialize module arrays
|
|
PSO2_DMS = 0d0
|
|
PMSA_DMS = 0d0
|
|
PSO4_SO2 = 0d0
|
|
PSO4_SS = 0d0
|
|
PNITs = 0d0
|
|
|
|
!=================================================================
|
|
! Call individual chemistry routines for sulfate/aerosol tracers
|
|
!=================================================================
|
|
|
|
! SO4s [kg] gravitational settling
|
|
CALL GRAV_SETTLING( STT(:,:,:,IDTSO4s), 1 )
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: GRAV_SET, SO4S' )
|
|
|
|
! NITs [kg] gravitational settling
|
|
CALL GRAV_SETTLING( STT(:,:,:,IDTNITs), 2 )
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: GRAV_SET, NITS' )
|
|
|
|
! Convert all tracers in STT from [kg] -> [v/v]
|
|
CALL CONVERT_UNITS( 1, N_TRACERS, TCVV, AD, STT )
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CONVERT UNITS' )
|
|
|
|
! For offline runs only ...
|
|
IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
! DMS (offline only)
|
|
CALL CHEM_DMS
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_DMS' )
|
|
|
|
! H2O2 (offline only)
|
|
CALL CHEM_H2O2
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_H2O2' )
|
|
|
|
ENDIF
|
|
|
|
! SO2
|
|
CALL GET_VCLDF
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a get VCLDF' )
|
|
CALL CHEM_SO2
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_SO2' )
|
|
|
|
! SO4
|
|
CALL CHEM_SO4
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_SO4' )
|
|
|
|
!-----------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% ! Only do the following if the crystalline sulfate & aqueous
|
|
!%%% ! tracers (AS, AHS, LET, SO4aq, NH4aq) are defined
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%%
|
|
!%%% ! Phase change
|
|
!%%% CALL PHASE_SO4
|
|
!%%% IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a PHASE_SO4' )
|
|
!%%%
|
|
!%%% ! Radiative forcing
|
|
!%%% CALL PHASE_RADIATIVE
|
|
!%%% IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a PHASE_RAD' )
|
|
!%%%
|
|
!%%% ENDIF
|
|
!-----------------------------------------------------------------------------
|
|
|
|
! MSA
|
|
CALL CHEM_MSA
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_MSA' )
|
|
|
|
! NH3
|
|
CALL CHEM_NH3
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_NH3' )
|
|
|
|
! NH4 (gas-phase)
|
|
CALL CHEM_NH4
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_NH4' )
|
|
|
|
!-----------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% ! NH4 (aqueous phase)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%% CALL CHEM_NH4aq
|
|
!%%% IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_NH4aq' )
|
|
!%%% ENDIF
|
|
!-----------------------------------------------------------------------------
|
|
|
|
! Sulfur Nitrate
|
|
CALL CHEM_NIT
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_NIT' )
|
|
|
|
! Convert STT from [v/v] -> [kg]
|
|
CALL CONVERT_UNITS( 2, N_TRACERS, TCVV, AD, STT )
|
|
|
|
! We have already gone thru one chemistry iteration
|
|
FIRSTCHEM = .FALSE.
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEMSULFATE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE GRAV_SETTLING( TC, N )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GRAV_SETTLING performs gravitational settling of sulfate
|
|
! and nitrate in coarse sea salt (SO4S and NITS).
|
|
! (bec, rjp, bmy, 4/20/04, 7/20/04, 10/25/05)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) TC (REAL*8 ) : Tracer [kg]
|
|
! (2 ) N (INTEGER) : N=1 is SO4S; N=2 is NITS
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) TC (REAL*8 ) : Contains modified tracer
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now references SALA_REDGE_um and SALC_REDGE_um from "tracer_mod.f"
|
|
! (bmy, 7/20/04)
|
|
! (2 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (3 ) Now limit relative humidity to [tiny(real*8),0.99] range for DLOG
|
|
! argument (phs, 5/1/08)
|
|
! (4 ) Bug fixes to the Gerber hygroscopic growth for sea salt aerosols (jaegle, 5/5/11)
|
|
! (5 ) Update hygroscopic growth to Lewis and Schwartz formulation (2006) and density
|
|
! calculation based on Tang et al. (1997) (bec, jaegle 5/5/11)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : T, BXHEIGHT, RH
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE PRESSURE_MOD, ONLY : GET_PCENTER
|
|
USE TRACER_MOD, ONLY : SALA_REDGE_um, SALC_REDGE_um, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO4s, IDTNITs
|
|
USE TIME_MOD, ONLY : GET_ELAPSED_SEC, GET_TS_CHEM
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_GCTM" ! g0
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: N
|
|
REAL*8, INTENT(INOUT) :: TC(IIPAR,JJPAR,LLPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, DTCHEM
|
|
REAL*8 :: DELZ, DELZ1, REFF
|
|
REAL*8 :: P, DP, PDP, TEMP
|
|
REAL*8 :: CONST, SLIP, VISC, FAC1
|
|
REAL*8 :: FAC2, FLUX, AREA_CM2, RHB
|
|
! replace RCM (radius in CM with RUM radius in microns) jaegle 5/11/11
|
|
REAL*8 :: RUM, RWET, RATIO_R, RHO
|
|
REAL*8 :: TOT1, TOT2
|
|
REAL*8 :: VTS(LLPAR)
|
|
REAL*8 :: TC0(LLPAR)
|
|
! added variables for density calculation (jaegle, bec 5/11/11)
|
|
REAL*8 :: RHO1, WTP
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: C1 = 0.7674d0
|
|
REAL*8, PARAMETER :: C2 = 3.079d0
|
|
REAL*8, PARAMETER :: C3 = 2.573d-11
|
|
REAL*8, PARAMETER :: C4 = -1.424d0
|
|
REAL*8, PARAMETER :: DEN = 2200.0d0 ! [kg/m3] sea-salt density
|
|
! Parameters for polynomial coefficients to derive seawater
|
|
! density. From Tang et al. (1997) (bec, jaegle, 5/11/11)
|
|
REAL*8, PARAMETER :: A1 = 7.93d-3 !from Tang et al., 1997 (bec, 6/17/10)
|
|
REAL*8, PARAMETER :: A2 = -4.28d-5
|
|
REAL*8, PARAMETER :: A3 = 2.52d-6
|
|
REAL*8, PARAMETER :: A4 = -2.35d-8
|
|
REAL*8, PARAMETER :: EPSI = 1.0D-4
|
|
|
|
! Arrays
|
|
INTEGER :: IDDEP(2)
|
|
INTEGER :: IDTRC(2)
|
|
|
|
!=================================================================
|
|
! GRAV_SETTLING begins here!
|
|
!=================================================================
|
|
|
|
! Return if tracers are undefined
|
|
IF ( IDTSO4s == 0 .and. IDTNITs == 0 ) RETURN
|
|
|
|
! Return if it's the start of the run
|
|
IF ( GET_ELAPSED_SEC() == 0 ) RETURN
|
|
|
|
! Chemistry timestep [s]
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Store in IDDEP array
|
|
IDDEP(1) = DRYSO4s
|
|
IDDEP(2) = DRYNITs
|
|
|
|
! Tracer array
|
|
IDTRC(1) = IDTSO4s
|
|
IDTRC(2) = IDTNITs
|
|
|
|
! Coarse mode
|
|
REFF = 0.5d-6 * ( SALC_REDGE_um(1) + SALC_REDGE_um(2) )
|
|
|
|
! Sea salt radius [cm]
|
|
!RCM = REFF * 100d0
|
|
! The Gerber formula for hygroscopic growth uses the radius in micrometers
|
|
! instead of centimeters. This fix is implemented by using RUM instead of RCM
|
|
! RCM is changed to RUM below
|
|
! (jaegle 5/5/11)
|
|
! Sea salt radius [um]
|
|
RUM = REFF * 1d6
|
|
|
|
|
|
! Exponential factors
|
|
! replace with radius in microns (jaegle 5/5/11)
|
|
FAC1 = C1 * ( RUM**C2 )
|
|
FAC2 = C3 * ( RUM**C4 )
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, VTS, P, TEMP, RHB, RWET )
|
|
!$OMP+PRIVATE( RATIO_R, RHO, DP, PDP, CONST, SLIP, VISC, TC0 )
|
|
!$OMP+PRIVATE( DELZ, DELZ1, TOT1, TOT2, AREA_CM2, FLUX )
|
|
!$OMP+PRIVATE( RHO1, WTP ) !bec (5/11/11)
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Initialize
|
|
DO L = 1, LLPAR
|
|
VTS(L) = 0d0
|
|
ENDDO
|
|
|
|
! Loop over levels
|
|
DO L = 1, LLPAR
|
|
|
|
! Pressure at center of the level [kPa]
|
|
P = GET_PCENTER(I,J,L) * 0.1d0
|
|
|
|
! Temperature [K]
|
|
TEMP = T(I,J,L)
|
|
|
|
! Cap RH at 0.99
|
|
RHB = MIN( 0.99d0, RH(I,J,L) * 1d-2 )
|
|
|
|
! Safety check (phs, 5/1/08)
|
|
RHB = MAX( TINY(RHB), RHB )
|
|
|
|
! Aerosol growth with relative humidity in radius [m]
|
|
! (Gerber, 1985)
|
|
!RWET = 0.01d0*(FAC1/(FAC2-DLOG(RHB))+RUM**3.d0)**0.33d0
|
|
! Several bug fixes to the Gerber formulation: a log10 (instead of ln) should be used and
|
|
! the dry radius should be expressed in micrometers (instead of cm) also add more significant digits to the exponent
|
|
! (jaegle 5/5/11)
|
|
!RWET = 1d-6*(FAC1/(FAC2-LOG10(RHB))+RUM**3.d0)**0.33333d0
|
|
|
|
! Use equation 5 in Lewis and Schwartz (2006) [m] for sea salt growth (jaegle 5/11/11)
|
|
RWET = REFF * (4.d0 / 3.7d0) *
|
|
& ( (2.d0 - RHB)/(1.d0 - RHB) )**(1.d0/3.d0)
|
|
|
|
|
|
! Ratio dry over wet radii at the cubic power
|
|
RATIO_R = ( REFF / RWET )**3.d0
|
|
|
|
! Density of the wet aerosol (kg/m3)
|
|
!RHO = RATIO_R * DEN + ( 1.d0 - RATIO_R ) * 1000.d0
|
|
|
|
|
|
! Above density calculation is chemically unsound because it ignores chemical solvation.
|
|
! Iteratively solve Tang et al., 1997 equation 5 to calculate density of wet aerosol (kg/m3)
|
|
! (bec, jaegle 5/11/11)
|
|
RATIO_R = ( REFF / RWET )
|
|
! Assume an initial density of 1000 kg/m3
|
|
RHO = 1000.D0
|
|
RHO1 = 0.d0 !initialize (bec, 6/21/10)
|
|
DO WHILE ( ABS( RHO1-RHO ) .gt. EPSI )
|
|
! First calculate weight percent of aerosol (kg_RH=0.8/kg_wet)
|
|
WTP = 100.d0 * DEN/RHO * RATIO_R**3.d0
|
|
! Then calculate density of wet aerosol using equation 5
|
|
! in Tang et al., 1997 [kg/m3]
|
|
RHO1 = ( 0.9971d0 + (A1 * WTP) + (A2 * WTP**2.d0) +
|
|
$ (A3 * WTP**3.d0) + (A4 * WTP**4.d0) ) * 1000.d0
|
|
! Now calculate new weight percent using above density calculation
|
|
WTP = 100.d0 * DEN/RHO1 * RATIO_R**3.d0
|
|
! Now recalculate new wet density [kg/m3]
|
|
RHO = ( 0.9971d0 + (A1 * WTP) + (A2 * WTP**2.d0) +
|
|
$ (A3 * WTP**3.d0) + (A4 * WTP**4.d0) ) * 1000.d0
|
|
ENDDO
|
|
|
|
! Dp = particle diameter [um]
|
|
DP = 2.d0 * RWET * 1.d6
|
|
|
|
! PdP = P * dP [hPa * um]
|
|
PDp = P * Dp
|
|
|
|
! Constant
|
|
CONST = 2.d0 * RHO * RWET**2 * g0 / 9.d0
|
|
|
|
!===========================================================
|
|
! NOTE: Slip correction factor calculations following
|
|
! Seinfeld, pp464 which is thought to be more accurate
|
|
! but more computation required. (rjp, 1/24/02)
|
|
!
|
|
! # air molecule number density
|
|
! num = P * 1d3 * 6.023d23 / (8.314 * Temp)
|
|
!
|
|
! # gas mean free path
|
|
! lamda = 1.d6/( 1.41421 * num * 3.141592 * (3.7d-10)**2 )
|
|
!
|
|
! # Slip correction
|
|
! Slip = 1. + 2. * lamda * (1.257 + 0.4 * exp( -1.1 * Dp
|
|
! & / (2. * lamda))) / Dp
|
|
!
|
|
! NOTE: Eq) 3.22 pp 50 in Hinds (Aerosol Technology)
|
|
! which produces slip correction factore with small error
|
|
! compared to the above with less computation.
|
|
!===========================================================
|
|
|
|
! Slip correction factor (as function of P*dp)
|
|
Slip = 1.d0+(15.60d0 + 7.0d0 * EXP(-0.059d0 * PDp)) / PDp
|
|
|
|
! Viscosity [Pa*s] of air as a function of temperature
|
|
VISC = 1.458d-6 * (Temp)**(1.5d0) / ( Temp + 110.4d0 )
|
|
|
|
! Settling velocity [m/s]
|
|
VTS(L) = CONST * Slip / VISC
|
|
ENDDO
|
|
|
|
! Method is to solve bidiagonal matrix which is
|
|
! implicit and first order accurate in z (rjp, 1/24/02)
|
|
|
|
! Save initial tracer concentration in column
|
|
DO L = 1, LLPAR
|
|
TC0(L) = TC(I,J,L)
|
|
ENDDO
|
|
|
|
! We know the boundary condition at the model top
|
|
L = LLTROP
|
|
DELZ = BXHEIGHT(I,J,L)
|
|
|
|
TC(I,J,L) = TC(I,J,L) / ( 1.d0 + DTCHEM * VTS(L) / DELZ )
|
|
|
|
DO L = LLTROP-1, 1, -1
|
|
DELZ = BXHEIGHT(I,J,L)
|
|
DELZ1 = BXHEIGHT(I,J,L+1)
|
|
TC(I,J,L) = 1.d0 / ( 1.d0 + DTCHEM * VTS(L) / DELZ )
|
|
& * ( TC(I,J,L) + DTCHEM * VTS(L+1) / DELZ1
|
|
& * TC(I,J,L+1) )
|
|
ENDDO
|
|
|
|
!==============================================================
|
|
! ND44 diagnostic: sea salt loss [molec/cm2/s]
|
|
!==============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
|
|
! Initialize
|
|
TOT1 = 0d0
|
|
TOT2 = 0d0
|
|
|
|
! Compute column totals of TCO(:) and TC(I,J,:,N)
|
|
DO L = 1, LLPAR
|
|
TOT1 = TOT1 + TC0(L)
|
|
TOT2 = TOT2 + TC(I,J,L)
|
|
ENDDO
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert sea salt flux from [kg/s] to [molec/cm2/s]
|
|
FLUX = ( TOT1 - TOT2 ) / DTCHEM
|
|
FLUX = FLUX * XNUMOL(IDTRC(N)) / AREA_CM2
|
|
|
|
! Store in AD44 array
|
|
AD44(I,J,IDDEP(N),1) = AD44(I,J,IDDEP(N),1) + FLUX
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE GRAV_SETTLING
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_DMS
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_DMS is the DMS chemistry subroutine from Mian Chin's
|
|
! GOCART model, modified for use with the GEOS-CHEM model.
|
|
! (rjp, bdf, bmy, 5/31/00, 10/25/05)
|
|
!
|
|
! Module Variables used:
|
|
! ============================================================================
|
|
! (1 ) PSO2_DMS (REAL*8 ) : Array for P(SO2) from DMS [v/v]
|
|
! (2 ) PMSA_DMS (REAL*8 ) : Array for P(MSA) from DMS [v/v]
|
|
!
|
|
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
|
|
! ============================================================================
|
|
!
|
|
! R1: DMS + OH -> a*SO2 + b*MSA OH addition channel
|
|
! k1 = { 1.7e-42*exp(7810/T)*[O2] / (1+5.5e-31*exp(7460/T)*[O2] }
|
|
! a = 0.75, b = 0.25
|
|
!
|
|
! R2: DMS + OH -> SO2 + ... OH abstraction channel
|
|
! k2 = 1.2e-11*exp(-260/T)
|
|
!
|
|
! DMS_OH = DMS0 * exp(-(r1+r2)* NDT1)
|
|
! where DMS0 is the DMS concentration at the beginning,
|
|
! r1 = k1*[OH], r2 = k2*[OH].
|
|
!
|
|
! R3: DMS + NO3 -> SO2 + ...
|
|
! k3 = 1.9e-13*exp(500/T)
|
|
!
|
|
! DMS = DMS_OH * exp(-r3*NDT1)
|
|
! where r3 = k3*[NO3].
|
|
!
|
|
! R4: DMS + X -> SO2 + ...
|
|
! assume to be at the rate of DMS+OH and DMS+NO3 combined.
|
|
!
|
|
! The production of SO2 and MSA here, PSO2_DMS and PMSA_DMS, are saved
|
|
! for use in CHEM_SO2 and CHEM_MSA subroutines as a source term. They
|
|
! are in unit of [v/v/timestep].
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD, AIRDEN, and SUNCOS from "dao_mod.f". Added
|
|
! parallel DO-loops. Also now extract OH and NO3 from SMVGEAR
|
|
! for coupled chemistry-aerosol runs. (rjp, bdf, bmy, 9/16/02)
|
|
! (2 ) Bug fix: remove duplicate definition of RK3 (bmy, 3/23/03)
|
|
! (3 ) Now use function GET_TS_CHEM from "time_mod.f". (bmy, 3/27/03)
|
|
! (4 ) Now reference STT and ITS_A_FULLCHEM_SIM from "tracer_mod.f"
|
|
! Now replace IJSURF w/ an analytic function. (bmy, 7/20/04)
|
|
! (5 ) Shift rows 8,9 in AD05 to 9,10 in to make room for P(SO4) from O3
|
|
! oxidation in sea-salt aerosols (bec, bmy, 4/13/05)
|
|
! (6 ) Now remove reference to CMN, it's obsolete. Now reference
|
|
! ITS_IN_THE_STRAT from "tropopause_mod.f". (bmy, 8/22/05)
|
|
! (7 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (8 ) Now correctly records P(SO2) from OH in AD05 (pjh)
|
|
! (9 ) Update reaction rate to match JPL06 and full chem (jaf, bmy, 10/15/09)
|
|
!******************************************************************************
|
|
|
|
!
|
|
! Reference to F90 modules
|
|
USE DAO_MOD, ONLY : AD, AIRDEN, SUNCOS, T
|
|
USE DIAG_MOD, ONLY : AD05
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, ITS_A_FULLCHEM_SIM, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTDMS
|
|
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_GCTM" ! AIRMW
|
|
# include "CMN_DIAG" ! ND05, LD05
|
|
|
|
! Local variables
|
|
LOGICAL :: IS_FULLCHEM
|
|
INTEGER :: I, J, L, IJLOOP
|
|
REAL*8 :: TK, O2, RK1, RK2, RK3, F
|
|
REAL*8 :: DMS, DMS0, DMS_OH, DTCHEM, XOH, XN3
|
|
REAL*8 :: XX, OH, OH0, XNO3, XNO30, LOH
|
|
REAL*8 :: LNO3
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: FX = 1.0d0
|
|
REAL*8, PARAMETER :: A = 0.75d0
|
|
REAL*8, PARAMETER :: B = 0.25d0
|
|
|
|
! From D4: only 0.8 efficiency, also some goes to DMSO and lost.
|
|
! So we assume 0.75 efficiency for DMS addtion channel to form
|
|
! products.
|
|
REAL*8, PARAMETER :: EFF = 1d0
|
|
|
|
! External functions
|
|
REAL*8, EXTERNAL :: BOXVL
|
|
|
|
!=================================================================
|
|
! CHEM_DMS begins here!
|
|
!=================================================================
|
|
IF ( IDTDMS == 0 ) RETURN
|
|
|
|
! Flag for fullchem simulation
|
|
IS_FULLCHEM = ITS_A_FULLCHEM_SIM()
|
|
|
|
! DTCHEM is the chemistry timestep in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Factor to convert AIRDEN from kgair/m3 to molecules/cm3:
|
|
f = 1000.d0 / AIRMW * 6.022d23 * 1.d-6
|
|
|
|
!=================================================================
|
|
! Do the chemistry over all tropospheric grid boxes!
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, IJLOOP, J, L, TK, O2, DMS0, OH, XNO3, RK1, RK2 )
|
|
!$OMP+PRIVATE( RK3, DMS_OH, DMS, OH0, XNO30, XOH, XN3, XX, LOH, LNO3 )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Skip stratospheric boxes
|
|
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
|
|
|
|
! IJLOOP is the 1-D grid box index for SUNCOS
|
|
IJLOOP = ( (J-1) * IIPAR ) + I
|
|
|
|
! Temperature [K]
|
|
TK = T(I,J,L)
|
|
|
|
! Get O2 [molec/cm3], DMS [v/v], OH [molec/cm3], NO3 [molec/cm3]
|
|
O2 = AIRDEN(L,I,J) * f * 0.21d0
|
|
DMS0 = STT(I,J,L,IDTDMS)
|
|
OH = GET_OH( I, J, L )
|
|
XNO3 = GET_NO3( I, J, L )
|
|
|
|
!==============================================================
|
|
! (1) DMS + OH: RK1 - addition channel
|
|
! RK2 - abstraction channel
|
|
!==============================================================
|
|
RK1 = 0.d0
|
|
RK2 = 0.d0
|
|
RK3 = 0.d0
|
|
|
|
IF ( OH > 0.d0 ) THEN
|
|
RK1 = ( 1.7d-42 * EXP( 7810.d0 / TK ) * O2 ) /
|
|
& ( 1.d0 + 5.5d-31 * EXP( 7460.d0 / TK ) * O2 ) * OH
|
|
|
|
!---------------------------------------------------------
|
|
! Prior to 10/15/09:
|
|
!RK2 = 1.2d-11 * EXP( -260.d0 / TK ) * OH
|
|
!---------------------------------------------------------
|
|
|
|
! Update reaction rate to match JPL06 and full chem
|
|
! (jaf, bmy, 10/15/09)
|
|
RK2 = 1.1d-11 * EXP( -240.d0 / TK ) * OH
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! (2) DMS + NO3 (only happens at night):
|
|
!==============================================================
|
|
IF ( SUNCOS(IJLOOP) <= 0d0 ) THEN
|
|
RK3 = 1.9d-13 * EXP( 500.d0 / TK ) * XNO3
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! Update DMS concentrations after reaction with OH and NO3,
|
|
! and also account for DMS + X assuming at a rate as
|
|
! (DMS+OH)*Fx in the day and (DMS+NO3)*Fx at night:
|
|
!
|
|
! DMS_OH : DMS concentration after reaction with OH
|
|
! DMS : DMS concentration after reaction with NO3
|
|
! (min(DMS) = 1.0E-32)
|
|
!
|
|
! NOTE: If we are doing a coupled fullchem/aerosol run, then
|
|
! also modify OH and NO3 concentrations after rxn w/ DMS.
|
|
!==============================================================
|
|
DMS_OH = DMS0 * EXP( -( RK1 + RK2 ) * Fx * DTCHEM )
|
|
DMS = DMS_OH * EXP( -( RK3 ) * Fx * DTCHEM )
|
|
IF ( DMS < SMALLNUM ) DMS = 0d0
|
|
|
|
! Archive initial OH and NO3 for diagnostics
|
|
OH0 = OH
|
|
XNO30 = XNO3
|
|
|
|
IF ( IS_FULLCHEM ) THEN
|
|
|
|
! Update OH after rxn w/ DMS (coupled runs only)
|
|
OH = OH0 - ( ( DMS0 - DMS_OH ) * AIRDEN(L,I,J) * f )
|
|
IF ( OH < SMALLNUM ) OH = 0d0
|
|
|
|
! Update NO3 after rxn w/ DMS (coupled runs only)
|
|
XNO3 = XNO30 - ( ( DMS_OH - DMS ) * AIRDEN(L,I,J) * f )
|
|
IF ( XNO3 < SMALLNUM ) XNO3 = 0d0
|
|
|
|
ENDIF
|
|
|
|
! Save DMS back to the tracer array
|
|
STT(I,J,L,IDTDMS) = DMS
|
|
|
|
!==============================================================
|
|
! Save SO2 and MSA production from DMS oxidation
|
|
! in [mixing ratio/timestep]:
|
|
!
|
|
! SO2 is formed in DMS+OH addition (0.85) and abstraction
|
|
! (1.0) channels as well as DMS + NO3 reaction. We also
|
|
! assume that SO2 yield from DMS + X is 1.0.
|
|
!
|
|
! MSA is formed in DMS + OH addition (0.15) channel.
|
|
!==============================================================
|
|
IF ( ( RK1 + RK2 ) == 0.d0 ) THEN
|
|
PMSA_DMS(I,J,L) = 0.d0
|
|
ELSE
|
|
PMSA_DMS(I,J,L) = ( DMS0 - DMS_OH ) *
|
|
& B*RK1 / ( ( RK1 + RK2 ) * Fx ) * EFF
|
|
ENDIF
|
|
|
|
PSO2_DMS(I,J,L) = DMS0 - DMS - PMSA_DMS(I,J,L)
|
|
|
|
!==============================================================
|
|
! ND05 diagnostic: production and loss
|
|
!
|
|
! For the offline run, we are reading in monthly mean OH, NO3
|
|
! from disk. We don't modify these, so LOH = 0 and LNO3 = 0.
|
|
!==============================================================
|
|
IF ( ND05 > 0 .and. L <= LD05 ) THEN
|
|
|
|
! P(SO2) from DMS+OH, DMS+NO3, and DMS+X
|
|
!---prior 8/10/09 (pjh)
|
|
! now correctly records P(SO2) from OH (pjh)
|
|
! XOH = ( DMS0 - DMS_OH ) / Fx * AD(I,J,L) / TCVV_S
|
|
XOH = ( DMS0 - DMS_OH - PMSA_DMS(I,J,L) ) /
|
|
$ Fx * AD(I,J,L) / TCVV_S
|
|
XN3 = ( DMS_OH - DMS ) / Fx * AD(I,J,L) / TCVV_S
|
|
XX = ( ( DMS0 - DMS ) * AD(I,J,L) / TCVV_S ) - XOH - XN3
|
|
|
|
! Convert L(OH) and L(NO3) from [molec/cm3] to [kg/timestep]
|
|
LOH = ( OH0 - OH ) * BOXVL(I,J,L) / XNUMOL_OH
|
|
LNO3 = ( XNO30 - XNO3 ) * BOXVL(I,J,L) / XNUMOL_NO3
|
|
|
|
! Store P(SO2) from DMS + OH [kg S/timestep]
|
|
AD05(I,J,L,1) = AD05(I,J,L,1) + XOH
|
|
|
|
! Store P(SO2) from DMS + NO3 [kg S/timestep]
|
|
AD05(I,J,L,2) = AD05(I,J,L,2) + XN3
|
|
|
|
! Store total P(SO2) from DMS [kg S/timestep]
|
|
AD05(I,J,L,3) = AD05(I,J,L,3) +
|
|
& ( PSO2_DMS(I,J,L) * AD(I,J,L) / TCVV_S )
|
|
|
|
! Store P(MSA) from DMS [kg S/timestep]
|
|
AD05(I,J,L,4) = AD05(I,J,L,4) +
|
|
& ( PMSA_DMS(I,J,L) * AD(I,J,L) / TCVV_S )
|
|
|
|
! Store L(OH) by DMS [kg OH/timestep]
|
|
AD05(I,J,L,9) = AD05(I,J,L,9) + LOH
|
|
|
|
! Store L(NO3) by DMS [kg NO3/timestep]
|
|
AD05(I,J,L,10) = AD05(I,J,L,10) + LNO3
|
|
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! For a coupled fullchem/aerosol run, save OH [molec/cm3]
|
|
! and NO3 [molec/cm3] back into the CSPEC array of SMVGEAR
|
|
!==============================================================
|
|
IF ( IS_FULLCHEM ) THEN
|
|
CALL SET_OH( I, J, L, OH )
|
|
CALL SET_NO3( I, J, L, XNO3 )
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_DMS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_H2O2
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_H2O2 is the H2O2 chemistry subroutine for offline sulfate
|
|
! simulations. For coupled runs, H2O2 chemistry is already computed by
|
|
! the SMVGEAR module. (rjp, bmy, 11/26/02, 10/25/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Bug fix: need to multiply DXYP by 1d4 for cm2 (bmy, 3/23/03)
|
|
! (2 ) Now replace DXYP(JREF)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
|
|
! Now use functions GET_MONTH and GET_TS_CHEM from "time_mod.f".
|
|
! (bmy, 3/27/03)
|
|
! (3 ) Now references PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! throughout the entire PBL. Added FREQ variable. (bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use diurnally-varying JO1D. Now use new unit conversion for
|
|
! the ND44 diagnostic. (rjp, bmy, 3/30/04)
|
|
! (6 ) Now use parallel DO-loop to zero ND44_TMP. Now uses ITS_A_NEW_MONTH
|
|
! from time_mod.f. (bmy, 4/14/04)
|
|
! (7 ) Now reference STT & TCVV from "tracer_mod.f". Also replace IJSURF
|
|
! with an analytic function. Now references DATA_DIR from
|
|
! "directory_mod.f". (bmy, 7/20/04)
|
|
! (8 ) Now suppress output from READ_BPCH with QUIET keyword (bmy, 1/25/05)
|
|
! (9 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP
|
|
! from "pbl_mix_mod.f" (bmy, 2/22/05)
|
|
! (10) Now read offline files from "sulfate_sim_200508/offline". Now remove
|
|
! reference to CMN, it's obsolete. Now reference ITS_IN_THE_STRAT from
|
|
! "tropopause_mod.f". (bmy, 8/22/05)
|
|
! (11) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (12) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DAO_MOD, ONLY : AD, AIRDEN, OPTD, SUNCOS, T
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP
|
|
USE TIME_MOD, ONLY : GET_MONTH, GET_TS_CHEM, ITS_A_NEW_MONTH
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTH2O2
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_3D_TROP
|
|
USE UVALBEDO_MOD, ONLY : UVALBEDO
|
|
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
|
|
# include "cmn_fj.h" ! IPAR, JPAR, LPAR, CMN_SIZE
|
|
# include "CMN_GCTM" ! AIRMW
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
LOGICAL :: FIRST = .TRUE.
|
|
INTEGER, SAVE :: LASTMONTH = -99
|
|
INTEGER :: I, J, L, JLOOP
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,LLTROP)
|
|
REAL*8 :: ND44_TMP(IIPAR,JJPAR,LLTROP)
|
|
REAL*8 :: DT, Koh, DH2O2, M, F , XTAU
|
|
REAL*8 :: H2O20, H2O2, ALPHA, FLUX, FREQ, PHOTJ
|
|
REAL*8, PARAMETER :: A = 2.9d-12
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! CHEM_H2O2 begins here!
|
|
!=================================================================
|
|
IF ( IDTH2O2 == 0 .or. DRYH2O2 == 0 ) RETURN
|
|
|
|
! Chemistry timestep [s]
|
|
DT = GET_TS_CHEM() * 60d0
|
|
|
|
! Factor to convert AIRDEN from kgair/m3 to molecules/cm3:
|
|
F = 1000.d0 / AIRMW * 6.022d23 * 1.d-6
|
|
|
|
! Zero ND44_TMP array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
ND44_TMP(I,J,L) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! For offline run: read J(H2O2) from disk below
|
|
!=================================================================
|
|
IF ( ITS_A_NEW_MONTH() ) THEN
|
|
|
|
! File name to read data
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/offline/JH2O2.' //
|
|
& GET_NAME_EXT() // '.' // GET_RES_EXT()
|
|
|
|
! Print filename
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - CHEM_H2O2: Reading ', a )
|
|
|
|
! Get TAU0 value for this month in "generic" year 1985
|
|
XTAU = GET_TAU0( GET_MONTH(), 1, 1985 )
|
|
|
|
! Read J(H2O2) [s-1] from disk (only up to tropopause)
|
|
! limit array 3d dimension to LLTROP_FIX, i.e, case of annual mean
|
|
! tropopause. This is backward compatibility with
|
|
! offline data set.
|
|
CALL READ_BPCH2( FILENAME, 'JV-MAP-$', 3,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& LLTROP_FIX, ARRAY(:,:,1:LLTROP_FIX), QUIET=.TRUE. )
|
|
! & XTAU, IGLOB, JGLOB,
|
|
! & LLTROP, ARRAY, QUIET=.TRUE. )
|
|
|
|
|
|
|
|
! Cast to REAL*8 and resize if necessary
|
|
CALL TRANSFER_3D_TROP( ARRAY, JH2O2 )
|
|
|
|
! Reset LASTMONTH
|
|
!LASTMONTH = GET_MONTH()
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! Loop over tropopsheric grid boxes and do chemistry
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, M, H2O20, KOH, FREQ, ALPHA, DH2O2, H2O2, FLUX )
|
|
!$OMP+PRIVATE( JLOOP, PHOTJ )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Initialize for safety's sake
|
|
FLUX = 0d0
|
|
FREQ = 0d0
|
|
|
|
! Skip stratospheric boxes
|
|
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
|
|
|
|
! Density of air [molec/cm3]
|
|
M = AIRDEN(L,I,J) * f
|
|
|
|
! Initial H2O2 [v/v]
|
|
H2O20 = STT(I,J,L,IDTH2O2)
|
|
|
|
! Loss frequenty due to OH oxidation [s-1]
|
|
KOH = A * EXP( -160.d0 / T(I,J,L) ) * GET_OH(I,J,L)
|
|
|
|
! H2O2 drydep frequency [1/s]. Account for the fraction
|
|
! of grid box (I,J,L) that is located beneath the PBL top.
|
|
FREQ = DEPSAV(I,J,DRYH2O2) * GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! 1-D grid box index for SUNCOS
|
|
JLOOP = ( (J-1) * IIPAR ) + I
|
|
|
|
! Impose a diurnal variation of jH2O2 by multiplying COS of
|
|
! solar zenith angle normalized by maximum solar zenith angle
|
|
! because the archived JH2O2 is for local noon time
|
|
IF ( COSZM(I,J) > 0.d0 ) THEN
|
|
PHOTJ = JH2O2(I,J,L) * SUNCOS(JLOOP) / COSZM(I,J)
|
|
PHOTJ = MAX( PHOTJ, 0d0 )
|
|
ELSE
|
|
PHOTJ = 0d0
|
|
ENDIF
|
|
|
|
! Compute loss fraction from OH, photolysis, drydep [unitless].
|
|
ALPHA = 1.D0 + ( KOH + PHOTJ + FREQ ) * DT
|
|
|
|
! Delta H2O2 [v/v]
|
|
DH2O2 = PH2O2m(I,J,L) * DT / ( ALPHA * M )
|
|
|
|
! Final H2O2 [v/v]
|
|
H2O2 = ( H2O20 / ALPHA + DH2O2 )
|
|
IF ( H2O2 < SMALLNUM ) H2O2 = 0d0
|
|
|
|
! Store final H2O2 in STT
|
|
STT(I,J,L,IDTH2O2) = H2O2
|
|
|
|
!==============================================================
|
|
! ND44 diagnostics: H2O2 drydep loss [molec/cm2/s]
|
|
!==============================================================
|
|
IF ( ND44 > 0 .AND. FREQ > 0d0 ) THEN
|
|
|
|
! Convert H2O2 from [v/v] to H2O2 [molec/cm2/s]
|
|
FLUX = H2O20 * FREQ * DT / ( 1.D0 + FREQ * DT )
|
|
FLUX = FLUX * AD(I,J,L) / TCVV(IDTH2O2)
|
|
FLUX = FLUX * XNUMOL(IDTH2O2) / ( GET_AREA_CM2( J ) * DT )
|
|
|
|
! Save dryd flx in ND44_TMP as a placeholder
|
|
ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, LLTROP
|
|
AD44(I,J,DRYH2O2,1) = AD44(I,J,DRYH2O2,1) + ND44_TMP(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_H2O2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_SO2
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_SO2 is the SO2 chemistry subroutine
|
|
! (rjp, bmy, 11/26/02, 10/25/05)
|
|
!
|
|
! Module variables used:
|
|
! ============================================================================
|
|
! (1 ) PSO2_DMS (REAL*8 ) : Array for P(SO2) from DMS [v/v/timestep]
|
|
! (2 ) PSO4_SO2 (REAL*8 ) : Array for P(SO4) from SO2 [v/v/timestep]
|
|
! (3 ) LSO2_AQ (REAL*8 ) : Array for L(SO2) from Aqueuos chem [v/v/timestep]
|
|
!
|
|
! Reaction List (by Rokjin Park, rjp@io.harvard.edu)
|
|
! ============================================================================
|
|
! (1 ) SO2 production:
|
|
! DMS + OH, DMS + NO3 (saved in CHEM_DMS)
|
|
!
|
|
! (2 ) SO2 loss:
|
|
! (a) SO2 + OH -> SO4
|
|
! (b) SO2 -> drydep
|
|
! (c) SO2 + H2O2 or O3 (aq) -> SO4
|
|
!
|
|
! (3 ) SO2 = SO2_0 * exp(-bt) + PSO2_DMS/bt * [1-exp(-bt)]
|
|
!
|
|
! where b is the sum of the reaction rate of SO2 + OH and the dry
|
|
! deposition rate of SO2, PSO2_DMS is SO2 production from DMS in
|
|
! MixingRatio/timestep.
|
|
!
|
|
! If there is cloud in the gridbox (fraction = fc), then the aqueous
|
|
! phase chemistry also takes place in cloud. The amount of SO2 oxidized
|
|
! by H2O2 in cloud is limited by the available H2O2; the rest may be
|
|
! oxidized due to additional chemistry, e.g, reaction with O3 or O2
|
|
! (catalyzed by trace metal).
|
|
!
|
|
! NOTES:
|
|
! (1 ) Removed duplicate definition of Ki (bmy, 11/15/01)
|
|
! (2 ) Eliminate duplicate HPLUS definition. Make adjustments to facilitate
|
|
! SMVGEAR chemistry for fullchem runs (rjp, bmy, 3/23/03)
|
|
! (3 ) Now replace DXYP(J+J0)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
|
|
! Now use function GET_TS_CHEM from "time_mod.f".
|
|
! (4 ) Now apply dry deposition to entire PBL. Now references PBLFRAC array
|
|
! from "drydep_mod.f". (bmy, 8/1/03)
|
|
! (5 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (6 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (7 ) Now reference STT, TCVV, & ITS_AN_AEROSOL_SIM from "tracer_mod.f".
|
|
! Now reference DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (8 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f" (bmy, 2/22/05)
|
|
! (9 ) Modified for SO4s, NITs. Also modified for alkalinity w/in the
|
|
! seasalt chemistry. (bec, bmy, 4/13/05)
|
|
! (10) Now remove reference to CMN, it's obsolete. Now reference
|
|
! ITS_IN_THE_STRAT from "tropopause_mod.f" (bmy, 8/22/05)
|
|
! (11) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (12) Updated to match JPL 2006 + full chem (jaf, bmy, 10/15/09)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to diagnostic arrays
|
|
USE DAO_MOD, ONLY : AD, AIRDEN, T
|
|
USE DIAG_MOD, ONLY : AD05, AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE ERROR_MOD, ONLY : IS_SAFE_EXP
|
|
USE GLOBAL_HNO3_MOD, ONLY : GET_GLOBAL_HNO3
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP
|
|
USE PRESSURE_MOD, ONLY : GET_PCENTER
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM, GET_MONTH
|
|
USE TIME_MOD, ONLY : ITS_A_NEW_MONTH
|
|
USE TRACER_MOD, ONLY : STT, TCVV, ITS_AN_AEROSOL_SIM
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTH2O2, IDTSO2
|
|
USE SEASALT_MOD, ONLY : GET_ALK
|
|
USE WETSCAV_MOD, ONLY : H2O2s, SO2s
|
|
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
! adj_group: add checkpointing of SO2 and H2O2 (dkh, 09/28/09)
|
|
USE CHECKPT_MOD, ONLY : SO2_CHK
|
|
USE CHECKPT_MOD, ONLY : H2O2_CHK
|
|
USE LOGICAL_ADJ_MOD, ONLY : LADJ
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_GCTM" ! AIRMW
|
|
# include "CMN_DIAG" ! LD05, ND05, ND44
|
|
|
|
! Local variables
|
|
LOGICAL :: IS_OFFLINE
|
|
INTEGER :: I, J, L, I1, I2
|
|
INTEGER :: II, NSTEP
|
|
REAL*8 :: K0, Ki, KK, M, L1
|
|
REAL*8 :: L2, L3, Ld, F, Fc
|
|
REAL*8 :: RK, RKT, DTCHEM, DT_T, TK
|
|
REAL*8 :: F1, RK1, RK2, RK3, SO20
|
|
REAL*8 :: SO2_cd, H2O20, O3, L2S, L3S
|
|
REAL*8 :: LWC, KaqH2O2, KaqO3, PATM, FLUX
|
|
REAL*8 :: ALK, ALK1, ALK2, SO2_ss
|
|
REAL*8 :: Kt1, Kt2, AREASS1, AREASS2
|
|
REAL*8 :: PSO4E, PSO4F, Kt1N, Kt2N
|
|
REAL*8 :: XX, AREA_CM2
|
|
REAL*8 :: ND44_TMP(IIPAR,JJPAR,LLTROP)
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: HPLUS = 3.16227766016837953d-5 !pH = 4.5
|
|
REAL*8, PARAMETER :: MINDAT = 1.d-20
|
|
|
|
!=================================================================
|
|
! CHEM_SO2 begins here!
|
|
!=================================================================
|
|
|
|
! adj_group: warn about missing processes:
|
|
IF ( LADJ ) THEN
|
|
print*, ' WARNING: removed PSO4E interaction'
|
|
ENDIF
|
|
|
|
IF ( IDTH2O2 == 0 .or. IDTSO2 == 0 .or. DRYSO2 == 0 ) RETURN
|
|
|
|
! Is it an offline simulation?
|
|
IS_OFFLINE = ITS_AN_AEROSOL_SIM()
|
|
|
|
! Read HNO3 for offline simulation
|
|
IF ( IS_OFFLINE ) THEN
|
|
IF ( ITS_A_NEW_MONTH() ) THEN
|
|
CALL GET_GLOBAL_HNO3( GET_MONTH() )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! DTCHEM is the chemistry timestep in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Factor to convert AIRDEN from [kg air/m3] to [molec air/cm3]
|
|
F = 1000.d0 / AIRMW * 6.022d23 * 1.d-6
|
|
!-----------------------------------------------
|
|
! Prior to 10/15/09:
|
|
! Moved this below (jaf, bmy, 10/15/09)
|
|
!Ki = 1.5d-12
|
|
!-----------------------------------------------
|
|
|
|
! Zero ND44_TMP array
|
|
ND44_TMP = 0d0
|
|
|
|
! Loop over tropospheric grid boxes
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, SO20, H2O20, O3, PATM, TK, K0, M, KK, F1, RK1 )
|
|
!$OMP+PRIVATE( RK2, RK, RKT, SO2_cd, L1, Ld, L2, L2S, L3, L3S, FC, LWC )
|
|
!$OMP+PRIVATE( KaqH2O2, KaqO3, AREA_CM2, FLUX, ALK, ALK1, ALK2 )
|
|
!$OMP+PRIVATE( Kt1, Kt2, AREASS1, AREASS2, SO2_ss, Kt1N, Kt2N )
|
|
!$OMP+PRIVATE( PSO4E, PSO4F, XX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Initialize for safety's sake
|
|
AREA_CM2 = 0d0
|
|
FLUX = 0d0
|
|
Ld = 0d0
|
|
|
|
! Skip stratospheric boxes
|
|
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
|
|
|
|
! Initial SO2, H2O2 and O3 [v/v]
|
|
SO20 = STT(I,J,L,IDTSO2)
|
|
H2O20 = STT(I,J,L,IDTH2O2)
|
|
O3 = GET_O3(I,J,L)
|
|
|
|
! Checkpt values of SO2 and H2O2. (dkh, 10/12/05)
|
|
IF ( LADJ ) THEN
|
|
SO2_CHK(I,J,L) = SO20
|
|
H2O2_CHK(I,J,L) = H2O20
|
|
ENDIF
|
|
|
|
! PATM : Atmospheric pressure in atm
|
|
PATM = GET_PCENTER( I, J, L ) / 1013.25d0
|
|
|
|
! TK : Temperature [K]
|
|
TK = T(I,J,L)
|
|
|
|
IF ( IS_OFFLINE ) THEN
|
|
|
|
!-----------------------------------------------------------------
|
|
! Prior to 10/15/09:
|
|
!! Gas phase SO4 production is done here in offline run only
|
|
!! RK1: SO2 + OH(g) [s-1] (rjp, bmy, 3/23/03)
|
|
!K0 = 3.0d-31 * ( 300.d0 / TK )**3.3d0
|
|
!M = AIRDEN(L,I,J) * F
|
|
!KK = K0 * M / Ki
|
|
!F1 = ( 1.d0 + ( LOG10( KK ) )**2 )**( -1 )
|
|
!RK1 = ( K0 * M / ( 1.d0 + KK ) ) * 0.6d0**F1 * GET_OH(I,J,L)
|
|
!-----------------------------------------------------------------
|
|
|
|
! Gas phase SO4 production is done here in offline run only
|
|
! Updated to match JPL 2006 + full chem (jaf, 10/14/09)
|
|
K0 = 3.3d-31 * ( 300.d0 / TK )**4.3d0
|
|
Ki = 1.6d-12
|
|
M = AIRDEN(L,I,J) * F
|
|
KK = K0 * M / Ki
|
|
F1 = ( 1.d0 + ( LOG10( KK ) )**2 )**( -1 )
|
|
RK1 = ( K0 * M / ( 1.d0 + KK ) ) * 0.6d0**F1 * GET_OH(I,J,L)
|
|
|
|
|
|
ELSE
|
|
|
|
! For online runs, SMVGEAR deals w/ this computation,
|
|
! so we can simply set RK1 = 0 (rjp, bmy, 3/23/03)
|
|
K0 = 0.d0
|
|
M = 0.d0
|
|
KK = 0.d0
|
|
F1 = 0.d0
|
|
RK1 = 0.d0
|
|
|
|
ENDIF
|
|
|
|
! SO2 drydep frequency [1/s]. Also accounts for the fraction
|
|
! of grid box (I,J,L) that is located beneath the PBL top.
|
|
RK2 = DEPSAV(I,J,DRYSO2) * GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! RK: total reaction rate [1/s]
|
|
RK = ( RK1 + RK2 )
|
|
|
|
! RKT: RK * DTCHEM [unitless] (bmy, 6/1/00)
|
|
RKT = RK * DTCHEM
|
|
|
|
!==============================================================
|
|
! Update SO2 conc. after gas phase chemistry and deposition
|
|
!==============================================================
|
|
IF ( RK > 0.d0 ) THEN
|
|
SO2_cd = ( SO20 * EXP( -RKT ) ) +
|
|
& ( PSO2_DMS(I,J,L) * ( 1.d0 - EXP( -RKT ) ) / RKT )
|
|
|
|
L1 = ( SO20 - SO2_cd + PSO2_DMS(I,J,L) ) * RK1/RK
|
|
|
|
Ld = ( SO20 - SO2_cd + PSO2_DMS(I,J,L) ) * RK2/RK
|
|
|
|
ELSE
|
|
SO2_cd = SO20
|
|
L1 = 0.d0
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! Update SO2 conc. after seasalt chemistry (bec, 12/7/04)
|
|
!==============================================================
|
|
|
|
! Get alkalinity of accum (ALK1) and coarse (ALK2) [kg]
|
|
CALL GET_ALK( I, J, L, ALK1, ALK2, Kt1, Kt2, Kt1N, Kt2N )
|
|
|
|
! Total alkalinity [kg]
|
|
ALK = ALK1 + ALK2
|
|
|
|
! If (1) there is alkalinity, (2) there is SO2 present, and
|
|
! (3) O3 is in excess, then compute seasalt SO2 chemistry
|
|
IF ( ( ALK > MINDAT ) .AND.
|
|
& ( SO2_cd > MINDAT ) .AND.
|
|
& ( SO2_cd < O3 ) ) THEN
|
|
|
|
! Compute oxidation of SO2 -> SO4 and condensation of
|
|
! HNO3 -> nitrate within the seasalt aerosol
|
|
CALL SEASALT_CHEM( I, J, L, ALK1, ALK2,
|
|
& SO2_cd, Kt1, Kt2, Kt1N, Kt2N,
|
|
& SO2_ss, PSO4E, PSO4F )
|
|
|
|
ELSE
|
|
|
|
! Otherwise set equal to zero
|
|
SO2_ss = SO2_cd
|
|
PSO4E = 0.d0
|
|
PSO4F = 0.d0
|
|
PNITS(I,J,L) = 0.d0
|
|
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! Update SO2 concentration after cloud chemistry
|
|
! SO2 chemical loss rate = SO4 production rate [v/v/timestep]
|
|
!==============================================================
|
|
|
|
! Volume cloud fraction (Sundqvist et al 1989) [unitless]
|
|
FC = VCLDF(I,J,L)
|
|
|
|
! Liquid water content in cloudy area of grid box [m3/m3]
|
|
LWC = GET_LWC( TK ) * FC
|
|
|
|
! Zero variables
|
|
KaqH2O2 = 0.d0
|
|
KaqO3 = 0.d0
|
|
L2 = 0.d0
|
|
L3 = 0.d0
|
|
L2S = 0.d0
|
|
L3S = 0.d0
|
|
|
|
! If (1) there is cloud, (2) there is SO2 present, and
|
|
! (3) the T > -15 C, then compute aqueous SO2 chemistry
|
|
IF ( ( FC > 0.d0 ) .AND.
|
|
& ( SO2_ss > MINDAT ) .AND.
|
|
& ( TK > 258.0 ) ) THEN
|
|
|
|
!===========================================================
|
|
! NOTE...Sulfate production from aquatic reactions of SO2
|
|
! with H2O2 & O3 is computed here and followings are
|
|
! approximations or method used for analytical (integral)
|
|
! solution of these computations. Please email us
|
|
! (rjp@io.harvard.edu or bmy@io.harvard.edu) if you find
|
|
! anything wrong or questionable.
|
|
!
|
|
! 1) with H2O2(aq)
|
|
! [HSO3-] + [H+] + [H2O2(aq)] => [SO4=] (rxn)
|
|
! d[SO4=]/dt = k[H+][HSO3-][H2O2(aq)] (M/s) (rate)
|
|
!
|
|
! we can rewrite k[H+][HSO3-] as K1 pSO2 hSO2,
|
|
! where pSO2 is equilibrium vapor pressure of SO2(g)
|
|
! in atm, and hSO2 is henry's law constant for SO2
|
|
!
|
|
! Therefore, rate can be written as
|
|
!
|
|
! k * K1 * pSO2 * hSO2 * pH2O2 * hH2O2,
|
|
!
|
|
! where pH2O2 is equilibrium vapor pressure of H2O2(g),
|
|
! and hH2O2 is henry's law constant for H2O2. Detailed
|
|
! values are given in AQCHEM_SO2 routine.
|
|
!
|
|
! Let us define a fraction of gas phase of A species
|
|
! in equilibrium with aqueous phase as
|
|
!
|
|
! xA = 1/(1+f),
|
|
!
|
|
! where f = hA * R * T * LWC,
|
|
! hA = Henry's constant,
|
|
! R = gas constant,
|
|
! T = temperature in kelvin,
|
|
! LWC = liquid water content [m3/m3]
|
|
!
|
|
! As a result, the rate would become:
|
|
!
|
|
! d[SO4=]
|
|
! ------- = k K1 hSO2 hH2O2 xSO2 xH2O2 P P [SO2][H2O2]
|
|
! dt
|
|
! ^ ^ ^ ^ ^
|
|
! | |____________________________| | |
|
|
!
|
|
! mole/l/s mole/l/s v/v v/v
|
|
!
|
|
!
|
|
! And we multiply rate by (LWC * R * T / P) in order to
|
|
! convert unit from mole/l/s to v/v/s
|
|
!
|
|
! Finally we come to
|
|
!
|
|
! d[SO4=]
|
|
! ------- = KaqH2O2 [SO2][H2O2],
|
|
! dt
|
|
!
|
|
! where
|
|
!
|
|
! KaqH2O2 = k K1 hSO2 hH2O2 xSO2 xH2O2 P LWC R T,
|
|
!
|
|
! this new rate corresponds to a typical second order
|
|
! reaction of which analytical (integral) solution is
|
|
!
|
|
! X = A0 B0 ( exp[(A0-B0) Ka t] - 1 )
|
|
! / ( A0 exp[(A0-B0) Ka t] - B0 )
|
|
!
|
|
! inserting variables into solution then we get
|
|
! [SO4=] = [SO2][H2O2](exp[([SO2]-[H2O2]) KaqH2O2 t] - 1 )
|
|
! / ( [SO2] exp[([SO2]-[H2O2]) KaqH2O2 t] - [H2O2] )
|
|
!
|
|
! Note...Exactly same method can be applied to O3 reaction
|
|
! in aqueous phase with different rate constants.
|
|
!===========================================================
|
|
|
|
! Compute aqueous rxn rates for SO2
|
|
CALL AQCHEM_SO2( LWC, TK, PATM, SO2_ss, H2O20,
|
|
& O3, HPLUS, KaqH2O2, KaqO3 )
|
|
|
|
|
|
! Previous code
|
|
!! Aqueous phase SO2 loss rate (v/v/timestep):
|
|
!L2 = EXP( ( SO2_ss - H2O20 ) * KaqH2O2 * DTCHEM )
|
|
!L3 = EXP( ( SO2_ss - O3 ) * KaqO3 * DTCHEM )
|
|
!
|
|
!! Loss by H2O2
|
|
!L2S = SO2_ss * H2O20 * (L2 - 1.D0) / ((SO2_ss * L2) - H2O20)
|
|
!
|
|
!! Loss by O3
|
|
!L3S = SO2_ss * O3 * (L3 - 1.D0) / ((SO2_ss * L3) - O3)
|
|
|
|
!----------------------------------------------------------
|
|
! Compute loss by H2O2. Prevent floating-point exception
|
|
! by not allowing the exponential to go to infinity if
|
|
! the argument is too large. (win, bmy, 1/4/09)
|
|
!----------------------------------------------------------
|
|
|
|
! Argument of the exponential
|
|
XX = ( SO2_ss - H2O20 ) * KaqH2O2 * DTCHEM
|
|
|
|
! Test if EXP(XX) can be computed w/o numerical exception
|
|
!----------------------------------------------------------------
|
|
! Prior to 11/12/10:
|
|
! If SO2_ss = H2O20 (i.e. if they are both zero), then prevent
|
|
! a division by zero, because SO2_ss*L2 - H2O20 will be zero.
|
|
! Only execute the "IF" part of the block if XX is nonzero.
|
|
! Otherwise shunt to the "ELSE" block. (koo, bmy, 11/12/10)
|
|
!IF ( IS_SAFE_EXP( XX ) ) THEN
|
|
!----------------------------------------------------------------
|
|
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 ) THEN
|
|
|
|
! Aqueous phase SO2 loss rate w/ H2O2 [v/v/timestep]
|
|
L2 = EXP( XX )
|
|
|
|
! Loss by H2O2
|
|
L2S = SO2_ss * H2O20 * ( L2 - 1.D0 ) /
|
|
& ( (SO2_ss * L2) - H2O20 )
|
|
ELSE
|
|
|
|
! NOTE from Jintai Lin (4/28/10):
|
|
! However, in the case of a negative XX, L2S should be
|
|
! approximated as SO2_ss, instead of H2O20. In other words,
|
|
! L2S = SO2_ss * H2O20 * ( L2 - 1.D0 ) / ( (SO2_ss*L2) - H2O20 )
|
|
! reaches different limits when XX reaches positive infinity
|
|
! and negative infinity.
|
|
IF ( XX > 0.d0 ) THEN
|
|
L2S = H2O20
|
|
ELSE
|
|
L2S = SO2_ss
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
!----------------------------------------------------------
|
|
! Compute loss by O3. Prevent floating-point exception
|
|
! by not allowing the exponential to go to infinity if
|
|
! the argument is too large. (win, bmy, 1/4/09)
|
|
!----------------------------------------------------------
|
|
|
|
! Argument of the exponential
|
|
XX = ( SO2_ss - O3 ) * KaqO3 * DTCHEM
|
|
|
|
! Test if EXP(XX) can be computed w/o numerical exception
|
|
!----------------------------------------------------------------
|
|
! Prior to 11/12/10:
|
|
! If SO2_ss = O3 (i.e. if they are both zero), then prevent
|
|
! a division by zero, because SO2_ss*L3 - O3 will be zero.
|
|
! Only execute the "IF" part of the block if XX is nonzero.
|
|
! Otherwise shunt to the "ELSE" block. (koo, bmy, 11/12/10)
|
|
!IF ( IS_SAFE_EXP( XX ) ) THEN
|
|
!----------------------------------------------------------------
|
|
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 ) THEN
|
|
|
|
! Aqueous phase SO2 loss rate w/ O3 [v/v/timestep]
|
|
L3 = EXP( XX )
|
|
|
|
! Loss by O3
|
|
L3S = SO2_ss * O3 * (L3 - 1.D0) / ((SO2_ss * L3) - O3)
|
|
|
|
ELSE
|
|
|
|
! Follow the same logic for L3S as described in
|
|
! Jintai Lin's note above (bmy, 4/28/10)
|
|
IF ( XX > 0.d0 ) THEN
|
|
L3S = O3
|
|
ELSE
|
|
L3S = SO2_ss
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
SO2_ss = MAX( SO2_ss - ( L2S + L3S ), MINDAT )
|
|
H2O20 = MAX( H2O20 - L2S, MINDAT )
|
|
|
|
! Update SO2 level, save SO2[ppv], H2O2[ppv] for WETDEP
|
|
SO2s( I,J,L) = SO2_ss
|
|
H2O2s(I,J,L) = H2O20
|
|
|
|
ELSE
|
|
|
|
! Otherwise, don't do aqueous chemistry, and
|
|
! save the original concentrations into SO2 and H2O2
|
|
H2O2s(I,J,L) = MAX( H2O20, 1.0d-32 )
|
|
SO2s(I,J,L ) = MAX( SO2_ss, 1.0d-32 )
|
|
L2S = 0.d0
|
|
L3S = 0.d0
|
|
|
|
ENDIF
|
|
|
|
! Store updated SO2, H2O2 back to the tracer arrays
|
|
STT(I,J,L,IDTSO2) = SO2s( I,J,L)
|
|
STT(I,J,L,IDTH2O2) = H2O2s(I,J,L)
|
|
|
|
! SO2 chemical loss rate = SO4 production rate [v/v/timestep]
|
|
! adj_group: don't have the adjoint of PSO4E yet
|
|
!PSO4_SO2(I,J,L) = L1 + L2S + L3S + PSO4E
|
|
PSO4_SO2(I,J,L) = L1 + L2S + L3S
|
|
PSO4_ss (I,J,L) = PSO4F
|
|
|
|
!=================================================================
|
|
! ND05 Diagnostics [kg S/timestep]
|
|
!=================================================================
|
|
IF ( ND05 > 0 .and. L <= LD05 ) THEN
|
|
|
|
! P(SO4) from gas-phase oxidation [kg S/timestep]
|
|
AD05(I,J,L,5) = AD05(I,J,L,5) +
|
|
& ( L1 * AD(I,J,L) / TCVV_S )
|
|
|
|
! P(SO4) from aqueous-phase oxidation with H2O2 [kg S/timestep]
|
|
AD05(I,J,L,6) = AD05(I,J,L,6) +
|
|
& ( L2S * AD(I,J,L) / TCVV_S )
|
|
|
|
! P(SO4) from aqueous-phase oxidation with O3 [kg S/timestep]
|
|
AD05(I,J,L,7) = AD05(I,J,L,7) +
|
|
& ( L3S * AD(I,J,L) / TCVV_S )
|
|
|
|
! P(SO4) from O3 oxidation in sea-salt aerosols [kg S/timestep]
|
|
AD05(I,J,L,8) = AD05(I,J,L,8) +
|
|
& ( (PSO4E + PSO4F) * AD(I,J,L) / TCVV_S )
|
|
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! ND44 Diagnostic: Drydep flux of SO2 [molec/cm2/s]
|
|
!=================================================================
|
|
IF ( ND44 > 0 .AND. Ld > 0d0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = Ld * AD(I,J,L) / TCVV(IDTSO2)
|
|
FLUX = FLUX * XNUMOL(IDTSO2) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, LLTROP
|
|
AD44(I,J,DRYSO2,1) = AD44(I,J,DRYSO2,1) + ND44_TMP(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SEASALT_CHEM ( I, J, L, ALK1, ALK2,
|
|
& SO2_cd, Kt1, Kt2, Kt1N, Kt2N,
|
|
& SO2_ss, PSO4E, PSO4F )
|
|
!
|
|
!******************************************************************************
|
|
! Function SEASALT_CHEM computes SO4 formed from S(IV) + O3 on seasalt
|
|
! aerosols as a function of seasalt alkalinity. (bec, bmy, 4/13/05, 10/7/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I (INTEGER) :
|
|
! (2 ) J (INTEGER) :
|
|
! (3 ) L (INTEGER) :
|
|
! (4 ) O30 (REAL*8) : Initial O3 mixing ratio (v/v]
|
|
! (5 ) ALK (REAL*8) : Alkalinity [kg] from seasalt from seasalt_mod
|
|
! (6 ) SO2_cd (REAL*8) : SO2 mixing ratio [v/v] after gas phase chemistry
|
|
! and dry deposition
|
|
! (7 ) Kt1 (REAL*8) : Rate constant [s-1] for sulfate formation on
|
|
! fine sea-salt aerosols from GET_ALK
|
|
! (8 ) Kt2 (REAL*8) : Rate constant [s-1] for sulfate formation on
|
|
! coarse sea-salt aerosols from GET_ALK
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (9 ) SO2_ss (REAL*8) : SO2 mixing ratio [v/v] updated after SS chemistry
|
|
! (10) SO4E (REAL*8) : SO4E (sulfate produced by S(IV)+O3 on fine seasalt)
|
|
! mixing ratio [v/v]
|
|
! (11) SO4F (REAL*8) : SO4F(sulfate produced by S(IV)+O3 on coarse seasalt)
|
|
! mixing ratio [v/v]
|
|
! (12) O3 (REAL*8) : Updated O3 mixing ratio [v/v] for fullchem runs
|
|
! only. Otherwise O30=O3.
|
|
!
|
|
! Chemical reactions:
|
|
! ============================================================================
|
|
! (R1) SO2 + O3 + ALK => SO4 + O2
|
|
! Modeled after Chamedies and Stelson, 1992?
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now references XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (2 ) Bug fix: now avoid seg fault error if IDTHNO3 is zero, as it would
|
|
! be for an offline aerosol simulation. (bmy, 3/29/06)
|
|
! (3 ) Fixed typo in FALK_A_SO2 equation: C_FLUX_C should be C_FLUX_A.
|
|
! (havala, bec, bmy, 12/8/06)
|
|
! (4 ) Bug fix for mass balance, replace TITR_HNO3 w/ HNO3_SSC in the
|
|
! expression for HNO3_ss. Bug fix: now do equivalent computation
|
|
! for GET_GNO3, which is now no longer called because it's in
|
|
! "isoropia_mod.f". (bec, bmy, 7/30/08)
|
|
! (5 ) ANISORROPIA available for aerosol thermo (slc, 3/9/13, ***)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME
|
|
USE DAO_MOD, ONLY : AD, AIRDEN, AIRVOL
|
|
USE TRACERID_MOD
|
|
!----------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
|
|
!USE DIAG_MOD, ONLY : AD09
|
|
!----------------------------------------------------------------
|
|
USE ERROR_MOD, ONLY : GEOS_CHEM_STOP
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM, GET_ELAPSED_SEC
|
|
USE ERROR_MOD, ONLY : IT_IS_NAN
|
|
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, STT
|
|
USE TRACER_MOD, ONLY : TCVV, XNUMOLAIR
|
|
USE GLOBAL_HNO3_MOD, ONLY : GET_HNO3_UGM3
|
|
USE TIME_MOD, ONLY : GET_ELAPSED_SEC, GET_MONTH
|
|
USE TIME_MOD, ONLY : ITS_A_NEW_MONTH
|
|
USE ISOROPIAII_ADJ_MOD, ONLY : GET_GNO3
|
|
|
|
! Add these for GET_GNO3 fix (lyj, bmy, 10/7/08)
|
|
USE GLOBAL_HNO3_MOD, ONLY : GET_HNO3_UGM3
|
|
USE DAO_MOD, ONLY : AIRVOL
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
!---------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
|
|
!# include "CMN_DIAG" ! ND19
|
|
!---------------------------------------------------------------
|
|
# include "CMN_GCTM" ! AIRMW
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
REAL*8, INTENT(IN) :: SO2_cd, Kt1, Kt2, Kt1N, Kt2N
|
|
REAL*8, INTENT(IN) :: ALK1, ALK2
|
|
REAL*8, INTENT(OUT) :: SO2_ss, PSO4E, PSO4F
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
REAL*8 :: SO2_chem, DTCHEM
|
|
REAL*8 :: O3_cspec, O3_lost
|
|
REAL*8 :: EQ_1_C, EQ_2_C
|
|
REAL*8 :: SO4E, SO2_new, SO4F
|
|
REAL*8 :: SO2_eq, N_FLUX_A, N_FLUX_C
|
|
REAL*8 :: END_ALK, L5A, L5C
|
|
REAL*8 :: EQ1, EQ2, TITR_SO2
|
|
REAL*8 :: TITR_HNO3, NIT_vv, NITs_vv
|
|
REAL*8 :: NIT0, NITS0
|
|
REAL*8 :: F_SO2, FALK_A_SO2, FALK_C_SO2
|
|
REAL*8 :: EQ_BEG, F_SO2_A, F_SO2_C
|
|
REAL*8 :: ALKA, ALKC, TOTAL_ACID_FLUX
|
|
REAL*8 :: HNO3_EQ, TOT_FLUX_A, TOT_FLUX_C
|
|
REAL*8 :: FALK_A_HNO3, HNO3_vv
|
|
REAL*8 :: FALK_C_HNO3, F_HNO3_A, F_HNO3_C
|
|
REAL*8 :: EQ_1_N, EQ_2_N, F_HNO3
|
|
REAL*8 :: HNO3_SSA, HNO3_SSC, N_FLUX
|
|
REAL*8 :: HNO3_EQ_C, L6A, L6C
|
|
REAL*8 :: C_FLUX_A, C_FLUX_C, C_FLUX
|
|
REAL*8 :: HNO3_ss, HNO3_kg
|
|
REAL*8, PARAMETER :: MINDAT = 1.0d-20
|
|
REAL*8, PARAMETER :: TCVV_HNO3 = 28.97d0 / 63.0d0
|
|
|
|
!=================================================================
|
|
! SEASALT_CHEM begins here!
|
|
!=================================================================
|
|
|
|
! DTCHEM is the chemistry timestep in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Convert SO2 [v/v] to [eq/gridbox]
|
|
SO2_eq = ( 2.d0 * SO2_cd * AD(I,J,L) ) / ( TCVV(IDTSO2) * 0.064d0)
|
|
SO2_eq = MAX( SO2_eq, MINDAT )
|
|
|
|
IF ( ITS_A_FULLCHEM_SIM() ) THEN
|
|
|
|
! Convert HNO3 [v/v] to [equivalents]
|
|
HNO3_vv = STT(I,J,L,IDTHNO3)
|
|
HNO3_eq = HNO3_vv * AD(I,J,L) / ( 28.97d0 / 63d0 ) / 63.d-3
|
|
|
|
ELSE
|
|
|
|
!--------------------------------------------------------------------
|
|
! Prior to 10/7/08:
|
|
! Now that we have switched from ISORROPIA to RPMARES, GET_GNO3
|
|
! is no longer defined. We therefore need to do the equivalent
|
|
! computation. NOTE: This is only an issue for the offline
|
|
! aerosol simulation. (lyj, bmy, 10/7/08)
|
|
!
|
|
! For more information, please see this Wiki post:
|
|
! http://wiki.seas.harvard.edu/geos-chem/index.php/Aerosol_thermodynamical_equilibrium#Bug_in_sulfate_mod.f_caused_by_switch_to_RPMARES
|
|
!
|
|
!! Get gas-phase HNO3 from ISORROPIA code
|
|
!CALL GET_GNO3( I, J, L, HNO3_kg )
|
|
!--------------------------------------------------------------------
|
|
|
|
! Get HNO3 in ug/m3, then multiply by volume in m3
|
|
! and 1e-6 kg/ug to get HNO3 in kg
|
|
HNO3_kg = GET_HNO3_UGM3( I, J, L ) * AIRVOL(I,J,L) * 1e-6
|
|
|
|
! Convert HNO3 [kg] first to [v/v]
|
|
HNO3_vv = HNO3_kg * ( 28.97d0 / 63d0 ) / AD(I,J,L)
|
|
|
|
! Then convert HNO3 [kg] to [equivalents]
|
|
HNO3_eq = HNO3_kg / 63d-3
|
|
|
|
ENDIF
|
|
|
|
!-----------
|
|
! SO2
|
|
!-----------
|
|
|
|
! Available flux of SO2 to accum sea salt aerosols [v/v/timestep]
|
|
L5A = EXP( -Kt1 * DTCHEM )
|
|
F_SO2_A = SO2_cd * ( 1.d0 - L5A )
|
|
F_SO2_A = MAX( F_SO2_A, 1.d-32 )
|
|
|
|
! Convert to [eq/timestep]
|
|
C_FLUX_A = 2.d0 * F_SO2_A * AD(I,J,L) / TCVV(IDTSO2) / 0.064d0
|
|
|
|
! Available flux of SO2 to coarse sea salt aerosols [v/v/timestep]
|
|
L5C = EXP( - Kt2 * DTCHEM )
|
|
F_SO2_C = SO2_cd * ( 1.d0 - L5C )
|
|
F_SO2_C = MAX( F_SO2_C, 1.0d-32 )
|
|
|
|
! Convert to [eq/timestep]
|
|
C_FLUX_C = 2.d0 * F_SO2_C * AD(I,J,L) / TCVV(IDTSO2) / 0.064d0
|
|
|
|
! Total flux of SO2 [v/v/timestep]
|
|
F_SO2 = F_SO2_A + F_SO2_C
|
|
|
|
! Total flux of SO2 [eq/timestep]
|
|
C_FLUX = C_FLUX_A + C_FLUX_C
|
|
|
|
!-----------
|
|
! HNO3
|
|
!-----------
|
|
|
|
! Available flux of HNO3 to accum sea salt aerosols [v/v/timestep]
|
|
L6A = EXP( - Kt1N * DTCHEM )
|
|
F_HNO3_A = HNO3_vv * ( 1.D0 - L6A )
|
|
F_HNO3_A = MAX( F_HNO3_A, 1.0D-32 )
|
|
|
|
! Convert to [eq/timestep]
|
|
N_FLUX_A = F_HNO3_A * AD(I,J,L)/( 28.97d0 / 63d0 )/0.063d0
|
|
|
|
! Available flux of HNO3 to coarse sea salt aerosols [v/v/timestep]
|
|
L6C = EXP( - Kt2N * DTCHEM )
|
|
F_HNO3_C = HNO3_vv * ( 1.D0 - L6C )
|
|
F_HNO3_C = MAX( F_HNO3_C, 1.0D-32 )
|
|
|
|
! convert to [eq/timestep]
|
|
N_FLUX_C = F_HNO3_C * AD(I,J,L)/( 28.97d0 / 63d0 )/0.063d0
|
|
|
|
! Total flux of HNO3
|
|
F_HNO3 = F_HNO3_A + F_HNO3_C ![v/v/timestep]
|
|
N_FLUX = N_FLUX_A + N_FLUX_C ![eq/timestep]
|
|
|
|
!-----------
|
|
! Acid
|
|
!-----------
|
|
|
|
! Total acid flux to accum sea-salt aerosols [eq/box/timestep]
|
|
TOT_FLUX_A = C_FLUX_A + N_FLUX_A
|
|
TOT_FLUX_A = MAX( TOT_FLUX_A, MINDAT )
|
|
|
|
! Total acid flux to coarse sea-salt aerosols [eq/box/timestep]
|
|
TOT_FLUX_C = C_FLUX_C + N_FLUX_C
|
|
TOT_FLUX_C = MAX( TOT_FLUX_C, MINDAT )
|
|
|
|
! Total acid flux to sea salt aerosols
|
|
TOTAL_ACID_FLUX = TOT_FLUX_A + TOT_FLUX_C
|
|
|
|
! Total available alkalinity [eq]
|
|
EQ1 = ALK1 * 0.07d0
|
|
EQ2 = ALK2 * 0.07d0
|
|
|
|
!----------------------------------------------------------------------
|
|
! NOTE: This was a sensitivity simulation, keep for future reference
|
|
! cf Alexander et al 2005 (bec, bmy, 4/13/05)
|
|
!! Total available alkalinity [eq] doubled for Sievering run
|
|
!EQ1 = ALK1 * 0.14d0
|
|
!EQ2 = ALK2 * 0.14d0
|
|
!----------------------------------------------------------------------
|
|
|
|
!----------------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave uncommented for now (bec, bmy, 4/13/05)
|
|
!! Write out beginning alkalinity [eq SO4]
|
|
!EQ_BEG = EQ1 + EQ2
|
|
!IF ( ND09 > 0 ) AD09(I,J,L,1) = AD09(I,J,L,1) + EQ_BEG
|
|
!----------------------------------------------------------------------
|
|
|
|
IF ( TOT_FLUX_A > EQ1 ) THEN
|
|
|
|
! Fraction of alkalinity available for each acid
|
|
FALK_A_SO2 = C_FLUX_A / TOT_FLUX_A
|
|
FALK_A_HNO3 = N_FLUX_A / TOT_FLUX_A
|
|
FALK_A_SO2 = MAX( FALK_A_SO2, MINDAT )
|
|
FALK_A_HNO3 = MAX( FALK_A_HNO3, MINDAT )
|
|
|
|
ELSE
|
|
|
|
FALK_A_SO2 = 1.0d0
|
|
FALK_A_HNO3 = 1.0d0
|
|
|
|
ENDIF
|
|
|
|
IF ( TOT_FLUX_C > EQ2 ) THEN
|
|
|
|
! Fraction of flkalinity available for each acid
|
|
FALK_C_SO2 = C_FLUX_C/TOT_FLUX_C
|
|
FALK_C_HNO3 = N_FLUX_C/TOT_FLUX_C
|
|
FALK_C_SO2 = MAX( FALK_C_SO2, MINDAT )
|
|
FALK_C_HNO3 = MAX( FALK_C_HNO3, MINDAT )
|
|
|
|
ELSE
|
|
|
|
FALK_C_SO2 = 1.0d0
|
|
FALK_C_HNO3 = 1.0d0
|
|
|
|
ENDIF
|
|
|
|
! Alkalinity available for S(IV) --> S(VI)
|
|
EQ_1_C = EQ1 * FALK_A_SO2
|
|
EQ_1_C = MAX( EQ_1_C, MINDAT )
|
|
EQ_1_N = EQ1 * FALK_A_HNO3
|
|
EQ_1_N = MAX( EQ_1_N, MINDAT )
|
|
|
|
EQ_2_C = EQ2 * FALK_C_SO2
|
|
EQ_2_C = MAX( EQ_2_C, MINDAT )
|
|
EQ_2_N = EQ2 * FALK_C_HNO3
|
|
EQ_2_N = MAX( EQ_2_N, MINDAT )
|
|
|
|
!-----------------
|
|
! Fine Seasalt
|
|
!-----------------
|
|
|
|
! don't produce more SO4 than available ALK or SO2
|
|
SO4E = MIN( C_FLUX_A, EQ_1_C, SO2_eq )
|
|
SO4E = MAX( SO4E, MINDAT )
|
|
|
|
! Update SO2 concentration [eq/box]
|
|
SO2_new = SO2_eq - SO4E
|
|
SO2_new = MAX( SO2_new, MINDAT )
|
|
|
|
!-----------------
|
|
! Coarse Seasalt
|
|
!-----------------
|
|
IF ( SO2_new > MINDAT ) THEN
|
|
|
|
! don't produce more SO4 than available ALK or SO2
|
|
SO4F = MIN( C_FLUX_C, SO2_new, EQ_2_C )
|
|
SO4F = MAX( SO4F, MINDAT )
|
|
|
|
!Update SO2 concentration [eq]
|
|
SO2_chem = SO2_new - SO4F
|
|
SO2_chem = MAX( SO2_chem, MINDAT )
|
|
ELSE
|
|
SO4F = MINDAT
|
|
SO2_chem = MINDAT
|
|
ENDIF
|
|
|
|
! Alkalinity titrated by S(IV) --> S(VI) [eq]
|
|
TITR_SO2 = SO4E + SO4F
|
|
|
|
!-------------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave uncommented for now
|
|
!! write out in diagnostic
|
|
!IF ( ND09 > 0 ) AD09(I,J,L,2) = AD09(I,J,L,2) + TITR_SO2
|
|
!-------------------------------------------------------------------
|
|
|
|
!Modified SO2 [eq] converted back to [v/v]
|
|
SO2_ss = SO2_chem * 0.064 * TCVV(IDTSO2)/AD(I,J,L)/2.0d0
|
|
SO2_ss = MAX( SO2_ss, MINDAT )
|
|
|
|
!SO4E produced converted from [eq/timestep] to [v/v/timestep]
|
|
PSO4E = SO4E * 0.096 * TCVV(IDTSO4)/AD(I,J,L)/2.0d0
|
|
|
|
!SO4F produced converted from [eq/timestep] to [v/v/timestep]
|
|
PSO4F = SO4F * 0.096 * TCVV(IDTSO4S)/AD(I,J,L)/2.0d0
|
|
|
|
! Alkalinity titrated by HNO3
|
|
HNO3_SSA = MIN(N_FLUX_A, HNO3_EQ, EQ_1_N)
|
|
HNO3_SSA = MAX(HNO3_SSA, MINDAT)
|
|
HNO3_EQ_C = HNO3_EQ - HNO3_SSA
|
|
HNO3_EQ_C = MAX(HNO3_EQ_C, MINDAT)
|
|
HNO3_SSC = MIN(N_FLUX_C, HNO3_EQ_C, EQ_2_N)
|
|
HNO3_SSC = MAX(HNO3_SSC, MINDAT)
|
|
TITR_HNO3 = HNO3_SSA + HNO3_SSC
|
|
|
|
!----------------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave commented out for now
|
|
! !write out alkalinity titrated by HNO3(g)
|
|
!IF ( ND09 > 0 ) AD09(I,J,L,3) = AD09(I,J,L,3) + TITR_HNO3
|
|
!----------------------------------------------------------------------
|
|
|
|
! HNO3 lost [eq/timestep] converted back to [v/v/timestep]
|
|
IF ( IDTHNO3 > 0 ) THEN
|
|
|
|
! Coupled sim: IDTHNO3 is defined, so use it
|
|
HNO3_ss = HNO3_SSC * 0.063 * TCVV(IDTHNO3)/AD(I,J,L)
|
|
STT(I,J,L,IDTHNO3) = MAX( HNO3_vv - HNO3_ss, MINDAT )
|
|
|
|
ELSE
|
|
|
|
! Offline aerosol sim: IDTHNO3 isn't defined, use TCVV_HNO3
|
|
HNO3_ss = TITR_HNO3 * 0.063 * TCVV_HNO3 / AD(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
! NITS produced converted from [eq/timestep] to [v/v/timestep]
|
|
PNITs(I,J,L) = HNO3_SSC * 0.063 * TCVV(IDTNITS)/AD(I,J,L)
|
|
|
|
! Modified accum alkalinity
|
|
ALKA = EQ1 - (SO4E + HNO3_SSA)
|
|
ALKA = MAX( ALKA, MINDAT )
|
|
|
|
!------------------------------------------------------------------------
|
|
! Uncomment this if you want to transport alkalinity (bec, bmy, 4/13/05)
|
|
![eq] --> [kg] --> [v/v] use this only if transporting alkalinity
|
|
!ALKAvv = (ALKA * TCVV(IDTSAL1))/(7.0d-2 * AD(I,J,L))
|
|
!ALKAvv = MAX( ALKAvv, MINDAT )
|
|
!------------------------------------------------------------------------
|
|
|
|
! Modified accum alkalinity
|
|
ALKC = EQ2 - (SO4F + HNO3_SSC)
|
|
ALKC = MAX( ALKC, MINDAT )
|
|
|
|
!------------------------------------------------------------------------
|
|
! Uncomment this if you want to transport alkalinity (bec, bmy, 4/13/05)
|
|
!! [eq] --> [kg] --> [v/v] use this only if transporting alkalinity
|
|
!ALKCvv = (ALKC * TCVV(IDTSAL2))/(7.0d-2 * AD(I,J,L))
|
|
!ALKCvv = MAX(ALKCvv, MINDAT)
|
|
!------------------------------------------------------------------------
|
|
|
|
!------------------------------------------------------------------------
|
|
! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
|
|
!! write out ending alkalinity
|
|
!END_ALK = ALKA + ALKC
|
|
!IF ( ND09 > 0 ) AD09(I,J,L,4) = AD09(I,J,L,4) + END_ALK
|
|
!------------------------------------------------------------------------
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SEASALT_CHEM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE AQCHEM_SO2( LWC, T, P, SO2, H2O2,
|
|
& O3, Hplus, KaqH2O2, KaqO3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function AQCHEM_SO2 computes the reaction rates for aqueous SO2 chemistry.
|
|
! (rjp, bmy, 10/31/02, 12/12/02)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) LWC (REAL*8) : Liquid water content [m3/m3] = 1.E-6*L [g/m3]
|
|
! (2 ) T (REAL*8) : Temperature [K]
|
|
! (3 ) P (REAL*8) : Pressure [atm]
|
|
! (4 ) SO2 (REAL*8) : SO2 mixing ratio [v/v]
|
|
! (5 ) H2O2 (REAL*8) : H2O2 mixing ratio [v/v]
|
|
! (6 ) O3 (REAL*8) : O3 mixing ratio [v/v]
|
|
! (7 ) HPLUS (REAL*8) : Concentration of H+ ion (i.e. the pH) [v/v]
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (8 ) KaqH2O2 (REAL*8) : Reaction rate for H2O2
|
|
! (9 ) KaqO3 (REAL*8) : Reaction rate for O3
|
|
!
|
|
! Chemical Reactions:
|
|
! ============================================================================
|
|
! (R1) HSO3- + H2O2(aq) + H+ => SO4-- + 2H+ + H2O [Jacob, 1986]
|
|
!
|
|
! d[S(VI)]/dt = k[H+][H2O2(aq)][HSO3-]/(1 + K[H+])
|
|
! [Seinfeld and Pandis, 1998, page 366]
|
|
!
|
|
! (R2) SO2(aq) + O3(aq) =>
|
|
! HSO3- + O3(aq) =>
|
|
! SO3-- + O3(aq) =>
|
|
! [Jacob, 1986; Jacobson, 1999]
|
|
!
|
|
! d[S(VI)]/dt = (k0[SO2(aq)] + k1[HSO3-] + K2[SO3--])[O3(aq)]
|
|
! [Seinfeld and Pandis, 1998, page 363]
|
|
!
|
|
! Reaction rates can be given as
|
|
! Ra = k [H2O2(ag)] [S(IV)] [mole/liter*s] OR
|
|
! Krate = Ra LWC R T / P [1/s]
|
|
!
|
|
! Where:
|
|
! LWC = Liquid water content(g/m3)*10-6 [m3(water)/m3(gas)]
|
|
! R = 0.08205 (atm L / mol-K), Universal gas const.
|
|
! T = Temperature (K)
|
|
! P = Pressure (atm)
|
|
!
|
|
! Procedure:
|
|
! ============================================================================
|
|
! (a ) Given [SO2] which is assumed to be total SO2 (gas+liquid) in
|
|
! equilibrium between gas and liquid phase.
|
|
!
|
|
! (b ) We can compute SO2(g) using Henry's law
|
|
! P(so2(g)) = Xg * [SO2]
|
|
! Xg = 1/(1 + Faq), Fraction of SO2 in gas
|
|
! where:
|
|
! Faq = Kheff * R * T * LWC,
|
|
! KHeff = Effective Henry's constant
|
|
!
|
|
! (c ) Then Calculate Aquous phase, S[IV] concentrations
|
|
! S[IV] = Kheff * P(so2(g) in atm) [M]
|
|
!
|
|
! (d ) The exact same procedure is applied to calculate H2O2(aq)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated by Rokjin Park (rjp, bmy, 12/12/02)
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: LWC, T, P, SO2, H2O2, O3, HPLUS
|
|
REAL*8, INTENT(OUT) :: KaqH2O2, KaqO3
|
|
|
|
! Local variables
|
|
REAL*8, PARAMETER :: R = 0.08205d0
|
|
REAL*8 :: KH2O2, RA, KS1, KS2, HCSO2
|
|
REAL*8 :: FHCSO2, XSO2G, SIV, HSO3, XSO2AQ
|
|
REAL*8 :: XHSO3, XSO3, KH1, HCH2O2, FHCH2O2
|
|
REAL*8 :: XH2O2G, H2O2aq, KO0, KO1, KO2
|
|
REAL*8 :: HCO3, XO3g, O3aq
|
|
|
|
!=================================================================
|
|
! AQCHEM_SO2 begins here!
|
|
!
|
|
! Aqueous reaction rate
|
|
! HSO3- + H2O2 + H+ => SO4-- + 2H+ + H2O [Jacob, 1986]
|
|
!=================================================================
|
|
|
|
! [Jacob, 1986]
|
|
KH2O2 = 6.31d14 * EXP( -4.76d3 / T )
|
|
|
|
! ! [Jacobson, 1999]
|
|
! KH2O2 = 7.45d07 * EXP( -15.96d0 * ( (298.15/T) - 1.) ) /
|
|
! & ( 1.d0 + 13.d0 * Hplus)
|
|
|
|
!=================================================================
|
|
! Equilibrium reaction of SO2-H2O
|
|
! SO2 + H2O = SO2(aq) (s0)
|
|
! SO2(ag) = HSO3- + H+ (s1)
|
|
! HSO3- = SO3-- + H+ (s2)
|
|
!
|
|
! Reaction constant for Aqueous chemistry -- No big difference
|
|
! between Jacob and Jacobson, choose one of them.
|
|
!
|
|
! Reaction rate dependent on Temperature is given
|
|
! H = A exp ( B (T./T - 1) )
|
|
!
|
|
! For equilibrium reactions of SO2:
|
|
! As1 Bs1 As2 Bs2
|
|
! Seinfeld 1.30d-2 7.02 6.60d-8 3.76 [1998]
|
|
! Jacob 1.30d-2 6.75 6.31d-8 5.05 [1986]
|
|
! Jacobson 1.71d-2 7.04 5.99d-8 3.74 [1996]
|
|
!=================================================================
|
|
Ks1 = 1.30d-2 * EXP( 6.75d0 * ( 298.15d0 / T - 1.d0 ) )
|
|
Ks2 = 6.31d-8 * EXP( 5.05d0 * ( 298.15d0 / T - 1.d0 ) )
|
|
|
|
! SIV Fraction
|
|
XSO2aq = 1.d0/(1.d0 + Ks1/Hplus + Ks1*Ks2/(Hplus*Hplus))
|
|
XHSO3 = 1.d0/(1.d0 + Hplus/Ks1 + Ks2/Hplus)
|
|
XSO3 = 1.d0/(1.d0 + Hplus/Ks2 + Hplus*Hplus/(Ks1*Ks2))
|
|
|
|
! Henry's constant [mol/l-atm] and Effective Henry's constant for SO2
|
|
HCSO2 = 1.22d0 * EXP( 10.55d0 * ( 298.15d0 / T - 1.d0) )
|
|
FHCSO2 = HCSO2 * (1.d0 + (Ks1/Hplus) + (Ks1*Ks2 / (Hplus*Hplus)))
|
|
|
|
XSO2g = 1.d0 / ( 1.d0 + ( FHCSO2 * R * T * LWC ) )
|
|
SIV = FHCSO2 * XSO2g * SO2 * P
|
|
! HSO3 = Ks1 * HCSO2 * XSO2g * SO2 * P
|
|
|
|
!=================================================================
|
|
! H2O2 equilibrium reaction
|
|
! H2O2 + H2O = H2O2.H2O
|
|
! H2O2.H2O = HO2- + H+ 1)
|
|
!
|
|
! Reaction rate dependent on Temperature is given
|
|
! H = A exp ( B (T./T - 1) )
|
|
!
|
|
! For equilibrium reactions of SO2
|
|
! Ah1 Bh1
|
|
! Jacob 1.58E-12 -12.49 [1986]
|
|
! Jacobson 2.20E-12 -12.52 [1996]
|
|
!=================================================================
|
|
Kh1 = 2.20d-12 * EXP( -12.52d0 * ( 298.15d0 / T - 1.d0 ) )
|
|
|
|
! Henry's constant [mol/l-atm] and Effective Henry's constant for H2O2
|
|
! [Seinfeld and Pandis, 1998]
|
|
! HCH2O2 = 7.45D4 * EXP( 24.48d0 * ( 298.15d0 / T - 1.d0) )
|
|
|
|
! [Jacobson,1999]
|
|
HCH2O2 = 7.45D4 * EXP( 22.21d0 * (298.15d0 / T - 1.d0) )
|
|
FHCH2O2 = HCH2O2 * (1.d0 + (Kh1 / Hplus))
|
|
|
|
XH2O2g = 1.d0 / ( 1.d0 + ( FHCH2O2 * R * T * LWC ) )
|
|
! H2O2aq = FHCH2O2 * XH2O2g * H2O2 * P
|
|
|
|
! Conversion rate from SO2 to SO4 via reaction with H2O2
|
|
KaqH2O2 = kh2o2 * Ks1 * FHCH2O2 * HCSO2 * XH2O2g * XSO2g
|
|
& * P * LWC * R * T ! [v/v/s]
|
|
|
|
!=================================================================
|
|
! Aqueous reactions of SO2 with O3
|
|
! SO2(aq) + O3 => (0)
|
|
! HSO3- + O3 => SO4-- + H+ + O2 (1)
|
|
! SO3-- + O3 => SO4-- + O2 (2)
|
|
!
|
|
! NOTE
|
|
! [Jacob, 1986]
|
|
! KO1 = 3.49E12 * EXP( -4.83E3 / T )
|
|
! KO2 = 7.32E14 * EXP( -4.03E3 / T )
|
|
!
|
|
! [Jacobson, 1999]
|
|
! KO0 = 2.40E+4
|
|
! KO1 = 3.70E+5 * EXP( -18.56 * ((298.15/T) - 1.))
|
|
! KO2 = 1.50E+9 * EXP( -17.72 * ((298.15/T) - 1.))
|
|
!
|
|
! Rate constants from Jacobson is larger than those of Jacob
|
|
! and results in faster conversion from S(IV) to S(VI)
|
|
! We choose Jacob 1) 2) and Jacobson 0) here
|
|
!=================================================================
|
|
KO0 = 2.40d+4
|
|
KO1 = 3.49d12 * EXP( -4.83d3 / T )
|
|
KO2 = 7.32d14 * EXP( -4.03d3 / T )
|
|
|
|
!=================================================================
|
|
! H2O2 equilibrium reaction
|
|
! O3 + H2O = O3.H2O
|
|
! HCO3 = 1.13E-2 * EXP( 8.51 * (298.15/T -1.) ), S & P
|
|
! HCO3 = 1.13E-2 * EXP( 7.72 * (298.15/T -1.) ), Jacobson
|
|
!=================================================================
|
|
|
|
! Calculate Henry's Law constant for atmospheric temperature
|
|
HCO3 = 1.13d-2 * EXP( 8.51d0 * ( 298.15d0 / T - 1.d0 ) )
|
|
|
|
XO3g = 1.d0 / ( 1.d0 + ( HCO3 * R * T * LWC ) )
|
|
! O3aq = HCO3 * XO3g * O3 * P
|
|
|
|
! Conversion rate from SO2 to SO4 via reaction with O3
|
|
KaqO3 = (KO0*XSO2AQ + KO1*XHSO3 + KO2*XSO3) * FHCSO2 * XSO2g
|
|
& * P * HCO3 * XO3g * LWC * R * T ! [v/v/s]
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE AQCHEM_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_SO4
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_SO4 is the SO4 chemistry subroutine from Mian Chin's GOCART
|
|
! model, modified for the GEOS-CHEM model. Now also modified to account
|
|
! for production of crystalline & aqueous sulfur tracers.
|
|
! (rjp, bdf, cas, bmy, 5/31/00, 5/23/06)
|
|
!
|
|
! Module Variables Used:
|
|
! ============================================================================
|
|
! (1 ) PSO4_SO2 (REAL*8 ) : Array for P(SO4) from SO2 [v/v/timestep]
|
|
! (2 ) PSO4_ss (REAL*8 ) : Array for P(SO4) from SO2
|
|
! (coarse sea-salt aerosols) [v/v/timestep]
|
|
!
|
|
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
|
|
! ============================================================================
|
|
! The Only production is from SO2 oxidation (save in CHEM_SO2), and the only
|
|
! loss is dry depsition here. Wet deposition will be treated in "wetdep.f".
|
|
!
|
|
! SO4 = SO4_0 * exp(-kt) + PSO4_SO2/kt * (1.-exp(-kt))
|
|
! where k = dry deposition.
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD from "dao_mod.f". Added parallel DO-loops.
|
|
! Updated comments, cosmetic changes. (rjp, bdf, bmy, 9/16/02)
|
|
! (2 ) Now replace DXYP(JREF)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
|
|
! Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! to the entire PBL. (rjp, bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (6 ) Now reference STT & TCVV from "tracer_mod.f" (bmy, 7/20/04)
|
|
! (7 ) Now references LCRYST from "logical_mod.f". Modified for crystalline
|
|
! and aqueous sulfate2 tracers: AS, AHS, LET, SO4aq. Also changed name
|
|
! of ND44_TMP to T44 to save space. (cas, bmy, 12/21/04)
|
|
! (8 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f" (bmy, 2/22/05)
|
|
! (9 ) Now remove reference to CMN, it's obsolete. Now reference
|
|
! ITS_IN_THE_STRAT from "tropopause_mod.f" (bmy, 8/22/05)
|
|
! (10) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (11) Rearrange error check to avoid SEG FAULTS (bmy, 5/23/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LCRYST, LSSALT
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTSO4s, IDTAS, IDTAHS
|
|
USE TRACERID_MOD, ONLY : IDTLET, IDTSO4aq, IDTNH4aq
|
|
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, N, N_ND44
|
|
REAL*8 :: AS, AS0, AHS, AHS0, LET
|
|
REAL*8 :: LET0, SO4, SO40, SO4aq, SO4aq0
|
|
REAL*8 :: SO4s, SO40s, RKT, RKTs, E_RKT
|
|
REAL*8 :: E_RKTs, DTCHEM, AREA_CM2, FLUX
|
|
REAL*8 :: T44(IIPAR,JJPAR,LLTROP,6)
|
|
|
|
!=================================================================
|
|
! CHEM_SO4 begins here!
|
|
!=================================================================
|
|
|
|
! Return if tracers are not defined
|
|
IF ( IDTSO4 == 0 .or. IDTSO4s == 0 ) RETURN
|
|
IF ( DRYSO4 == 0 .or. DRYSO4s == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry timestep in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Number of drydep tracers to save
|
|
N_ND44 = 2
|
|
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 4/13/05)
|
|
!%%% ! Number of drydep tracers to save
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%% N_ND44 = 6
|
|
!%%% ELSE
|
|
!%%% N_ND44 = 2
|
|
!%%% ENDIF
|
|
!------------------------------------------------------------------------------
|
|
|
|
! Zero T44 array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, N )
|
|
DO N = 1, N_ND44
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
T44(I,J,L,N) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Loop over tropospheric grid boxes
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% $OMP PARALLEL DO
|
|
!%%% $OMP+DEFAULT( SHARED )
|
|
!%%% $OMP+PRIVATE( I, J, L, AREA_CM2, RKT, RKTs )
|
|
!%%% $OMP+PRIVATE( E_RKT, E_RKTs, FLUX, SO4, SO4s, SO4aq )
|
|
!%%% $OMP+PRIVATE( AS, AHS, LET, SO40, SO40s, SO4aq0 )
|
|
!%%% $OMP+PRIVATE( AS0, AHS0, LET0 )
|
|
!%%% $OMP+SCHEDULE( DYNAMIC )
|
|
!------------------------------------------------------------------------------
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, AREA_CM2, RKT, RKTs, E_RKT )
|
|
!$OMP+PRIVATE( E_RKTs, FLUX, SO4, SO4s, SO40, SO40s )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Initialize for safety's sake
|
|
AREA_CM2 = 0d0
|
|
RKT = 0d0
|
|
RKTs = 0d0
|
|
E_RKT = 0d0
|
|
E_RKTs = 0d0
|
|
FLUX = 0d0
|
|
SO4 = 0d0
|
|
SO4s = 0d0
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% SO4aq = 0d0
|
|
!%%% AS = 0d0
|
|
!%%% AHS = 0d0
|
|
!%%% LET = 0d0
|
|
!------------------------------------------------------------------------------
|
|
|
|
! Skip stratospheric boxes
|
|
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
|
|
|
|
!==============================================================
|
|
! Initial concentrations before chemistry
|
|
!==============================================================
|
|
|
|
! SO4 [v/v]
|
|
SO40 = STT(I,J,L,IDTSO4)
|
|
|
|
! SO4 within coarse seasalt aerosol [v/v]
|
|
SO40s = STT(I,J,L,IDTSO4s)
|
|
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% ! SO4aq, AS, LET, AHS (if necessary) [v/v]
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%% SO4aq0 = STT(I,J,L,IDTSO4aq)
|
|
!%%% AS0 = STT(I,J,L,IDTAS)
|
|
!%%% AHS0 = STT(I,J,L,IDTAHS)
|
|
!%%% LET0 = STT(I,J,L,IDTLET)
|
|
!%%% ENDIF
|
|
!------------------------------------------------------------------------------
|
|
|
|
!==============================================================
|
|
! SO4 chemistry:
|
|
!
|
|
! (CASE 1) SO4 production from SO2 and loss by drydep
|
|
! --> see equation in header notes above
|
|
!
|
|
! (CASE 2) SO4 production from SO2 with no SO4 loss by drydep
|
|
!==============================================================
|
|
|
|
! SO4 drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each vertical level that is located below the PBL top
|
|
RKT = DEPSAV(I,J,DRYSO4) * GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! RKT > 0 denotes that we have SO4 drydep occurring
|
|
IF ( RKT > 0d0 ) THEN
|
|
|
|
!-----------------------------------------------------------
|
|
! CASE 1: SO4 production from SO2 and SO4 loss by drydep
|
|
!-----------------------------------------------------------
|
|
|
|
! Fraction of SO4 lost to drydep [unitless]
|
|
RKT = RKT * DTCHEM
|
|
|
|
! Pre-compute exponential term for use below
|
|
E_RKT = EXP( -RKT )
|
|
|
|
! Updated SO4 (gas phase) [v/v]
|
|
SO4 = ( SO40 * E_RKT ) +
|
|
& ( PSO4_SO2(I,J,L)/RKT * ( 1.d0 - E_RKT ) )
|
|
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%%
|
|
!%%% ! Updated SO4 (aqueous phase) [v/v]
|
|
!%%% SO4aq = ( SO4aq0 * E_RKT ) +
|
|
!%%% & ( PSO4_SO2(I,J,L)/RKT * ( 1.d0 - E_RKT ) )
|
|
!%%%
|
|
!%%% ! Updated AS, AHS, LET [v/v]
|
|
!%%% AS = AS0 * E_RKT
|
|
!%%% AHS = AHS0 * E_RKT
|
|
!%%% LET = LET0 * E_RKT
|
|
!%%%
|
|
!%%% ENDIF
|
|
!------------------------------------------------------------------------------
|
|
|
|
ELSE
|
|
|
|
!-----------------------------------------------------------
|
|
! CASE 2: Production of SO4 from SO2; no SO4 drydep loss
|
|
!-----------------------------------------------------------
|
|
|
|
!-----------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%%
|
|
!%%% ! SO4 production from SO2 (both gas-phase & aqueous)
|
|
!%%% SO4 = SO40 + ( 2d0 * PSO4_SO2(I,J,L) )
|
|
!%%% SO4aq = SO4aq0 + ( 2d0 * PSO4_SO2(I,J,L) )
|
|
!%%%
|
|
!%%% ! No production from AS, AHS, LET
|
|
!%%% AS = AS0
|
|
!%%% AHS = AHS0
|
|
!%%% LET = LET0
|
|
!%%%
|
|
!%%% ELSE
|
|
!%%%
|
|
!%%% ! SO4 production from SO2 [v/v/timestep]
|
|
!%%% SO4 = SO40 + PSO4_SO2(I,J,L)
|
|
!%%%
|
|
!%%% ENDIF
|
|
!-----------------------------------------------------------------------------
|
|
|
|
! SO4 production from SO2 [v/v/timestep]
|
|
SO4 = SO40 + PSO4_SO2(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! SO4s (SO4 w/in seasalt aerosol) chemistry:
|
|
!
|
|
! (CASE 3) SO4s production from seasalt and loss by drydep
|
|
! --> see equation in header notes above
|
|
!
|
|
! (CASE 4) SO4s prod from seasalt w/ no SO4s loss by drydep
|
|
!==============================================================
|
|
|
|
! SO4s drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each vertical level that is located below the PBL top
|
|
RKTs = DEPSAV(I,J,DRYSO4s) * GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! RKTs > 0 indicates that SO4s drydep occurs
|
|
IF ( RKTs > 0d0 ) THEN
|
|
|
|
!-----------------------------------------------------------
|
|
! CASE 3: SO4s prod from seasalt SO4s loss by drydep
|
|
!-----------------------------------------------------------
|
|
|
|
! Fraction of SO4s lost to drydep [unitless]
|
|
RKTs = RKTs * DTCHEM
|
|
|
|
! Pre-compute exponential term for use below
|
|
E_RKTs = EXP( -RKTs )
|
|
|
|
! Updated SO4 (gas phase) [v/v]
|
|
SO4s = ( SO40s * E_RKTs ) +
|
|
& ( PSO4_ss(I,J,L)/RKTs * ( 1.d0 - E_RKTs ) )
|
|
|
|
ELSE
|
|
|
|
!--------------------------------------------------------
|
|
! CASE 4: Prod of SO4s from seasalt; no SO4s drydep loss
|
|
!--------------------------------------------------------
|
|
|
|
! SO4 production from SO2 [v/v/timestep]
|
|
SO4s = SO40s + PSO4_ss(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! Final concentrations after chemistry
|
|
!==============================================================
|
|
|
|
! Error check
|
|
IF ( SO4 < SMALLNUM ) SO4 = 0d0
|
|
IF ( SO4s < SMALLNUM ) SO4s = 0d0
|
|
|
|
! Final concentrations [v/v]
|
|
STT(I,J,L,IDTSO4) = SO4
|
|
STT(I,J,L,IDTSO4s) = SO4s
|
|
|
|
!-----------------------------------------------------------------------------
|
|
!%%% Currently under development (bmy, 3/15/05)
|
|
!%%% ! SO4aq, AS, AHS, LET (if necessary)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%%
|
|
!%%% ! Error check
|
|
!%%% IF ( SO4aq < SMALLNUM ) SO4aq = 0d0
|
|
!%%% IF ( AS < SMALLNUM ) AS = 0d0
|
|
!%%% IF ( AHS < SMALLNUM ) AHS = 0d0
|
|
!%%% IF ( LET < SMALLNUM ) LET = 0d0
|
|
!%%%
|
|
!%%% ! Final SO4aq, AS, AHS, LET [v/v]
|
|
!%%% STT(I,J,L,IDTSO4aq) = SO4aq
|
|
!%%% STT(I,J,L,IDTAS) = AS
|
|
!%%% STT(I,J,L,IDTAHS) = AHS
|
|
!%%% STT(I,J,L,IDTLET) = LET
|
|
!%%%
|
|
!%%% ENDIF
|
|
!-----------------------------------------------------------------------------
|
|
|
|
!==============================================================
|
|
! ND44 Diagnostic: Drydep flux of SO4 and the crystalline &
|
|
! aqueous tracers (AS, AHS, LET, SO4aq) in [molec/cm2/s]
|
|
!==============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! SO4 drydep flux [molec/cm2/s]
|
|
FLUX = SO40 - SO4 + PSO4_SO2(I,J,L)
|
|
FLUX = FLUX * AD(I,J,L) / TCVV(IDTSO4)
|
|
FLUX = FLUX * XNUMOL(IDTSO4) / AREA_CM2 / DTCHEM
|
|
T44(I,J,L,1) = T44(I,J,L,1) + FLUX
|
|
|
|
! SO4s drydep flux [molec/cm2/s]
|
|
FLUX = SO40s - SO4s + PSO4_ss(I,J,L)
|
|
FLUX = FLUX * AD(I,J,L) / TCVV(IDTSO4s)
|
|
FLUX = FLUX * XNUMOL(IDTSO4s) / AREA_CM2 / DTCHEM
|
|
T44(I,J,L,2) = T44(I,J,L,2) + FLUX
|
|
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% ! SO4aq, AS, AHS, LET drydep fluxes (if necessary)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%%
|
|
!%%% ! SO4aq drydep flux [molec/cm2/s]
|
|
!%%% FLUX = SO4aq0 - SO4aq + PSO4_SO2(I,J,L)
|
|
!%%% FLUX = FLUX * AD(I,J,L) / TCVV(IDTSO4aq)
|
|
!%%% FLUX = FLUX * XNUMOL(IDTSO4aq) / AREA_CM2 / DTCHEM
|
|
!%%% T44(I,J,L,3) = T44(I,J,L,3) + FLUX
|
|
!%%%
|
|
!%%% ! AS drydep flux [molec/cm2/s]
|
|
!%%% FLUX = AS0 - AS
|
|
!%%% FLUX = FLUX * AD(I,J,L) / TCVV(IDTAS)
|
|
!%%% FLUX = FLUX * XNUMOL(IDTAS) / AREA_CM2 / DTCHEM
|
|
!%%% T44(I,J,L,4) = T44(I,J,L,4) + FLUX
|
|
!%%%
|
|
!%%% ! AHS drydep flux [molec/cm2/s]
|
|
!%%% FLUX = AHS0 - AHS
|
|
!%%% FLUX = FLUX * AD(I,J,L) / TCVV(IDTAHS)
|
|
!%%% FLUX = FLUX * XNUMOL(IDTAHS) / AREA_CM2 / DTCHEM
|
|
!%%% T44(I,J,L,5) = T44(I,J,L,5) + FLUX
|
|
!%%%
|
|
!%%% ! LET drydep flux [molec/cm2/s]
|
|
!%%% FLUX = LET0 - LET
|
|
!%%% FLUX = FLUX * AD(I,J,L) / TCVV(IDTLET)
|
|
!%%% FLUX = FLUX * XNUMOL(IDTLET) / AREA_CM2 / DTCHEM
|
|
!%%% T44(I,J,L,6) = T44(I,J,L,6) + FLUX
|
|
!%%%
|
|
!%%% ENDIF
|
|
!------------------------------------------------------------------------------
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, LLTROP
|
|
|
|
! Sum SO4, SO4s drydep fluxes in the vertical [molec/cm2/s]
|
|
AD44(I,J,DRYSO4, 1) = AD44(I,J,DRYSO4, 1) + T44(I,J,L,1)
|
|
AD44(I,J,DRYSO4s,1) = AD44(I,J,DRYSO4s,1) + T44(I,J,L,2)
|
|
|
|
!------------------------------------------------------------------------------
|
|
!%%% Currently under development (rjp, bmy, 3/15/05)
|
|
!%%% ! Sum SO4aq, AS, AHS, LET drydep fluxes (if necessary)
|
|
!%%% IF ( LCRYST ) THEN
|
|
!%%% AD44(I,J,DRYSO4aq,1) = AD44(I,J,DRYSO4aq,1)+T44(I,J,L,3)
|
|
!%%% AD44(I,J,DRYAS, 1) = AD44(I,J,DRYAS, 1)+T44(I,J,L,4)
|
|
!%%% AD44(I,J,DRYAHS, 1) = AD44(I,J,DRYAHS, 1)+T44(I,J,L,5)
|
|
!%%% AD44(I,J,DRYLET, 1) = AD44(I,J,DRYLET, 1)+T44(I,J,L,6)
|
|
!%%% ENDIF
|
|
!------------------------------------------------------------------------------
|
|
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_SO4
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
!SUBROUTINE PHASE_SO4
|
|
!
|
|
! *** Currently under development ***
|
|
!
|
|
!END SUBROUTINE PHASE_SO4
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
!SUBROUTINE PHASE_RADIATIVE
|
|
!
|
|
! *** Currently under development ***
|
|
!
|
|
!END SUBROUTINE PHASE_RADIATIVE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_MSA
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_MSA is the SO4 chemistry subroutine from Mian Chin's GOCART
|
|
! model, modified for the GEOS-CHEM model. (rjp, bdf, bmy, 5/31/00, 10/25/05)
|
|
!
|
|
! Module Variables Used:
|
|
! ============================================================================
|
|
! (1 ) PMSA_DMS (REAL*8 ) : Array for P(MSA) from DMS [v/v/timestep]
|
|
!
|
|
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
|
|
! ============================================================================
|
|
! The Only production is from DMS oxidation (saved in CHEM_DMS), and the only
|
|
! loss is dry depsition here. Wet deposition will be treated in "wetdep.f".
|
|
!
|
|
! MSA = MSA_0 * exp(-dt) + PMSA_DMS/kt * (1.-exp(-kt))
|
|
! where k = dry deposition.
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD from "dao_mod.f". Added parallel DO-loops.
|
|
! Updated comments, cosmetic changes. (rjp, bmy, bdf, 9/16/02)
|
|
! (2 ) Now replace DXYP(JREF)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
|
|
! Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! to the entire PBL. (rjp, bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (6 ) Now references STT & TCVV from "tracer_mod.f" (bmy, 7/20/04)
|
|
! (7 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
|
|
! Vertical DO-loops can run up to PBL_MAX and not LLTROP. Also
|
|
! remove reference to header file CMN. (bmy, 2/22/05)
|
|
! (8 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (9 ) Change loop back to over entire troposphere to correctly add production
|
|
! of MSA (PMSA_dms) to the MSA tracer array.
|
|
! Added reference USE_TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
! as a precaution. (pjh, 8/19/2009)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTMSA
|
|
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_GCTM" ! AIRMW
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, PBL_MAX
|
|
REAL*8 :: DTCHEM, MSA0, MSA, RK
|
|
REAL*8 :: RKT, FLUX, AREA_CM2, F_UNDER_TOP
|
|
REAL*8 :: ND44_TMP(IIPAR,JJPAR,LLTROP)
|
|
|
|
!=================================================================
|
|
! CHEM_MSA begins here!
|
|
!=================================================================
|
|
IF ( IDTMSA == 0 .or. DRYMSA == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry interval in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Model level where maximum PBL height occurs
|
|
PBL_MAX = GET_PBL_MAX_L()
|
|
|
|
! Zero ND44_TMP array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
ND44_TMP(I,J,L) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Loop over tropospheric grid boxes
|
|
! Loop over tropospheric grid boxes
|
|
!--------------------------
|
|
! pjh 8/18/2009
|
|
! Change the loop from over L = 1, PBL_MAX to over the entire
|
|
! troposphere. Cycle if in the stratosphere. Allow dry dep only up to
|
|
! the PBL_MAX, otherwise add PMSA_DMS to the MSA tracer array above
|
|
! PBL. Previous changes had not accounted for PMSA_DMS into the MSA
|
|
! tracer array and therefore lost the MSA source above the PBL.
|
|
!--------------
|
|
|
|
|
|
!---- prior 24/8/09 (phs, pjh)
|
|
! !$OMP PARALLEL DO
|
|
! !$OMP+DEFAULT( SHARED )
|
|
! !$OMP+PRIVATE( I, J, L, F_UNDER_TOP, MSA0, RKT, MSA, AREA_CM2, FLUX )
|
|
! !$OMP+SCHEDULE( DYNAMIC )
|
|
! DO L = 1, PBL_MAX
|
|
! DO J = 1, JJPAR
|
|
! DO I = 1, IIPAR
|
|
!
|
|
! ! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
! F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
!
|
|
! ! Only apply drydep loss to boxes w/in the PBL
|
|
! IF ( F_UNDER_TOP > 0 ) THEN
|
|
!
|
|
! ! Initial MSA [v/v]
|
|
! MSA0 = STT(I,J,L,IDTMSA)
|
|
!
|
|
! ! MSA drydep frequency [1/s]. Also accounts for the fraction
|
|
! ! of each grid box (I,J,L) that is located beneath the PBL top
|
|
! RKT = DEPSAV(I,J,DRYMSA) * F_UNDER_TOP
|
|
!
|
|
! ! RKT > 0 denotes that we have drydep occurring
|
|
! IF ( RKT > 0.d0 ) THEN
|
|
!
|
|
! ! Fraction of MSA lost to drydep [unitless]
|
|
! RKT = RKT * DTCHEM
|
|
!
|
|
! ! Modified MSA concentration
|
|
! MSA = ( MSA0 * EXP( -RKT ) ) +
|
|
! & ( PMSA_DMS(I,J,L)/RKT * ( 1d0 - EXP( -RKT ) ) )
|
|
!
|
|
! ELSE
|
|
!
|
|
! ! MSA production from DMS [v/v/timestep]
|
|
! MSA = MSA0 + PMSA_DMS(I,J,L)
|
|
!
|
|
! ENDIF
|
|
!
|
|
! ! Final MSA [v/v]
|
|
! IF ( MSA < SMALLNUM ) MSA = 0d0
|
|
! STT(I,J,L,IDTMSA) = MSA
|
|
!
|
|
! !===========================================================
|
|
! ! ND44 Diagnostic: Drydep flux of MSA [molec/cm2/s]
|
|
! !===========================================================
|
|
! IF ( ND44 > 0 .and. RKT > 0d0 ) THEN
|
|
!
|
|
! ! Surface area [cm2]
|
|
! AREA_CM2 = GET_AREA_CM2( J )
|
|
!
|
|
! ! Convert [v/v/timestep] to [molec/cm2/s]
|
|
! FLUX = MSA0 - MSA + PMSA_DMS(I,J,L)
|
|
! FLUX = FLUX * AD(I,J,L) / TCVV(IDTMSA)
|
|
! FLUX = FLUX * XNUMOL(IDTMSA) / AREA_CM2 / DTCHEM
|
|
!
|
|
! ! Store dryd flux in ND44_TMP as a placeholder
|
|
! ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
! ENDIF
|
|
! ENDIF
|
|
! ENDDO
|
|
! ENDDO
|
|
! ENDDO
|
|
! !$OMP END PARALLEL DO
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, MSA0, RKT, MSA, AREA_CM2, FLUX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Skip stratospheric boxes
|
|
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
|
|
|
|
! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! Initial MSA [v/v]
|
|
MSA0 = STT(I,J,L,IDTMSA)
|
|
|
|
! MSA drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each grid box (I,J,L) that is located beneath the PBL top
|
|
RKT = DEPSAV(I,J,DRYMSA) * F_UNDER_TOP
|
|
|
|
!! Add option for non-local PBL (Lin, 03/31/09)
|
|
!IF (LNLPBL) RKT = 0.D0
|
|
|
|
! RKT > 0 denotes that we have drydep occurring
|
|
IF ( RKT > 0.d0 ) THEN
|
|
|
|
! Fraction of MSA lost to drydep [unitless]
|
|
RKT = RKT * DTCHEM
|
|
|
|
! Modified MSA concentration
|
|
MSA = ( MSA0 * EXP( -RKT ) ) +
|
|
& ( PMSA_DMS(I,J,L)/RKT * ( 1d0 - EXP( -RKT ) ) )
|
|
|
|
ELSE
|
|
|
|
! MSA production from DMS [v/v/timestep]
|
|
MSA = MSA0 + PMSA_DMS(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
! Final MSA [v/v]
|
|
IF ( MSA < SMALLNUM ) MSA = 0d0
|
|
STT(I,J,L,IDTMSA) = MSA
|
|
|
|
!===========================================================
|
|
! ND44 Diagnostic: Drydep flux of MSA [molec/cm2/s]
|
|
!===========================================================
|
|
IF ( ND44 > 0 .and. RKT > 0d0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = MSA0 - MSA + PMSA_DMS(I,J,L)
|
|
FLUX = FLUX * AD(I,J,L) / TCVV(IDTMSA)
|
|
FLUX = FLUX * XNUMOL(IDTMSA) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flux in ND44_TMP as a placeholder
|
|
ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, PBL_MAX
|
|
AD44(I,J,DRYMSA,1) = AD44(I,J,DRYMSA,1) + ND44_TMP(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_MSA
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_NH3
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_NH3 removes NH3 from the surface via dry deposition.
|
|
! (rjp, bdf, bmy, 1/2/02, 10/25/05)
|
|
!
|
|
! Reaction List:
|
|
! ============================================================================
|
|
! (1 ) NH3 = NH3_0 * EXP( -dt ) where d = dry deposition rate [s-1]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD from "dao_mod.f". Added parallel DO-loops.
|
|
! Updated comments, cosmetic changes. (rjp, bmy, bdf, 9/16/02)
|
|
! (2 ) Now replace DXYP(J+J0)*1d4 with routine GET_AREA_CM2 from "grid_mod.f"
|
|
! Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! to the entire PBL. Added L and FREQ variables. Recode to avoid
|
|
! underflow from the EXP() function. (rjp, bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (6 ) Now references STT & TCVV from "tracer_mod.f" Also remove reference to
|
|
! CMN, it's not needed(bmy, 7/20/04)
|
|
! (7 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
|
|
! Vertical DO-loops can run up to PBL_MAX and not LLTROP. (bmy, 2/22/05)
|
|
! (8 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH3
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, PBL_MAX
|
|
REAL*8 :: DTCHEM, NH30, NH3
|
|
REAL*8 :: FREQ, AREA_CM2, FLUX, F_UNDER_TOP
|
|
REAL*8 :: ND44_TMP(IIPAR,JJPAR,LLTROP)
|
|
|
|
!=================================================================
|
|
! CHEM_NH3 begins here!
|
|
!=================================================================
|
|
IF ( IDTNH3 == 0 .or. DRYNH3 == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry interval in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Model level where maximum PBL height occurs
|
|
PBL_MAX = GET_PBL_MAX_L()
|
|
|
|
! Zero ND44_TMP array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
ND44_TMP(I,J,L) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ, NH30, NH3, AREA_CM2, FLUX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, PBL_MAX
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! Only apply drydep to boxes w/in the PBL
|
|
IF ( F_UNDER_TOP > 0d0 ) THEN
|
|
|
|
! NH3 drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each grid box (I,J,L) that is located beneath the PBL top
|
|
FREQ = DEPSAV(I,J,DRYNH3) * F_UNDER_TOP
|
|
|
|
! Only compute drydep loss if FREQ is nonzero
|
|
IF ( FREQ > 0d0 ) THEN
|
|
|
|
! Initial NH3 [v/v]
|
|
NH30 = STT(I,J,L,IDTNH3)
|
|
|
|
! Amount of NH3 lost to drydep [v/v]
|
|
NH3 = NH30 * ( 1d0 - EXP( -FREQ * DTCHEM ) )
|
|
|
|
! Prevent underflow condition
|
|
IF ( NH3 < SMALLNUM ) NH3 = 0d0
|
|
|
|
! Subtract NH3 lost to drydep from initial NH3 [v/v]
|
|
STT(I,J,L,IDTNH3) = NH30 - NH3
|
|
|
|
!========================================================
|
|
! ND44 diagnostic: Drydep flux of NH3 [molec/cm2/s]
|
|
!========================================================
|
|
IF ( ND44 > 0 .and. NH3 > 0d0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert drydep loss from [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = NH3 * AD(I,J,L) / TCVV(IDTNH3)
|
|
FLUX = FLUX * XNUMOL(IDTNH3) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, PBL_MAX
|
|
AD44(I,J,DRYNH3,1) = AD44(I,J,DRYNH3,1) + ND44_TMP(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_NH3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_NH4
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_NH4 removes NH4 from the surface via dry deposition.
|
|
! (rjp, bdf, bmy, 1/2/02, 10/25/05)
|
|
!
|
|
! Reaction List:
|
|
! ============================================================================
|
|
! (1 ) NH4 = NH4_0 * EXP( -dt ) where d = dry deposition rate [s-1]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD from "dao_mod.f". Added parallel DO-loops.
|
|
! Updated comments, cosmetic changes. (rjp, bmy, bdf, 9/16/02)
|
|
! (2 ) Now replace DXYP(JREF)*1d4 with routine GET_AREA_CM2 of "grid_mod.f".
|
|
! Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! to the entire PBL. Added L and FREQ variables. Recode to avoid
|
|
! underflow from EXP(). (rjp, bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (6 ) Now reference STT & TCVV from "tracer_mod.f". Also remove reference
|
|
! to CMN, it's not needed (bmy, 7/20/04)
|
|
! (7 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
|
|
! Vertical DO-loops can run up to PBL_MAX and not LLTROP. (bmy, 2/22/05)
|
|
! (8 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH4
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, PBL_MAX
|
|
REAL*8 :: DTCHEM, NH4, NH40
|
|
REAL*8 :: FREQ, FLUX, AREA_CM2, F_UNDER_TOP
|
|
REAL*8 :: ND44_TMP(IIPAR,JJPAR,LLTROP)
|
|
|
|
!=================================================================
|
|
! CHEM_NH4 begins here!
|
|
!=================================================================
|
|
IF ( IDTNH4 == 0 .or. DRYNH4 == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry interval in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Model level where maximum PBL height occurs
|
|
PBL_MAX = GET_PBL_MAX_L()
|
|
|
|
! Zero ND44_TMP array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
ND44_TMP(I,J,L) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ, NH40, NH4, AREA_CM2, FLUX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, PBL_MAX
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! Only apply drydep to boxes w/in the PBL
|
|
IF ( F_UNDER_TOP > 0d0 ) THEN
|
|
|
|
! NH4 drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each grid box (I,J,L) that is located beneath the PBL top
|
|
FREQ = DEPSAV(I,J,DRYNH4) * F_UNDER_TOP
|
|
|
|
! Only apply drydep loss if FREQ is nonzero
|
|
IF ( FREQ > 0d0 ) THEN
|
|
|
|
! Initial NH4 [v/v]
|
|
NH40 = STT(I,J,L,IDTNH4)
|
|
|
|
! Amount of NH4 lost to drydep [v/v]
|
|
NH4 = NH40 * ( 1d0 - EXP( -FREQ * DTCHEM ) )
|
|
|
|
! Prevent underflow condition
|
|
IF ( NH4 < SMALLNUM ) NH4 = 0d0
|
|
|
|
! Subtract NH4 lost to drydep from initial NH4 [v/v]
|
|
STT(I,J,L,IDTNH4) = NH40 - NH4
|
|
|
|
!========================================================
|
|
! ND44 diagnostic: Drydep flux of NH4 [molec/cm2/s]
|
|
!========================================================
|
|
IF ( ND44 > 0 .and. NH4 > 0d0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert drydep loss from [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = NH4 * AD(I,J,L) / TCVV(IDTNH4)
|
|
FLUX = FLUX * XNUMOL(IDTNH4) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
ND44_TMP(I,J,L) = ND44_TMP(I,J,L) + FLUX
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, PBL_MAX
|
|
AD44(I,J,DRYNH4,1) = AD44(I,J,DRYNH4,1) + ND44_TMP(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_NH4
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_NH4aq
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_NH4aq removes NH4aq from the surface via dry deposition.
|
|
! (cas, bmy, 1/6/05, 10/25/05)
|
|
!
|
|
! Reaction List:
|
|
! ============================================================================
|
|
! (1 ) NH4aq = NH4_0aq * EXP( -dt ) where d = dry deposition rate [s-1]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
|
|
! Vertical DO-loops can run up to PBL_MAX and not LLTROP. (bmy, 2/22/05)
|
|
! (31) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH4aq
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, PBL_MAX
|
|
REAL*8 :: DTCHEM, NH4aq, NH4aq0
|
|
REAL*8 :: FREQ, FLUX, AREA_CM2, F_UNDER_TOP
|
|
REAL*8 :: T44(IIPAR,JJPAR,LLTROP)
|
|
|
|
!=================================================================
|
|
! CHEM_NH4 begins here!
|
|
!=================================================================
|
|
IF ( IDTNH4aq == 0 .or. DRYNH4aq == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry interval in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Model level where maximum PBL height occurs
|
|
PBL_MAX = GET_PBL_MAX_L()
|
|
|
|
! Zero T44 array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
T44(I,J,L) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ )
|
|
!$OMP+PRIVATE( NH4aq0, NH4aq, AREA_CM2, FLUX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, PBL_MAX
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! Only apply drydep to boxes w/in the PBL
|
|
IF ( F_UNDER_TOP > 0d0 ) THEN
|
|
|
|
! NH4 drydep frequency [1/s] -- PBLFRAC accounts for the fraction
|
|
! of each grid box (I,J,L) that is located beneath the PBL top
|
|
FREQ = DEPSAV(I,J,DRYNH4aq) * F_UNDER_TOP
|
|
|
|
! Only apply drydep loss if FREQ is nonzero
|
|
IF ( FREQ > 0d0 ) THEN
|
|
|
|
! Initial NH4 [v/v]
|
|
NH4aq0 = STT(I,J,L,IDTNH4aq)
|
|
|
|
! Amount of NH4 lost to drydep [v/v]
|
|
NH4aq = NH4aq0 * ( 1d0 - EXP( -FREQ * DTCHEM ) )
|
|
|
|
! Prevent underflow condition
|
|
IF ( NH4aq < SMALLNUM ) NH4aq = 0d0
|
|
|
|
! Subtract NH4 lost to drydep from initial NH4 [v/v]
|
|
STT(I,J,L,IDTNH4aq) = NH4aq0 - NH4aq
|
|
|
|
!========================================================
|
|
! ND44 diagnostic: Drydep flux of NH4 [molec/cm2/s]
|
|
!========================================================
|
|
IF ( ND44 > 0 .and. NH4aq > 0d0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Convert drydep loss from [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = NH4aq * AD(I,J,L) / TCVV(IDTNH4aq)
|
|
FLUX = FLUX * XNUMOL(IDTNH4aq) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
T44(I,J,L) = T44(I,J,L) + FLUX
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, PBL_MAX
|
|
AD44(I,J,DRYNH4aq,1) = AD44(I,J,DRYNH4aq,1) + T44(I,J,L)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_NH4aq
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CHEM_NIT
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CHEM_NIT removes SULFUR NITRATES (NIT) from the surface
|
|
! via dry deposition. (rjp, bdf, bmy, 1/2/02, 5/23/06)
|
|
!
|
|
! Reaction List:
|
|
! ============================================================================
|
|
! (1 ) NIT = NIT_0 * EXP( -dt ) where d = dry deposition rate [s-1]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference AD from "dao_mod.f". Added parallel DO-loops.
|
|
! Updated comments, cosmetic changes. (rjp, bmy, bdf, 9/20/02)
|
|
! (2 ) Now replace DXYP(J+J0)*1d4 with routine GET_AREA_CM2 from "grid_mod.f".
|
|
! Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference PBLFRAC from "drydep_mod.f". Now apply dry deposition
|
|
! to the entire PBL. Added L and FREQ variables. Recode to avoid
|
|
! underflow from EXP(). (rjp, bmy, 8/1/03)
|
|
! (4 ) Now use ND44_TMP array to store vertical levels of drydep flux, then
|
|
! sum into AD44 array. This preents numerical differences when using
|
|
! multiple processors. (bmy, 3/24/04)
|
|
! (5 ) Now use parallel DO-loop to zero ND44_TMP (bmy, 4/14/04)
|
|
! (6 ) Now reference STT & TCVV from "tracer_mod.f". Also remove reference
|
|
! to CMN, it's not needed anymore. (bmy, 7/20/04)
|
|
! (7 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
|
|
! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
|
|
! Vertical DO-loops can run up to PBL_MAX and not LLTROP. (bmy, 2/22/05)
|
|
! (8 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (9 ) Rearrange error check to avoid SEG FAULTS (bmy, 5/23/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIAG_MOD, ONLY : AD44
|
|
USE DRYDEP_MOD, ONLY : DEPSAV
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LSSALT
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNIT, IDTNITs
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND44
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, N, N_ND44, PBL_MAX
|
|
REAL*8 :: DTCHEM, NIT, NITs, NIT0, NIT0s, E_RKT
|
|
REAL*8 :: E_RKTs, FLUX, FREQ, FREQs, RKT, RKTs
|
|
REAL*8 :: AREA_CM2, F_UNDER_TOP
|
|
REAL*8 :: T44(IIPAR,JJPAR,LLTROP,2)
|
|
|
|
!=================================================================
|
|
! CHEM_NIT begins here!
|
|
!=================================================================
|
|
|
|
! Return if tracers are not defined
|
|
IF ( IDTNIT == 0 .or. IDTNITs == 0 ) RETURN
|
|
IF ( DRYNIT == 0 .or. DRYNITs == 0 ) RETURN
|
|
|
|
! DTCHEM is the chemistry interval in seconds
|
|
DTCHEM = GET_TS_CHEM() * 60d0
|
|
|
|
! Model level where maximum PBL height occurs
|
|
PBL_MAX = GET_PBL_MAX_L()
|
|
|
|
! Number of tracers for ND44
|
|
N_ND44 = 2
|
|
|
|
! Zero ND44 array
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, N )
|
|
DO N = 1, N_ND44
|
|
DO L = 1, LLTROP
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
T44(I,J,L,N) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, NIT0, NIT0s, NIT )
|
|
!$OMP+PRIVATE( NITs, FREQ, FREQs, F_UNDER_TOP, RKT, E_RKT )
|
|
!$OMP+PRIVATE( RKTs, E_RKTs, AREA_CM2, FLUX )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO L = 1, PBL_MAX
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Initial NITRATE [v/v]
|
|
NIT0 = STT(I,J,L,IDTNIT)
|
|
|
|
! Initial NITRATE w/in seasalt [v/v]
|
|
NIT0s = STT(I,J,L,IDTNITs)
|
|
|
|
! Initialize variables
|
|
NIT = 0d0
|
|
NITs = 0d0
|
|
FREQ = 0d0
|
|
FREQs = 0d0
|
|
|
|
! Fraction of box (I,J,L) underneath the PBL top [unitless]
|
|
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
|
|
|
|
! Only apply drydep to boxes w/in the PBL
|
|
IF ( F_UNDER_TOP > 0d0 ) THEN
|
|
|
|
!===========================================================
|
|
! NIT chemistry
|
|
!===========================================================
|
|
|
|
! NIT drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each vertical level that is located below the PBL top
|
|
FREQ = DEPSAV(I,J,DRYNIT) * F_UNDER_TOP
|
|
|
|
! If there is drydep ...
|
|
IF ( FREQ > 0d0 ) THEN
|
|
|
|
! Fraction of NIT lost to drydep [unitless] (bec, 12/15/04)
|
|
RKT = FREQ * DTCHEM
|
|
|
|
! Pre-compute the exponential term
|
|
E_RKT = EXP( -RKT )
|
|
|
|
! Amount of NITRATE lost to drydep [v/v]
|
|
NIT = NIT0 * ( 1d0 - E_RKT )
|
|
|
|
! Prevent underflow condition
|
|
IF ( NIT < SMALLNUM ) NIT = 0d0
|
|
|
|
! Subtract NITRATE lost to drydep from initial NITRATE [v/v]
|
|
STT(I,J,L,IDTNIT) = NIT0 - NIT
|
|
|
|
ELSE
|
|
|
|
! No deposition occurs
|
|
NIT = 0d0
|
|
|
|
ENDIF
|
|
|
|
!===========================================================
|
|
! NITs chemistry
|
|
!===========================================================
|
|
|
|
! NITs drydep frequency [1/s]. Also accounts for the fraction
|
|
! of each vertical level that is located below the PBL top
|
|
FREQs = DEPSAV(I,J,DRYNITs) * F_UNDER_TOP
|
|
|
|
! If there is drydep ...
|
|
IF ( FREQs > 0d0 ) THEN
|
|
|
|
! Fraction of NIT lost to drydep [unitless] (bec, 12/15/04)
|
|
RKTs = FREQs * DTCHEM
|
|
|
|
! Pre-compute the exponential term
|
|
E_RKTs = EXP( -RKTs )
|
|
|
|
! Compute new NIT concentration [v/v],
|
|
! updated for seasalt chemistry
|
|
NITs = ( NIT0s * E_RKTs ) +
|
|
& ( PNITs(I,J,L)/RKTs * ( 1.d0 - E_RKTs ) )
|
|
|
|
ELSE
|
|
|
|
! NIT prod from HNO3 uptake on fine sea-salt [v/v/timestep]
|
|
NITs = NIT0s + PNITs(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
! Store final concentration in STT [v/v]
|
|
STT(I,J,L,IDTNITs) = NITs
|
|
|
|
!========================================================
|
|
! ND44 Diagnostic: Drydep flux of NIT [molec/cm2/s]
|
|
!========================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
|
|
! Surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
!-------------
|
|
! NIT drydep
|
|
!-------------
|
|
|
|
! If NIT drydep occurs ...
|
|
IF ( FREQ > 0d0 ) THEN
|
|
|
|
! Convert from [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = NIT * AD(I,J,L) / TCVV(IDTNIT)
|
|
FLUX = FLUX * XNUMOL(IDTNIT) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
T44(I,J,L,1) = T44(I,J,L,1) + FLUX
|
|
|
|
ENDIF
|
|
|
|
!-------------
|
|
! NITs drydep
|
|
!-------------
|
|
|
|
! NOTE: if drydep doesn't occur then we still have
|
|
! production from seasalt (bec, bmy, 4/13/05)
|
|
|
|
! Convert from [v/v/timestep] to [molec/cm2/s]
|
|
FLUX = NIT0s - NITs + PNITs(I,J,L)
|
|
FLUX = FLUX * AD(I,J,L) / TCVV(IDTNITs)
|
|
FLUX = FLUX * XNUMOL(IDTNITs) / AREA_CM2 / DTCHEM
|
|
|
|
! Store dryd flx in ND44_TMP as a placeholder
|
|
T44(I,J,L,2) = T44(I,J,L,2) + FLUX
|
|
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!===============================================================
|
|
! ND44: Sum drydep fluxes by level into the AD44 array in
|
|
! order to ensure that we get the same results w/ sp or mp
|
|
!===============================================================
|
|
IF ( ND44 > 0 ) THEN
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
DO L = 1, PBL_MAX
|
|
AD44(I,J,DRYNIT, 1) = AD44(I,J,DRYNIT, 1) + T44(I,J,L,1)
|
|
AD44(I,J,DRYNITs,1) = AD44(I,J,DRYNITs,1) + T44(I,J,L,2)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CHEM_NIT
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
SUBROUTINE EMISSSULFATE
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine EMISSSULFATE is the interface between the GEOS-CHEM model and
|
|
! the sulfate emissions routines in "sulfate_mod.f" (bmy, 6/7/00, 10/3/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) BXHEIGHT is now dimensioned IIPAR,JJPAR,LLPAR (bmy, 9/26/01)
|
|
! (2 ) Removed obsolete commented out code from 9/01 (bmy, 10/24/01)
|
|
! (3 ) Now reference all arguments except FIRSTEMISS, LENV, LEEV from
|
|
! header files or F90 modules. Removed NSRCE, MONTH, JDAY,
|
|
! LWI, BXHEIGHT, DXYP, AD, PTOP, SIGE, PS, PBL, XTRA2, STT, DATA_DIR,
|
|
! JYEAR from the arg list. Now reference GET_PEDGE from F90 module
|
|
! "pressure_mod.f" to compute grid box edge pressures. Now uses
|
|
! GET_SEASON from "time_mod.f" to get the season. Now references
|
|
! IDTDMS, IDTSO2, etc from "tracerid_mod.f". Now make FIRSTEMISS
|
|
! a local SAVEd variable. Now call READ_BIOMASS_NH3 to read NH3
|
|
! biomass and biofuel emissions. (bmy, 12/13/02)
|
|
! (4 ) Now call READ_NATURAL_NH3 to read the NH3 source from natural
|
|
! emissions. (rjp, bmy, 3/23/03)
|
|
! (5 ) Now use functions GET_SEASON and GET_MONTH from the new "time_mod.f"
|
|
! (bmy, 3/27/03)
|
|
! (6 ) Added first-time printout message (bmy, 4/6/04)
|
|
! (7 ) Now references CMN_SETUP. Now read ship SO2 if LSHIPSO2=T. Also
|
|
! references ITS_A_NEW_MONTH from "time_mod.f". (bec, bmy, 5/20/04)
|
|
! (8 ) Now references STT and ITS_AN_AEROSOL_SIM from "tracer_mod.f".
|
|
! Now references LSHIPSO2 from "logical_mod.f" (bmy, 7/20/04)
|
|
! (9 ) Now references GET_YEAR from "time_mod.f". (bmy, 8/1/05)
|
|
! (10) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (11) Now check if GFED2 has been updated (yc, phs, 12/23/08)
|
|
! (12) Add LANTHRO switch to properly turn off the anthropogenic emissions,
|
|
! READ_AIRCRAFT_SO2, READ_ANTHRO_SOx, READ_ANTHRO_NH3 (ccc, 4/15/09)
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE ERROR_MOD, ONLY : DEBUG_MSG
|
|
USE LOGICAL_MOD, ONLY : LSHIPSO2, LPRT, LBIOMASS !(win,5/1/09)
|
|
USE LOGICAL_MOD, ONLY : LHTAP
|
|
USE TIME_MOD, ONLY : GET_SEASON, GET_MONTH
|
|
USE TIME_MOD, ONLY : GET_YEAR, ITS_A_NEW_MONTH
|
|
USE TRACER_MOD, ONLY : STT, ITS_AN_AEROSOL_SIM
|
|
USE TRACERID_MOD, ONLY : IDTNITs, IDTSO4s
|
|
USE TRACERID_MOD, ONLY : IDTDMS, IDTSO2
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTNH3
|
|
USE GFED2_BIOMASS_MOD, ONLY : GFED2_IS_NEW
|
|
USE GFED3_BIOMASS_MOD, ONLY : GFED3_IS_NEW
|
|
USE LOGICAL_MOD, ONLY : LANTHRO, LBIOFUEL
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
LOGICAL, SAVE :: FIRSTEMISS = .TRUE.
|
|
INTEGER :: NSEASON, MONTH, YEAR
|
|
|
|
!=================================================================
|
|
! EMISSSULFATE begins here!
|
|
!=================================================================
|
|
|
|
! Do only on the first timestep
|
|
IF ( FIRSTEMISS ) THEN
|
|
|
|
! Echo info
|
|
WRITE( 6, '(a)' ) REPEAT( '=', 79 )
|
|
WRITE( 6, 100 )
|
|
WRITE( 6, 110 )
|
|
WRITE( 6, 120 )
|
|
WRITE( 6, 130 )
|
|
WRITE( 6, '(a)' ) REPEAT( '=', 79 )
|
|
|
|
! FORMAT strings
|
|
100 FORMAT( 'S U L F A T E A E R O S O L E M I S S I O N S' )
|
|
110 FORMAT( 'Routines originally by Mian Chin''s GOCART model' )
|
|
120 FORMAT( 'Modified for GEOS-CHEM by R. Park and R. Yantosca' )
|
|
130 FORMAT( 'Last Modification Date: 4/6/04' )
|
|
|
|
! Initialize arrays
|
|
CALL INIT_SULFATE
|
|
|
|
! Read emissions from volcanoes
|
|
#if defined ( GRID025x03125 )
|
|
! Volcanoes emissions are bad for 0.25 degree. !yd
|
|
WRITE(*,*) 'Warning: Volcanoes Emissions for the selected grid
|
|
& are not supported.'
|
|
#else
|
|
IF ( LENV ) CALL READ_NONERUP_VOLC
|
|
IF ( LEEV ) CALL READ_ERUP_VOLC
|
|
#endif
|
|
|
|
! We have now gone thru the first timestep
|
|
FIRSTEMISS = .FALSE.
|
|
ENDIF
|
|
|
|
! Get the season and month
|
|
NSEASON = GET_SEASON()
|
|
MONTH = GET_MONTH()
|
|
YEAR = GET_YEAR()
|
|
|
|
!=================================================================
|
|
! If this is a new month, read in the monthly mean quantities
|
|
!=================================================================
|
|
IF ( ITS_A_NEW_MONTH() ) THEN
|
|
|
|
! Read monthly mean data
|
|
CALL READ_SST( MONTH, YEAR )
|
|
CALL READ_OCEAN_DMS( MONTH )
|
|
!-- prior 12/23/08
|
|
! CALL READ_BIOMASS_SO2( MONTH )
|
|
IF ( LBIOFUEL ) CALL READ_BIOFUEL_SO2( MONTH )
|
|
!-- prior 12/23/08
|
|
! CALL READ_BIOMASS_NH3( MONTH )
|
|
IF ( LBIOFUEL ) CALL READ_BIOFUEL_NH3( MONTH )
|
|
!fp (replace by actual natural emissions)
|
|
! CALL READ_NATURAL_NH3( MONTH )
|
|
|
|
#if defined ( GRID025x03125 )
|
|
! Natural NH3 emissions are bad for 0.25 degree. !yd
|
|
WRITE(*,*) 'Warning: Natural NH3 Emissions for the selected
|
|
& grid are not supported.'
|
|
#else
|
|
CALL READ_GEIA_NH3( MONTH )
|
|
#endif
|
|
|
|
! Add LANTHRO switch to turn off anthropogenic emissions.
|
|
! (ccc, 4/15/09)
|
|
IF ( LANTHRO ) THEN
|
|
CALL READ_AIRCRAFT_SO2( MONTH )
|
|
CALL READ_ANTHRO_SOx( MONTH, NSEASON )
|
|
CALL READ_ANTHRO_NH3( MONTH )
|
|
ENDIF
|
|
|
|
! Also read ship exhaust SO2 if necessary
|
|
!-- prior 12/23/08
|
|
! IF ( LSHIPSO2 ) CALL READ_SHIP_SO2( MONTH )
|
|
CALL READ_SHIP_SO2( MONTH )
|
|
|
|
! Read oxidants for the offline simulation only
|
|
IF ( ITS_AN_AEROSOL_SIM() ) CALL READ_OXIDANT( MONTH )
|
|
|
|
ENDIF
|
|
|
|
!prior to (win, 5/1/09)
|
|
! IF ( GFED2_IS_NEW() .or. ITS_A_NEW_MONTH() ) THEN
|
|
! w/o the LBIOMASS switch, GET_BIOMASS_SO2 is called but the biomass
|
|
! emission array was not setup properly, which then crashes the run (win, 5/1/09)
|
|
IF( ( GFED2_IS_NEW() .or. GFED3_IS_NEW() .or.
|
|
& ITS_A_NEW_MONTH() ) .AND.
|
|
& ( LBIOMASS ) ) THEN
|
|
CALL GET_BIOMASS_SO2
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### EMISSSULFATE: GET_BM_SO2')
|
|
|
|
CALL GET_BIOMASS_NH3
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### EMISSSULFATE: GET_BM_NH3')
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! Add emissions into the STT tracer array
|
|
!=================================================================
|
|
IF ( IDTDMS /= 0 ) CALL SRCDMS( STT(:,:,:,IDTDMS) )
|
|
IF ( IDTSO2 /= 0 ) CALL SRCSO2( STT(:,:,:,IDTSO2), NSEASON )
|
|
IF ( IDTSO4 /= 0 .and. .not. LHTAP )
|
|
& CALL SRCSO4( STT(:,:,:,IDTSO4) )
|
|
IF ( IDTNH3 /= 0 ) CALL SRCNH3( STT(:,:,:,IDTNH3) )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE EMISSSULFATE
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SRCDMS( TC )
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine SRCDMS, from Mian Chin's GOCART model, add DMS emissions
|
|
! to the tracer array. Modified for use with the GEOS-CHEM model.
|
|
! (bmy, 6/2/00, 8/16/05)
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ===========================================================================
|
|
! (1 ) TC (REAL*8 ) : Initial tracer mass [kg], plus DMS emissions
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference NSRCE, LWI, DXYP, XTRA2 from either header files or
|
|
! F90 modules. Now use routines from "pressure_mod.f" to compute
|
|
! grid box surface pressures. (bmy, 9/18/02)
|
|
! (2 ) Now replace DXYP(J) with routine GET_AREA_M2 of "grid_mod.f"
|
|
! Now use routine GET_TS_EMIS from the new "time_mod.f". (bmy, 3/27/03)
|
|
! (3 ) For GEOS-4, convert PBL from [m] to [hPa] w/ the hydrostatic law.
|
|
! Now references SCALE_HEIGHT from "CMN_GCTM". Added BLTHIK variable
|
|
! for PBL thickness in [hPa]. (bmy, 1/15/04)
|
|
! (4 ) Remove reference to "pressure_mod.f". Now reference GET_FRAC_OF_PBL
|
|
! and GET_PBL_TOP_L from "pbl_mix_mod.f". (bmy, 2/22/05)
|
|
! (5 ) Switch from Liss & Merlivat to Nightingale formulation for DMS
|
|
! emissions. (swu, bmy, 8/16/05)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to diagnostic arrays
|
|
USE DIAG_MOD, ONLY : AD13_DMS
|
|
USE DAO_MOD, ONLY : IS_WATER, LWI, PBL
|
|
USE GRID_MOD, ONLY : GET_AREA_M2
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
|
|
USE TIME_MOD, ONLY : GET_TS_EMIS
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND13 (for now)
|
|
# include "CMN_GCTM" ! SCALE_HEIGHT
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(INOUT) :: TC(IIPAR,JJPAR,LLPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, NTOP
|
|
REAL*8 :: DTSRCE, SST, Sc, CONC, W10
|
|
REAL*8 :: ScCO2, AKw, ERATE, DMSSRC, FEMIS
|
|
|
|
! Molecular weight of DMS, kg/mole
|
|
REAL*8, PARAMETER :: DMS_MW = 62d0
|
|
|
|
! Ratio of molecular weights: S/DMS
|
|
REAL*8, PARAMETER :: S_DMS = 32d0 / 62d0
|
|
|
|
! External functions
|
|
REAL*8, EXTERNAL :: SFCWINDSQR
|
|
|
|
!=================================================================
|
|
! SRCDMS begins here!
|
|
!=================================================================
|
|
|
|
! Chemistry timestep in seconds
|
|
DTSRCE = GET_TS_EMIS() * 60d0
|
|
|
|
!=================================================================
|
|
! Compute DMS emissions = seawater DMS * transfer velocity
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, SST, Sc, CONC, W10, ScCO2 )
|
|
!$OMP+PRIVATE( AKw, ERATE, DMSSRC, NTOP, L, FEMIS )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Sea surface temperature in Celsius
|
|
SST = SSTEMP(I,J) - 273.15d0
|
|
|
|
! Only do the following for water boxes
|
|
IF ( IS_WATER(I,J) ) THEN
|
|
|
|
! Schmidt number for DMS (Saltzman et al., 1993)
|
|
Sc = 2674.0d0 - 147.12d0*SST +
|
|
& 3.726d0*(SST**2) - 0.038d0*(SST**3)
|
|
|
|
!===========================================================
|
|
! Calculate transfer velocity in cm/hr (AKw)
|
|
!
|
|
! Tans et al. transfer velocity (1990) for CO2 at
|
|
! 25oC (Erickson, 1993)
|
|
!
|
|
! Tans et al. assumed AKW=0 when W10<=3. I modified it
|
|
! to let DMS emit at low windseeds too. Chose 3.6m/s as
|
|
! the threshold.
|
|
!
|
|
! Schmidt number for CO2: Sc = 600 (20oC, fresh water)
|
|
! Sc = 660 (20oC, seawater)
|
|
! Sc = 428 (25oC, Erickson 93)
|
|
!===========================================================
|
|
CONC = DMSo(I,J)
|
|
W10 = SQRT( SFCWINDSQR(I,J) )
|
|
|
|
!-----------------------------------------------------------
|
|
! Tans et al. (1990)
|
|
!ScCO2 = 428.d0
|
|
!IF (W10 .LE. 3.6) THEN
|
|
! AKw = 1.0667d0 * W10
|
|
!ELSE
|
|
! AKw = 6.4d0 * (W10 - 3.d0)
|
|
!ENDIF
|
|
!-----------------------------------------------------------
|
|
! Wanninkhof (1992)
|
|
!ScCO2 = 660.d0
|
|
!AKw = 0.31d0 * W10**2
|
|
!-----------------------------------------------------------
|
|
!! Liss and Merlivat (1986)
|
|
!ScCO2 = 600.d0
|
|
!IF ( W10 <= 3.6d0 ) then
|
|
! AKw = 0.17d0 * W10
|
|
!
|
|
!ELSE IF ( W10 <= 13.d0 ) THEN
|
|
! AKw = 2.85d0 * W10 - 9.65d0
|
|
!
|
|
!ELSE
|
|
! AKw = 5.90d0 * W10 - 49.3d0
|
|
!
|
|
!ENDIF
|
|
!-----------------------------------------------------------
|
|
! NOTE: Also need to uncomment this section if using
|
|
! Tans, Wanninkhof, or Liss & Merlivat
|
|
!IF ( W10 <= 3.6d0 ) THEN
|
|
! AKw = AKw * ( (ScCO2/Sc)**0.667 )
|
|
!ELSE
|
|
! AKw = AKw * SQRT(ScCO2/Sc)
|
|
!ENDIF
|
|
!-----------------------------------------------------------
|
|
! Nightingale [2000] (swu, bmy, 8/16/05)
|
|
!
|
|
! Note that from Nightingale et al [2000a],
|
|
! the best fit formulation should be:
|
|
!
|
|
! AKw = ( 0.222*W10*W10 + 0.333*W10 ) * sqrt( ScCO2/Sc )
|
|
!
|
|
! But from Nightingale et al [2000b], which reported that
|
|
! more measurements were incorported, they claimed that
|
|
! the following is the best fit:
|
|
!
|
|
ScCO2 = 600.d0
|
|
AKw = ( 0.24d0*W10*W10 + 0.061d0*W10 ) * SQRT( ScCO2/Sc )
|
|
!-----------------------------------------------------------
|
|
|
|
!===========================================================
|
|
! Calculate emission flux in kg/box/timestep
|
|
!
|
|
! AKw is in cm/hr : AKw/100/3600 is m/sec.
|
|
! CONC is in nM/L (nM/dm3) : CONC*1E-12*1000 is kmole/m3.
|
|
! DMS_MW is in g DMS/mol = kg/kmole
|
|
! ERATE is in kg DMS/m2/timestep
|
|
! DMSSRC is in kg DMS/box/timestep
|
|
!===========================================================
|
|
ERATE = ( AKw / 100.d0 / 3600.d0 ) *
|
|
& ( CONC * 1.d-12 * 1000.d0 ) * DMS_MW * DTSRCE
|
|
|
|
DMSSRC = ERATE * GET_AREA_M2( J )
|
|
|
|
!===========================================================
|
|
! Add DMS emissions [kg DMS/box] into the tracer array
|
|
!===========================================================
|
|
|
|
! Top layer of the PBL
|
|
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
|
|
|
|
! Loop thru the boundary layer
|
|
DO L = 1, NTOP
|
|
|
|
! Fraction of PBL spanned by grid box (I,J,L) [unitless]
|
|
FEMIS = GET_FRAC_OF_PBL( I, J, L )
|
|
|
|
! DMS in box (I,J,L) plus emissions [kg]
|
|
TC(I,J,L) = TC(I,J,L) + ( FEMIS * DMSSRC )
|
|
|
|
ENDDO
|
|
|
|
ELSE
|
|
|
|
! If we are not over water, then there is no DMS source
|
|
DMSSRC = 0.d0
|
|
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! ND13 diagnostic: DMS emissions [kg S/box/timestep]
|
|
!==============================================================
|
|
IF ( ND13 > 0 ) THEN
|
|
AD13_DMS(I,J) = AD13_DMS(I,J) + ( DMSSRC * S_DMS ) ! / DTSRCE
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SRCDMS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SRCSO2( TC, NSEASON )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SRCSO2 (originally from Mian Chin) computes SO2 emissons from
|
|
! aircraft, biomass, and anthro sources. (rjp, bdf, bmy, 6/2/00, 2/27/09)
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ===========================================================================
|
|
! (1 ) NSEASON (INTEGER) : Season number: 1=DJF; 2=MAM; 3=JJA; 4=SON
|
|
! (2 ) TC (REAL*8 ) : SO2 tracer mass [kg]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now reference NSRCE, JDAY, PBL, XTRA2, BXHEIGHT from either header
|
|
! files or F90 modules. Also use routines from "pressure_mod.f" to
|
|
! compute grid box pressures. (bmy, 9/18/02)
|
|
! (2 ) Now use routines GET_TS_EMIS and GET_DAY_OF_YEAR from the new
|
|
! "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) For GEOS-4, convert PBL from [m] to [hPa] w/ the hydrostatic law.
|
|
! Now references SCALE_HEIGHT from "CMN_GCTM". Added BLTHIK variable
|
|
! to hold PBL thickness in [hPa]. (bmy, 1/15/04)
|
|
! (4 ) Now references AD13_SO2_sh array from "diag_mod.f". Also references
|
|
! LSHIPSO2 from "CMN_SETUP" (bec, bmy, 5/20/04)
|
|
! (5 ) Now references LSHIPSO2 from "logical_mod.f" (bmy, 7/20/04)
|
|
! (6 ) Now references routines GET_EPA_ANTHRO and GET_USA_MASK from
|
|
! "epa_nei_mod.f". Now references GET_AREA_CM2 from "grid_mod.f".
|
|
! Now references GET_DAY_OF_WEEK from "time_mod.f" Now references
|
|
! LNEI99 from "logical_mod.f". Now can overwrite the anthro SOx
|
|
! emissions over the continental US if LNEI99=T. Now references IDTSO2
|
|
! from "tracerid_mod.f. (rch, rjp, bmy, 11/16/04)
|
|
! (7 ) Remove reference to "pressure_mod.f". Now reference GET_FRAC_OF_PBL
|
|
! and GET_PBL_TOP_L from "pbl_mix_mod.f". Removed reference to header
|
|
! file CMN. (bmy, 2/22/05)
|
|
! (8 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (9 ) Now references GET_BRAVO_ANTHRO and GET_BRAVO_MASK from "bravo_mod.f"
|
|
! for BRAVO Mexican emissions. (rjp, kfb, bmy, 6/26/06)
|
|
! (10) Bug fix: EPA emissions were overwritten by regular ones when both BRAVO
|
|
! and EPA were used. (phs, 10/4/07)
|
|
! (11) Now use CAC Canadian emissions, if necessary (amv, 1/10/08)
|
|
! (12) Bug fix: Always fill the diagnostic array AD13_SO2_sh because it
|
|
! is allocated anyway (phs, 2/27/09)
|
|
! (13) adj_group: add scaling factors for SO2 emissions (dkh, 02/03/10)
|
|
! (14) Read NEI now (amv, 10/07/2009)
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to diagnostic arrays
|
|
USE BRAVO_MOD, ONLY : GET_BRAVO_ANTHRO, GET_BRAVO_MASK
|
|
USE CAC_ANTHRO_MOD, ONLY : GET_CANADA_MASK, GET_CAC_ANTHRO
|
|
USE DIAG_MOD, ONLY : AD13_SO2_an, AD13_SO2_ac
|
|
USE DIAG_MOD, ONLY : AD13_SO2_bb, AD13_SO2_nv
|
|
USE DIAG_MOD, ONLY : AD13_SO2_ev, AD13_SO2_bf
|
|
USE DIAG_MOD, ONLY : AD13_SO2_sh
|
|
USE DAO_MOD, ONLY : BXHEIGHT, PBL
|
|
USE EPA_NEI_MOD, ONLY : GET_EPA_ANTHRO, GET_EPA_BIOFUEL
|
|
USE EPA_NEI_MOD, ONLY : GET_USA_MASK
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LBRAVO, LNEI99, LSHIPSO2
|
|
USE LOGICAL_MOD, ONLY : LCAC, LNEI05, LNEI08
|
|
USE NEI2005_ANTHRO_MOD, ONLY : GET_NEI2005_ANTHRO
|
|
USE NEI2005_ANTHRO_MOD, ONLY : NEI05_MASK => USA_MASK
|
|
USE NEI2008_ANTHRO_MOD, ONLY : GET_NEI2008_ANTHRO
|
|
USE NEI2008_ANTHRO_MOD, ONLY : NEI08_MASK => USA_MASK
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
|
|
USE TIME_MOD, ONLY : GET_TS_EMIS, GET_DAY_OF_YEAR
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK, GET_HOUR
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK_LT
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO2
|
|
USE HTAP_MOD, ONLY : GET_HTAP
|
|
|
|
! adj_group
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_an1, IDADJ_ESO2_an2
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_bb, IDADJ_ESO2_bf
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_sh
|
|
USE ADJ_ARRAYS_MOD, ONLY : IS_SULF_EMS_ADJ
|
|
USE ADJ_ARRAYS_MOD, ONLY : EMS_SF
|
|
USE LOGICAL_ADJ_MOD,ONLY : LADJ
|
|
USE LOGICAL_MOD, ONLY : LHTAP
|
|
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND13, LD13 (for now)
|
|
# include "CMN_GCTM" ! SCALE_HEIGHT
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: NSEASON
|
|
REAL*8, INTENT(INOUT) :: TC(IIPAR,JJPAR,LLPAR)
|
|
|
|
! Local variables
|
|
LOGICAL :: WEEKDAY
|
|
INTEGER :: I, J, K, L, LV1, LV2, NTOP, JDAY
|
|
INTEGER :: DAY_NUM, IH, DOW_LT
|
|
REAL*8 :: ZH(0:LLPAR), DZ(LLPAR), SO2(LLPAR)
|
|
REAL*8 :: DTSRCE, HGHT, SO2SRC
|
|
REAL*8 :: SLAB, SLAB1
|
|
REAL*8 :: TSO2, FEMIS
|
|
REAL*8 :: AREA_CM2, AN, BF
|
|
REAL*8 :: SO2an(IIPAR,JJPAR,2)
|
|
REAL*8 :: SO2bf(IIPAR,JJPAR)
|
|
REAL*8 :: HTAP
|
|
|
|
! Ratio of molecular weights: S/SO2
|
|
REAL*8, PARAMETER :: S_SO2 = 32d0 / 64d0
|
|
|
|
!=================================================================
|
|
! SRCSO2 begins here!
|
|
!================================================================
|
|
|
|
! DTSRCE is the emission timestep in seconds
|
|
DTSRCE = GET_TS_EMIS() * 60d0
|
|
|
|
! JDAY is the day of year (0-365 or 0-366)
|
|
JDAY = GET_DAY_OF_YEAR()
|
|
|
|
! Get current day of the week
|
|
DAY_NUM = GET_DAY_OF_WEEK()
|
|
|
|
! Get hour (for NEI08)
|
|
IH = GET_HOUR() + 1
|
|
|
|
! Is it a weekday?
|
|
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
|
|
|
|
!=================================================================
|
|
! SO2 emissions from non-eruptive volcanoes [kg SO2/box/s].
|
|
! Assume that emission only occurs at the crater altitude.
|
|
!=================================================================
|
|
IF ( LENV ) THEN
|
|
|
|
! Initialize
|
|
ESO2_nv = 0.d0
|
|
|
|
! Loop thru each non-erupting volcano
|
|
DO K = 1, NNVOL
|
|
|
|
! Elevation of volcano crater
|
|
HGHT = DBLE( IELVn(k) )
|
|
|
|
! Altitude of crater from the ground
|
|
ZH(0) = 0.d0
|
|
|
|
! Loop over levels
|
|
DO L = 1, LLPAR
|
|
|
|
! Thickness of layer [m] w/ crater
|
|
DZ(L) = BXHEIGHT(INV(K),JNV(K),L)
|
|
|
|
! Increment altitude
|
|
ZH(L) = ZH(L-1) + DZ(L)
|
|
|
|
! If we are at the crater altitude, add emissions and exit
|
|
IF ( ZH(L-1) <= HGHT .AND. ZH(L) > HGHT ) THEN
|
|
ESO2_nv(INV(K),JNV(K),L) =
|
|
& ESO2_nv(INV(K),JNV(K),L) + Env(K)
|
|
EXIT
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! Calculate eruptive volcanic emission of SO2.
|
|
!=================================================================
|
|
IF ( LEEV ) THEN
|
|
|
|
! Initialize
|
|
ESO2_ev = 0.D0
|
|
|
|
! Loop thru each erupting volcano
|
|
DO K = 1, NEVOL
|
|
|
|
! Test to see if the volcano is erupting
|
|
IF ( JDAY < IDAYS(K) .OR. JDAY > IDAYe(K) ) GOTO 20
|
|
|
|
!===========================================================
|
|
! Define a slab at the top 1/3 of the volcano plume.
|
|
!===========================================================
|
|
HGHT = DBLE( IHGHT(K) )
|
|
|
|
! slab bottom height
|
|
SLAB1 = HGHT - ( HGHT - DBLE ( IELVe(K) ) ) / 3.d0
|
|
|
|
! Slab thickness
|
|
SLAB = HGHT - SLAB1
|
|
ZH(0) = 0.d0
|
|
|
|
! Loop over each level
|
|
DO L = 1, LLPAR
|
|
|
|
! DZ is the thickness of level L [m]
|
|
DZ(L) = BXHEIGHT(IEV(K),JEV(K),L)
|
|
|
|
! ZH is the height of the top edge of
|
|
! level L, measured from the ground up [m]
|
|
ZH(L) = ZH(L-1) + DZ(L)
|
|
|
|
! max model erup.height
|
|
IF ( L == LLPAR .AND. HGHT > ZH(L) ) THEN
|
|
LV2 = LLPAR
|
|
!HGHT = ZH(L)
|
|
!SLAB1 = SLAB1 - ( HGHT - ZH(L) )
|
|
ENDIF
|
|
|
|
!========================================================
|
|
! If Zh(l) <= bottom of the slab, go to next level.
|
|
!========================================================
|
|
IF ( ZH(L) <= SLAB1 ) GOTO 22
|
|
|
|
!========================================================
|
|
! If the slab is only in current level: CASE 1
|
|
! ---------------------------------- ZH(L)
|
|
! HGHT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
! SLAB1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
! ---------------------------------- ZH(L-1)
|
|
!========================================================
|
|
IF ( ZH(L-1) <= SLAB1 .AND. ZH(L) >= HGHT ) THEN
|
|
LV1 = L
|
|
LV2 = L
|
|
DZ(L) = SLAB
|
|
|
|
!========================================================
|
|
! The slab extends more then one level. Find the
|
|
! lowest (lv1) and the highest (lv2) levels:
|
|
! --------------------------------- ZH(L)
|
|
! HGHT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
! --------------------------------- ZH(L-1)
|
|
!
|
|
! --------------------------------- ZH(L)
|
|
! SLAB1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
! --------------------------------- ZH(L-1)
|
|
!========================================================
|
|
ELSE IF (ZH(L-1) <= SLAB1 .AND. ZH(L) > SLAB1) THEN
|
|
LV1 = L
|
|
DZ(L) = ZH(L) - SLAB1
|
|
|
|
ELSE IF (ZH(L-1) < HGHT .AND. ZH(L) > HGHT ) THEN
|
|
LV2 = L
|
|
DZ(L) = HGHT - ZH(L-1)
|
|
EXIT ! do 20
|
|
|
|
ENDIF
|
|
|
|
! Go to next level
|
|
22 CONTINUE
|
|
ENDDO
|
|
|
|
!===========================================================
|
|
! Calculate SO2 emission in the levels between LV1 and LV2.
|
|
! Convert Eev from [kg SO2/box/event] to [kg SO2/box/s].
|
|
! ESO2_ev is distributed evenly with altitude among the slab.
|
|
!===========================================================
|
|
DO L = LV1, LV2
|
|
ESO2_ev(IEV(K),JEV(K),L) = ESO2_ev(IEV(K),JEV(K),L) +
|
|
& EEV(K) / ( (IDAYe(K)-IDAYs(K)+1) * 24.d0 * 3600.d0 )
|
|
& * DZ(L) / SLAB
|
|
ENDDO
|
|
|
|
! Go to next volcano
|
|
20 CONTINUE
|
|
ENDDO
|
|
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! Overwrite USA w/ EPA/NEI99 (anthro+biofuel) SO2 emissions
|
|
! Overwrite MEXICO w/ BRAVO (anthro only ) SO2 emissions
|
|
! Overwrite CANADA w/ CAC (anthro only ) SO2 emissions
|
|
!-----------------------------------------------------------------
|
|
! Note that we:
|
|
! Overwrite ASIA w/ STREETS and EUROPE w/ EMEP
|
|
! in READ_ANTHRO_SOx.
|
|
!
|
|
! In both cases, SO4 is a fraction of provided SO2 (except for
|
|
! EPA). It is done in READ_ANTHRO_SOX in the 1st case, and in
|
|
! SRCSO4 for inventories dealt with here. EPA is the only one to
|
|
! provide direct SO4, which is why we deal with it here, even
|
|
! though it does not have to be like that. Historical.
|
|
!
|
|
! So, since we have EPA here, we have to deal with BRAVO and
|
|
! CAC here to deal with their overlaping mask.
|
|
!
|
|
! (amv, phs, 3/12/08, 8/24/09)
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, AREA_CM2, AN, BF, DOW_LT, WEEKDAY )
|
|
!$OMP+PRIVATE( HTAP )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO J = 1, JJPAR
|
|
|
|
! Initialize
|
|
AN = 0d0
|
|
BF = 0d0
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2(J)
|
|
|
|
DO I = 1, IIPAR
|
|
!------- Prior to 3/8/07 (phs)
|
|
!!-----------------------------------------------------------
|
|
!! If we are using EPA/NEI99 (anthro + biofuel) ...
|
|
!!-----------------------------------------------------------
|
|
!IF ( LNEI99 ) THEN
|
|
!
|
|
! ! If we are over the USA ...
|
|
! IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
|
|
!
|
|
! ! Read EPA/NEI99 SO2 emissions in [molec/cm2/s]
|
|
! AN = GET_EPA_ANTHRO( I, J, IDTSO2, WEEKDAY )
|
|
! BF = GET_EPA_BIOFUEL(I, J, IDTSO2, WEEKDAY )
|
|
!
|
|
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! ! Place all anthro SO2 into surface layer
|
|
! SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
! SO2an(I,J,2) = 0d0
|
|
!
|
|
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! SO2bf(I,J) = BF * AREA_CM2 / XNUMOL(IDTSO2)
|
|
!
|
|
! ELSE
|
|
!
|
|
! ! If we are not over the USA, then just use the regular
|
|
! ! emissions from ESO2_an and ESO2_bf (bmy, 11/16/04)
|
|
! SO2an(I,J,1) = ESO2_an(I,J,1)
|
|
! SO2an(I,J,2) = ESO2_an(I,J,2)
|
|
! SO2bf(I,J) = ESO2_bf(I,J)
|
|
!
|
|
! ENDIF
|
|
!
|
|
!ELSE
|
|
!
|
|
! ! If we are not using EPA/NEI99 emissions, then just copy
|
|
! ! ESO2_an and ESO2_bf into local arrays (bmy, 11/16/04)
|
|
! SO2an(I,J,1) = ESO2_an(I,J,1)
|
|
! SO2an(I,J,2) = ESO2_an(I,J,2)
|
|
! SO2bf(I,J) = ESO2_bf(I,J)
|
|
!
|
|
!ENDIF
|
|
!
|
|
!!-----------------------------------------------------------
|
|
!! If we are using BRAVO emissions over Mexico ...
|
|
!!-----------------------------------------------------------
|
|
!IF ( LBRAVO ) THEN
|
|
!
|
|
! ! If we are over Mexico ...
|
|
! IF ( GET_BRAVO_MASK( I, J ) > 0d0 ) THEN
|
|
!
|
|
! ! Read BRAVO SO2 emissions in [molec/cm2/s]
|
|
! AN = GET_BRAVO_ANTHRO( I, J, IDTSO2 )
|
|
!
|
|
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! ! Place all anthro SO2 into surface layer
|
|
! SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
! SO2an(I,J,2) = 0d0
|
|
!
|
|
! ELSE
|
|
!
|
|
! ! If we are not over MEXICO, then just use
|
|
! ! the regular emissions from ESO2_an
|
|
! SO2an(I,J,1) = ESO2_an(I,J,1)
|
|
! SO2an(I,J,2) = ESO2_an(I,J,2)
|
|
!
|
|
! ENDIF
|
|
!
|
|
!ELSE
|
|
!
|
|
! ! If we are not using BRAVO emissions, then just copy
|
|
! ! ESO2_an and ESO2_bf into local arrays
|
|
! SO2an(I,J,1) = ESO2_an(I,J,1)
|
|
! SO2an(I,J,2) = ESO2_an(I,J,2)
|
|
! SO2bf(I,J) = ESO2_bf(I,J)
|
|
!
|
|
!ENDIF
|
|
|
|
!-----------------------------------------------------------
|
|
! Default SO2 from GEIA or EDGAR (w/ optional STREETS for
|
|
! ASIA, and EMEP for Europe)
|
|
!-----------------------------------------------------------
|
|
SO2an(I,J,1) = ESO2_an(I,J,1)
|
|
SO2an(I,J,2) = ESO2_an(I,J,2)
|
|
SO2bf(I,J) = ESO2_bf(I,J)
|
|
|
|
!-----------------------------------------------------------
|
|
! If we are using EPA/NEI99 over the USA (anthro + biofuel)
|
|
!-----------------------------------------------------------
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read EPA/NEI99 SO2 emissions in [molec/cm2/s]
|
|
AN = GET_EPA_ANTHRO( I, J, IDTSO2, WEEKDAY )
|
|
BF = GET_EPA_BIOFUEL(I, J, IDTSO2, WEEKDAY )
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! Place all anthro SO2 into surface layer
|
|
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
SO2an(I,J,2) = 0d0
|
|
|
|
! Convert biofuel SO2 from [molec/cm2/s] to [kg/box/s]
|
|
SO2bf(I,J) = BF * AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
!-----------------------------------------------------------
|
|
! If we are using BRAVO emissions over Mexico (anthro)
|
|
!-----------------------------------------------------------
|
|
IF ( LBRAVO ) THEN
|
|
IF ( GET_BRAVO_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Read BRAVO SO2 emissions in [molec/cm2/s]
|
|
AN = GET_BRAVO_ANTHRO( I, J, IDTSO2 )
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! Place all anthro SO2 into surface layer.
|
|
! Add to USA emissions if on the border.
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J) > 0d0 ) THEN
|
|
|
|
SO2an(I,J,1) = SO2an(I,J,1) +
|
|
& AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
ELSE
|
|
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SO2an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
!-----------------------------------------------------------
|
|
! If we are using CAC emissions over Canada ...
|
|
!-----------------------------------------------------------
|
|
IF ( LCAC ) THEN
|
|
IF ( GET_CANADA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Read CAC SO2 emissions in [molec/cm2/s]
|
|
AN = GET_CAC_ANTHRO( I, J, IDTSO2,
|
|
& MOLEC_CM2_s=.TRUE. )
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! Place all anthro SO2 into surface layer.
|
|
! Add to USA emissions if on the border.
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J) > 0d0 ) THEN
|
|
|
|
SO2an(I,J,1) = SO2an(I,J,1) +
|
|
& AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
ELSE
|
|
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SO2an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
!-----------------------------------------------------------
|
|
! If we are using EPA/NEI 2005 over USA.
|
|
! Must be called after CAC and BRAVO to simply overwrite
|
|
! where they overlap
|
|
! Modify for use with 2-level SO2an (dkh, 02/19/11)
|
|
!-----------------------------------------------------------
|
|
IF ( LNEI05 ) THEN
|
|
IF ( NEI05_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read USA SO2 emissions in [molec/cm2/s]
|
|
! Level L=1 (dkh, 02/19/11)
|
|
AN = GET_NEI2005_ANTHRO( I, J, 1, IDTSO2, WEEKDAY,
|
|
& MOLEC_CM2_s=.TRUE. )
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
SO2an(I,J,2) = 0d0
|
|
|
|
! Read USA SO2 emissions in [molec/cm2/s]
|
|
DO L = 2, NOXLEVELS
|
|
AN = GET_NEI2005_ANTHRO( I, J, L, IDTSO2, WEEKDAY,
|
|
& MOLEC_CM2_s=.TRUE. )
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
!SO2an(I,J,L) = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
SO2an(I,J,2) = SO2an(I,J,2)
|
|
& + AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
ENDDO
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
! updated to NEI08
|
|
IF ( LNEI08 ) THEN
|
|
IF ( NEI08_MASK( I, J ) > 0d0 ) THEN
|
|
! Determine if we should use weekday or weekend NEI
|
|
! emissions at grid box (I,J,L). Since NEI is over
|
|
! the US, then weekend is Sat/Sun.
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read USA SO2 emissions in [molec/cm2/s]
|
|
DO L = 1, NOXLEVELS
|
|
IF ( L .gt. 3 ) CYCLE
|
|
|
|
AN = GET_NEI2008_ANTHRO( I, J, L, IH, IDTSO2, WEEKDAY)
|
|
|
|
AN = AN * AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
! fp (compatibility)
|
|
!fp for compatibility
|
|
IF ( L == 1 ) THEN
|
|
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
|
|
SO2an(I,J,1) = AN
|
|
ELSE
|
|
SO2an(I,J,2) = SO2an(I,J,2) + AN
|
|
ENDIF
|
|
ENDDO
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( LHTAP ) THEN
|
|
DO L = 1, NOXLEVELS
|
|
|
|
HTAP = GET_HTAP( I, J, IDTSO2 )
|
|
|
|
IF ( L == 1 ) THEN
|
|
! Convert anthro SO2 from [kg/m2/s] to [kg/box/s]
|
|
SO2an(I,J,1) = HTAP * AREA_CM2 * 1d-4
|
|
ELSE
|
|
! SO2an(I,J,2) = SO2an(I,J,2) + HTAP(I,J)
|
|
! & * AREA_CM2 * 1d-4
|
|
SO2an(I,J,2) = 0d0
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!=================================================================
|
|
! Add SO2 emissions into model levels
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, NTOP, L, SO2, TSO2, FEMIS, SO2SRC )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Top of the boundary layer
|
|
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
|
|
|
|
! Zero SO2 array
|
|
DO L = 1, LLPAR
|
|
SO2(L) = 0d0
|
|
ENDDO
|
|
|
|
! adj_group: apply scaling factors to SO2 sources (dkh, 02/03/10)
|
|
IF ( LADJ .and. IS_SULF_EMS_ADJ ) THEN
|
|
|
|
! Sum of anthro (surface + 100m), biomass, biofuel SO2 at (I,J)
|
|
TSO2 = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
|
|
& + SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
|
|
& + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
|
|
& + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
|
|
|
|
! Also add SO2 from ship exhaust if necessary (bec, bmy, 5/20/04)
|
|
! IF ( LSHIPSO2 ) TSO2 = TSO2 + ESO2_sh(I,J)
|
|
TSO2 = TSO2 + ESO2_sh(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_sh)
|
|
|
|
ELSE
|
|
! Sum of anthro (surface + 100m), biomass, biofuel SO2 at (I,J)
|
|
TSO2 = SUM( SO2an(I,J,:) ) + ESO2_bb(I,J) + SO2bf(I,J)
|
|
|
|
! Also add SO2 from ship exhaust if necessary (bec, bmy, 5/20/04)
|
|
! IF ( LSHIPSO2 ) TSO2 = TSO2 + ESO2_sh(I,J)
|
|
TSO2 = TSO2 + ESO2_sh(I,J)
|
|
|
|
ENDIF
|
|
|
|
! Zero SO2SRC
|
|
SO2SRC = 0d0
|
|
|
|
!===============================================================
|
|
! Partition the total anthro and biomass SO2 emissions thru
|
|
! the entire boundary layer (if PBL top is higher than level 2)
|
|
!===============================================================
|
|
IF ( NTOP > 2 ) THEN
|
|
|
|
! Loop thru levels in the PBL
|
|
DO L = 1, NTOP
|
|
|
|
! Fraction of PBL spanned by grid box (I,J,L) [unitless]
|
|
FEMIS = GET_FRAC_OF_PBL( I, J, L )
|
|
|
|
! Partition total SO2 into level K
|
|
SO2(L) = FEMIS * TSO2
|
|
|
|
ENDDO
|
|
|
|
!===============================================================
|
|
! If PBL top occurs lower than or close to the top of level 2,
|
|
! then then surface SO2 goes into level 1 and the smokestack
|
|
! stack SO2 goes into level 2.
|
|
!===============================================================
|
|
ELSE
|
|
|
|
|
|
! adj_group: apply scaling factors to SO2 sources (dkh, 02/03/10)
|
|
IF ( LADJ .and. IS_SULF_EMS_ADJ ) THEN
|
|
SO2(1) = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
|
|
& + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
|
|
& + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
|
|
SO2(2) = SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
|
|
|
|
! Also add ship exhaust SO2 into surface if necessary
|
|
! (bec, bmy, 5/20/04)
|
|
!-- prior 6/08 (phs)
|
|
! IF ( LSHIPSO2 ) SO2(1) = SO2(1) + ESO2_sh(I,J)
|
|
SO2(1) = SO2(1)
|
|
& + ESO2_sh(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_sh)
|
|
|
|
ELSE
|
|
SO2(1) = SO2an(I,J,1) + ESO2_bb(I,J) + SO2bf(I,J)
|
|
SO2(2) = SO2an(I,J,2)
|
|
|
|
! Also add ship exhaust SO2 into surface if necessary
|
|
! (bec, bmy, 5/20/04)
|
|
!-- prior 6/08 (phs)
|
|
! IF ( LSHIPSO2 ) SO2(1) = SO2(1) + ESO2_sh(I,J)
|
|
SO2(1) = SO2(1) + ESO2_sh(I,J)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
|
|
! Error check
|
|
IF ( ABS( SUM( SO2 ) - TSO2 ) > 1.D-5 ) THEN
|
|
!$OMP CRITICAL
|
|
PRINT*, '### ERROR in SRCSO2!'
|
|
PRINT*, '### I, J, L, : ', I, J, L
|
|
PRINT*, '### SUM(SO2) : ', SUM( SO2 )
|
|
PRINT*, '### TSO2 : ', TSO2
|
|
!$OMP END CRITICAL
|
|
CALL ERROR_STOP( 'Check SO2 redistribution!',
|
|
& 'SRCSO2 (sulfate_mod.f)' )
|
|
ENDIF
|
|
|
|
!==============================================================
|
|
! Add anthro SO2, aircraft SO2, volcano SO2, and biomass SO2
|
|
! Convert from [kg SO2/box/s] -> [kg SO2/box/timestep]
|
|
!==============================================================
|
|
DO L = 1, LLPAR
|
|
|
|
! SO2 emissions [kg/box/s]
|
|
SO2SRC = SO2(L) + ESO2_ac(I,J,L) +
|
|
& ESO2_nv(I,J,L) + ESO2_ev(I,J,L)
|
|
|
|
! Add SO2 to TC array [kg/box/timestep]
|
|
TC(I,J,L) = TC(I,J,L) + ( SO2SRC * DTSRCE )
|
|
|
|
ENDDO
|
|
|
|
!==============================================================
|
|
! ND13 Diagnostic: SO2 emissions in [kg S/box/timestep]
|
|
!==============================================================
|
|
IF ( ND13 > 0 ) THEN
|
|
|
|
! adj_group: add scaling of SO2 emissions to diagnostic
|
|
IF ( LADJ .and. IS_SULF_EMS_ADJ ) THEN
|
|
|
|
! Anthropogenic SO2 -- Level 1
|
|
AD13_SO2_an(I,J,1) = AD13_SO2_an(I,J,1) +
|
|
& ( SO2an(I,J,1) * S_SO2 * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ESO2_an1)
|
|
|
|
! Anthropogenic SO2 -- Level 2
|
|
AD13_SO2_an(I,J,2) = AD13_SO2_an(I,J,2) +
|
|
& ( SO2an(I,J,2) * S_SO2 * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ESO2_an2)
|
|
|
|
! SO2 from biomass burning
|
|
AD13_SO2_bb(I,J) = AD13_SO2_bb(I,J) +
|
|
& ( ESO2_bb(I,J) * S_SO2 * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ESO2_bb)
|
|
|
|
! SO2 from biofuel burning
|
|
AD13_SO2_bf(I,J) = AD13_SO2_bf(I,J) +
|
|
& ( SO2bf(I,J) * S_SO2 * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ESO2_bf)
|
|
|
|
! SO2 from ship emissions (bec, bmy, 5/20/04)
|
|
! Always fill the diagnostic array since
|
|
! it is allocated anyway (phs, 2/27/09)
|
|
AD13_SO2_sh(I,J) = AD13_SO2_sh(I,J) +
|
|
& ( ESO2_sh(I,J) * S_SO2 * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ESO2_sh)
|
|
|
|
! Loop thru LD13 levels
|
|
DO L = 1, LD13
|
|
|
|
! SO2 from aircraft emissions
|
|
AD13_SO2_ac(I,J,L) = AD13_SO2_ac(I,J,L) +
|
|
& ( ESO2_ac(I,J,L) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from non-eruptive volcanoes
|
|
AD13_SO2_nv(I,J,L) = AD13_SO2_nv(I,J,L) +
|
|
& ( ESO2_nv(I,J,L) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from eruptive volcanoes
|
|
AD13_SO2_ev(I,J,L) = AD13_SO2_ev(I,J,L) +
|
|
& ( ESO2_ev(I,J,L) * S_SO2 * DTSRCE )
|
|
ENDDO
|
|
|
|
ELSE
|
|
! Anthropogenic SO2 -- Levels 1-2
|
|
DO L = 1, 2
|
|
AD13_SO2_an(I,J,L) = AD13_SO2_an(I,J,L) +
|
|
& ( SO2an(I,J,L) * S_SO2 * DTSRCE )
|
|
ENDDO
|
|
|
|
! SO2 from biomass burning
|
|
AD13_SO2_bb(I,J) = AD13_SO2_bb(I,J) +
|
|
& ( ESO2_bb(I,J) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from biofuel burning
|
|
AD13_SO2_bf(I,J) = AD13_SO2_bf(I,J) +
|
|
& ( SO2bf(I,J) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from ship emissions (bec, bmy, 5/20/04)
|
|
! Always fill the diagnostic array since
|
|
! it is allocated anyway (phs, 2/27/09)
|
|
AD13_SO2_sh(I,J) = AD13_SO2_sh(I,J) +
|
|
& ( ESO2_sh(I,J) * S_SO2 * DTSRCE )
|
|
|
|
! Loop thru LD13 levels
|
|
DO L = 1, LD13
|
|
|
|
! SO2 from aircraft emissions
|
|
AD13_SO2_ac(I,J,L) = AD13_SO2_ac(I,J,L) +
|
|
& ( ESO2_ac(I,J,L) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from non-eruptive volcanoes
|
|
AD13_SO2_nv(I,J,L) = AD13_SO2_nv(I,J,L) +
|
|
& ( ESO2_nv(I,J,L) * S_SO2 * DTSRCE )
|
|
|
|
! SO2 from eruptive volcanoes
|
|
AD13_SO2_ev(I,J,L) = AD13_SO2_ev(I,J,L) +
|
|
& ( ESO2_ev(I,J,L) * S_SO2 * DTSRCE )
|
|
ENDDO
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SRCSO2
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SRCSO4( TC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SRCSO4 (originally from Mian Chin) computes SO4 emissions from
|
|
! anthropogenic sources (rjp, bdf, bmy, 6/2/00, 10/25/05)
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ===========================================================================
|
|
! (2) TC (REAL*8 ) : Array for SO4 mass [kg]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Emission of SO4 is read in SULFATE_READYR, in [kg/box/s].
|
|
! It is converted to [kg/box/timestep] here.
|
|
! (2 ) Now use routine GET_TS_EMIS from the new "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) For GEOS-4, convert PBL from [m] to [hPa] w/ the barometric law.
|
|
! Now references SCALE_HEIGHT from "CMN_GCTM". Added BLTHIK variable
|
|
! to hold PBL thickness in [hPa]. (bmy, 1/15/04)
|
|
! (4 ) Now references GET_EPA_ANTHRO, GET_EPA_BIOFUEL, and GET_USA_MASK from
|
|
! "epa_nei_mod.f". Now references AD13_SO4_bf from "diag_mod.f". Now
|
|
! references GET_AREA_CM2 from "grid_mod.f". Now references
|
|
! GET_DAY_OF_WEEK from "time_mod.f". Now references LNEI99 from
|
|
! "logical_mod.f". Now can overwrite the anthro SOx emissions over
|
|
! the continental US if LNEI99=T. Now references IDTSO4 from
|
|
! "tracerid_mod.f". (rch, rjp, bmy, 11/16/04)
|
|
! (5 ) Remove reference to "pressure_mod.f". Now reference GET_FRAC_OF_PBL
|
|
! and GET_PBL_TOP_L from "pbl_mix_mod.f". Removed reference to header
|
|
! file CMN. (bmy, 2/22/05)
|
|
! (6 ) Now references XNUMOL & XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (7 ) Now overwrite CAC emissions over Canada, if necessary (amv, 1/10/08)
|
|
! (8 ) Need to add CAC_AN to the PRIVATE statement (bmy, 5/27/09)
|
|
! (9 ) Now account for BRAVO SO4. Fix typo for CAC (phs, 8/24/09)
|
|
! (10) Now account for NEI 2005 inventory (amv, 10/07/2009)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to diagnostic arrays
|
|
USE BRAVO_MOD, ONLY : GET_BRAVO_ANTHRO, GET_BRAVO_MASK
|
|
USE CAC_ANTHRO_MOD, ONLY : GET_CANADA_MASK, GET_CAC_ANTHRO
|
|
USE DAO_MOD, ONLY : PBL
|
|
USE DIAG_MOD, ONLY : AD13_SO4_an, AD13_SO4_bf
|
|
USE EPA_NEI_MOD, ONLY : GET_EPA_ANTHRO, GET_EPA_BIOFUEL
|
|
USE EPA_NEI_MOD, ONLY : GET_USA_MASK
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LNEI99, LCAC, LBRAVO, LNEI05, LNEI08
|
|
USE NEI2005_ANTHRO_MOD, ONLY : GET_NEI2005_ANTHRO
|
|
USE NEI2005_ANTHRO_MOD, ONLY : NEI05_MASK => USA_MASK
|
|
USE NEI2008_ANTHRO_MOD, ONLY : GET_NEI2008_ANTHRO
|
|
USE NEI2008_ANTHRO_MOD, ONLY : NEI08_MASK => USA_MASK
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK, GET_TS_EMIS
|
|
USE TIME_MOD, ONLY : GET_HOUR
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK_LT
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTSO2
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND13 (for now)
|
|
# include "CMN_GCTM" ! SCALE_HEIGHT
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(INOUT) :: TC(IIPAR,JJPAR,LLPAR)
|
|
|
|
! Local variables
|
|
LOGICAL :: WEEKDAY
|
|
INTEGER :: I, J, K, L, DAY_NUM, NTOP, IH, DOW_LT
|
|
REAL*8 :: SO4(LLPAR), DTSRCE
|
|
REAL*8 :: TSO4, FEMIS
|
|
REAL*8 :: AREA_CM2, EPA_AN, EPA_BF
|
|
REAL*8 :: AN
|
|
REAL*8 :: SO4an(IIPAR,JJPAR,2)
|
|
REAL*8 :: SO4bf(IIPAR,JJPAR)
|
|
|
|
! Ratio of molecular weights: S/SO4
|
|
REAL*8, PARAMETER :: S_SO4 = 32d0 / 96d0
|
|
|
|
!=================================================================
|
|
! SRCSO4 begins here!
|
|
!=================================================================
|
|
|
|
! DTSRCE is the emission timestep in seconds
|
|
DTSRCE = GET_TS_EMIS() * 60d0
|
|
|
|
! Get current day of the week
|
|
DAY_NUM = GET_DAY_OF_WEEK()
|
|
|
|
! Get hour
|
|
IH = GET_HOUR() + 1 ! to increment from 1-24
|
|
|
|
! Is it a weekday?
|
|
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
|
|
|
|
!=================================================================
|
|
! Overwrite USA w/ EPA/NEI99 SO4 emissions (if necessary)
|
|
! Overwrite CANADA w/ CAC SO2-fraction emiss. (if necessary)
|
|
! Overwrite MEXICO w/ BRAVO SO2-fraction emiss. (if necessary)
|
|
! Store emissions into local arrays SO4an, SO4bf
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF )
|
|
!!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF, CAC_AN )
|
|
!$OMP+PRIVATE( I, J, L, AREA_CM2, EPA_AN, EPA_BF, AN, DOW_LT, WEEKDAY )
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2(J)
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
!-----------------------------------------------------------
|
|
! Default SO4 from GEIA, or (as a fraction of SO2) from
|
|
! EDGAR w/ optional STREETS for S.E.-ASIA, and optional
|
|
! EMEP for Europe
|
|
!-----------------------------------------------------------
|
|
SO4an(I,J,1) = ESO4_an(I,J,1)
|
|
SO4an(I,J,2) = ESO4_an(I,J,2)
|
|
SO4bf(I,J) = 0d0
|
|
|
|
|
|
! If we are using EPA/NEI99 emissions and over the USA
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read SO4 emissions in [molec/cm2/s]
|
|
EPA_AN = GET_EPA_ANTHRO( I, J, IDTSO4, WEEKDAY )
|
|
EPA_BF = GET_EPA_BIOFUEL(I, J, IDTSO4, WEEKDAY )
|
|
|
|
! Convert anthro SO4 from [molec/cm2/s] to [kg/box/s]
|
|
! Place all EPA/NEI99 anthro SO4 into surface layer
|
|
SO4an(I,J,1) = EPA_AN * AREA_CM2 / XNUMOL(IDTSO4)
|
|
SO4an(I,J,2) = 0d0
|
|
|
|
! Convert biofuel SO4 from [molec/cm2/s] to [kg/box/s]
|
|
SO4bf(I,J) = EPA_BF * AREA_CM2 / XNUMOL(IDTSO4)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! If we are using CAC emissions and over CANADA ...
|
|
IF ( LCAC ) THEN
|
|
IF ( GET_CANADA_MASK( I, J) > 0d0 ) THEN
|
|
|
|
! Read SO4 emissions in [molec/cm2/s]
|
|
AN = GET_CAC_ANTHRO( I, J, IDTSO2, MOLEC_CM2_S=.TRUE. )
|
|
|
|
! Convert anthro SO2 to SO4 and from [molec/cm2/s] to
|
|
! [kg/box/s]
|
|
! Place all CAC anthro SO4 into surface layer
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J) > 0d0 ) THEN
|
|
SO4an(I,J,1) = SO4an(I,J,1) + AN * 0.014/ 0.986
|
|
& * AREA_CM2 / XNUMOL(IDTSO4)
|
|
ELSE
|
|
SO4an(I,J,1) = AN * 0.014 / 0.986 * AREA_CM2
|
|
& / XNUMOL(IDTSO4)
|
|
SO4bf(I,J) = 0d0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SO4an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! If we are using BRAVO emissions and over MEXICO ...
|
|
IF ( LBRAVO ) THEN
|
|
IF ( GET_BRAVO_MASK( I, J) > 0d0 ) THEN
|
|
|
|
! Read SO4 emissions in [molec/cm2/s]
|
|
AN = GET_BRAVO_ANTHRO( I, J, IDTSO2 )
|
|
|
|
! Convert anthro SO2 to SO4 and from [molec/cm2/s] to
|
|
! [kg/box/s]
|
|
! Place all BRAVO anthro SO4 into surface layer
|
|
IF ( LNEI99 ) THEN
|
|
IF ( GET_USA_MASK( I, J) > 0d0 ) THEN
|
|
SO4an(I,J,1) = SO4an(I,J,1) + AN * 0.014/ 0.986
|
|
& * AREA_CM2 / XNUMOL(IDTSO4)
|
|
ELSE
|
|
SO4an(I,J,1) = AN * 0.014 / 0.986 * AREA_CM2
|
|
& / XNUMOL(IDTSO4)
|
|
SO4bf(I,J) = 0d0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SO4an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
!-----------------------------------------------------------
|
|
! If we are using NEI 2005 over the USA ...
|
|
! Must be called after CAC and BRAVO to simply overwrite
|
|
! where they overlap
|
|
IF ( LNEI05 ) THEN
|
|
IF ( NEI05_MASK( I, J) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read SO4 emissions in [molec/cm2/s]
|
|
!mkeller: fix; see below
|
|
SO4an(I,J,:) = 0d0
|
|
DO L = 1, NOXLEVELS
|
|
EPA_AN = GET_NEI2005_ANTHRO( I, J, L, IDTSO4,
|
|
& WEEKDAY, MOLEC_CM2_S=.TRUE. )
|
|
!SO4an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTSO4)
|
|
! mkeller: the code above doesn't work with with NOXLEVELS=3, as
|
|
! currently defined in CMN_SIZE; temporarily fix this by
|
|
! putting all emission in lowermost layer
|
|
SO4an(I,J,1) = SO4an(I,J,1) + EPA_AN * AREA_CM2 /
|
|
& XNUMOL(IDTSO4)
|
|
|
|
ENDDO
|
|
SO4bf(I,J) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( LNEI08 ) THEN
|
|
IF ( NEI08_MASK( I, J) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! Read SO4 emissions in [molec/cm2/s]
|
|
DO L = 1, NOXLEVELS
|
|
EPA_AN = GET_NEI2008_ANTHRO( I, J, L, IH, IDTSO4,
|
|
& WEEKDAY )
|
|
IF ( L .EQ. 1 ) THEN
|
|
SO4an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTSO4)
|
|
ELSE
|
|
SO4an(I,J,2) = SO4an(I,J,2) +
|
|
& EPA_AN * AREA_CM2 / XNUMOL(IDTSO4)
|
|
ENDIF
|
|
ENDDO
|
|
SO4bf(I,J) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!=================================================================
|
|
! Compute SO4 emissions
|
|
!=================================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, NTOP, SO4, TSO4, L, FEMIS )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Top level of boundary layer at (I,J)
|
|
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
|
|
|
|
! Zero SO4 array at all levels
|
|
DO L = 1, LLPAR
|
|
SO4(L) = 0.0
|
|
ENDDO
|
|
|
|
! Compute total anthro SO4 (surface + 100m) plus biofuel SO4
|
|
TSO4 = SUM( SO4an(I,J,:) ) + SO4bf(I,J)
|
|
|
|
!==============================================================
|
|
! Partition the total anthro SO4 emissions thru the entire
|
|
! boundary layer (if PBL top is higher than level 2)
|
|
!==============================================================
|
|
IF ( NTOP > 2 ) THEN
|
|
|
|
! Loop thru boundary layer
|
|
DO L = 1, NTOP
|
|
|
|
! Fraction of PBL spanned by grid box (I,J,L) [unitless]
|
|
FEMIS = GET_FRAC_OF_PBL( I, J, L )
|
|
|
|
! Fraction of total SO4 in layer L
|
|
SO4(L) = FEMIS * TSO4
|
|
|
|
ENDDO
|
|
|
|
!==============================================================
|
|
! If PBL height is low and lower or similar to the second
|
|
! model layer then surface emission is emitted to the first
|
|
! model layer and the stack emission goes to the second model
|
|
! layer. Also add biofuel SO4 into the surface layer.
|
|
!==============================================================
|
|
ELSE
|
|
|
|
SO4(1) = SO4an(I,J,1) + SO4bf(I,J)
|
|
SO4(2) = SO4an(I,J,2)
|
|
|
|
ENDIF
|
|
|
|
IF ( ABS( SUM( SO4 ) - TSO4 ) > 1.D-5 ) THEN
|
|
!$OMP CRITICAL
|
|
PRINT*, '### ERROR in SRCSO4!'
|
|
PRINT*, '### I, J, L, : ', I, J, L
|
|
PRINT*, '### SUM(SO4) : ', SUM( SO4 )
|
|
PRINT*, '### TSO4 : ', TSO4
|
|
!$OMP END CRITICAL
|
|
CALL ERROR_STOP( 'Check SO4 redistribution',
|
|
& 'SRCSO4 (sulfate_mod.f)' )
|
|
ENDIF
|
|
|
|
!=============================================================
|
|
! Add SO4 emissions to tracer array
|
|
! Convert from [kg SO4/box/s] -> [kg SO4/box/timestep]
|
|
!=============================================================
|
|
DO L = 1, LLPAR
|
|
TC(I,J,L) = TC(I,J,L) + ( SO4(L) * DTSRCE )
|
|
ENDDO
|
|
|
|
!==============================================================
|
|
! ND13 Diagnostic: SO4 emission in [kg S/box/timestep]
|
|
!==============================================================
|
|
IF ( ND13 > 0 ) THEN
|
|
|
|
! Anthro SO4
|
|
DO L = 1, 2
|
|
AD13_SO4_an(I,J,L) = AD13_SO4_an(I,J,L) +
|
|
& ( SO4an(I,J,L) * S_SO4 * DTSRCE )
|
|
ENDDO
|
|
|
|
! Biofuel SO4
|
|
AD13_SO4_bf(I,J) = AD13_SO4_bf(I,J) +
|
|
& ( SO4bf(I,J) * S_SO4 * DTSRCE )
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SRCSO4
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SRCNH3( TC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SRCNH3 handles NH3 emissions into the GEOS-CHEM tracer array.
|
|
! (rjp, bmy, 12/17/01, 2/22/05)
|
|
!
|
|
! Arguments as Input/Output
|
|
! ============================================================================
|
|
! (1 ) TC (REAL*8 ) : Array for NH3 tracer mass in kg
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now save NH3 emissions to ND13 diagnostic (bmy, 12/13/02)
|
|
! (2 ) Now reference AD13_NH3_na from "diag_mod.f", and archive natural
|
|
! source NH3 diagnostics for ND13. Also consider natural source NH3
|
|
! when partitioning by level into the STT array. (rjp, bmy, 3/23/03)
|
|
! (3 ) Now use routine GET_TS_EMIS from the new "time_mod.f" (bmy, 3/27/03)
|
|
! (4 ) For GEOS-4, convert PBL from [m] to [hPa] w/ the barometric law.
|
|
! Now references SCALE_HEIGHT from "CMN_GCTM". Added BLTHIK variable
|
|
! to hold PBL thickness in [hPa]. (bmy, 1/15/04)
|
|
! (5 ) Now references GET_EPA_ANTHRO, GET_EPA_BIOFUEL, and GET_USA_MASK from
|
|
! "epa_nei_mod.f". Now references GET_DAY_OF_WEEK from "time_mod.f".
|
|
! Now references LNEI99 from "logical_mod.f". Now references
|
|
! GET_AREA_CM2 from "grid_mod.f". Now references IDTNH3 from
|
|
! "tracerid_mod.f". Now references XNUMOL from CMN_O3. Now can
|
|
! overwrite the anthro & biofuel NH3 emissions over the continental US
|
|
! if LNEI99=T. Now references IDTNH3 from "tracerid_mod.f".
|
|
! (rjp, rch, bmy, 11/16/04)
|
|
! (6 ) Remove reference to "pressure_mod.f". Now reference GET_FRAC_OF_PBL
|
|
! and GET_PBL_TOP_L from "pbl_mix_mod.f". Removed reference to header
|
|
! file CMN. (bmy, 2/22/05)
|
|
! (7 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (8 ) Need to add CAC_AN to the PRIVATE loop (bmy, 5/27/09)
|
|
! (9 ) Added NIE 2005 (amv, 10/07/2009)
|
|
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE CAC_ANTHRO_MOD, ONLY : GET_CANADA_MASK
|
|
USE CAC_ANTHRO_MOD, ONLY : GET_CAC_ANTHRO
|
|
USE DIAG_MOD, ONLY : AD13_NH3_an, AD13_NH3_bb
|
|
USE DIAG_MOD, ONLY : AD13_NH3_bf, AD13_NH3_na
|
|
USE DAO_MOD, ONLY : PBL
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE EPA_NEI_MOD, ONLY : GET_EPA_ANTHRO, GET_EPA_BIOFUEL
|
|
USE EPA_NEI_MOD, ONLY : GET_USA_MASK
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE LOGICAL_MOD, ONLY : LRCP
|
|
USE LOGICAL_MOD, ONLY : LNEI99, LCAC, LNEI05, LNEI08
|
|
USE NEI2005_ANTHRO_MOD, ONLY : GET_NEI2005_ANTHRO
|
|
USE NEI2005_ANTHRO_MOD, ONLY : NEI05_MASK => USA_MASK
|
|
USE NEI2008_ANTHRO_MOD, ONLY : GET_NEI2008_ANTHRO
|
|
USE NEI2008_ANTHRO_MOD, ONLY : NEI08_MASK => USA_MASK
|
|
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK, GET_TS_EMIS, GET_HOUR
|
|
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK_LT
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH3
|
|
USE LOGICAL_MOD, ONLY : LHTAP, LRCP
|
|
|
|
! adj_group: now include emissions scaling factors (dkh, 11/04/09)
|
|
USE ADJ_ARRAYS_MOD, ONLY : EMS_SF
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_an
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_na
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_bf
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_bb
|
|
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_bb
|
|
USE ADJ_ARRAYS_MOD, ONLY : IS_SULF_EMS_ADJ
|
|
USE LOGICAL_ADJ_MOD,ONLY : LADJ
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
|
|
USE LOGICAL_ADJ_MOD,ONLY : LPRINTFD
|
|
USE LOGICAL_ADJ_MOD,ONLY : LADJ_EMS
|
|
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! ND13
|
|
# include "CMN_GCTM" ! SCALE_HEIGHT
|
|
|
|
! Argumetns
|
|
REAL*8, INTENT(INOUT) :: TC(IIPAR,JJPAR,LLPAR)
|
|
|
|
! Local variables
|
|
LOGICAL :: WEEKDAY
|
|
INTEGER :: I, J, L, K, NTOP, DAY_NUM, IH, DOW_LT
|
|
REAL*8 :: FEMIS, DTSRCE, TNH3
|
|
REAL*8 :: AREA_CM2, EPA_AN, EPA_BF
|
|
REAL*8 :: CAC_AN
|
|
REAL*8 :: NH3an(IIPAR,JJPAR)
|
|
REAL*8 :: NH3bf(IIPAR,JJPAR)
|
|
|
|
!=================================================================
|
|
! SRCNH3 begins here!
|
|
!=================================================================
|
|
|
|
! Emission timestep [s]
|
|
DTSRCE = GET_TS_EMIS() * 60d0
|
|
|
|
! Get current day of the week
|
|
DAY_NUM = GET_DAY_OF_WEEK()
|
|
|
|
! Is it a weekday?
|
|
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
|
|
|
|
! Get hour
|
|
IH = GET_HOUR() + 1 ! to increment form 1-24
|
|
|
|
!=================================================================
|
|
! Overwrite USA with EPA/NEI NH3 emissions (if necessary)
|
|
! Store emissions into local arrays NH3an, NH3bf
|
|
!=================================================================
|
|
!!$OMP PARALLEL DO
|
|
!!$OMP+DEFAULT( SHARED )
|
|
!!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF, CAC_AN )
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF, CAC_AN, L )
|
|
DO J = 1, JJPAR
|
|
|
|
!-------------------------------------------------------------------
|
|
! NOTE: There seems to be some problems with the EPA/NEI NH3
|
|
! emissions. Therefore we will use the existing emissions for NH3
|
|
! until further notice. Comment out the lines below until
|
|
! further notice. (bmy, 11/17/04)
|
|
!! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
!-------------------------------------------------------------------
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
!-----------------------------------------------------------------
|
|
! NOTE: There seems to be some problems with the EPA/NEI NH3
|
|
! emissions. Therefore we will use the existing emissions for
|
|
! NH3 until further notice. Comment out the lines below until
|
|
! further notice. (bmy, 11/17/04)
|
|
!
|
|
!! If we are using EPA/NEI99 emissions ...
|
|
!IF ( LNEI99 ) THEN
|
|
!
|
|
! ! If we are over the USA ...
|
|
! IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
|
|
!
|
|
! ! Read NH3 anthro emissions in [molec NH3/cm2/s]
|
|
! EPA_AN = GET_EPA_ANTHRO( I, J, IDTNH3, WEEKDAY )
|
|
! EPA_BF = GET_EPA_BIOFUEL( I, J, IDTNH3, WEEKDAY )
|
|
!
|
|
! ! Convert from [molec NH3/cm2/s] to [kg NH3/box/sec]
|
|
! NH3an(I,J) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
! NH3bf(I,J) = EPA_BF * AREA_CM2 / XNUMOL(IDTNH3)
|
|
!
|
|
! ELSE
|
|
!
|
|
! ! If we are not over the USA, just use the regular
|
|
! ! emissions in NH3_an and NH3bf (bmy, 11/16/04)
|
|
! NH3an(I,J) = ENH3_an(I,J)
|
|
! NH3bf(I,J) = ENH3_bf(I,J)
|
|
!
|
|
! ENDIF
|
|
!
|
|
!ELSE
|
|
!-----------------------------------------------------------------
|
|
|
|
! If we are not using the EPA/NEI emissions, just copy the
|
|
! regular ENH3_an and ENH3_bf to local arrays. (bmy, 11/16/04)
|
|
NH3an(I,J) = ENH3_an(I,J)
|
|
NH3bf(I,J) = ENH3_bf(I,J)
|
|
|
|
! The RCP anthropogenic emission inventory already includes
|
|
! biofuel emissions, so we turn off the additional biofuel
|
|
! inventory (cdh, 8/31/12)
|
|
IF ( LRCP ) NH3bf(I,J) = 0d0
|
|
|
|
!-----------------------------------------------------------------
|
|
! NOTE: There seems to be some problems with the EPA/NEI NH3
|
|
! emissions. Therefore we will use the existing emissions for
|
|
! NH3 until further notice. Comment out the lines below until
|
|
! further notice. (bmy, 11/17/04)
|
|
!ENDIF
|
|
!-----------------------------------------------------------------
|
|
|
|
! If we are using CAC emissions and over CANADA
|
|
IF ( LCAC .and. .not. LHTAP .and. .not. LRCP ) THEN
|
|
IF ( GET_CANADA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Read NH3 anthro emissions in [molec NH3/cm2/s]
|
|
CAC_AN = GET_CAC_ANTHRO( I, J, IDTNH3,
|
|
& MOLEC_CM2_S=.TRUE.)
|
|
|
|
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
|
|
NH3an(I,J) = CAC_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! If we are using NEI 2005 over North America
|
|
IF ( LNEI05 .and. .not. LHTAP .and. .not. LRCP ) THEN
|
|
IF ( NEI05_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
! For 2D NH3an (dkh, 02/19/11)
|
|
NH3an(I,J) = 0d0
|
|
|
|
DO L = 1, NOXLEVELS
|
|
|
|
! Read NH3 anthro emissions in [molec NH3/cm2/s]
|
|
EPA_AN = GET_NEI2005_ANTHRO( I, J, L, IDTNH3,
|
|
& WEEKDAY, MOLEC_CM2_S=.TRUE.)
|
|
|
|
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
|
|
! Keep NH3an 2D for now. (dkh, 02/19/11)
|
|
!NH3an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
NH3an(I,J) = NH3an(I,J)
|
|
& + EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
|
|
ENDDO
|
|
|
|
ENDIF
|
|
ENDIF
|
|
! If we are using NEI 2008 over North America
|
|
IF ( LNEI08 .and. .not. LHTAP .and. .not. LRCP ) THEN
|
|
IF ( NEI08_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
|
|
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
|
|
|
|
NH3an(I,J) = 0d0
|
|
|
|
DO L = 1, NOXLEVELS
|
|
|
|
! Read NH3 anthro emissions in [molec NH3/cm2/s]
|
|
EPA_AN = GET_NEI2008_ANTHRO( I, J, L, IH, IDTNH3,
|
|
& WEEKDAY )
|
|
|
|
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
|
|
! same as daven keep NH3an 2d
|
|
! NH3an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
NH3an(I,J) = NH3an(I,J)
|
|
& + EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
|
|
ENDDO
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!=================================================================
|
|
! Partition NH3 emissions into the STT tracer array
|
|
!=================================================================
|
|
|
|
! Loop over surface grid boxes
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, NTOP, TNH3, L, FEMIS )
|
|
!$OMP+SCHEDULE( DYNAMIC )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Layer where the PBL top happens
|
|
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
|
|
|
|
! Sum all types of NH3 emission [kg/box/s]
|
|
! adj_group: apply emissions scaling factors (dkh, 11/04/09)
|
|
! adj_group: now use IS_SULF_EMS_ADJ (dkh, 02/04/10)
|
|
!IF ( LADJ .and. LADJ_EMS .and.
|
|
! IDADJ_ENH3_an > 0 .and. IDADJ_ENH3_bb > 0 .and.
|
|
! IDADJ_ENH3_bf > 0 .and. IDADJ_ENH3_na > 0 ) THEN
|
|
IF ( LADJ .and. IS_SULF_EMS_ADJ ) THEN
|
|
|
|
TNH3 = NH3an (I,J) * EMS_SF(I,J,1,IDADJ_ENH3_an)
|
|
& + ENH3_bb(I,J) * EMS_SF(I,J,1,IDADJ_ENH3_bb)
|
|
& + NH3bf (I,J) * EMS_SF(I,J,1,IDADJ_ENH3_bf)
|
|
& + ENH3_na(I,J) * EMS_SF(I,J,1,IDADJ_ENH3_na)
|
|
|
|
! dkh debug
|
|
IF ( I == IFD .and. J == JFD .AND. LPRINTFD ) THEN
|
|
print*, ' SRCNH3 fwd : NH3an = ', NH3an(I,J)
|
|
print*, ' SRCNH3 fwd : ENH3_bb= ', ENH3_bb(I,J)
|
|
print*, ' SRCNH3 fwd : NH3bf = ', NH3bf(I,J)
|
|
print*, ' SRCNH3 fwd : ENH3_na= ', ENH3_na(I,J)
|
|
print*, ' SRCNH3 fwd scaled : NH3an = ', NH3an(I,J)
|
|
& * EMS_SF(I,J,1,IDADJ_ENH3_an)
|
|
ENDIF
|
|
|
|
ELSE
|
|
TNH3 = NH3an(I,J) + ENH3_bb(I,J) +
|
|
& NH3bf(I,J) + ENH3_na(I,J)
|
|
|
|
ENDIF
|
|
|
|
|
|
!==============================================================
|
|
! Add NH3 emissions [kg NH3/box] into the tracer array
|
|
! Partition total NH3 throughout the entire boundary layer
|
|
!==============================================================
|
|
|
|
! Loop over all levels in the boundary layer
|
|
DO L = 1, NTOP
|
|
|
|
! Fraction of PBL spanned by grid box (I,J,L) [unitless]
|
|
FEMIS = GET_FRAC_OF_PBL( I, J, L )
|
|
|
|
! Add NH3 emissions into tracer array [kg NH3/timestep]
|
|
TC(I,J,L) = TC(I,J,L) + ( TNH3 * FEMIS * DTSRCE )
|
|
|
|
ENDDO
|
|
|
|
!============================================================
|
|
! ND13 diagnostics: NH3 emissions [kg NH3/box/timestep]
|
|
!============================================================
|
|
IF ( ND13 > 0 ) THEN
|
|
|
|
! adj_group: now include emissions scaling factors (dkh, 11/04/09)
|
|
! adj_group: now use IS_SULF_EMS_ADJ
|
|
!IF ( LADJ .and. LADJ_EMS .and.
|
|
! IDADJ_ENH3_an > 0 .and. IDADJ_ENH3_bb > 0 .and.
|
|
! IDADJ_ENH3_bf > 0 .and. IDADJ_ENH3_na > 0 ) THEN
|
|
IF ( LADJ .and. IS_SULF_EMS_ADJ ) THEN
|
|
|
|
! Anthro NH3
|
|
AD13_NH3_an(I,J) = AD13_NH3_an(I,J) +
|
|
& ( NH3an(I,J) * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ENH3_an)
|
|
|
|
! Biomass NH3
|
|
AD13_NH3_bb(I,J) = AD13_NH3_bb(I,J) +
|
|
& ( ENH3_bb(I,J) * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ENH3_bb)
|
|
|
|
! Biofuel NH3
|
|
AD13_NH3_bf(I,J) = AD13_NH3_bf(I,J) +
|
|
& ( NH3bf(I,J) * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ENH3_bf)
|
|
|
|
! Natural source NH3
|
|
AD13_NH3_na(I,J) = AD13_NH3_na(I,J) +
|
|
& ( ENH3_na(I,J) * DTSRCE )
|
|
& * EMS_SF(I,J,1,IDADJ_ENH3_na)
|
|
ELSE
|
|
! Anthro NH3
|
|
AD13_NH3_an(I,J) = AD13_NH3_an(I,J) +
|
|
& ( NH3an(I,J) * DTSRCE )
|
|
|
|
! Biomass NH3
|
|
AD13_NH3_bb(I,J) = AD13_NH3_bb(I,J) +
|
|
& ( ENH3_bb(I,J) * DTSRCE )
|
|
|
|
! Biofuel NH3
|
|
AD13_NH3_bf(I,J) = AD13_NH3_bf(I,J) +
|
|
& ( NH3bf(I,J) * DTSRCE )
|
|
|
|
! Natural source NH3
|
|
AD13_NH3_na(I,J) = AD13_NH3_na(I,J) +
|
|
& ( ENH3_na(I,J) * DTSRCE )
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SRCNH3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_OH( I, J, L ) RESULT( OH_MOLEC_CM3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_OH returns OH from SMVGEAR's CSPEC array (for coupled runs)
|
|
! or monthly mean OH (for offline runs). Imposes a diurnal variation on
|
|
! OH for offline simulations. (bmy, 12/16/02, 7/20/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
|
|
!
|
|
! NOTES:
|
|
! (1 ) We assume SETTRACE has been called to define IDOH (bmy, 11/1/02)
|
|
! (2 ) Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
|
|
! (3 ) Now reference ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM from
|
|
! "tracer_mod.f". Also replace IJSURF w/ an analytic function.
|
|
! (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP
|
|
USE DAO_MOD, ONLY : SUNCOS
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GLOBAL_OH_MOD, ONLY : OH
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM
|
|
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
|
|
USE TRACERID_MOD, ONLY : IDOH
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
REAL*8 :: OH_MOLEC_CM3
|
|
|
|
!=================================================================
|
|
! GET_OH begins here!
|
|
!=================================================================
|
|
IF ( ITS_A_FULLCHEM_SIM() ) THEN
|
|
|
|
!---------------------
|
|
! Coupled simulation
|
|
!---------------------
|
|
|
|
! JLOOP = SMVGEAR 1-D grid box index
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Take OH from the SMVGEAR array CSPEC
|
|
! OH is defined only in the troposphere
|
|
IF ( JLOOP > 0 ) THEN
|
|
OH_MOLEC_CM3 = CSPEC(JLOOP,IDOH)
|
|
ELSE
|
|
OH_MOLEC_CM3 = 0d0
|
|
ENDIF
|
|
|
|
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
!---------------------
|
|
! Offline simulation
|
|
!---------------------
|
|
|
|
! 1-D grid box index for SUNCOS
|
|
JLOOP = ( (J-1) * IIPAR ) + I
|
|
|
|
! Test for sunlight...
|
|
IF ( SUNCOS(JLOOP) > 0d0 .and. TCOSZ(I,J) > 0d0 ) THEN
|
|
|
|
! Impose a diurnal variation on OH during the day
|
|
OH_MOLEC_CM3 = OH(I,J,L) *
|
|
& ( SUNCOS(JLOOP) / TCOSZ(I,J) ) *
|
|
& ( 1440d0 / GET_TS_CHEM() )
|
|
|
|
! Make sure OH is not negative
|
|
OH_MOLEC_CM3 = MAX( OH_MOLEC_CM3, 0d0 )
|
|
|
|
ELSE
|
|
|
|
! At night, OH goes to zero
|
|
OH_MOLEC_CM3 = 0d0
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
!---------------------
|
|
! Invalid simulation
|
|
!---------------------
|
|
CALL ERROR_STOP( 'Invalid NSRCX!', 'GET_OH (sulfate_mod.f)')
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_OH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_OH( I, J, L, OH )
|
|
!
|
|
!******************************************************************************
|
|
! Function SET_OH saves the modified OH value back to SMVGEAR's CSPEC array
|
|
! for coupled sulfate/aerosol simulations. (bmy, 12/16/02)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
|
|
! (4 ) OH (REAL*8 ) : OH at grid box (I,J,L) to be saved into CSPEC
|
|
!
|
|
! NOTES:
|
|
! (1 ) We assume SETTRACE has been called to define IDOH (bmy, 12/16/02)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP
|
|
USE TRACERID_MOD, ONLY : IDOH
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
REAL*8, INTENT(IN) :: OH
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
|
|
!=================================================================
|
|
! SET_OH begins here!
|
|
!=================================================================
|
|
|
|
! JLOOP = SMVGEAR 1-D grid box index
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Replace OH into CSPEC(troposphere only)
|
|
IF ( JLOOP > 0 ) THEN
|
|
CSPEC(JLOOP,IDOH) = OH
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_OH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NO3( I, J, L ) RESULT( NO3_MOLEC_CM3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NO3 returns NO3 from SMVGEAR's CSPEC array (for coupled runs)
|
|
! or monthly mean OH (for offline runs). For offline runs, the concentration
|
|
! of NO3 is set to zero during the day. (rjp, bmy, 12/16/02)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now references ERROR_STOP from "error_mod.f". We also assume that
|
|
! SETTRACE has been called to define IDNO3. Now also set NO3 to
|
|
! zero during the day. (rjp, bmy, 12/16/02)
|
|
! (2 ) Now reference ITS_A_FULLCHEM_SIM and ITS_AN_AEROSOL_SIM from
|
|
! "tracer_mod.f". Also remove reference to CMN. Also replace
|
|
! IJSURF with an analytic function. (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP
|
|
USE DAO_MOD, ONLY : AD, SUNCOS
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GLOBAL_NO3_MOD, ONLY : NO3
|
|
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
|
|
USE TRACERID_MOD, ONLY : IDNO3
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
REAL*8 :: NO3_MOLEC_CM3
|
|
|
|
! External functions
|
|
REAL*8, EXTERNAL :: BOXVL
|
|
|
|
!=================================================================
|
|
! GET_NO3 begins here!
|
|
!=================================================================
|
|
IF ( ITS_A_FULLCHEM_SIM() ) THEN
|
|
|
|
!--------------------
|
|
! Coupled simulation
|
|
!--------------------
|
|
|
|
! 1-D SMVGEAR grid box index
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Take NO3 from the SMVGEAR array CSPEC
|
|
! NO3 is defined only in the troposphere
|
|
IF ( JLOOP > 0 ) THEN
|
|
NO3_MOLEC_CM3 = CSPEC(JLOOP,IDNO3)
|
|
ELSE
|
|
NO3_MOLEC_CM3 = 0d0
|
|
ENDIF
|
|
|
|
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
!==============================================================
|
|
! Offline simulation: Read monthly mean GEOS-CHEM NO3 fields
|
|
! in [v/v]. Convert these to [molec/cm3] as follows:
|
|
!
|
|
! vol NO3 moles NO3 kg air kg NO3/mole NO3
|
|
! ------- = --------- * -------- * ---------------- = kg NO3
|
|
! vol air moles air 1 kg air/mole air
|
|
!
|
|
! And then we convert [kg NO3] to [molec NO3/cm3] by:
|
|
!
|
|
! kg NO3 molec NO3 mole NO3 1 molec NO3
|
|
! ------ * --------- * -------- * ----- = ---------
|
|
! 1 mole NO3 kg NO3 cm3 cm3
|
|
! ^ ^
|
|
! |____________________|
|
|
! this is XNUMOL_NO3
|
|
!
|
|
! If at nighttime, use the monthly mean NO3 concentration from
|
|
! the NO3 array of "global_no3_mod.f". If during the daytime,
|
|
! set the NO3 concentration to zero. We don't have to relax to
|
|
! the monthly mean concentration every 3 hours (as for HNO3)
|
|
! since NO3 has a very short lifetime. (rjp, bmy, 12/16/02)
|
|
!==============================================================
|
|
|
|
! 1-D grid box index for SUNCOS
|
|
JLOOP = ( (J-1) * IIPAR ) + I
|
|
|
|
! Test if daylight
|
|
IF ( SUNCOS(JLOOP) > 0d0 ) THEN
|
|
|
|
! NO3 goes to zero during the day
|
|
NO3_MOLEC_CM3 = 0d0
|
|
|
|
ELSE
|
|
|
|
! At night: Get NO3 [v/v] and convert it to [kg]
|
|
NO3_MOLEC_CM3 = NO3(I,J,L) * AD(I,J,L) * ( 62d0/28.97d0 )
|
|
|
|
! Convert NO3 from [kg] to [molec/cm3]
|
|
NO3_MOLEC_CM3 = NO3_MOLEC_CM3 * XNUMOL_NO3 / BOXVL(I,J,L)
|
|
|
|
ENDIF
|
|
|
|
! Make sure NO3 is not negative
|
|
NO3_MOLEC_CM3 = MAX( NO3_MOLEC_CM3, 0d0 )
|
|
|
|
ELSE
|
|
|
|
!--------------------
|
|
! Invalid simulation
|
|
!--------------------
|
|
CALL ERROR_STOP( 'Invalid NSRCX!','GET_NO3 (sulfate_mod.f)')
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NO3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_NO3( I, J, L, NO3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function SET_NO3 saves the modified NO3 value back to SMVGEAR's CSPEC array
|
|
! for coupled lfate/aerosol simulations. (rjp, bmy, 12/16/02, 7/20/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
|
|
! (4 ) NO3 (REAL*8 ) : OH at grid box (I,J,L) to be saved into CSPEC
|
|
!
|
|
! NOTES:
|
|
! (1 ) We assume SETTRACE has been called to define IDNO3. (bmy, 12/16/02)
|
|
! (2 ) Remove references to "error_mod.f" and CMN (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP
|
|
USE TRACERID_MOD, ONLY : IDNO3
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
REAL*8, INTENT(IN) :: NO3
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
|
|
!=================================================================
|
|
! SET_NO3 begins here!
|
|
!=================================================================
|
|
|
|
! 1-D grid box index for CSPEC
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Replace OH into CSPEC (troposphere only)
|
|
IF ( JLOOP > 0 ) THEN
|
|
CSPEC(JLOOP,IDNO3) = NO3
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_NO3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_O3( I, J, L ) RESULT( O3_VV )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_O3 returns monthly mean O3 for offline sulfate aerosol
|
|
! simulations. (bmy, 12/16/02, 10/25/05)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
|
|
!
|
|
! NOTES:
|
|
! (1 ) We assume SETTRACE has been called to define IDO3. (bmy, 12/16/02)
|
|
! (2 ) Now reference inquiry functions from "tracer_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now remove reference to CMN, it's obsolete. (bmy, 8/22/05)
|
|
! (4 ) Now references XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME
|
|
USE DAO_MOD, ONLY : AIRDEN
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
|
|
USE TRACER_MOD, ONLY : XNUMOLAIR
|
|
USE TRACERID_MOD, ONLY : IDO3
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J, L
|
|
|
|
! Local variables
|
|
INTEGER :: JLOOP
|
|
REAL*8 :: O3_VV
|
|
|
|
!=================================================================
|
|
! GET_O3 begins here!
|
|
!=================================================================
|
|
IF ( ITS_A_FULLCHEM_SIM() ) THEN
|
|
|
|
!--------------------
|
|
! Coupled simulation
|
|
!--------------------
|
|
|
|
! JLOOP = SMVGEAR 1-D grid box index
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Get O3 from CSPEC [molec/cm3] and convert it to [v/v]
|
|
! O3 data will only be defined below the tropopause
|
|
IF ( JLOOP > 0 ) THEN
|
|
O3_VV = ( CSPEC(JLOOP,IDO3) * 1d6 ) /
|
|
& ( AIRDEN(L,I,J) * XNUMOLAIR )
|
|
ELSE
|
|
O3_VV = 0d0
|
|
ENDIF
|
|
|
|
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
!--------------------
|
|
! Offline simulation
|
|
!--------------------
|
|
|
|
! Get O3 [v/v] for this gridbox & month
|
|
! O3 data will only be defined below the tropopause
|
|
IF ( L <= LLTROP ) THEN
|
|
O3_VV = O3m(I,J,L)
|
|
ELSE
|
|
O3_VV = 0d0
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
!--------------------
|
|
! Invalid simulation
|
|
!--------------------
|
|
CALL ERROR_STOP( 'Invalid NSRCX!', 'GET_OH (sulfate_mod.f)')
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_O3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_NONERUP_VOLC
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_NONERUP_VOLC reads SO2 emissions from non-eruptive
|
|
! volcanoes. (rjp, bdf, bmy, 9/19/02, 10/3/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Split off from old module routine "sulfate_readyr" (bmy, 9/19/02)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/" (bmy, 7/28/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE FILE_MOD, ONLY : IU_FILE, IOERROR
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
INTEGER :: I, IOS, J, K, L
|
|
REAL*8 :: EE
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_NONERUP_VOLC begins here!
|
|
!=================================================================
|
|
|
|
! Initialize
|
|
K = 1
|
|
Env = 0.d0
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/volcano.con.' // GET_RES_EXT()
|
|
|
|
!=================================================================
|
|
! Read NON-eruptive volcanic SO2 emission (GEIA) into Env.
|
|
! Convert Env from [Mg SO2/box/day] to [kg SO2/box/s].
|
|
!=================================================================
|
|
|
|
! Fancy output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_NONERUP_VOLC: Reading ', a )
|
|
|
|
! Open file
|
|
OPEN( IU_FILE, FILE=TRIM( FILENAME ), STATUS='OLD', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:1' )
|
|
|
|
! Read header lines
|
|
DO L = 1, 2
|
|
READ( IU_FILE, '(a)', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) THEN
|
|
CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:2' )
|
|
ENDIF
|
|
ENDDO
|
|
|
|
! Read data values
|
|
DO
|
|
READ( IU_FILE, '(49x,i4,e11.3,1x,2i4)', IOSTAT=IOS )
|
|
& IELVn(k), EE, INV(K), JNV(k)
|
|
|
|
! Check for EOF
|
|
IF ( IOS < 0 ) EXIT
|
|
|
|
! Trap I/O error
|
|
IF ( IOS > 0 ) THEN
|
|
CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:3' )
|
|
ENDIF
|
|
|
|
! Unit conversion: [Mg SO2/box/day] -> [kg SO2/box/s]
|
|
Env(k) = EE * 1000.d0 / ( 24.d0 * 3600.d0 )
|
|
|
|
! Increment counter
|
|
K = K + 1
|
|
ENDDO
|
|
|
|
! Close file
|
|
CLOSE( IU_FILE )
|
|
|
|
! NNVOL = Number of non-eruptive volcanoes
|
|
NNVOL = K - 1
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_NONERUP_VOLC
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_ERUP_VOLC
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine READ_ERUP_VOLC reads SO2 emissions from eruptive
|
|
! volcanoes. (rjp, bdf, bmy, 9/19/02, 10/3/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Split off from old module routine "sulfate_readyr" (bmy, 9/19/02)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/" (bmy, 7/28/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
!*****************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE FILE_MOD, ONLY : IU_FILE, IOERROR
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
INTEGER :: I, IOS, IUNIT, J, K, L, M
|
|
REAL*8 :: A, B, Fe, X, EE
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!==================================================================
|
|
! READ_ERUP_VOLC begins here
|
|
!==================================================================
|
|
|
|
! Initialize
|
|
K = 1
|
|
Eev(:) = 0.d0
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/volcano.erup.1990.' //
|
|
& GET_RES_EXT()
|
|
|
|
!==================================================================
|
|
! Read eruptive volcanic SO2 emission (based on Smithsonian data
|
|
! base, SO2 emission and cloud height are a function of VEI.
|
|
! Data are over-written if TOMS observations are available.
|
|
! Also define a slab with a thickness of 1/3 of the cloud column,
|
|
! and SO2 are emitted uniformely within the slab.
|
|
!
|
|
! Convert Ee from [kton SO2] to [kg SO2/box] and store in Eev.
|
|
! ESO2_ev(i,j,l) in [kg SO2/box/s] will be calculated in SRCSO2.
|
|
!==================================================================
|
|
|
|
! Fancy output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_ERUP_VOLC: Reading ', a )
|
|
|
|
! Open file
|
|
OPEN( IU_FILE, FILE=TRIM( FILENAME ), STATUS='OLD', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_erup_volc:1' )
|
|
|
|
! Read header lines
|
|
DO L = 1, 2
|
|
READ( IU_FILE, '(a)', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) THEN
|
|
CALL IOERROR( IOS, IU_FILE, 'read_erup_volc:2' )
|
|
ENDIF
|
|
ENDDO
|
|
|
|
! Read data values
|
|
DO
|
|
READ( IU_FILE, '(47x,3i6,6x,i6,es11.3,1x,2i4)', IOSTAT=IOS )
|
|
& IELVe(K), IDAYs(K), IDAYe(K), IHGHT(K),
|
|
& Ee, IEV(K), JEV(K)
|
|
|
|
! Check for EOF
|
|
IF ( IOS < 0 ) EXIT
|
|
|
|
! Trap I/O error
|
|
IF ( IOS > 0 ) THEN
|
|
CALL IOERROR( IOS, IU_FILE, 'sulfate_readyr:6' )
|
|
ENDIF
|
|
|
|
! Unit conversion: [kton SO2/box/event] -> [kg SO2/box/event]
|
|
Eev(k) = Ee * 1.d6
|
|
|
|
! Increment count
|
|
K = K + 1
|
|
ENDDO
|
|
|
|
! Close file
|
|
CLOSE( IU_FILE )
|
|
|
|
! NEVOL = Number of eruptive volcanoes
|
|
NEVOL = K - 1
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_ERUP_VOLC
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_ANTHRO_SOx( THISMONTH, NSEASON )
|
|
!
|
|
!******************************************************************************
|
|
! Suborutine READ_ANTHRO_SOx reads the anthropogenic SOx from disk,
|
|
! and partitions it into anthropogenic SO2 and SO4.
|
|
! (rjp, bdf, bmy, 9/20/02, 10/31/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now use functions GET_XMID and GET_YMID to compute lon and lat
|
|
! centers of grid box (I,J). Now replace DXYP(JREF)*1d4 with routine
|
|
! GET_AREA_CM2 of "grid_mod.f". Now use functions GET_MONTH and
|
|
! GET_YEAR of time_mod.f". Now call READ_BPCH2 with QUIET=.TRUE.
|
|
! (bmy, 3/27/03)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f". Also removed
|
|
! reference to CMN, it's not needed. (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids (bmy, 8/16/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (5 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (6 ) Now computes future SOx emissions (swu, bmy, 5/30/06)
|
|
! (7 ) Now can read either EDGAR or GEIA emissions (avd, bmy, 7/14/06)
|
|
! (8 ) Now overwrite David Streets' SO2, if necessary (yxw, bmy, 8/14/06)
|
|
! (9 ) Now accounts for FSCLYR (phs, 3/17/08)
|
|
! (9 ) Bug fix: Using tracer #30 in the call to GET_STREETS_ANTHRO can cause
|
|
! problems when adding or removing species. Replace w/ IDTNH3.
|
|
! (dkh, 10/31/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE EDGAR_MOD, ONLY : GET_EDGAR_ANTH_SO2
|
|
USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO
|
|
USE EMEP_MOD, ONLY : GET_EUROPE_MASK
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2ff
|
|
USE GRID_MOD, ONLY : GET_XMID, GET_YMID
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LFUTURE, LEDGARSOx
|
|
USE LOGICAL_MOD, ONLY : LSTREETS, LEMEP
|
|
USE LOGICAL_MOD, ONLY : LRCP
|
|
USE RCP_MOD, ONLY : GET_RCP_EMISSION
|
|
USE STREETS_ANTHRO_MOD, ONLY : GET_SE_ASIA_MASK
|
|
USE STREETS_ANTHRO_MOD, ONLY : GET_STREETS_ANTHRO
|
|
USE TIME_MOD, ONLY : GET_YEAR
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO2, IDTSO4
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
USE SCALE_ANTHRO_MOD, ONLY : GET_ANNUAL_SCALAR
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_O3" ! FSCALYR
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH, NSEASON
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, IX, JX, IOS
|
|
INTEGER, SAVE :: LASTYEAR = -99
|
|
INTEGER :: SCALEYEAR
|
|
REAL*4 :: E_SOx(IGLOB,JGLOB,2)
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: XTAU, Fe, X, Y, AREA_CM2
|
|
REAL*8 :: EDG_SO2
|
|
CHARACTER(LEN=4) :: SYEAR
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_ANTHRO_SOx begins here!
|
|
!=================================================================
|
|
|
|
IF ( FSCALYR < 0 ) THEN
|
|
SCALEYEAR = GET_YEAR()
|
|
ELSE
|
|
SCALEYEAR = FSCALYR
|
|
ENDIF
|
|
|
|
|
|
IF ( LEDGARSOx .OR. LRCP ) THEN
|
|
|
|
!==============================================================
|
|
! Use EDGAR SOx emissions
|
|
!
|
|
! Partition SOx into SO2 and SO4, according to the following
|
|
! fractions (cf Chin et al, 2000):
|
|
!
|
|
! Europe [ 36N-78N, 12.5W-60.0E ]: 5.0% of SOx is SO4
|
|
! 95.0% of SOx is SO2
|
|
!
|
|
! N. America [ 26N-74N, 167.5W-52.5W ]: 1.4% of SOx is SO4
|
|
! 98.6% of SOx is SO2
|
|
!
|
|
! Everywhere else: 3.0% of SOx is SO4
|
|
! 97.0% of SOx is SO2
|
|
!==============================================================
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, X, Y, AREA_CM2, EDG_SO2, Fe )
|
|
|
|
! Loop over latitudes
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Latitude [degrees]
|
|
Y = GET_YMID( J )
|
|
|
|
! Loop over longitudes
|
|
DO I = 1, IIPAR
|
|
|
|
! Longitude [degrees]
|
|
X = GET_XMID( I )
|
|
|
|
! Get EDGAR SO2 emissions [kg/s]
|
|
! NOTE: Future emissions are already applied!
|
|
EDG_SO2 = GET_EDGAR_ANTH_SO2( I, J, KG_S=.TRUE. )
|
|
|
|
! Use RCP SO2 emissions
|
|
IF ( LRCP ) THEN
|
|
|
|
! Get RCP SO2 emissions, molec/cm2/s
|
|
! NOTE: Future emissions assumed to already be included
|
|
EDG_SO2 = GET_RCP_EMISSION( I, J, IDTSO2,
|
|
& LAND=.TRUE., SHIP=.FALSE. )
|
|
|
|
! Convert molec/cm2/s -> kg/s
|
|
EDG_SO2 = EDG_SO2 * AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
! RCP includes biofuels
|
|
! However, if regional inventories without biofuels
|
|
! are used, then there will be no biofuel emissions
|
|
! from that region
|
|
ESO2_bf(I,J) = 0d0
|
|
|
|
ENDIF
|
|
|
|
! If we are using David Streets' emissions ...
|
|
IF ( LSTREETS ) THEN
|
|
|
|
! If we are over the SE Asia region ...
|
|
IF ( GET_SE_ASIA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Overwrite EDGAR SO2 w/ David Streets' [kg SO2/s]
|
|
EDG_SO2 = GET_STREETS_ANTHRO( I, J,
|
|
& IDTSO2, KG_S=.TRUE. )
|
|
|
|
! Streets 2006 includes biofuels.
|
|
IF ( SCALEYEAR >= 2006 ) ESO2_bf(I,J) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! If we are using EMEP over Europe...
|
|
IF ( LEMEP ) THEN
|
|
|
|
IF (GET_EUROPE_MASK(I,J) > 0d0) THEN
|
|
|
|
!-----------------------------------------------------------------------------
|
|
! Prior to 11/14/08:
|
|
! BUG FIX: Using tracer #26 in the call to GET_EMEP_ANTHRO can cause
|
|
! problems when adding or removing species. Replace w/ IDTSO2.
|
|
! (phs, 11/14/08)
|
|
! EDG_SO2 = GET_EMEP_ANTHRO( I, J, 26, KG_S=.TRUE. )
|
|
!-----------------------------------------------------------------------------
|
|
EDG_SO2 = GET_EMEP_ANTHRO( I, J,
|
|
$ IDTSO2, KG_S=.TRUE. )
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
! Compute SO4/SOx fraction for EUROPE
|
|
IF ( ( X >= -12.5 .and. X <= 60.0 ) .and.
|
|
& ( Y >= 36.0 .and. Y <= 78.0 ) ) THEN
|
|
Fe = 0.05d0
|
|
|
|
! Compute SO4/SOx fraction for NORTH AMERICA
|
|
ELSE IF ( ( X >= -167.5 .and. X <= -52.5 ) .and.
|
|
& ( Y >= 26.0 .and. Y <= 74.0 ) ) THEN
|
|
Fe = 0.014d0
|
|
|
|
! Compute SO4/SOx fraction for EVERYWHERE ELSE
|
|
ELSE
|
|
Fe = 0.03d0
|
|
|
|
ENDIF
|
|
|
|
! Store SO2 emission [kg SO2/s]
|
|
ESO2_an(I,J,1) = EDG_SO2
|
|
ESO4_an(I,J,2) = 0d0
|
|
|
|
! Compute SO4 from SO2 [kg SO4/s]
|
|
ESO4_an(I,J,1) = EDG_SO2 * Fe / ( 1.d0 - Fe )
|
|
ESO4_an(I,J,2) = 0d0
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
ELSE
|
|
|
|
!==============================================================
|
|
! Use GEIA SOx emissions
|
|
!==============================================================
|
|
|
|
! Define filename
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'fossil_200104/merge_nobiofuels.' //
|
|
& GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_ANTHRO_SOx: Reading ', a )
|
|
|
|
! Pick the right TAU value for the given season
|
|
! Seasons: 1=DJF, 2=MAM, 3=JJA, 4=SON
|
|
SELECT CASE ( NSEASON )
|
|
CASE ( 1 )
|
|
XTAU = -744d0
|
|
CASE ( 2 )
|
|
XTAU = 1416d0
|
|
CASE ( 3 )
|
|
XTAU = 3624d0
|
|
CASE ( 4 )
|
|
XTAU = 5832d0
|
|
END SELECT
|
|
|
|
! Read anthropogenic SOx [molec/cm2/s]
|
|
CALL READ_BPCH2( FILENAME, 'ANTHSRCE', 27,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 2, E_SOx, QUIET=.TRUE. )
|
|
|
|
!=================================================================
|
|
! Read in yearly SO2 scale factors here
|
|
! (For now we only have 1998, deal w/ other years later)
|
|
!=================================================================
|
|
!-- prior to 3/11/08
|
|
!IF ( LASTYEAR < 0 ) THEN
|
|
!
|
|
! ! put in SOX scale year here (hardwired to 1998 for now)
|
|
! SYEAR = '1998'
|
|
! FILENAME = TRIM( DATA_DIR ) //
|
|
!& 'sulfate_sim_200508/scalefoss.SOx.' //
|
|
!& GET_RES_EXT() // '.' // SYEAR
|
|
!
|
|
! ! Echo output
|
|
! WRITE( 6, 100 ) TRIM( FILENAME )
|
|
!
|
|
! ! Get TAU value (use Jan 1, 1998 for scale factors)
|
|
! XTAU = GET_TAU0( 1, 1, 1998 )
|
|
!
|
|
! ! Read anthropogenic SOx [molec/cm2/s]
|
|
! CALL READ_BPCH2( FILENAME, 'SCALFOSS', 3,
|
|
!& XTAU, IGLOB, JGLOB,
|
|
!& 1, ARRAY, QUIET=.TRUE. )
|
|
!
|
|
! ! Cast from REAL*4 to REAL*8
|
|
! CALL TRANSFER_2D( ARRAY(:,:,1), SOx_SCALE )
|
|
!
|
|
! ! Reset LASTYEAR
|
|
! LASTYEAR = GET_YEAR()
|
|
!ENDIF
|
|
|
|
|
|
! Get annual scalar factor (amv, 08/24/07)
|
|
CALL GET_ANNUAL_SCALAR( 73, 1985, SCALEYEAR, SOx_SCALE )
|
|
|
|
!==============================================================
|
|
! Partition SOx into SO2 and SO4, according to the following
|
|
! fractions (cf Chin et al, 2000):
|
|
!
|
|
! Europe [ 36N-78N, 12.5W-60.0E ]: 5.0% of SOx is SO4
|
|
! 95.0% of SOx is SO2
|
|
!
|
|
! N. America [ 26N-74N, 167.5W-52.5W ]: 1.4% of SOx is SO4
|
|
! 98.6% of SOx is SO2
|
|
!
|
|
! Everywhere else: 3.0% of SOx is SO4
|
|
! 97.0% of SOx is SO2
|
|
!==============================================================
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L, AREA_CM2, Y, X, Fe )
|
|
DO L = 1, 2
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Latitude [degrees]
|
|
Y = GET_YMID( J )
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
! Longitude [degrees]
|
|
X = GET_XMID( I )
|
|
|
|
! First scale SOx to the given fossil fuel year
|
|
E_SOx(I,J,L) = E_SOx(I,J,L) * SOx_SCALE(I,J)
|
|
|
|
! Compute future SOx emissions (if necessary)
|
|
IF ( LFUTURE ) THEN
|
|
E_SOx(I,J,L) = E_SOx(I,J,L) *
|
|
& GET_FUTURE_SCALE_SO2ff( I, J )
|
|
ENDIF
|
|
|
|
! Compute SO4/SOx fraction for EUROPE
|
|
IF ( ( X >= -12.5 .and. X <= 60.0 ) .and.
|
|
& ( Y >= 36.0 .and. Y <= 78.0 ) ) THEN
|
|
Fe = 0.05d0
|
|
|
|
! Compute SO4/SOx fraction for NORTH AMERICA
|
|
ELSE IF ( ( X >= -167.5 .and. X <= -52.5 ) .and.
|
|
& ( Y >= 26.0 .and. Y <= 74.0 ) ) THEN
|
|
Fe = 0.014d0
|
|
|
|
! Compute SO4/SOx fraction for EVERYWHERE ELSE
|
|
ELSE
|
|
Fe = 0.03d0
|
|
|
|
ENDIF
|
|
|
|
! Compute SO2 (tracer #2) from SOx
|
|
! Convert from [molec SOx/cm2/s] to [kg SO2/box/s]
|
|
ESO2_an(I,J,L) = E_SOx(I,J,L) * ( 1.d0 - Fe ) *
|
|
& AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
! If we are using David Streets' emissions
|
|
! Remember: those include BF if Year is GE 2006
|
|
IF ( LSTREETS ) THEN
|
|
|
|
! If we are over the SE Asia region
|
|
IF ( GET_SE_ASIA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Overwrite GEIA SO2 w/ David Streets' SO2 [kg SO2/s]
|
|
ESO2_an(I,J,1) = GET_STREETS_ANTHRO( I, J, IDTSO2,
|
|
& KG_S=.TRUE. )
|
|
|
|
! Zero 2nd level of emissions
|
|
ESO2_an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( LEMEP ) THEN
|
|
|
|
IF (GET_EUROPE_MASK(I,J) > 0d0 ) THEN
|
|
|
|
ESO2_an(I,J,1) = GET_EMEP_ANTHRO( I, J, IDTSO2,
|
|
& KG_S=.TRUE. )
|
|
|
|
ESO2_an(I,J,2) = 0d0
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
!--- prior 6/23/08
|
|
! Now calculate SO4 from SO2, since SOx not available with STREETS and EMEP
|
|
! ! Compute SO4 (tracer #3) from SOx
|
|
! ! Convert from [molec SOx/cm2/s] to [kg SO4/box/s]
|
|
! ESO4_an(I,J,L) = E_SOx(I,J,L) * Fe *
|
|
! & AREA_CM2 / XNUMOL(IDTSO4)
|
|
|
|
ESO4_an(I,J,L) = ESO2_an(I,J,L) * Fe / (1.d0-Fe)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_ANTHRO_SOx
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_OCEAN_DMS( THISMONTH )
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine READ_OCEAN_DMS reads seawater concentrations of DMS (nmol/L).
|
|
! (rjp, bdf, bmy, 9/20/02, 10/3/05)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
|
|
! (2 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (3 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (4 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids (bmy, 8/16/05)
|
|
! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
!*****************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: XTAU
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!==================================================================
|
|
! READ_OCEAN_DMS begins here!
|
|
!==================================================================
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/DMS_seawater.' //
|
|
& GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_OCEAN_DMS: Reading ', a )
|
|
|
|
! TAU value (use generic year 1985)
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1985 )
|
|
|
|
! Read ocean DMS [nmol/L]
|
|
CALL READ_BPCH2( FILENAME, 'BIOGSRCE', 25,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), DMSo )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_OCEAN_DMS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_SST( THISMONTH, THISYEAR )
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine READ_SST reads monthly mean sea surface temperatures.
|
|
! (rjp, bdf, bmy, 9/18/02, 11/17/05)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
! (2 ) THISYEAR (INTEGER) : Current 4-digit year
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
|
|
! (2 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (3 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (4 ) Now use interannual SST data from NOAA if present; otherwise use
|
|
! climatological SST data. Now read data for both GCAP and GEOS
|
|
! grids (bmy, 8/16/05)
|
|
! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (6 ) Now read int'annual SST data on the GEOS 1x1 grid (bmy, 11/17/05)
|
|
! (7 ) Last year of data is now 2008 (bmy, 7/13/09)
|
|
!*****************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR, DATA_DIR_1x1
|
|
USE REGRID_1x1_MOD, ONLY : DO_REGRID_1x1
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH, THISYEAR
|
|
|
|
! Local variables
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*4 :: ARRAY1(I1x1,J1x1,1)
|
|
REAL*8 :: XTAU
|
|
CHARACTER(LEN=4) :: SYEAR
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!==================================================================
|
|
! READ_SST begins here!
|
|
!==================================================================
|
|
|
|
!---------------------------------------------------------
|
|
! Prior to 7/13/09:
|
|
! Max year is now 2008 (bmy, 7/13/09)
|
|
!IF ( THISYEAR >= 1985 .and. THISYEAR <= 2004 ) THEN
|
|
!---------------------------------------------------------
|
|
IF ( THISYEAR >= 1985 .and. THISYEAR <= 2008 ) THEN
|
|
|
|
!------------------------------------
|
|
! Use interannual SST data from NOAA
|
|
! Data exists for 1985 - 2004,
|
|
! Add other years as necessary
|
|
!------------------------------------
|
|
|
|
! Make a string for THISYEAR
|
|
WRITE( SYEAR, '(i4)' ) THISYEAR
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR_1x1 ) //
|
|
& 'SST_200508/SST.geos.1x1.' // SYEAR
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_SST: Reading ', a )
|
|
|
|
! TAU value (use this year)
|
|
XTAU = GET_TAU0( THISMONTH, 1, THISYEAR )
|
|
|
|
! Read sea surface temperature [K]
|
|
CALL READ_BPCH2( FILENAME, 'GMAO-2D', 69,
|
|
& XTAU, I1x1, J1x1,
|
|
& 1, ARRAY1(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Regrid from 1x1 and cast to REAL*8
|
|
CALL DO_REGRID_1x1( 'K', ARRAY1, SSTEMP )
|
|
|
|
ELSE
|
|
|
|
!-------------------------------
|
|
! Use climatological SST data
|
|
!-------------------------------
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/SST.' // GET_NAME_EXT_2D() //
|
|
& '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
|
|
! TAU value (use generic year 1985)
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1985 )
|
|
|
|
! Read sea surface temperature [K]
|
|
CALL READ_BPCH2( FILENAME, 'DAO-FLDS', 5,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), SSTEMP )
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_SST
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_BIOFUEL_SO2( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_BIOFUEL_SO2 reads monthly mean biomass burning
|
|
! emissions for SO2. SOx is read in, and converted to SO2.
|
|
! (rjp, bdf, bmy, phs, 1/16/03, 12/23/08)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
|
|
! (2 ) Modified molar ratio of biomass burning SO2 per CO. Added SO2
|
|
! emission from biofuel burning. (rjp, bmy, 1/16/03)
|
|
! (3 ) Now replace DXYP(J+J0)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
|
|
! Now replace MONTH with the argument THISMONTH. Now call READ_BPCH2
|
|
! with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (4 ) Now references DATA_DIR from "directory_mod.f". Also removed
|
|
! references to CMN and CMN_SETUP. (bmy, 7/20/04)
|
|
! (5 ) Now can read either seasonal or interannual biomass burning emissions.
|
|
! Now references routines from both "logical_mod.f" and "time_mod.f".
|
|
! Now reads SO2 biomass emissions directly rather than computing
|
|
! it by mole fraction from CO. (rjp, bmy, 1/11/05)
|
|
! (6 ) Now read data for both GCAP and GEOS grids (bmy, 8/16/05)
|
|
! (7 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (8 ) Now computes future biomass emissions, if necessary (swu, bmy, 5/30/06)
|
|
! (9 ) Now only read the biofuel, we have moved the biomass-reading code
|
|
! to "gc_biomass_mod.f" for compatibility with GFED2 biomass emissions
|
|
! (bmy, 9/27/06)
|
|
! (10) Now prevent seg fault if BIOMASS emissions are turned off.
|
|
! (bmy, 10/3/06)
|
|
! (11) Renamed READ_BIOFUEL_SO2, and move all biomass code to GET_BIOMASS_SO2
|
|
! to account for several GFED2 products (yc, phs, 12/23/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BIOMASS_MOD, ONLY : BIOMASS, IDBSO2
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2bf
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LBIOMASS, LFUTURE
|
|
USE TIME_MOD, ONLY : ITS_A_LEAPYEAR
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO2
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, THISYEAR
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: BIOCO(IIPAR,JJPAR)
|
|
!-- prior 12/23/08
|
|
! REAL*8 :: CONV, XTAU
|
|
REAL*8 :: XTAU
|
|
CHARACTER(LEN=4 ) :: CYEAR
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
! Days per month
|
|
REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0, 31d0, 30d0,
|
|
& 31d0, 31d0, 30d0, 31d0, 30d0, 31d0/)
|
|
|
|
!=================================================================
|
|
! READ_BIOFUEL_SO2 begins here!
|
|
!=================================================================
|
|
|
|
!=================================================================
|
|
! Compute biofuel SO2 from biofuel CO. Use a molar
|
|
! ratio of 0.0015 moles SO2/mole CO from biofuel burning.
|
|
! (Table 2, [Andreae and Merlet, 2001])
|
|
!=================================================================
|
|
|
|
! File name for biofuel burning file
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'biofuel_200202/biofuel.' // GET_NAME_EXT_2D() //
|
|
& '.' // GET_RES_EXT()
|
|
|
|
! Echo info
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_BIOFUEL_SO2: Reading ', a )
|
|
|
|
! Get TAU0 value (use generic year 1985)
|
|
XTAU = GET_TAU0( 1, 1, 1985 )
|
|
|
|
! Read Biofuel burning of CO [kg/yr]
|
|
CALL READ_BPCH2( FILENAME, 'BIOFSRCE', 4,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), BIOCO )
|
|
|
|
!=================================================================
|
|
! Unit conversion to [kg SO2/s]
|
|
!=================================================================
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!----------------------------------------------------------------------
|
|
! Prior to 1/28/09:
|
|
! Need to remove CONV from the PRIVATE statement (bmy, 1/28/09)
|
|
!!$OMP+PRIVATE( I, J, CONV )
|
|
!----------------------------------------------------------------------
|
|
!$OMP+PRIVATE( I, J )
|
|
! Loop over longitudes
|
|
DO J = 1, JJPAR
|
|
|
|
!-- prior 12/23/08
|
|
! ! Conversion factor for [cm2 * kg/molec]
|
|
! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTSO2)
|
|
|
|
! Loop over latitudes
|
|
DO I = 1, IIPAR
|
|
|
|
!-- prior 12/23/08
|
|
! ! Convert biomass SO2 from [molec SO2/cm2/s] -> [kg SO2/s]
|
|
! ! NOTE: Future scale has already been applied by this point
|
|
! IF ( LBIOMASS ) THEN
|
|
! ESO2_bb(I,J) = BIOMASS(I,J,IDBSO2) * CONV
|
|
! ELSE
|
|
! ESO2_bb(I,J) = 0d0
|
|
! ENDIF
|
|
|
|
! Convert biofuel SO2 from [kg CO/yr] to [kg SO2/s]
|
|
ESO2_bf(I,J) = ( BIOCO(I,J) * 64d-3 * 0.0015d0 /
|
|
& ( 28d-3 * 86400.d0 * 365.25d0 ) )
|
|
|
|
! Apply future emissions to biofuel SO2, if necessary
|
|
IF ( LFUTURE ) THEN
|
|
ESO2_bf(I,J) = ESO2_bf(I,J) *
|
|
& GET_FUTURE_SCALE_SO2bf( I, J )
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_BIOFUEL_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE GET_BIOMASS_SO2
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_BIOMASS_SO2 retrieve monthly/8-day/3hr biomass burning
|
|
! emissions for SO2. (yc, phs, 12/23/08)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 )
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module subroutine READ_BIOMASS_SO2
|
|
! (yc, phs, 12/23/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BIOMASS_MOD, ONLY : BIOMASS, IDBSO2
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO2
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
INTEGER :: I, J
|
|
REAL*8 :: CONV
|
|
|
|
!=================================================================
|
|
! GET_BIOMASS_SO2 begins here!
|
|
!=================================================================
|
|
! Unit conversion to [kg SO2/s]
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, CONV )
|
|
|
|
! Loop over longitudes
|
|
DO J = 1, JJPAR
|
|
|
|
! Conversion factor for [cm2 * kg/molec]
|
|
CONV = GET_AREA_CM2( J ) / XNUMOL(IDTSO2)
|
|
|
|
! Loop over latitudes
|
|
DO I = 1, IIPAR
|
|
|
|
! Convert biomass SO2 from [molec SO2/cm2/s] -> [kg SO2/s]
|
|
! NOTE: Future scale has already been applied by this point
|
|
ESO2_bb(I,J) = BIOMASS(I,J,IDBSO2) * CONV
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE GET_BIOMASS_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_AIRCRAFT_SO2( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_AIRCRAFT_SO2 reads monthly mean aircraft fuel emissions
|
|
! and converts them to SO2 emissions. (rjp, bdf, bmy, 9/18/02, 10/3/05)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids (bmy, 8/16/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (5 ) Now checkpoint aircraft SO2 emissions (dkh, 04/08/12)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
|
|
USE DAO_MOD, ONLY : BXHEIGHT
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE FILE_MOD, ONLY : IU_FILE, IOERROR
|
|
|
|
! add for adjoint support
|
|
USE LOGICAL_ADJ_MOD, ONLY : LADJ
|
|
USE TIME_MOD, ONLY : GET_DIRECTION
|
|
USE CHECKPT_MOD, ONLY : MAKE_SO2ac_FILE
|
|
USE CHECKPT_MOD, ONLY : READ_SO2ac_FILE
|
|
USE ADJ_ARRAYS_MOD, ONLY : DO_CHK_FILE
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
INTEGER :: I, IOS, J, K, L, DOW_LT
|
|
REAL*8 :: ACSO2(IGLOB,JGLOB,20)
|
|
REAL*8 :: FAC, FUEL, DZ(LLPAR), ZH(0:LLPAR)
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
! Month names
|
|
CHARACTER(LEN=3) :: CMONTH(12) = (/'jan', 'feb', 'mar', 'apr',
|
|
& 'may', 'jun', 'jul', 'aug',
|
|
& 'sep', 'oct', 'nov', 'dec'/)
|
|
|
|
!=================================================================
|
|
! READ_AIRCRAFT_SO2 begins here!
|
|
!=================================================================
|
|
|
|
! Zero arrays
|
|
ESO2_ac = 0d0
|
|
ACSO2 = 0d0
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/aircraft.' // GET_RES_EXT() //
|
|
& '.1992.' // CMONTH(THISMONTH)
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_AIRCRAFT_SO2: Reading ', a )
|
|
|
|
!=================================================================
|
|
! Read aircraft emissions. These are fuel burned in [kg/box/day],
|
|
! from AEAP for 1992. SO2 emission is calculated by assuming
|
|
! an emission index EI of 1.0, i.e., 1g of SO2 emitted per kg
|
|
! of fuel burned. It is also assumed that there is no diurnal
|
|
! variation of emission rate. Convert to [kg SO2/box/s].
|
|
!=================================================================
|
|
|
|
! Open file
|
|
OPEN( IU_FILE, FILE=FILENAME, STATUS='OLD', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:1' )
|
|
|
|
! Read header line
|
|
READ( IU_FILE, '(/)', IOSTAT=IOS )
|
|
IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:2' )
|
|
|
|
! Read data values until an EOF is found
|
|
DO
|
|
READ( IU_FILE, '(3i4,e11.3)', IOSTAT=IOS ) I, J, L, FUEL
|
|
|
|
! EOF encountered
|
|
IF ( IOS < 0 ) EXIT
|
|
|
|
! I/O error condition
|
|
IF ( IOS > 0 ) THEN
|
|
CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:3' )
|
|
ENDIF
|
|
|
|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
!%%% KLUDGE FOR NORTH AMERICAN NESTED GRID (bmy, 7/2/12)
|
|
!%%% For some reason there seems to be bad data within the N. American
|
|
!%%% nested grid data files. Some of the longitude indices are out of bounds
|
|
!%%% for the grid. Put in a simple kludge to just skip over these boxes.
|
|
!%%% We are going to be reinventing how emissions get done in GEOS-Chem,
|
|
!%%% so it's probably not worth recreating the the file at this time.
|
|
!%%%
|
|
#if defined( NESTED_NA )
|
|
IF ( I > IIPAR ) CYCLE
|
|
IF ( J > JJPAR ) CYCLE
|
|
#endif
|
|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
! Unit conversion: [kg Fuel/box/day] -> [kg SO2/box/s]
|
|
! Assuming an emission index of 1.0,
|
|
! 1 g SO2 / kg fuel burned [Weisenstein et al., 1996]
|
|
ACSO2(I,J,L+1) = 1.d-3 * FUEL / ( 24.d0 * 3600d0 )
|
|
ENDDO
|
|
|
|
! Close file
|
|
CLOSE( IU_FILE )
|
|
|
|
!=================================================================
|
|
! Interpolate from the 1-km grid to the given GEOS-CHEM grid
|
|
! NOTE: we need to account for window grids (bmy, 9/20/02)
|
|
!=================================================================
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! ACSO2 is the aircraft SO2 on the 1-km vertical grid
|
|
FUEL = SUM( ACSO2(I,J,:) )
|
|
IF ( FUEL < 1d-20 ) CYCLE
|
|
|
|
! There are 20 1-km levels
|
|
DO K = 1, 20
|
|
|
|
! Initialize
|
|
ZH(0) = 0.d0
|
|
|
|
! Loop over levels
|
|
DO L = 1, LLPAR
|
|
|
|
! Altitude of top edge of level L, from ground [km]
|
|
ZH(L) = ZH(L-1) + ( BXHEIGHT(I,J,L) * 1d-3 )
|
|
|
|
IF ( ZH(L-1) > DBLE(K) ) EXIT
|
|
IF ( ZH(L ) < DBLE(K-1) ) CYCLE
|
|
|
|
IF ( ZH(L) < DBLE(K) ) THEN
|
|
FAC = ZH(L) - MAX( ZH(L-1), DBLE(K-1) )
|
|
ESO2_ac(I,J,L) = ESO2_ac(I,J,L) + ACSO2(I,J,K) * FAC
|
|
ELSE
|
|
FAC = DBLE(K) - MAX( ZH(L-1), DBLE(K-1) )
|
|
ESO2_ac(I,J,L) = ESO2_ac(I,J,L) + ACSO2(I,J,K) * FAC
|
|
EXIT
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
|
|
! adj_group: checkpoint these. recalculating them is tricky owing
|
|
! to influence of BXHEIGHT (dkh, 04/08/12)
|
|
IF ( GET_DIRECTION() > 0 ) THEN
|
|
IF (DO_CHK_FILE())
|
|
& CALL MAKE_SO2ac_FILE ( ESO2_ac, CMONTH(THISMONTH) )
|
|
ELSE
|
|
CALL READ_SO2ac_FILE ( ESO2_ac, CMONTH(THISMONTH) )
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_AIRCRAFT_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_SHIP_SO2( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_SHIP_SO2 reads in ship SO2 emissions, from either Corbett
|
|
! et al or EDGAR inventories. (bec, qli, 10/01/03, 7/14/06)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (2 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids. (bmy, 8/16/05)
|
|
! (3 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (4 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
|
|
! (5 ) Now get EDGAR ship SO2 emissions if necessary. Also apply future
|
|
! emissions scale factors to the default Corbett et al ship emissions.
|
|
! (avd, bmy, 7/14/06)
|
|
! (6 ) Now references GET_ARCTAS_HIP from 'arctas_ship_emiss_mod.f" and
|
|
! GET_EMEP_ANTHRO to get ARCTAS and EMEP SO2 ship emissions (phs, 12/5/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE ARCTAS_SHIP_EMISS_MOD,ONLY : GET_ARCTAS_SHIP
|
|
USE ICOADS_SHIP_MOD, ONLY : GET_ICOADS_SHIP !(cklee, 7/09/09)
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE EDGAR_MOD, ONLY : GET_EDGAR_SHIP_SO2
|
|
USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO, GET_EUROPE_MASK
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2ff
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LRCPSHIP
|
|
USE RCP_MOD, ONLY : GET_RCP_EMISSION
|
|
USE LOGICAL_MOD, ONLY : LEDGARSHIP, LFUTURE,
|
|
& LARCSHIP, LSHIPSO2,
|
|
$ LEMEPSHIP
|
|
USE LOGICAL_MOD, ONLY : LICOADSSHIP !(cklee, 6/30/09)
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTSO2
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
INTEGER :: I, J
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*4 :: SHIPSO2(IIPAR,JJPAR)
|
|
REAL*8 :: XTAU, AREA_CM2
|
|
CHARACTER (LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_SHIP_SO2 begins here!
|
|
!=================================================================
|
|
|
|
! Reset
|
|
ESO2_sh = 0D0
|
|
|
|
|
|
! Test for EDAGR last, since this is default inventory by design.
|
|
! So we can still use EDGAR SHIP to get ship-NOX and CO, and
|
|
! overwrite ship-SO2 with ARCTAS or Colbert (phs, 12/5/08)
|
|
|
|
!-----------------------------------------------------------
|
|
! Use ARCTAS SHIP emissions (EDGAR 2006 update)
|
|
!-----------------------------------------------------------
|
|
IF ( LARCSHIP ) THEN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Read ARCTAS SO2 emissions in [kg SO2/BOX/s]
|
|
ESO2_sh(I,J) = GET_ARCTAS_SHIP( I, J, IDTSO2, KG_S=.TRUE. )
|
|
|
|
IF ( LEMEPSHIP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0 )
|
|
$ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
|
|
& KG_S=.TRUE.,
|
|
$ SHIP=.TRUE.)
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!-----------------------------------------------------------
|
|
! Or RCP SHIP emissions (EDGAR 2006 update)
|
|
!-----------------------------------------------------------
|
|
ELSE IF ( LRCPSHIP ) THEN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, AREA_CM2 )
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
! Read RCP SO2 emissions in [molec/cm2/s]
|
|
ESO2_sh(I,J) = GET_RCP_EMISSION( I, J, IDTSO2,
|
|
& SHIP=.TRUE. )
|
|
|
|
! Convert molec/cm2/s -> kg SO2/BOX/s
|
|
ESO2_sh(I,J) = ESO2_sh(I,J) * AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
IF ( LEMEPSHIP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0 )
|
|
$ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
|
|
& KG_S=.TRUE.,
|
|
$ SHIP=.TRUE.)
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
!----------------------------------------
|
|
! Or Corbett et al ship SO2 emissions
|
|
!----------------------------------------
|
|
ELSE IF ( LSHIPSO2 ) THEN
|
|
|
|
! Filename
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/shipSOx.' // GET_NAME_EXT_2D() //
|
|
& '.' // GET_RES_EXT()
|
|
|
|
! Echo some information to the standard output
|
|
WRITE( 6, 110 ) TRIM( FILENAME )
|
|
110 FORMAT( ' - READ_SHIP_SO2 ', a )
|
|
|
|
! TAU value at the beginning of this month
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1985 )
|
|
|
|
! Read in this month's ship SO2 emissions [molec SO2/cm2/s]
|
|
CALL READ_BPCH2( FILENAME, 'SO2-SHIP', 26,
|
|
& XTAU, IIPAR, JJPAR,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), SHIPSO2 )
|
|
|
|
! Loop over latitudes
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
! Loop over longitudes
|
|
DO I = 1, IIPAR
|
|
|
|
! Convert [molec SO2/cm2/s] to [kg SO2/box/s]
|
|
ESO2_sh(I,J) = SHIPSO2(I,J) * AREA_CM2 / XNUMOL(IDTSO2)
|
|
|
|
! Apply future emissions (if necessary)
|
|
IF ( LFUTURE ) THEN
|
|
ESO2_sh(I,J) = ESO2_sh(I,J) *
|
|
& GET_FUTURE_SCALE_SO2ff( I, J )
|
|
ENDIF
|
|
|
|
IF ( LEMEPSHIP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0 )
|
|
$ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
|
|
$ KG_S=.TRUE., SHIP=.TRUE.)
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
|
|
!-----------------------------------------------------------
|
|
! Test for EDGAR ship emissions
|
|
!-----------------------------------------------------------
|
|
ELSE IF ( LEDGARSHIP ) THEN
|
|
|
|
!----------------------------------------
|
|
! Use EDGAR ship SO2 emissions
|
|
!----------------------------------------
|
|
|
|
! Get EDGAR ship SO2 [kg SO2/box/s]
|
|
! NOTE: Future emissions have already been applied!
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
ESO2_sh(I,J) = GET_EDGAR_SHIP_SO2( I, J, KG_S=.TRUE. )
|
|
|
|
IF ( LEMEPSHIP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0 )
|
|
$ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
|
|
& KG_S=.TRUE.,
|
|
$ SHIP=.TRUE.)
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
|
|
!----------------------------------------
|
|
! Use ICOADS ship SOx emissions !(cklee, 6/24/09)
|
|
! Replace the above ship emissions
|
|
!----------------------------------------
|
|
ELSE IF ( LICOADSSHIP ) THEN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Read ICOADS emissions in [kg SO2/box/s]
|
|
ESO2_sh(I,J) = GET_ICOADS_SHIP( I, J, IDTSO2, KG_S=.TRUE. )
|
|
|
|
IF ( LEMEPSHIP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0 )
|
|
$ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, 26, KG_S=.TRUE.,
|
|
$ SHIP=.TRUE.)
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_SHIP_SO2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_ANTHRO_NH3( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_ANTHRO_NH3 reads the monthly mean anthropogenic
|
|
! NH3 emissions from disk and converts to [kg NH3/box/s].
|
|
! (rjp, bdf, bmy, 9/20/02, 10/31/08)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Renamed from NH3_READ to READ_ANTHRO_NH3. Also updated comments,
|
|
! made cosmetic changes. (bmy, 9/20/02)
|
|
! (2 ) Changed filename to NH3_anthsrce.geos.*. Also now reads data under
|
|
! category name "NH3-ANTH". (rjp, bmy, 3/23/03)
|
|
! (3 ) Now reads from NH3emis.monthly.geos.* files. Now call READ_BPCH2
|
|
! with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (4 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (5 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids. (bmy, 8/16/05)
|
|
! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (6 ) Now compute future emissions, if necessary (swu, bmy, 5/30/06)
|
|
! (7 ) Now overwrite w/ David Streets' NH3, if necessary (yxw, bmy, 8/17/06)
|
|
! (8 ) Bug fix: Using tracer #30 in the call to GET_STREETS_ANTHRO can cause
|
|
! problems when adding or removing species. Replace w/ IDTNH3.
|
|
! (dkh, 10/31/08)
|
|
! (9 ) Now check if NH3 Streets is available (phs, 12/10/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO
|
|
USe EMEP_MOD, ONLY : GET_EUROPE_MASK
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_NH3an
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE LOGICAL_MOD, ONLY : LFUTURE, LSTREETS
|
|
USE LOGICAL_MOD, ONLY : LEMEP, LRCP
|
|
USE RCP_MOD, ONLY : GET_RCP_EMISSION
|
|
USE STREETS_ANTHRO_MOD, ONLY : GET_SE_ASIA_MASK
|
|
USE STREETS_ANTHRO_MOD, ONLY : GET_STREETS_ANTHRO
|
|
USE TRACERID_MOD, ONLY : IDTNH3
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
USE HTAP_MOD, ONLY : GET_HTAP
|
|
USE LOGICAL_MOD, ONLY : LHTAP
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
LOGICAL :: WEEKDAY
|
|
INTEGER :: I, J, DAY_NUM
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: AREA_CM2, EPA_NEI, XTAU
|
|
REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0,
|
|
& 31d0, 30d0, 31d0, 31d0,
|
|
& 30d0, 31d0, 30d0, 31d0 /)
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
REAL*8 :: STREETS
|
|
|
|
!=================================================================
|
|
! READ_ANTHRO_NH3 begins here!
|
|
!=================================================================
|
|
|
|
!-----------------------------------------------------------
|
|
! Use RCP NH3 emissions
|
|
! (mpayer, cdh, 6/28/12)
|
|
!-----------------------------------------------------------
|
|
IF ( LRCP ) THEN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, AREA_CM2 )
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box surface area [cm2]
|
|
AREA_CM2 = GET_AREA_CM2( J )
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
! Read RCP NH3 emissions in [molec/cm2/s]
|
|
ENH3_an(I,J) = GET_RCP_EMISSION( I, J, IDTNH3,
|
|
& LAND=.TRUE. )
|
|
|
|
! Convert molec/cm2/s -> kg NH3/BOX/s
|
|
ENH3_an(I,J) = ENH3_an(I,J) * AREA_CM2 / XNUMOL(IDTNH3)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
ELSE
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/NH3_anthsrce.' //
|
|
& GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_ANTHRO_NH3: Reading ', a )
|
|
|
|
! Get TAU value (use year 1990, the year of the data!)
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1990 )
|
|
|
|
! Read 1990 NH3 emissions [kg N/box/mon]
|
|
CALL READ_BPCH2( FILENAME, 'NH3-ANTH', 29,
|
|
& XTAU, IIPAR, JJPAR,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_an )
|
|
|
|
! Convert from [kg N/box/mon] to [kg NH3/box/s]
|
|
ENH3_an = ENH3_an * ( 17.d0 / 14.d0 )
|
|
& / ( NMDAY(THISMONTH) * 86400.d0 )
|
|
|
|
ENDIF
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, STREETS )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Compute future NH3an emissions, if necessary
|
|
! Moved here since Streets and EMEP should have already
|
|
! applied FUTURE scale factors if needed
|
|
IF ( LFUTURE ) ENH3_an(I,J) = ENH3_an(I,J) *
|
|
& GET_FUTURE_SCALE_NH3an( I, J )
|
|
|
|
! If we are using David Streets' emissions ...
|
|
IF ( LSTREETS ) THEN
|
|
|
|
! If we are over the SE Asia region ...
|
|
IF ( GET_SE_ASIA_MASK( I, J ) > 0d0 ) THEN
|
|
|
|
! Overwrite with David Streets emissions
|
|
! [kg NH3/s]
|
|
STREETS = GET_STREETS_ANTHRO( I, J,
|
|
& IDTNH3, KG_S=.TRUE.)
|
|
|
|
IF ( .not. ( STREETS < 0d0 ) )
|
|
$ ENH3_an(I,J) = STREETS
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( LEMEP ) THEN
|
|
IF ( GET_EUROPE_MASK(I,J) > 0d0) THEN
|
|
ENH3_an(I,J) = GET_EMEP_ANTHRO(I,J,IDTNH3,KG_S=.TRUE.)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( LHTAP ) THEN
|
|
ENH3_an(I,J) = GET_HTAP(I,J,IDTNH3) * GET_AREA_CM2(J)
|
|
& * 1d-4
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_ANTHRO_NH3
|
|
|
|
SUBROUTINE READ_GEIA_NH3( MONTH )
|
|
|
|
!fp: for now use only natural geia nh3 emission in adjoint
|
|
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_NH3an
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR_1x1, DATA_DIR
|
|
USE REGRID_A2A_MOD, ONLY : DO_REGRID_A2A
|
|
|
|
USE m_netcdf_io_open
|
|
USE m_netcdf_io_read
|
|
USE m_netcdf_io_readattr
|
|
USE m_netcdf_io_close
|
|
USE m_netcdf_io_get_dimlen
|
|
|
|
!fp comment out for adjoint
|
|
|
|
C USE LOGICAL_MOD, ONLY : LNH3_OCEAN ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_INDUSTRY ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_CROP ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_LIVESTOCK ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_HUMAN ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_NATURAL_SOIL ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_WILDLIFE ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_BIOFUEL ! geia
|
|
C USE LOGICAL_MOD, ONLY : LNH3_FFUEL ! geia
|
|
|
|
USE LOGICAL_MOD, ONLY : LFUTURE
|
|
|
|
!
|
|
! !REVISION HISTORY:
|
|
! (1 ) Updated FORMAT string. Now also call READ_BPCH2 with QUIET=.TRUE.
|
|
! (bmy, 4/8/03)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids. (bmy, 8/16/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (5 ) replace by actual raw geia files (fp)
|
|
! 22 Dec 2011 - M. Payer - Added ProTeX headers
|
|
!EOP
|
|
!------------------------------------------------------------------------------
|
|
!BOC
|
|
!
|
|
! !LOCAL VARIABLES:
|
|
!
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
INTEGER, INTENT(IN) :: MONTH
|
|
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
CHARACTER(LEN=255) :: LLFILENAME
|
|
INTEGER :: FID
|
|
INTEGER :: STD(2),CTD(2)
|
|
INTEGER :: I,J
|
|
|
|
REAL*8, POINTER :: OUTGRID(:,:) => NULL()
|
|
REAL*8, POINTER :: INGRID(:,:) => NULL()
|
|
|
|
REAL*4 :: DATA(I1x1,J1x1)
|
|
!mkeller: change this name to something that doesn't exist so that the code uses the 1x1 version
|
|
! according to the GEOS-Chem wiki, the GEIA data set has resolution of 1x1, so I really
|
|
! don't understand what's happening here...
|
|
#if defined( NESTED_NA_FAKEVAR )
|
|
REAL*4 :: SEASON(IIPAR,JJPAR)
|
|
#else
|
|
REAL*4 :: SEASON(I1x1,J1x1)
|
|
#endif
|
|
REAL*8, TARGET :: GEOS_GRID(IIPAR,JJPAR,1)
|
|
REAL*8, TARGET :: DATA_GRID(I1x1,J1x1,1)
|
|
|
|
|
|
LOGICAL, PARAMETER :: LNH3_OCEAN = .true.
|
|
LOGICAL, PARAMETER :: LNH3_INDUSTRY = .false.
|
|
LOGICAL, PARAMETER :: LNH3_CROP = .false.
|
|
LOGICAL, PARAMETER :: LNH3_LIVESTOCK = .false.
|
|
LOGICAL, PARAMETER :: LNH3_HUMAN = .false.
|
|
LOGICAL, PARAMETER :: LNH3_NATURAL_SOIL = .true.
|
|
LOGICAL, PARAMETER :: LNH3_WILDLIFE = .true.
|
|
LOGICAL, PARAMETER :: LNH3_BIOFUEL = .false.
|
|
LOGICAL, PARAMETER :: LNH3_FFUEL = .false.
|
|
#if defined( NESTED_SD )
|
|
INTEGER, PARAMETER :: ini_lon = 22
|
|
INTEGER, PARAMETER :: ini_lat = 7
|
|
#else
|
|
INTEGER, PARAMETER :: ini_lon = 1
|
|
INTEGER, PARAMETER :: ini_lat = 1
|
|
#endif
|
|
|
|
|
|
#if defined( NESTED_NA_FAKEVAR )
|
|
|
|
FILENAME = TRIM(DATA_DIR) // 'GEIA_NH3/NH3_GEIA_NA_GC.nc'
|
|
|
|
ENH3_HU(:,:) = 0d0
|
|
ENH3_LS(:,:) = 0d0
|
|
ENH3_FE(:,:) = 0d0
|
|
ENH3_ID(:,:) = 0d0
|
|
ENH3_FF(:,:) = 0d0
|
|
ENH3_BF(:,:) = 0d0
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( Season, fId, "Seasonal_Scaling",
|
|
& (/ ini_lon, ini_lat, MONTH /), (/ IIPAR, JJPAR, 1 /) )
|
|
|
|
CALL NcRd( ENH3_OC, fId, "ocean",
|
|
& (/ ini_lon, ini_lat/), (/ IIPAR, JJPAR /) )
|
|
|
|
CALL NcRd( ENH3_NS, fId, "natural_soil",
|
|
& (/ ini_lon, ini_lat/), (/ IIPAR, JJPAR /) )
|
|
|
|
CALL NcRd( ENH3_WL, fId, "wildlife",
|
|
& (/ ini_lon, ini_lat/), (/ IIPAR, JJPAR /) )
|
|
|
|
|
|
DO I=1,IIPAR
|
|
DO J=1,JJPAR
|
|
|
|
ENH3_WL(I,J) = ENH3_WL(I,J)*SEASON(I,J)
|
|
ENH3_NS(I,J) = ENH3_NS(I,J)*SEASON(I,J)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
|
|
|
|
#else
|
|
|
|
STD(1)=1
|
|
STD(2)=1
|
|
CTD(1)=I1x1
|
|
CTD(2)=J1x1
|
|
|
|
!natural emissions from GEIA include (wild animals, soil under natural vegetation, and ocean)
|
|
!now save under different category
|
|
|
|
FILENAME = TRIM(DATA_DIR_1x1) // 'GEIA_NH3/NH3_GEIA.nc'
|
|
|
|
LLFILENAME = TRIM( DATA_DIR_1x1 ) //
|
|
& 'MAP_A2A_Regrid_201203/MAP_A2A_latlon_geos1x1.nc'
|
|
|
|
!read seasonal variation
|
|
WRITE( 6, 100 ) 'Seasonal Scaling',TRIM( FILENAME )
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
CALL NcRd( Season, fId, "Seasonal_Scaling",
|
|
& (/ 1, 1, MONTH /), (/ I1x1, J1x1, 1 /) )
|
|
|
|
|
|
IF ( LNH3_WILDLIFE ) THEN
|
|
|
|
! Read wildlife
|
|
WRITE( 6, 100 ) 'Wildlife',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "wildlife",std,ctd)
|
|
|
|
DO I=1,I1x1
|
|
DO J=1,J1x1
|
|
DATA(I,J) = SEASON(I,J)*DATA(I,J)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_WL = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_WL)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_WL(:,:) = 0d0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_OCEAN ) THEN
|
|
|
|
! Read wildlife
|
|
WRITE( 6, 100 ) 'Ocean',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "ocean",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_OC = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_OC)*1D-6
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_NATURAL_SOIL ) THEN
|
|
|
|
! Read wildlife
|
|
WRITE( 6, 100 ) 'Natural Soil',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "natural_soil",std,ctd)
|
|
|
|
DO I=1,I1x1
|
|
DO J=1,J1x1
|
|
DATA(I,J) = SEASON(I,J)*DATA(I,J)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_NS = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_NS)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_NS = 0d0
|
|
|
|
ENDIF
|
|
|
|
|
|
IF ( LNH3_HUMAN ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Human',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "human",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_HU = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_HU)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_HU = 0D0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_LIVESTOCK ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Livestock',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "livestock",std,ctd)
|
|
|
|
DO I=1,I1x1
|
|
DO J=1,J1x1
|
|
DATA(I,J) = SEASON(I,J)*DATA(I,J)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_LS = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_LS)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_LS = 0D0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_CROP ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Crop + Fertilizer',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "crop",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
|
|
CALL NcRd( DATA, fId, "fertilizer",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:) + DATA_GRID(:,:,1)
|
|
|
|
DO I=1,I1x1
|
|
DO J=1,J1x1
|
|
DATA_GRID(I,J,1) = SEASON(I,J)*DATA_GRID(I,J,1)
|
|
ENDDO
|
|
ENDDO
|
|
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_FE = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_FE)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_FE = 0D0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_INDUSTRY ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Industry',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "industry",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_ID = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_ID)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_ID = 0D0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_FFUEL ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Fossil Fuel',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "fossil_fuel",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_FF = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_FF)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_FF = 0D0
|
|
|
|
ENDIF
|
|
|
|
IF ( LNH3_BIOFUEL ) THEN
|
|
|
|
WRITE( 6, 100 ) 'Biofuel',TRIM( FILENAME )
|
|
|
|
CALL Ncop_Rd( fId, TRIM(FILENAME) )
|
|
|
|
CALL NcRd( DATA, fId, "biofuel",std,ctd)
|
|
|
|
DATA_GRID(:,:,1) = DATA(:,:)
|
|
|
|
INGRID => DATA_GRID(:,:,1)
|
|
OUTGRID => GEOS_GRID(:,:,1)
|
|
|
|
CALL DO_REGRID_A2A( LLFILENAME,I1x1,J1x1,
|
|
& INGRID, OUTGRID, IS_MASS=1,
|
|
& netCDF=.TRUE. )
|
|
|
|
ENH3_BF = GEOS_GRID(:,:,1)
|
|
|
|
WRITE(6, 101 ) SUM(ENH3_BF)*1D-6
|
|
|
|
ELSE
|
|
|
|
ENH3_BF = 0D0
|
|
|
|
ENDIF
|
|
|
|
CALL NcCl( fId )
|
|
|
|
#endif
|
|
|
|
! Convert from [kg N/box] to [kg NH3/box/s]
|
|
|
|
ENH3_BF = ENH3_BF * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_FF = ENH3_FF * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_FE = ENH3_FE * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_Ls = ENH3_LS * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_HU = ENH3_HU * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_ID = ENH3_ID * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_OC = ENH3_OC * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_NS = ENH3_NS * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
ENH3_WL = ENH3_WL * 17D0/14D0 * 1D0 / (86400D0 * 365D0)
|
|
|
|
IF ( LFUTURE ) THEN
|
|
DO I=1,IIPAR
|
|
DO J=1,JJPAR
|
|
ENH3_HU(I,J) =
|
|
& ENH3_HU(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
|
|
ENH3_FF(I,J) =
|
|
& ENH3_FF(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
|
|
ENH3_FE(I,J) =
|
|
& ENH3_FE(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
|
|
ENH3_LS(I,J) =
|
|
& ENH3_LS(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
|
|
ENH3_ID(I,J) =
|
|
& ENH3_ID(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
|
|
ENDDO
|
|
ENDDO
|
|
ENDIF
|
|
|
|
!for simplicity let's just sum oc,wl, and ns to make the natural fields.
|
|
!this way, adjoint code remains the same elsewhere
|
|
|
|
ENH3_na(:,:) = ENH3_wl(:,:) + ENH3_ns(:,:) + ENH3_oc(:,:)
|
|
|
|
WRITE(*,*) 'na',SUM(ENH3_NA(:,:))
|
|
|
|
|
|
100 FORMAT( ' - GEIA_NH3 ', a ' Reading ', a )
|
|
101 FORMAT( ' => NH3 emissions (GgN/yr): ', f11.4 )
|
|
|
|
END SUBROUTINE READ_GEIA_NH3
|
|
|
|
|
|
SUBROUTINE READ_NATURAL_NH3( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_NATURAL_NH3 reads the monthly mean natural
|
|
! NH3 emissions from disk and converts to [kg NH3/box/s].
|
|
! (rjp, bdf, bmy, 9/20/02, 10/3/05)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated FORMAT string. Now also call READ_BPCH2 with QUIET=.TRUE.
|
|
! (bmy, 4/8/03)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids. (bmy, 8/16/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: XTAU
|
|
REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0,
|
|
& 31d0, 30d0, 31d0, 31d0,
|
|
& 30d0, 31d0, 30d0, 31d0 /)
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_NATURAL_NH3 begins here!
|
|
!=================================================================
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/NH3_natusrce.' //
|
|
& GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_NATURAL_NH3: Reading ', a )
|
|
|
|
! Get TAU value (use year 1990, the year of the data!)
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1990 )
|
|
|
|
! Read 1990 NH3 emissions [kg N/box/mon]
|
|
CALL READ_BPCH2( FILENAME, 'NH3-NATU', 29,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_na )
|
|
|
|
! Convert from [kg N/box/mon] to [kg NH3/box/s]
|
|
ENH3_na = ENH3_na * ( 17.d0 / 14.d0 ) /
|
|
& ( NMDAY(THISMONTH) * 86400.d0 )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_NATURAL_NH3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_BIOFUEL_NH3( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_BIOFUEL_NH3 reads the monthly mean biomass NH3
|
|
! and biofuel emissions from disk and converts to [kg NH3/box/s].
|
|
! (rjp, bdf, bmy, phs, 9/20/02, 12/23/08)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Renamed from NH3_READ to READ_BIOMASS_NH3. Also updated comments,
|
|
! made cosmetic changes. Now reads in both biomass and biofuel
|
|
! emissions. (rjp, bmy, 12/13/02)
|
|
! (2 ) Now replace DXYP(J+J0) with routine GET_AREA_M2 of "grid_mod.f"
|
|
! Now use function GET_YEAR from "time_mod.f". Replace MONTH with
|
|
! THISMONTH when referencing the NMDAY variable. Now call READ_BPCH2
|
|
! with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (3 ) If using interannual biomass emissions, substitute seasonal emissions
|
|
! for years where internannual emissions do not exist. Now also
|
|
! reference GET_TAU from "time_mod.f" (bmy, 5/15/03)
|
|
! (4 ) Now use ENCODE statement for PGI/F90 on Linux (bmy, 9/29/03)
|
|
! (5 ) Changed cpp switch name from LINUX to LINUX_PGI (bmy, 12/2/03)
|
|
! (6 ) Now references DATA_DIR from "directory_mod.f". Now references LBBSEA
|
|
! from "logical_mod.f". Removed references to CMN and CMN_SETUP.
|
|
! (bmy, 7/20/04)
|
|
! (7 ) Now can read either seasonal or interannual biomass burning emissions.
|
|
! Now references routines from both and "time_mod.f". Now reads SO2
|
|
! biomass emissions directly rather than computing it by mole fraction
|
|
! from CO. (rjp, bmy, 1/11/05)
|
|
! (8 ) Now read files from "sulfate_sim_200508/". Now read data for both
|
|
! GCAP and GEOS grids. (bmy, 8/16/05)
|
|
! (9 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
! (10) Now only read the biofuel, we have moved the biomass-reading code to
|
|
! "gc_biomass_mod.f" for compatibility with GFED2 biomass emissions
|
|
! (bmy, 9/27/06)
|
|
! (11) Prevent seg fault error when LBIOMASS=F (bmy, 11/3/06)
|
|
! (12) Renamed READ_BIOFUEL_NH3, and move all biomass code to GET_BIOMASS_NH3
|
|
! to account for several GFED2 products (yc, phs, 12/23/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BIOMASS_MOD, ONLY : BIOMASS, IDBNH3
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_NH3bf
|
|
USE LOGICAL_MOD, ONLY : LBIOMASS, LFUTURE
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE TIME_MOD, ONLY : ITS_A_LEAPYEAR
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH3
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_2D
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISMONTH
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, THISYEAR
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,1)
|
|
REAL*8 :: XTAU, DMASS!, CONV
|
|
REAL*8 :: NMDAY(12) = (/31d0, 28d0, 31d0,
|
|
& 30d0, 31d0, 30d0,
|
|
& 31d0, 31d0, 30d0,
|
|
& 31d0, 30d0, 31d0/)
|
|
CHARACTER(LEN=4 ) :: CYEAR
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_BIOFUEL_NH3 begins here!
|
|
!=================================================================
|
|
|
|
!=================================================================
|
|
! Read NH3 biofuel emissions
|
|
!=================================================================
|
|
|
|
! File name
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/NH3_biofuel.' //
|
|
& GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
|
|
|
|
! Echo output
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_BIOFUEL_NH3: Reading ', a )
|
|
|
|
! Get TAU0 value for 1998
|
|
XTAU = GET_TAU0( THISMONTH, 1, 1998 )
|
|
|
|
! Read NH3 biofuel data [kg NH3/box/month]
|
|
CALL READ_BPCH2( FILENAME, 'BIOFSRCE', 29,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& 1, ARRAY(:,:,1), QUIET=.TRUE. )
|
|
|
|
! Cast from REAL*4 to REAL*8 and resize if necesary
|
|
CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_bf )
|
|
|
|
! Store NH3 in ENH3_bf array [kg NH3/box/s]
|
|
ENH3_bf = ENH3_bf / ( NMDAY(THISMONTH) * 86400.d0 )
|
|
|
|
!=================================================================
|
|
! Convert units and apply IPCC future emissions (if necessary)
|
|
!=================================================================
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!------------------------------------------------------------------
|
|
! Prior to 1/28/09:
|
|
! Need to remove CONV from the PRIVATE statement (bmy, 1/28/09)
|
|
!!$OMP+PRIVATE( I, J, CONV )
|
|
!------------------------------------------------------------------
|
|
!$OMP+PRIVATE( I, J )
|
|
|
|
! Loop over latitudes
|
|
DO J = 1, JJPAR
|
|
|
|
!-- prior 12/23/08
|
|
! ! Conversion factor for [cm2 * kg/molec]
|
|
! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTNH3)
|
|
|
|
! Loop over longitudes
|
|
DO I = 1, IIPAR
|
|
|
|
!-- prior 12/23/08
|
|
! ! Convert biomass NH3 from [molec NH3/cm2/s] -> [kg NH3/s]
|
|
! ! NOTE: Future scale is applied by this point (if necessary)
|
|
! IF ( LBIOMASS ) THEN
|
|
! ENH3_bb(I,J) = BIOMASS(I,J,IDBNH3) * CONV
|
|
! ELSE
|
|
! ENH3_bb(I,J) = 0d0
|
|
! ENDIF
|
|
|
|
! Scale biofuel NH3 to IPCC future scenario (if necessary)
|
|
IF ( LFUTURE ) THEN
|
|
ENH3_bf(I,J) = ENH3_bf(I,J) *
|
|
& GET_FUTURE_SCALE_NH3bf( I, J )
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_BIOFUEL_NH3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE GET_BIOMASS_NH3
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_BIOMASS_NH3 retrieve the monthly/8days/3hr mean biomass NH3
|
|
! (yc, phs, 12/23/08)
|
|
!
|
|
! Arguments as input:
|
|
! ===========================================================================
|
|
! (1 )
|
|
!
|
|
! NOTES:
|
|
! (1 ) Extracted from old module subroutine READ_BIOMASS_NH3
|
|
! (yc, phs, 12/23/08)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BIOMASS_MOD, ONLY : BIOMASS, IDBNH3
|
|
USE GRID_MOD, ONLY : GET_AREA_CM2
|
|
USE TRACER_MOD, ONLY : XNUMOL
|
|
USE TRACERID_MOD, ONLY : IDTNH3
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
INTEGER :: I, J
|
|
REAL*8 :: CONV
|
|
|
|
!=================================================================
|
|
! READ_BIOMASSBURN_NH3 begins here!
|
|
!=================================================================
|
|
! Convert units
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, CONV )
|
|
|
|
! Loop over latitudes
|
|
DO J = 1, JJPAR
|
|
|
|
! Conversion factor for [cm2 * kg/molec]
|
|
CONV = GET_AREA_CM2( J ) / XNUMOL(IDTNH3)
|
|
|
|
! Loop over longitudes
|
|
DO I = 1, IIPAR
|
|
|
|
! Convert biomass NH3 from [molec NH3/cm2/s] -> [kg NH3/s]
|
|
! NOTE: Future scale is applied by this point (if necessary)
|
|
ENH3_bb(I,J) = BIOMASS(I,J,IDBNH3) * CONV
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE GET_BIOMASS_NH3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_OXIDANT( MONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_OXIDANT reads in monthly mean H2O2 and O3 fields for the
|
|
! offline sulfate + aerosol simulation. (rjp, bdf, bmy, 11/1/02, 10/3/05)
|
|
!
|
|
! Arguments as input:
|
|
! ============================================================================
|
|
! (1 ) MONTH (INTEGER ) : Emission timestep in minutes
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
|
|
! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
|
|
! (3 ) Now read files from "sulfate_sim_200508/offline/". Now read data
|
|
! for both GEOS and GCAP grids (bmy, 8/16/05)
|
|
! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : GET_NAME_EXT, GET_RES_EXT
|
|
USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE TRANSFER_MOD, ONLY : TRANSFER_3D_TROP
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: MONTH
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, L, K
|
|
REAL*4 :: ARRAY(IGLOB,JGLOB,LLTROP)
|
|
REAL*8 :: XTAU
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
!=================================================================
|
|
! READ_OXIDANT begins here !
|
|
!
|
|
! Oxidant fields were computed for 1998 using coupled aerosol
|
|
! and gas chemistry GEOS-CHEM by Brendan Field (bdf, 5/23/02).
|
|
! Bob Yantosca has regridded these fields to all GEOS-CHEM grids.
|
|
! Data is saved from the surface to the tropopause.
|
|
!=================================================================
|
|
|
|
! Use generic year 1985
|
|
XTAU = GET_TAU0( MONTH, 1, 1985 )
|
|
|
|
!=================================================================
|
|
! Read monthly mean PH2O2 (from HO2 + HO2 = H2O2) [molec/cm3/s]
|
|
!=================================================================
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/offline/PH2O2.' //
|
|
& GET_NAME_EXT() // '.' // GET_RES_EXT()
|
|
|
|
! Echo filename
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_OXIDANT: Reading ', a )
|
|
|
|
! Read data
|
|
CALL READ_BPCH2( FILENAME, 'PORL-L=$', 5,
|
|
! limit array 3d dimension to LLTROP_FIX, i.e, case of annual mean
|
|
! tropopause. This is backward compatibility with
|
|
! offline data set.
|
|
& XTAU, IGLOB, JGLOB,
|
|
& LLTROP_FIX, ARRAY(:,:,1:LLTROP_FIX), QUIET=.TRUE. )
|
|
! & XTAU, IGLOB, JGLOB,
|
|
! & LLTROP, ARRAY, QUIET=.TRUE. )
|
|
|
|
! Cast to REAL*8 and resize if necessary
|
|
CALL TRANSFER_3D_TROP( ARRAY, PH2O2m )
|
|
|
|
!=================================================================
|
|
! Read monthly mean O3 [v/v]
|
|
!=================================================================
|
|
FILENAME = TRIM( DATA_DIR ) //
|
|
& 'sulfate_sim_200508/offline/O3.' //
|
|
& GET_NAME_EXT() // '.' // GET_RES_EXT()
|
|
|
|
! Echo filename
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
|
|
! Read data
|
|
! limit array 3d dimension to LLTROP_FIX, i.e, case of annual mean
|
|
! tropopause. This is backward compatibility with
|
|
! offline data set.
|
|
CALL READ_BPCH2( FILENAME, 'IJ-AVG-$', 51,
|
|
& XTAU, IGLOB, JGLOB,
|
|
& LLTROP_FIX, ARRAY(:,:,1:LLTROP_FIX), QUIET=.TRUE. )
|
|
! & XTAU, IGLOB, JGLOB,
|
|
! & LLTROP, ARRAY, QUIET=.TRUE. )
|
|
|
|
! Cast to REAL*8 and resize if necessary
|
|
CALL TRANSFER_3D_TROP( ARRAY, O3m )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_OXIDANT
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE OHNO3TIME
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine OHNO3TIME computes the sum of cosine of the solar zenith
|
|
! angle over a 24 hour day, as well as the total length of daylight.
|
|
! This is needed to scale the offline OH and NO3 concentrations.
|
|
! (rjp, bmy, 12/16/02, 3/30/04)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Copy code from COSSZA directly for now, so that we don't get NaN
|
|
! values. Figure this out later (rjp, bmy, 1/10/03)
|
|
! (2 ) Now replace XMID(I) with routine GET_XMID from "grid_mod.f".
|
|
! Now replace RLAT(J) with routine GET_YMID_R from "grid_mod.f".
|
|
! Removed NTIME, NHMSb from the arg list. Now use GET_NHMSb,
|
|
! GET_ELAPSED_SEC, GET_TS_CHEM, GET_DAY_OF_YEAR, GET_GMT from
|
|
! "time_mod.f". (bmy, 3/27/03)
|
|
! (3 ) Now store the peak SUNCOS value for each surface grid box (I,J) in
|
|
! the COSZM array. (rjp, bmy, 3/30/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE GRID_MOD, ONLY : GET_XMID, GET_YMID_R
|
|
USE TIME_MOD, ONLY : GET_NHMSb, GET_ELAPSED_SEC
|
|
USE TIME_MOD, ONLY : GET_TS_CHEM, GET_DAY_OF_YEAR, GET_GMT
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_GCTM"
|
|
|
|
! Local variables
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
INTEGER :: I, IJLOOP, J, L, N, NT, NDYSTEP
|
|
REAL*8 :: A0, A1, A2, A3, B1, B2, B3
|
|
REAL*8 :: LHR0, R, AHR, DEC, TIMLOC, YMID_R
|
|
REAL*8 :: SUNTMP(MAXIJ)
|
|
|
|
!=================================================================
|
|
! OHNO3TIME begins here!
|
|
!=================================================================
|
|
|
|
! Solar declination angle (low precision formula, good enough for us):
|
|
A0 = 0.006918
|
|
A1 = 0.399912
|
|
A2 = 0.006758
|
|
A3 = 0.002697
|
|
B1 = 0.070257
|
|
B2 = 0.000907
|
|
B3 = 0.000148
|
|
R = 2.* PI * float( GET_DAY_OF_YEAR() - 1 ) / 365.
|
|
|
|
DEC = A0 - A1*cos( R) + B1*sin( R)
|
|
& - A2*cos(2*R) + B2*sin(2*R)
|
|
& - A3*cos(3*R) + B3*sin(3*R)
|
|
|
|
LHR0 = int(float( GET_NHMSb() )/10000.)
|
|
|
|
! Only do the following at the start of a new day
|
|
IF ( FIRST .or. GET_GMT() < 1e-5 ) THEN
|
|
|
|
! Zero arrays
|
|
TTDAY(:,:) = 0d0
|
|
TCOSZ(:,:) = 0d0
|
|
COSZM(:,:) = 0d0
|
|
|
|
! NDYSTEP is # of chemistry time steps in this day
|
|
NDYSTEP = ( 24 - INT( GET_GMT() ) ) * 60 / GET_TS_CHEM()
|
|
|
|
! NT is the elapsed time [s] since the beginning of the run
|
|
NT = GET_ELAPSED_SEC()
|
|
|
|
! Loop forward through NDYSTEP "fake" timesteps for this day
|
|
DO N = 1, NDYSTEP
|
|
|
|
! Zero SUNTMP array
|
|
SUNTMP(:) = 0d0
|
|
|
|
! IJLOOP is the 1-D loop index for SUNCOS
|
|
IJLOOP = 0
|
|
|
|
! Loop over surface grid boxes
|
|
DO J = 1, JJPAR
|
|
|
|
! Grid box latitude center [radians]
|
|
YMID_R = GET_YMID_R( J )
|
|
|
|
DO I = 1, IIPAR
|
|
|
|
! Increment IJLOOP
|
|
IJLOOP = IJLOOP + 1
|
|
TIMLOC = real(LHR0) + real(NT)/3600.0 + GET_XMID(I)/15.0
|
|
|
|
DO WHILE (TIMLOC .lt. 0)
|
|
TIMLOC = TIMLOC + 24.0
|
|
ENDDO
|
|
|
|
DO WHILE (TIMLOC .gt. 24.0)
|
|
TIMLOC = TIMLOC - 24.0
|
|
ENDDO
|
|
|
|
AHR = abs(TIMLOC - 12.) * 15.0 * PI_180
|
|
|
|
!===========================================================
|
|
! The cosine of the solar zenith angle (SZA) is given by:
|
|
!
|
|
! cos(SZA) = sin(LAT)*sin(DEC) + cos(LAT)*cos(DEC)*cos(AHR)
|
|
!
|
|
! where LAT = the latitude angle,
|
|
! DEC = the solar declination angle,
|
|
! AHR = the hour angle, all in radians.
|
|
!
|
|
! If SUNCOS < 0, then the sun is below the horizon, and
|
|
! therefore does not contribute to any solar heating.
|
|
!===========================================================
|
|
|
|
! Compute Cos(SZA)
|
|
SUNTMP(IJLOOP) = sin(YMID_R) * sin(DEC) +
|
|
& cos(YMID_R) * cos(DEC) * cos(AHR)
|
|
|
|
! TCOSZ is the sum of SUNTMP at location (I,J)
|
|
! Do not include negative values of SUNTMP
|
|
TCOSZ(I,J) = TCOSZ(I,J) + MAX( SUNTMP(IJLOOP), 0d0 )
|
|
|
|
! COSZM is the peak value of SUMTMP during a day at (I,J)
|
|
! (rjp, bmy, 3/30/04)
|
|
COSZM(I,J) = MAX( COSZM(I,J), SUNTMP(IJLOOP) )
|
|
|
|
! TTDAY is the total daylight time at location (I,J)
|
|
IF ( SUNTMP(IJLOOP) > 0d0 ) THEN
|
|
TTDAY(I,J) = TTDAY(I,J) + DBLE( GET_TS_CHEM() )
|
|
ENDIF
|
|
ENDDO
|
|
ENDDO
|
|
|
|
!### Debug
|
|
!PRINT*, '### IN OHNO3TIME'
|
|
!PRINT*, '### N : ', N
|
|
!PRINT*, '### NDYSTEP : ', NDYSTEP
|
|
!PRINT*, '### NT : ', NT
|
|
!PRINT*, '### JDAY : ', JDAY
|
|
!PRINT*, '### RLAT : ', RLAT
|
|
!PRINT*, '### XMID : ', XMID
|
|
!PRINT*, '### SUNTMP : ', SUNTMP
|
|
!PRINT*, '### TCOSZ : ', MINVAL( TCOSZ ), MAXVAL( TCOSZ )
|
|
!PRINT*, '### TTDAY : ', MINVAL( TCOSZ ), MAXVAL( TCOSZ )
|
|
|
|
! Increment elapsed time [sec]
|
|
NT = NT + ( GET_TS_CHEM() * 60 )
|
|
ENDDO
|
|
|
|
! Reset first-time flag
|
|
FIRST = .FALSE.
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE OHNO3TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE INIT_SULFATE
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine INIT_SULFATE initializes and zeros all allocatable arrays
|
|
! declared in "sulfate_mod.f" (bmy, 6/2/00, 5/23/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Only allocate some arrays for the standalone simulation (NSRCX==10).
|
|
! Also reference NSRCX from "CMN". Now eferences routine ALLOC_ERR
|
|
! from "error_mod.f" ((rjp, bdf, bmy, 10/15/02)
|
|
! (2 ) Now also allocate the IJSURF array to keep the 1-D grid box indices
|
|
! for SUNCOS (for both coupled & offline runs). Now allocate PH2O2m
|
|
! and O3m for offline runs. Also allocate ESO2_bf (bmy, 1/16/03)
|
|
! (3 ) Now allocate ENH3_na array (rjp, bmy, 3/23/03)
|
|
! (4 ) Now allocate COSZM for offline runs (bmy, 3/30/04)
|
|
! (5 ) Now allocate ESO2_sh array (bec, bmy, 5/20/04)
|
|
! (6 ) Now allocates ITS_AN_AEROSOL_SIM from "tracer_mod.f". Now remove
|
|
! IJSURF (bmy, 7/20/04)
|
|
! (7 ) Now locate species in the DEPSAV array here instead of in CHEMSULFATE.
|
|
! Now reference LDRYD from "logical_mod.f". Updated for AS, AHS, LET,
|
|
! SO4aq, NH4aq. (bmy, 1/6/06)
|
|
! (8 ) Now allocates PSO4_ss, PNITs (bec, bmy, 4/13/05)
|
|
! (9 ) Initialize drydep flags outside of IF block (bmy, 5/23/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE DRYDEP_MOD, ONLY : DEPNAME, NUMDEP
|
|
USE ERROR_MOD, ONLY : ALLOC_ERR
|
|
USE LOGICAL_MOD, ONLY : LDRYD
|
|
USE TRACER_MOD, ONLY : ITS_AN_AEROSOL_SIM
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Local variables
|
|
LOGICAL, SAVE :: IS_INIT = .FALSE.
|
|
INTEGER :: AS, I, J, N, IJLOOP
|
|
|
|
!=================================================================
|
|
! INIT_SULFATE begins here!
|
|
!=================================================================
|
|
|
|
! Return if we have already initialized
|
|
IF ( IS_INIT ) RETURN
|
|
|
|
! Allocate arrays
|
|
ALLOCATE( SSTEMP( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'SSTEMP' )
|
|
SSTEMP = 0d0
|
|
|
|
ALLOCATE( DMSo( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'DMSo' )
|
|
DMSo = 0d0
|
|
|
|
ALLOCATE( EEV( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'Eev' )
|
|
Eev = 0d0
|
|
|
|
ALLOCATE( ENV( NNV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENV' )
|
|
ENV = 0d0
|
|
|
|
ALLOCATE( ESO2_ac( IIPAR, JJPAR, LLPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_ac' )
|
|
ESO2_ac = 0d0
|
|
|
|
ALLOCATE( ESO2_an( IIPAR, JJPAR, 2 ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_an' )
|
|
ESO2_an = 0d0
|
|
|
|
ALLOCATE( ESO2_bb( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_bb' )
|
|
ESO2_bb = 0d0
|
|
|
|
ALLOCATE( ESO2_bf( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_bf' )
|
|
ESO2_bf = 0d0
|
|
|
|
ALLOCATE( ESO2_ev( IIPAR, JJPAR, LLPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_ev' )
|
|
ESO2_ev = 0d0
|
|
|
|
ALLOCATE( ESO2_nv( IIPAR, JJPAR, LLPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_nv' )
|
|
ESO2_nv = 0d0
|
|
|
|
ALLOCATE( ESO2_sh( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO2_sh' )
|
|
ESO2_sh = 0d0
|
|
|
|
ALLOCATE( ESO4_an( IIPAR, JJPAR, 2 ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ESO4_an' )
|
|
ESO4_an = 0d0
|
|
|
|
ALLOCATE( IDAYe( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IDAYe' )
|
|
IDAYe = 0d0
|
|
|
|
ALLOCATE( IDAYs( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IDAYs' )
|
|
IDAYs = 0d0
|
|
|
|
ALLOCATE( IELVe( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IELVe' )
|
|
IELVe = 0d0
|
|
|
|
ALLOCATE( IELVn( NNV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IELVn' )
|
|
IELVn = 0d0
|
|
|
|
ALLOCATE( IEV( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IEV' )
|
|
IEV = 0d0
|
|
|
|
ALLOCATE( IHGHT( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'IHGHT' )
|
|
IHGHT = 0d0
|
|
|
|
ALLOCATE( INV( NNV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'INV' )
|
|
INV = 0d0
|
|
|
|
ALLOCATE( JEV( NEV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'JEV' )
|
|
JEV = 0d0
|
|
|
|
ALLOCATE( JNV( NNV ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'JNV' )
|
|
JNV = 0d0
|
|
|
|
ALLOCATE( PMSA_DMS( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PMSA_DMS' )
|
|
PMSA_DMS = 0d0
|
|
|
|
ALLOCATE( PSO2_DMS( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PSO2_DMS' )
|
|
PSO2_DMS = 0d0
|
|
|
|
ALLOCATE( PSO4_SO2( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PSO4_SO2' )
|
|
PSO4_SO2 = 0d0
|
|
|
|
ALLOCATE( PSO4_ss( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PSO4_ss' )
|
|
PSO4_ss = 0d0
|
|
|
|
ALLOCATE( PNITs( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PNITs' )
|
|
PNITs = 0d0
|
|
|
|
ALLOCATE( SOx_SCALE( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'SOx_SCALE' )
|
|
SOx_SCALE = 0d0
|
|
|
|
ALLOCATE( VCLDF( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'VCLDF' )
|
|
VCLDF = 0d0
|
|
|
|
ALLOCATE( ENH3_an( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_an' )
|
|
ENH3_an = 0d0
|
|
|
|
ALLOCATE( ENH3_bb( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_bb' )
|
|
ENH3_bb = 0d0
|
|
|
|
ALLOCATE( ENH3_bf( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_bf' )
|
|
ENH3_bf = 0d0
|
|
|
|
ALLOCATE( ENH3_na( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_na' )
|
|
ENH3_na = 0d0
|
|
|
|
ALLOCATE( ENH3_fe( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_fe' )
|
|
ENH3_fe = 0d0
|
|
|
|
ALLOCATE( ENH3_ff( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_ff' )
|
|
ENH3_ff = 0d0
|
|
|
|
ALLOCATE( ENH3_hu( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_hu' )
|
|
ENH3_hu = 0d0
|
|
|
|
ALLOCATE( ENH3_id( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_id' )
|
|
ENH3_id = 0d0
|
|
|
|
ALLOCATE( ENH3_ls( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_ls' )
|
|
ENH3_ls = 0d0
|
|
|
|
ALLOCATE( ENH3_ns( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_ns' )
|
|
ENH3_ns = 0d0
|
|
|
|
ALLOCATE( ENH3_oc( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_oc' )
|
|
ENH3_oc = 0d0
|
|
|
|
ALLOCATE( ENH3_wl( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ENH3_wl' )
|
|
ENH3_wl = 0d0
|
|
|
|
!=================================================================
|
|
! Only initialize the following for offline aerosol simulations
|
|
!=================================================================
|
|
IF ( ITS_AN_AEROSOL_SIM() ) THEN
|
|
|
|
ALLOCATE( PH2O2m( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'PH2O2m' )
|
|
PH2O2m = 0d0
|
|
|
|
ALLOCATE( O3m( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'O3m' )
|
|
O3m = 0d0
|
|
|
|
ALLOCATE( JH2O2( IIPAR, JJPAR, LLTROP ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'JH2O' )
|
|
JH2O2 = 0d0
|
|
|
|
ALLOCATE( TCOSZ( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'TCOSZ' )
|
|
TCOSZ = 0d0
|
|
|
|
ALLOCATE( TTDAY( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'TTDAY' )
|
|
TTDAY = 0d0
|
|
|
|
ALLOCATE( COSZM( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'COSZM' )
|
|
COSZM = 0d0
|
|
ENDIF
|
|
|
|
!================================================================
|
|
! Find drydep species in the DEPSAV array
|
|
!=================================================================
|
|
|
|
! Initialize flags
|
|
DRYH2O2 = 0
|
|
DRYSO2 = 0
|
|
DRYSO4 = 0
|
|
DRYSO4s = 0
|
|
DRYMSA = 0
|
|
DRYNH3 = 0
|
|
DRYNH4 = 0
|
|
DRYNIT = 0
|
|
DRYSO4s = 0
|
|
DRYAS = 0
|
|
DRYAHS = 0
|
|
DRYLET = 0
|
|
DRYSO4aq = 0
|
|
DRYNH4aq = 0
|
|
|
|
IF ( LDRYD ) THEN
|
|
|
|
! Locate position of each tracer in DEPSAV
|
|
DO N = 1, NUMDEP
|
|
SELECT CASE ( TRIM( DEPNAME(N) ) )
|
|
CASE ( 'H2O2' )
|
|
DRYH2O2 = N
|
|
CASE ( 'SO2' )
|
|
DRYSO2 = N
|
|
CASE ( 'SO4' )
|
|
DRYSO4 = N
|
|
CASE ( 'SO4S' )
|
|
DRYSO4s = N
|
|
CASE ( 'MSA' )
|
|
DRYMSA = N
|
|
CASE ( 'NH3' )
|
|
DRYNH3 = N
|
|
CASE ( 'NH4' )
|
|
DRYNH4 = N
|
|
CASE ( 'NIT' )
|
|
DRYNIT = N
|
|
CASE ( 'NITS' )
|
|
DRYNITs = N
|
|
CASE ( 'AS' )
|
|
DRYAS = N
|
|
CASE ( 'AHS' )
|
|
DRYAHS = N
|
|
CASE ( 'LET' )
|
|
DRYLET = N
|
|
CASE ( 'SO4aq' )
|
|
DRYSO4aq = N
|
|
CASE ( 'NH4aq' )
|
|
DRYNH4aq = N
|
|
CASE DEFAULT
|
|
! Nothing
|
|
END SELECT
|
|
ENDDO
|
|
|
|
ENDIF
|
|
|
|
! Reset IS_INIT so we do not allocate arrays again
|
|
IS_INIT = .TRUE.
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE INIT_SULFATE
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CLEANUP_SULFATE
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CLEANUP_SULFATE deallocates all previously allocated arrays
|
|
! for sulfate emissions -- call at the end of the run (bmy, 6/1/00, 5/3/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now also deallocates IJSURF. (bmy, 11/12/02)
|
|
! (2 ) Now also deallocates ENH3_na (rjp, bmy, 3/23/03)
|
|
! (3 ) Now also deallocates COSZM (rjp, bmy, 3/30/04)
|
|
! (4 ) Now also deallocates ESO4_sh (bec, bmy, 5/20/04)
|
|
! (5 ) Now remove IJSURF (bmy, 7/20/04)
|
|
! (6 ) Bug fix: now deallocate PSO4_ss, PNITs (bmy, 5/3/06)
|
|
!******************************************************************************
|
|
!
|
|
!=================================================================
|
|
! CLEANUP_SULFATE begins here!
|
|
!=================================================================
|
|
IF ( ALLOCATED( DMSo ) ) DEALLOCATE( DMSo )
|
|
IF ( ALLOCATED( EEV ) ) DEALLOCATE( EEV )
|
|
IF ( ALLOCATED( ENV ) ) DEALLOCATE( ENV )
|
|
IF ( ALLOCATED( ENH3_an ) ) DEALLOCATE( ENH3_an )
|
|
IF ( ALLOCATED( ENH3_bb ) ) DEALLOCATE( ENH3_bb )
|
|
IF ( ALLOCATED( ENH3_bf ) ) DEALLOCATE( ENH3_bf )
|
|
IF ( ALLOCATED( ENH3_na ) ) DEALLOCATE( ENH3_na )
|
|
IF ( ALLOCATED( ESO2_ac ) ) DEALLOCATE( ESO2_ac )
|
|
IF ( ALLOCATED( ESO2_an ) ) DEALLOCATE( ESO2_an )
|
|
IF ( ALLOCATED( ESO2_nv ) ) DEALLOCATE( ESO2_nv )
|
|
IF ( ALLOCATED( ESO2_ev ) ) DEALLOCATE( ESO2_ev )
|
|
IF ( ALLOCATED( ESO2_bb ) ) DEALLOCATE( ESO2_bb )
|
|
IF ( ALLOCATED( ESO2_bf ) ) DEALLOCATE( ESO2_bf )
|
|
IF ( ALLOCATED( ESO2_sh ) ) DEALLOCATE( ESO2_sh )
|
|
IF ( ALLOCATED( ESO4_an ) ) DEALLOCATE( ESO4_an )
|
|
IF ( ALLOCATED( IDAYs ) ) DEALLOCATE( IDAYs )
|
|
IF ( ALLOCATED( IDAYe ) ) DEALLOCATE( IDAYe )
|
|
IF ( ALLOCATED( IELVe ) ) DEALLOCATE( IELVe )
|
|
IF ( ALLOCATED( IELVn ) ) DEALLOCATE( IELVn )
|
|
IF ( ALLOCATED( IEV ) ) DEALLOCATE( IEV )
|
|
IF ( ALLOCATED( IHGHT ) ) DEALLOCATE( IHGHT )
|
|
IF ( ALLOCATED( INV ) ) DEALLOCATE( INV )
|
|
IF ( ALLOCATED( JEV ) ) DEALLOCATE( JEV )
|
|
IF ( ALLOCATED( JH2O2 ) ) DEALLOCATE( JH2O2 )
|
|
IF ( ALLOCATED( JNV ) ) DEALLOCATE( JNV )
|
|
IF ( ALLOCATED( O3m ) ) DEALLOCATE( O3m )
|
|
IF ( ALLOCATED( PH2O2m ) ) DEALLOCATE( PH2O2m )
|
|
IF ( ALLOCATED( PMSA_DMS ) ) DEALLOCATE( PMSA_DMS )
|
|
IF ( ALLOCATED( PNITs ) ) DEALLOCATE( PNITs )
|
|
IF ( ALLOCATED( PSO2_DMS ) ) DEALLOCATE( PSO2_DMS )
|
|
IF ( ALLOCATED( PSO4_SO2 ) ) DEALLOCATE( PSO4_SO2 )
|
|
IF ( ALLOCATED( PSO4_ss ) ) DEALLOCATE( PSO4_ss )
|
|
IF ( ALLOCATED( SOx_SCALE ) ) DEALLOCATE( SOx_SCALE )
|
|
IF ( ALLOCATED( SSTEMP ) ) DEALLOCATE( SSTEMP )
|
|
IF ( ALLOCATED( TCOSZ ) ) DEALLOCATE( TCOSZ )
|
|
IF ( ALLOCATED( TTDAY ) ) DEALLOCATE( TTDAY )
|
|
IF ( ALLOCATED( VCLDF ) ) DEALLOCATE( VCLDF )
|
|
IF ( ALLOCATED( COSZM ) ) DEALLOCATE( COSZM )
|
|
IF ( ALLOCATED( ENH3_oc ) ) DEALLOCATE( ENH3_oc )
|
|
IF ( ALLOCATED( ENH3_wl ) ) DEALLOCATE( ENH3_wl )
|
|
IF ( ALLOCATED( ENH3_fe ) ) DEALLOCATE( ENH3_fe )
|
|
IF ( ALLOCATED( ENH3_ff ) ) DEALLOCATE( ENH3_ff )
|
|
IF ( ALLOCATED( ENH3_hu ) ) DEALLOCATE( ENH3_hu )
|
|
IF ( ALLOCATED( ENH3_ls ) ) DEALLOCATE( ENH3_ls )
|
|
IF ( ALLOCATED( ENH3_id ) ) DEALLOCATE( ENH3_id )
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CLEANUP_SULFATE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
END MODULE SULFATE_MOD
|