! $Id: sulfate_mod.f,v 1.36 2007/03/29 20:31:23 bmy Exp $
MODULE SULFATE_MOD 3
!
!******************************************************************************
! 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, 12/8/06)
!
! 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_BIOMASS_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) isoropia_mod.f : Module w/ ISORROPIA 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_BIOMASS_SO2 (bmy, 11/3/06)
! (39) Bug fix in SEASALT_CHEM (havala, bec, bmy, 12/8/06)
!******************************************************************************
!
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
!=================================================================
! 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 :: 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*8, 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 2,8
!
!******************************************************************************
! 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 ) 2
!
!******************************************************************************
! 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 2,47
!
!******************************************************************************
! 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 ) 2,12
!
!******************************************************************************
! 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)
!******************************************************************************
!
! 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
REAL*8 :: RCM, RWET, RATIO_R, RHO
REAL*8 :: TOT1, TOT2
REAL*8 :: VTS(LLPAR)
REAL*8 :: TC0(LLPAR)
! 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
! 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
! Exponential factors
FAC1 = C1 * ( RCM**C2 )
FAC2 = C3 * ( RCM**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+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 )
! Aerosol growth with relative humidity in radius [m]
! (Gerber, 1985)
RWET = 0.01d0*(FAC1/(FAC2-DLOG(RHB))+RCM**3.d0)**0.33d0
! 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
! 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 1,16
!
!******************************************************************************
! 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)
!******************************************************************************
!
! 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
RK2 = 1.2d-11 * EXP( -260.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
XOH = ( DMS0 - DMS_OH ) / 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 1,25
!
!******************************************************************************
! 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 1,31
!
!******************************************************************************
! 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)
!******************************************************************************
!
! 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 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
# 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 :: 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!
!=================================================================
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
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 )
!$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)
! 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
! 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)
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 )
! 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)
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]
PSO4_SO2(I,J,L) = L1 + L2S + L3S + PSO4E
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, 1,15
& 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, 12/8/06)
!
! 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)
!******************************************************************************
!
! 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 ISOROPIA_MOD
, ONLY : GET_GNO3
# 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
! Get gas-phase HNO3 from ISORROPIA code
CALL GET_GNO3
( I, J, L, HNO3_kg )
! 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 = TITR_HNO3 * 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, 1
& 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 1,16
!
!******************************************************************************
! 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 1,12
!
!******************************************************************************
! 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)
!******************************************************************************
!
! 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
# 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
!$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
!===============================================================
! 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 1,12
!
!******************************************************************************
! 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 1,12
!
!******************************************************************************
! 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,12
!
!******************************************************************************
! 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 1,13
!
!******************************************************************************
! 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 2,29
!
!******************************************************************************
! 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)
!******************************************************************************
!
! References to F90 modules
USE LOGICAL_MOD
, ONLY : LSHIPSO2
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
# 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 ( LENV ) CALL READ_NONERUP_VOLC
IF ( LEEV ) CALL READ_ERUP_VOLC
! 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 )
CALL READ_AIRCRAFT_SO2
( MONTH )
CALL READ_BIOMASS_SO2
( MONTH )
CALL READ_ANTHRO_SOx
( MONTH, NSEASON )
CALL READ_ANTHRO_NH3
( MONTH )
CALL READ_BIOMASS_NH3
( MONTH )
CALL READ_NATURAL_NH3
( MONTH )
! Also read ship exhaust SO2 if necessary
IF ( LSHIPSO2 ) CALL READ_SHIP_SO2
( MONTH )
! Read oxidants for the offline simulation only
IF ( ITS_AN_AEROSOL_SIM
() ) CALL READ_OXIDANT
( MONTH )
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 ) CALL SRCSO4
( STT(:,:,:,IDTSO4) )
IF ( IDTNH3 /= 0 ) CALL SRCNH3
( STT(:,:,:,IDTNH3) )
! Return to calling program
END SUBROUTINE EMISSSULFATE
!-----------------------------------------------------------------------------
SUBROUTINE SRCDMS( TC ) 1,11
!
!*****************************************************************************
! 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 ) 1,28
!
!******************************************************************************
! Subroutine SRCSO2 (originally from Mian Chin) computes SO2 emissons from
! aircraft, biomass, and anthro sources. (rjp, bdf, bmy, 6/2/00, 6/26/06)
!
! 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)
!******************************************************************************
!
! Reference to diagnostic arrays
USE BRAVO_MOD
, ONLY : GET_BRAVO_ANTHRO, GET_BRAVO_MASK
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 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
USE TRACER_MOD
, ONLY : XNUMOL
USE TRACERID_MOD
, ONLY : IDTSO2
# 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
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)
! 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
()
! 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
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, AREA_CM2, AN, BF )
!$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
!-----------------------------------------------------------
! 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
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
! 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)
! 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
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)
IF ( LSHIPSO2 ) SO2(1) = SO2(1) + ESO2_sh(I,J)
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
! 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)
IF ( LSHIPSO2 ) THEN
AD13_SO2_sh(I,J) = AD13_SO2_sh(I,J) +
& ( ESO2_sh(I,J) * S_SO2 * DTSRCE )
ENDIF
! 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
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE SRCSO2
!-----------------------------------------------------------------------------
SUBROUTINE SRCSO4( TC ) 1,20
!
!******************************************************************************
! 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)
!******************************************************************************
!
! Reference to diagnostic arrays
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
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 TRACER_MOD
, ONLY : XNUMOL
USE TRACERID_MOD
, ONLY : IDTSO4
# 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
REAL*8 :: SO4(LLPAR), DTSRCE
REAL*8 :: TSO4, FEMIS
REAL*8 :: AREA_CM2, EPA_AN, EPA_BF
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
()
! Is it a weekday?
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
!=================================================================
! Overwrite USA w/ EPA/NEI99 SO4 emissions (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 )
DO J = 1, JJPAR
! Grid box surface area [cm2]
AREA_CM2 = GET_AREA_CM2
(J)
DO I = 1, IIPAR
! 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 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)
ELSE
! If we are not over the USA, then just use the regular
! emissions from ESO4_an. Also set biofuel SO4 to zero
! since we currently don't read this in. (bmy, 11/16/04)
SO4an(I,J,1) = ESO4_an(I,J,1)
SO4an(I,J,2) = ESO4_an(I,J,2)
SO4bf(I,J) = 0d0
ENDIF
ELSE
! If we are not using EPA/NEI99 emissions, then just copy
! ESO4_an into ESO4 array. Also set biofuel SO4 to zero
! since we currently don't read this in. (bmy, 11/16/04)
SO4an(I,J,1) = ESO4_an(I,J,1)
SO4an(I,J,2) = ESO4_an(I,J,2)
SO4bf(I,J) = 0d0
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 ) 1,16
!
!******************************************************************************
! 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)
!******************************************************************************
!
! References to F90 modules
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 : LNEI99
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 TRACER_MOD
, ONLY : XNUMOL
USE TRACERID_MOD
, ONLY : IDTNH3
# 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
REAL*8 :: FEMIS, DTSRCE, TNH3
REAL*8 :: AREA_CM2, EPA_AN, EPA_BF
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 )
!=================================================================
! Overwrite USA with EPA/NEI NH3 emissions (if necessary)
! Store emissions into local arrays NH3an, NH3bf
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!-----------------------------------------------------------------------------
! 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)
!!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF )
!-----------------------------------------------------------------------------
!$OMP+PRIVATE( I, J )
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)
!-----------------------------------------------------------------
! 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
!-----------------------------------------------------------------
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]
TNH3 = NH3an(I,J) + ENH3_bb(I,J) +
& NH3bf(I,J) + ENH3_na(I,J)
!==============================================================
! 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
! 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
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE SRCNH3
!------------------------------------------------------------------------------
FUNCTION GET_OH( I, J, L ) RESULT( OH_MOLEC_CM3 ) 5,26
!
!******************************************************************************
! 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 ) 1,2
!
!******************************************************************************
! 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 ) 2,20
!
!******************************************************************************
! 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 ) 1,2
!
!******************************************************************************
! 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 ) 3,25
!
!******************************************************************************
! 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 1,7
!
!******************************************************************************
! 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 1,7
!
!*****************************************************************************
! 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 ) 1,33
!
!******************************************************************************
! Suborutine READ_ANTHRO_SOx reads the anthropogenic SOx from disk,
! and partitions it into anthropogenic SO2 and SO4.
! (rjp, bdf, bmy, 9/20/02, 8/17/06)
!
! 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)
!******************************************************************************
!
! 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 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
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
# 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
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 ( LEDGARSOx ) 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, EDG_SO2, Fe )
! Loop over latitudes
DO J = 1, JJPAR
! 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. )
! 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,
& 26, 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)
!=================================================================
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
!==============================================================
! 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
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, 26,
& KG_S=.TRUE. )
! Zero 2nd level of emissions
ESO2_an(I,J,2) = 0d0
ENDIF
ENDIF
! 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)
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
ENDIF
! Return to calling program
END SUBROUTINE READ_ANTHRO_SOx
!------------------------------------------------------------------------------
SUBROUTINE READ_OCEAN_DMS( THISMONTH ) 1,8
!
!*****************************************************************************
! 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 ) 1,11
!
!*****************************************************************************
! 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)
!*****************************************************************************
!
! 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!
!==================================================================
IF ( THISYEAR >= 1985 .and. THISYEAR <= 2004 ) 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_BIOMASS_SO2( THISMONTH ) 1,17
!
!******************************************************************************
! Subroutine READ_BIOMASS_SO2 reads monthly mean biomass burning
! emissions for SO2. SOx is read in, and converted to SO2.
! (rjp, bdf, bmy, 1/16/03, 10/3/06)
!
! 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)
!******************************************************************************
!
! 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)
REAL*8 :: CONV, 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_BIOMASS_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_BIOMASS_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 )
!$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
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_BIOMASS_SO2
!------------------------------------------------------------------------------
SUBROUTINE READ_AIRCRAFT_SO2( THISMONTH ) 1,8
!
!******************************************************************************
! Subroutine READ_AIRCRAFT_SO2 reads monthly mean aircraft fuel emissions
! and converts them to SO2 emissions.