Files
GEOS-Chem-adjoint-v35-note/code/adjoint/sulfate_adj_mod.f
2025-10-08 21:56:36 +08:00

7274 lines
270 KiB
Fortran

! $Id: sulfate_adj_mod.f,v 1.8 2012/09/05 22:35:07 yanko Exp $
MODULE SULFATE_ADJ_MOD
!
!******************************************************************************
! Module SULFATE_MOD contains arrays and routines for performing either a
! coupled chemistry/aerosol run or an offline sulfate aerosol simulation.
! Original code taken from Mian Chin's GOCART model and modified accordingly.
! (rjp, bdf, bmy, 6/22/00, 10/31/08)
!
! Module Variables:
! ============================================================================
! (1 ) XNUMOL_OH (REAL*8 ) : Molecules OH per kg OH [molec/kg]
! (2 ) XNUMOL_O3 (REAL*8 ) : Molecules O3 per kg O3 [molec/kg]
! (3 ) XNUMOL_NO3 (REAL*8 ) : Molecules NO3 per kg NO3 [molec/kg]
! (4 ) TCVV_S (REAL*8 ) : Ratio: Molwt air / Molwt S [unitless]
! (5 ) DMSo (REAL*8 ) : DMS oceanic emissions [v/v/timestep]
! (6 ) DRYH2O2 (INTEGER) : Pointer to H2O2 in DEPVEL array [unitless]
! (7 ) DRYSO2 (INTEGER) : Pointer to SO2 in DEPVEL array [unitless]
! (8 ) DRYSO4 (INTEGER) : Pointer to SO4 in DEPVEL array [unitless]
! (9 ) DRYSO4s (INTEGER) : Pointer to SO4s in DEPVEL array [unitless]
! (10) DRYMSA (INTEGER) : Pointer to MSA in DEPVEL array [unitless]
! (11) DRYNH3 (INTEGER) : Pointer to NH3 in DEPVEL array [unitless]
! (12) DRYNH4 (INTEGER) : Pointer to NH4 in DEPVEL array [unitless]
! (13) DRYNIT (INTEGER) : Pointer to NIT in DEPVEL array [unitless]
! (14) DRYNITs (INTEGER) : Pointer to NITs in DEPVEL array [unitless]
! (15) DRYSO4aq (INTEGER) : Pointer to SO4aq in DEPVEL array [unitless]
! (16) DRYAS (INTEGER) : Pointer to AS in DEPVEL array [unitless]
! (17) DRYAHS (INTEGER) : Pointer to AHS in DEPVEL array [unitless]
! (18) DRYLET (INTEGER) : Pointer to LET in DEPVEL array [unitless]
! (19) DRYNH4aq (INTEGER) : Pointer to NH4aq in DEPVEL array [unitless]
! (20) ENH3_an (REAL*8 ) : NH3 anthropogenic emissions [kg NH3/box/s]
! (21) ENH3_bb (REAL*8 ) : NH3 biomass emissions [kg NH3/box/s]
! (22) ENH3_bf (REAL*8 ) : NH3 biofuel emissions [kg NH3/box/s]
! (23) ENH3_na (REAL*8 ) : NH73 natural source emissions [kg NH3/box/s]
! (24) ESO2_ac (REAL*8 ) : SO2 aircraft emissions [kg SO2/box/s]
! (25) ESO2_an (REAL*8 ) : SO2 anthropogenic emissions [kg SO2/box/s]
! (26) ESO2_ev (REAL*8 ) : SO2 eruptive volcanic em. [kg SO2/box/s]
! (27) ESO2_nv (REAL*8 ) : SO2 non-eruptive volcanic em. [kg SO2/box/s]
! (28) ESO2_bb (REAL*8 ) : SO2 biomass burning emissions [kg SO2/box/s]
! (29) ESO2_bf (REAL*8 ) : SO2 biofuel burning emissions [kg SO2/box/s]
! (30) ESO2_sh (REAL*8 ) : SO2 ship emissions [kg SO2/box/s]
! (31) ESO4_an (REAL*8 ) : SO4 anthropogenic emissions [kg SO4/box/s]
! (32) JH2O2 (REAL*8 ) : Monthly mean J(H2O2) values [s-1]
! (33) O3m (REAL*8 ) : Monthly mean O3 concentration [v/v]
! (34) PH2O2m (REAL*8 ) : Monthly mean P(H2O2) [molec/cm3/s]
! (35) PMSA_DMS (REAL*8 ) : P(MSA) from DMS [v/v/timestep]
! (36) PSO2_DMS (REAL*8 ) : P(SO2) from DMS [v/v/timestep]
! (37) PSO4_SO2 (REAL*8 ) : P(SO4) from SO2 [v/v/timestep]
! (38) SSTEMP (REAL*8 ) : Sea surface temperatures [K]
! (39) VCLDF (REAL*8 ) : Volume cloud frac. for SO2 aq. [unitless]
! (40) NEV (INTEGER) : Max # of eruptive volcanoes [unitless]
! (41) IEV (INTEGER) : Longitudes of eruptive volcanoes [degrees]
! (42) JEV (INTEGER) : Latitudes of eruptive volcanoes [degrees ]
! (43) IHGHT (INTEGER) : Height of eruptive volcano plume [m]
! (44) IELVe (INTEGER) : Elevation of eruptive volcanoes [m]
! (45) Eev (REAL*8 ) : SO2 em. from eruptive volcanoes [kg SO2/box/s]
! (46) NNV (INTEGER) : Max # of non-eruptive volcanoes [unitless]
! (47) NNVOL (INTEGER) : Number of non-eruptive volcanoes [unitless]
! (48) INV (INTEGER) : Longitude of non-erup volcanoes [degrees]
! (49) JNV (INTEGER) : Latitude of non-erup volcanoes [degrees]
! (50) IELVn (INTEGER) : Elevation of non-erup volcanoes [m]
! (51) Env (INTEGER) : SO2 em. from non-erup volcanoes [kg SO2/box/s]
! (52) TCOSZ (REAL*8 ) : Sum of cos(SZA) for offline run [unitless]
! (53) TTDAY (REAL*8 ) : Total daylight length at (I,J) [minutes]
! (54) SMALLNUM (REAL*8 ) : Small number - prevent underflow [unitless]
! (55) COSZM (REAL*8 ) : Array for MAX(cos(SZA)) at (I,J) [unitless]
!
! Module Routines:
! ===========================================================================
! (1 ) GET_VCLDF : Computes volume cloud fraction for SO2 chemistry
! (2 ) GET_LWC : Computes liquid water content as a function of T
! (3 ) CHEMSULFATE : Driver routine for sulfate/aerosol chemistry
! (4 ) GRAV_SETTLING : Routine to compute settling of SO4s and NITs
! (5 ) CHEM_DMS : Chemistry routine for DMS tracer
! (6 ) CHEM_H2O2 : Chemistry routine for H2O2 tracer
! (7 ) CHEM_SO2 : Chemistry routine for SO2 tracer
! (8 ) SEASALT_CHEM : Computes SO2->SO4 and HNO3->nitrate w/in seasalt
! (9 ) AQCHEM_SO2 : Computes reaction rates for aqueous SO2 chemistry
! (10) CHEM_SO4 : Chemistry routine for SO4 tracer
! (11) PHASE_SO4 : Computes phase transition for crystalline tracers
! (12) PHASE_RADIATIVE : Computes radiative forcing for crystalline tracers
! (13) CHEM_MSA : Chemistry routine for MSA tracer
! (14) CHEM_NH3 : Chemistry routine for ammonia tracer
! (15) CHEM_NH4 : Chemistry routine for ammonium tracer
! (16) CHEM_NIT : Chemistry routine for nitrates tracer
! (17) EMISSSULFATE : Driver routine for sulfate/aerosol emissions
! (18) SRCDMS : Emission routine for DMS tracer
! (19) SRCSO2 : Emission routine for SO2 tracer
! (20) SRCSO4 : Emission routine for SO4 tracer
! (21) SRCNH3 : Emission routine for NH3 tracer
! (22) GET_OH : Returns OH for coupled or offline simulations
! (23) SET_OH : Resets modified OH in SMVGEAR's CSPEC array
! (24) GET_NO3 : Returns NO3 for coupled or offline simulations
! (25) SET_NO3 : Resets modified OH in SMVGEAR's CSPEC array
! (26) GET_O3 : Returns O3 for coupled or offline simulations
! (27) READ_NONERUP_VOLC : Reads SO2 emissions from non-eruptive volcanoes
! (28) READ_ERUP_VOLC : Reads SO2 emissions from eruptive volcanoes
! (29) READ_ANTHRO_SOx : Reads anthropogenic SO2 and SO4 emissions
! (30) READ_OCEAN_DMS : Reads biogenic DMS emissions from oceans
! (31) READ_SST : Reads monthly mean sea-surface temperatures
! (32) READ_BIOFUEL_SO2 : Reads SO2 emissions from biomass burning
! (33) READ_AIRCRAFT_SO2 : Reads SO2 emissions from aircraft exhaust
! (34) READ_SHIP_SO2 : Reads SO2 emissions from ship exhaust
! (35) READ_ANTHRO_NH3 : Reads NH3 emissions from anthropogenic sources
! (36) READ_NATURAL_NH3 : Reads NH3 emissions from natural sources
! (37) READ_BIOMASS_NH3 : Reads NH3 biomass burning emissions
! (38) READ_OXIDANT : Reads monthly mean O3 and H2O2 for offline run
! (39) OHNO3TIME : Computes time arrays for scaling offline OH, NO3
! (40) INIT_SULFATE : Allocates & zeroes module arrays
! (41) CLEANUP_SULFATE : Deallocates module arrays
!
! GEOS-CHEM modules referenced by sulfate_mod.f
! ============================================================================
! (1 ) biomass_mod.f : Module w/ routines for biomass burning
! (2 ) bpch2_mod.f : Module w/ routines for binary pch file I/O
! (3 ) bravo_mod.f : Module w/ routines to read BRAVO emissions
! (4 ) comode_mod.f : Module w/ SMVGEAR allocatable arrays
! (5 ) dao_mod.f : Module w/ DAO met field arrays
! (6 ) diag_mod.f : Module w/ GEOS-Chem diagnostic arrays
! (7 ) directory_mod.f : Module w/ GEOS-Chem data & met field dirs
! (8 ) drydep_mod.f : Module w/ GEOS-Chem dry deposition routines
! (9 ) epa_nei_mod.f : Module w/ routines to read EPA/NEI99 data
! (10) error_mod.f : Module w/ NaN, other error check routines
! (11) file_mod.f : Module w/ file unit numbers & error checks
! (12) future_emissions_mod.f : Module w/ routines for IPCC future emissions
! (13) grid_mod.f : Module w/ horizontal grid information
! (14) global_no3_mod.f : Module w/ routines to read 3-D NO3 field
! (15) global_oh_mod.f : Module w/ routines to read 3-D OH field
! (16) isoropiaii_adj_mod.f : Module w/ 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_BIOFUEL_SO2 (bmy, 11/3/06)
! (39) Bug fix in SEASALT_CHEM (havala, bec, bmy, 12/8/06)
! (40) Extra error check for low RH in GRAV_SETTLING (phs, 6/11/08)
! (41) Now references "cac_anthro_mod.f". And apply SO2 yearly scale factor
! to SO2 from GEIA (amv, phs, 3/11/08)
! (41) Bug fixes in reading EDGAR data w/ the right tracer number,
! when we are doing offline or nonstd simulations (dkh, 10/31/08)
! (42) Bug fix for AD13_SO2_sh in SRCSO2 (phs, 2/27/09)
!******************************************************************************
!
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_ADJ
PUBLIC :: CLEANUP_SULFATE_ADJ
PUBLIC :: EMISSSULFATE_ADJ
!=================================================================
! 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 :: VCLDF(:,:,:)
REAL*8, ALLOCATABLE :: ADPSO4_SO2(:,:,:)
! Eruptive volcanoes
INTEGER, PARAMETER :: NEV=50
INTEGER :: NEVOL
INTEGER, ALLOCATABLE :: IEV(:), JEV(:)
INTEGER, ALLOCATABLE :: IDAYs(:), IDAYe(:)
INTEGER, ALLOCATABLE :: IHGHT(:), IELVe(:)
REAL*8, ALLOCATABLE :: EEV(:)
! Non-eruptive volcanoes
INTEGER, PARAMETER :: NNV=50
INTEGER :: NNVOL
INTEGER, ALLOCATABLE :: INV(:), JNV(:), IELVn(:)
REAL*8, ALLOCATABLE :: ENV(:)
! Pointers to drydep species w/in DEPSAV
INTEGER :: DRYSO2, DRYSO4, DRYMSA, DRYNH3
INTEGER :: DRYNH4, DRYNIT, DRYSO4s, DRYNITs
INTEGER :: DRYH2O2, DRYSO4aq, DRYAS, DRYAHS
INTEGER :: DRYLET, DRYNH4aq
!=================================================================
! MODULE ROUTINES -- follow below the "CONTAINS" statement
!=================================================================
CONTAINS
!------------------------------------------------------------------------------
SUBROUTINE GET_VCLDF
!
!******************************************************************************
! Subroutine GET_VCLDF computes the volume cloud fraction for SO2 chemistry.
! (rjp, bdf, bmy, 9/23/02)
!
! References:
! ============================================================================
! (1) Sundqvist et al. [1989]
!
! NOTES:
!******************************************************************************
!
! References to F90 modules
USE DAO_MOD, ONLY : RH
USE PRESSURE_MOD, ONLY : GET_PCENTER, GET_PEDGE
# include "CMN_SIZE" ! Size parameters
! Local variables
INTEGER :: I, J, L
REAL*8 :: PRES, PSFC, RH2, R0, B0
! Parameters
REAL*8, PARAMETER :: ZRT = 0.60d0, ZRS = 0.99d0
!=================================================================
! GET_VCLDF begins here!
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, PSFC, PRES, RH2, R0, B0 )
DO L = 1, LLTROP
DO J = 1, JJPAR
DO I = 1, IIPAR
! Surface pressure
PSFC = GET_PEDGE(I,J,1)
! Pressure at the center of the grid box
PRES = GET_PCENTER(I,J,L)
! RH (from "dao_mod.f") is relative humidity [%]
! Convert to fraction and store in RH2
RH2 = RH(I,J,L) * 1.0d-2
! Terms from Sundqvist ???
R0 = ZRT + ( ZRS - ZRT ) * EXP( 1d0 - ( PSFC / PRES )**2.5 )
B0 = ( RH2 - R0 ) / ( 1d0 - R0 )
! Force B0 into the range 0-1
IF ( RH2 < R0 ) B0 = 0d0
IF ( B0 > 1d0 ) B0 = 1d0
! Volume cloud fraction
VCLDF(I,J,L) = 1d0 - SQRT( 1d0 - B0 )
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE GET_VCLDF
!------------------------------------------------------------------------------
FUNCTION GET_LWC( T ) RESULT( LWC )
!
!******************************************************************************
! Function GET_LWC returns the cloud liquid water content at a GEOS-CHEM
! grid box as a function of temperature. (rjp, bmy, 10/31/02, 1/14/03)
!
! Arguments as Input:
! ============================================================================
! (1 ) T (REAL*8) : Temperature value at a GEOS-CHEM grid box [K]
!
! NOTES:
!******************************************************************************
!
! Arguments
REAL*8, INTENT(IN) :: T
! Function value
REAL*8 :: LWC
!=================================================================
! GET_LWC begins here!
!=================================================================
! Compute Liquid water content in [g/m3]
IF ( T > 293d0 ) THEN
LWC = 0.2d0
ELSE IF ( T >= 280.d0 .AND. T <= 293.d0 ) THEN
LWC = 0.32d0 - 0.0060d0 * ( T - 273.D0 )
ELSE IF ( T >= 248.d0 .AND. T < 280.d0 ) THEN
LWC = 0.23d0 + 0.0065d0 * ( T - 273.D0 )
ELSE IF ( T < 248.d0 ) THEN
LWC = 0.07d0
ENDIF
! Convert from [g/m3] to [m3/m3]
LWC = LWC * 1.D-6
! Return to calling program
END FUNCTION GET_LWC
!------------------------------------------------------------------------------
SUBROUTINE CHEMSULFATE_ADJ
!******************************************************************************
! Subroutine CHEMSULFATE_ADJ is the interface between the GEOS-CHEM main program
! and the adjoint sulfate chemistry routines. This version only supports
! full chemistry. (dkh, 10/12/05)
!
! It is attempted to be as similar as possible to the forward
! routine CHEMSULFATE (rjp, bdf, bmy, 5/31/00, 3/16/06)
!
! NOTES:
! (1 ) Now we call ADJ_CHEM_xxx rather than computing the adjoint chemistry
! routines directly. (dkh, 10/12/05)
! (2 ) Recalculate VCLDF. (dkh, 08/27/06)
! (3 ) Updated to GCv8 adjoint (dkh, 09/27/09)
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
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 ERROR_MOD, ONLY : ERROR_STOP
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_ADJ 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_ADJ
! Reset first-time flag
FIRSTCHEM = .FALSE.
ENDIF
! If it's an offline simulation ...
IF ( ITS_AN_AEROSOL_SIM() ) THEN
CALL ERROR_STOP('offline aerosol not supported in adjoint',
& 'sulfate_adj_mod.f')
!
! ! 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 adjoint module arrays
!PSO2_DMS = 0d0
!PMSA_DMS = 0d0
!PSO4_SO2 = 0d0
!PSO4_SS = 0d0
!PNITs = 0d0
ADPSO4_SO2 = 0d0
!=================================================================
! Call individual chemistry routines for sulfate/aerosol tracers
!=================================================================
! Redo forward model unit conversion
! Convert all tracers in STT from [kg] -> [v/v]
CALL CONVERT_UNITS( 1, N_TRACERS, TCVV, AD, STT )
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CONV UNIT 1 ')
! fwd code:
!! Convert STT from [v/v] -> [kg]
!CALL CONVERT_UNITS( 2, N_TRACERS, TCVV, AD, STT )
! adj code:
CALL CONVERT_UNITS( 2, N_TRACERS, TCVV, AD, STT_ADJ )
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CONV UNIT 2 ')
! fwd code:
!CALL CHEM_NIT
! adj code:
CALL CHEM_NIT_ADJ
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CHEM_NIT_ADJ ' )
! fwd code:
!CALL CHEM_NH4
! adj code:
CALL CHEM_NH4_ADJ
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CHEM_NH4_ADJ ' )
! fwd code:
!CALL CHEM_NH3
! adj code:
CALL CHEM_NH3_ADJ
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CHEM_NH3_ADJ ' )
! fwd code:
!CALL CHEM_MSA
! adj code:
CALL CHEM_MSA_ADJ
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CHEM_MSA_ADJ ' )
! fwd code:
!CALL CHEM_SO4
! adj code:
CALL CHEM_SO4_ADJ
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CHEM_SO4_ADJ ' )
! SO2
! added in v16 of GCv6 adj (dkh, 08/27/06)
CALL GET_VCLDF
IF ( LPRT )
& CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a GET_VCLDF ' )
! fwd code:
!CALL CHEM_SO2
! adj code:
CALL CHEM_SO2_ADJ
! Redo forward model unit conversion
! Convert STT from [v/v] -> [kg]
CALL CONVERT_UNITS( 2, N_TRACERS, TCVV, AD, STT )
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CONV UNIT 3 ')
! We have already gone thru one chemistry iteration
FIRSTCHEM = .FALSE.
! For offline runs only ...
IF ( ITS_AN_AEROSOL_SIM() ) THEN
CALL ERROR_STOP('offline aerosol not supported in adjoint',
& 'sulfate_adj_mod.f')
! fwd code:
!! H2O2 (offline only)
!CALL CHEM_H2O2
!IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_H2O2' )
! adj code:
! fwd code:
!! DMS (offline only)
!CALL CHEM_DMS
!IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: a CHEM_DMS' )
! adj code:
ENDIF
! fwd code:
!! Convert all tracers in STT from [kg] -> [v/v]
!CALL CONVERT_UNITS( 1, N_TRACERS, TCVV, AD, STT )
! adj code:
CALL CONVERT_UNITS( 1, N_TRACERS, TCVV, AD, STT_ADJ )
IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE_ADJ: a CONV UNIT 4 ')
! fwd code:
!! NITs [kg] gravitational settling
!CALL GRAV_SETTLING( STT(:,:,:,IDTNITs), 2 )
!IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: GRAV_SET, NITS' )
! adj code:
print*, ' WARNING: no adjoint of NITs gravitational settling'
! fwd code:
!! SO4s [kg] gravitational settling
!CALL GRAV_SETTLING( STT(:,:,:,IDTSO4s), 1 )
!IF ( LPRT ) CALL DEBUG_MSG( '### CHEMSULFATE: GRAV_SET, SO4S' )
! adj code:
print*, ' WARNING: no adjoint of SO4s gravitational settling'
! Return to calling program
END SUBROUTINE CHEMSULFATE_ADJ
!!------------------------------------------------------------------------------
!!
!
! SUBROUTINE GRAV_SETTLING( TC, N )
!!
!!******************************************************************************
!! Subroutine GRAV_SETTLING performs gravitational settling of sulfate
!! and nitrate in coarse sea salt (SO4S and NITS).
!! (bec, rjp, bmy, 4/20/04, 7/20/04, 10/25/05)
!!
!! Arguments as Input:
!! ============================================================================
!! (1 ) TC (REAL*8 ) : Tracer [kg]
!! (2 ) N (INTEGER) : N=1 is SO4S; N=2 is NITS
!!
!! Arguments as Output:
!! ============================================================================
!! (1 ) TC (REAL*8 ) : Contains modified tracer
!!
!! NOTES:
!! (1 ) Now references SALA_REDGE_um and SALC_REDGE_um from "tracer_mod.f"
!! (bmy, 7/20/04)
!! (2 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
!! (3 ) Now limit relative humidity to [tiny(real*8),0.99] range for DLOG
!! argument (phs, 5/1/08)
!!******************************************************************************
!!
! ! 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 )
!
! ! Safety check (phs, 5/1/08)
! RHB = MAX( TINY(RHB), RHB )
!
! ! Aerosol growth with relative humidity in radius [m]
! ! (Gerber, 1985)
! RWET = 0.01d0*(FAC1/(FAC2-DLOG(RHB))+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
!!
!!******************************************************************************
!! 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
!!
!!******************************************************************************
!! 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_ADJ
!
!******************************************************************************
! Subroutine CHEM_SO2_ADJ is the adjoint of the SO2 chemistry subroutine
! (dkh, 10/11/05)
!
! Based on forward model subroutine CHEM_SO2 (rjp, bmy, 11/26/02, 10/25/05)
!
! NOTES:
! (1 ) Now reference WETSCAV_MOD instead of WETSCAV_ADJ_MOD. (dkh, 10/24/05)
! (2 ) BUG FIX Add ADL3S to list of PRIVATE variables. (dkh, 10/08/06)
! (3 ) BUG FIX Initialize ADL3S to zero. (dkh, 01/25/07)
! (4 ) Updated to GCv8 adj (dkh, 09/27/09)
! (5 ) Several bugs fixed (Jamin, Daven)
! (6 ) Watch for L3 = 1d0 (dkh, 01/06/12, adj32_005)
! (7 ) Add support for dry deposition (fp)
!******************************************************************************
!
! Reference to diagnostic arrays
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD
USE CHECKPT_MOD, ONLY : SO2_CHK
USE CHECKPT_MOD, ONLY : H2O2_CHK
USE DAO_MOD, ONLY : AD, AIRDEN, T
USE DIAG_MOD, ONLY : AD05, AD44
USE DRYDEP_MOD, ONLY : DEPSAV
USE DIRECTORY_MOD, ONLY : DATA_DIR
USE ERROR_MOD, ONLY : ERROR_STOP
USE ERROR_MOD, ONLY : IS_SAFE_DIV
USE ERROR_MOD, ONLY : IS_SAFE_EXP
USE ERROR_MOD, ONLY : IT_IS_NAN
USE GLOBAL_HNO3_MOD, ONLY : GET_GLOBAL_HNO3
USE GRID_MOD, ONLY : GET_AREA_CM2
USE LOGICAL_ADJ_MOD, ONLY : LPRINTFD
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 WETSCAV_ADJ_MOD, ONLY : H2O2s_ADJ, SO2s_ADJ
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
!support for dry deposition of so2
USE LOGICAL_ADJ_MOD, ONLY : LMAX_OBS, LADJ_DDEP_TRACER
USE ADJ_ARRAYS_MOD, ONLY : GET_CF_REGION, ADJOINT_AREA_M2
USE ADJ_ARRAYS_MOD, ONLY : OBS_THIS_TRACER, DEP_UNIT
USE ADJ_ARRAYS_MOD, ONLY : NSPAN, TR_DDEP_CONV
# include "CMN_SIZE" ! Size parameters
# include "CMN_GCTM" ! AIRMW
! 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 :: XX_ADJ
REAL*8 :: XX
REAL*8 :: tmp1, tmp2
!for dry deposition forcing
REAL*8, SAVE :: NTSCHEM
REAL*8, SAVE :: FACT
LOGICAL :: FORCE
LOGICAL, SAVE :: FIRST = .TRUE.
INTEGER, SAVE :: OBS_COUNT = 0
! Parameters
REAL*8, PARAMETER :: HPLUS = 3.16227766016837953d-5 !pH = 4.5
REAL*8, PARAMETER :: MINDAT = 1.d-20
C==============================================
C define local TAMC generated variables
C==============================================
real*8 adh2o20
real*8 adl1
real*8 adl2
real*8 adl2s
real*8 adl3
real*8 adl3s
real*8 ado3
real*8 adso20
real*8 adso2_cd
!=================================================================
! CHEM_SO2_ADJ begins here!
!=================================================================
IF ( IDTH2O2 == 0 .or. IDTSO2 == 0 .or. DRYSO2 == 0 ) RETURN
!determine if it is time to apply deposition forcing
FORCE = .FALSE.
IF ( LMAX_OBS ) THEN
OBS_COUNT = OBS_COUNT + 1
IF ( OBS_COUNT <= NSPAN
& .and. LADJ_DDEP_TRACER
& .and. OBS_THIS_TRACER(IDTSO2) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'SO2' , TRIM( DEP_UNIT )
ENDIF
ELSEIF ( LADJ_DDEP_TRACER .and. OBS_THIS_TRACER(IDTSO2) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'SO2' , TRIM( DEP_UNIT )
ENDIF
100 FORMAT('Forcing ',a,' drydep (', a,')')
! DTCHEM is the chemistry timestep in seconds
DTCHEM = GET_TS_CHEM() * 60d0
! initialize some constants for depostion forcing
IF ( FORCE .and. FIRST ) THEN
! here we aren't assuming that TS_CHEM is necessarily 1 hr
NTSCHEM = NSPAN / ( GET_TS_CHEM() / 60D0 )
!default is molec/cm2/s
FACT = XNUMOL(IDTSO2) / DTCHEM
& / TCVV(IDTSO2) / NTSCHEM
FIRST = .FALSE.
ENDIF
! 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
! 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
! 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+PRIVATE( ADH2O20, ADL1, ADL2, ADL2S, ADL3, ADO3, ADSO20, ADSO2_CD)
!$OMP+PRIVATE( ADL3S )
!$OMP+PRIVATE( XX, XX_ADJ, TMP1, TMP2 )
!$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 = SO2_CHK(I,J,L)
H2O20 = H2O2_CHK(I,J,L)
O3 = GET_O3(I,J,L)
! Initialize local adjoint variables.
! Note: O3 influences sulfate chemistry but not vice versa, hence
! we initialize ADO3 to zeroo here and update the global array
! later. Also, adpso4_so2 got it's initial value during
! ADJ_CHEM_SO4. adso2s(:,:,:) and adh2o2s(:,:,:) get their
! values from adj_wetdep
! ( would it be faster to intialize them to zero outside the loop
! and then declare them FIRSTPRIVATE ? )
ADO3 = 0d0
ADL1 = 0d0
ADL2 = 0d0
ADL2S = 0d0
ADL3S = 0d0
ADL3 = 0d0
ADSO20 = 0d0
ADH2O20 = 0D0
ADSO2_CD = 0d0
XX_ADJ = 0d0
!---------------------------------------------------------
! Initialize parameters not affected by active variables
!---------------------------------------------------------
! 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
! Not yet supported in adjoint:
!! 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)
!
CALL ERROR_STOP(' IS_OFFLINE ', 'sulfate_adj_mod.f')
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
! 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
C----------------------------------------------
C ROUTINE BODY
C----------------------------------------------
! dkh debug
IF ( LPRINTFD .and. I == IFD .and.
& J == JFD .and. L == LFD ) THEN
print*, ' ADJ_CHEM_SO2: rk1, rk2, rk ! ' , rk1, rk2, rk
ENDIF
if (rk .gt. 0.d0) then
so2_cd = so20*exp(-rkt)
else
so2_cd = so20
endif
! adjoint skips sea salt sulfate, so copy SO2_cd directly into SO2_ss
SO2_ss = SO2_cd
adl1 = adl1+adpso4_so2(i,j,l)
adl2s = adl2s+adpso4_so2(i,j,l)
adl3s = adl3s+adpso4_so2(i,j,l)
adpso4_so2(i,j,l) = 0.d0
! Initialize with global arrays above. "in" and "out"
! were just dummy variables used to create the adjoint code.
!adpso4_so2(i,j,l) = adpso4_so2(i,j,l)+adout(3)
!adout(3) = 0.
!adso2s(i,j,l) = adso2s(i,j,l)+adout(2)
!!adout(2) = 0.
!adh2o2s(i,j,l) = adh2o2s(i,j,l)+adout(1)
!adout(1) = 0.
SO2s_ADJ(I,J,L) = SO2s_ADJ(I,J,L) + STT_ADJ(I,J,L,IDTSO2)
STT_ADJ(I,J,L,IDTSO2) = 0d0
H2O2s_ADJ(I,J,L) = H2O2s_ADJ(I,J,L) + STT_ADJ(I,J,L,IDTH2O2)
STT_ADJ(I,J,L,IDTH2O2) = 0d0
if (fc .gt. 0.d0 .and. so2_cd .gt. mindat .and. tk .gt. 258.) then
! Strange, though true, this routine's output, kaqh2o2 and
! kaqo3, don't actually depend upon h2o20 or o3 !
call aqchem_so2( lwc,tk,patm,so2_cd,h2o20,o3,hplus,kaqh2o2,
$kaqo3 )
! Argument of the exponential
XX = ( SO2_ss - O3 ) * KaqO3 * DTCHEM
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 ) THEN
! Aqueous phase SO2 loss rate w/ O3 [v/v/timestep]
L3 = EXP( XX )
! Loss by O3
L3S = SO2_ss * O3 * (L3 - 1.D0) / ((SO2_ss * L3) - O3)
ELSE
! Follow the same logic for L3S as described in
! Jintai Lin's note above (bmy, 4/28/10)
IF ( XX > 0.d0 ) THEN
L3S = O3
ELSE
L3S = SO2_ss
ENDIF
ENDIF
! fwd:
!SO2s( I,J,L) = SO2_ss
!H2O2s(I,J,L) = H2O20
! adj:
!adh2o20 = adh2o20+adh2o2s(i,j,l)
!adh2o2s(i,j,l) = 0.d0
adh2o20 = adh2o20+H2O2s_ADJ(i,j,l)
H2O2s_ADJ(i,j,l) = 0.d0
!adso2_cd = adso2_cd+adso2s(i,j,l)
!adso2s(i,j,l) = 0.d0
adso2_cd = adso2_cd+SO2s_ADJ(i,j,l)
SO2s_ADJ(i,j,l) = 0.d0
! fwd:
!SO2_ss = MAX( SO2_ss - ( L2S + L3S ), MINDAT )
!H2O20 = MAX( H2O20 - L2S, MINDAT )
! adj:
adl2s = adl2s-adh2o20*(0.5+sign(0.5d0,h2o20-l2s-mindat))
adh2o20 = adh2o20*(0.5+sign(0.5d0,h2o20-l2s-mindat))
adl2s = adl2s-adso2_cd*
& (0.5+sign(0.5d0,so2_cd-(l2s+l3s)-mindat))
adl3s = adl3s-adso2_cd*
& (0.5+sign(0.5d0,so2_cd-(l2s+l3s)-mindat))
adso2_cd = adso2_cd*
& (0.5+sign(0.5d0,so2_cd-(l2s+l3s)-mindat))
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 .and.
& ( SO2_CD * L3 - O3 ) .ne. 0d0 ) THEN
! fwd:
!L3S = SO2_ss * O3 * (L3 - 1.D0) / ((SO2_ss * L3) - O3)
! adj: original TAMC code
! adl3 = adl3+adl3s*(so2_cd*o3/(so2_cd*l3-o3)-so2_cd*o3*(l3-1.d0)*
! $so2_cd/((so2_cd*l3-o3)*(so2_cd*l3-o3)))
! ado3 = ado3+adl3s*(so2_cd*(l3-1.d0)/(so2_cd*l3-o3)+so2_cd*o3*
! $(l3-1.d0)/((so2_cd*l3-o3)*(so2_cd*l3-o3)))
! adso2_cd = adso2_cd+adl3s*(o3*(l3-1.d0)/(so2_cd*l3-o3)-so2_cd*
! $o3*(l3-1.d0)*l3/((so2_cd*l3-o3)*(so2_cd*l3-o3)))
! adj: numerically stable code avoids L3^2 terms.
TMP1 = ( L3 - 1D0 ) / ( SO2_cd * L3 - O3 )
TMP2 = 1D0 / ( SO2_cd * L3 - O3 )
ADO3 = ADO3 + ADL3S *
& ( SO2_cd * TMP1 + SO2_cd * O3 * TMP1 * TMP2 )
ADL3 = ADL3 + ADL3S *
& ( SO2_CD * O3 * TMP2
& - SO2_CD * O3 * SO2_cd * TMP1 * TMP2 )
ADSO2_cd = ADSO2_cd + ADL3S *
& ( O3 * TMP1
& - SO2_cd * O3 * L3 * TMP1 * TMP2 )
! dkh debug
IF ( LPRINTFD .and. I == IFD .and.
& J == JFD .and. L == LFD ) THEN
print*, ' ADJ_CHEM_SO2: adl3s = ', adl3s
print*, ' ADJ_CHEM_SO2: adl3 = ', adl3
print*, ' ADJ_CHEM_SO2: ado3 = ', ado3
print*, ' ADJ_CHEM_SO2: adso2_cd = ', adso2_cd
print*, ' ADJ_CHEM_SO2: L3 = ', L3
print*, ' ADJ_CHEM_SO2: SO2_SS = ', SO2_SS, SO2_cd
print*, ' ADJ_CHEM_SO2: O3 = ', O3
ENDIF
ADL3S = 0.d0
! fwd:
!L3 = EXP( XX )
! adj:
XX_ADJ = XX_ADJ + ADL3 * L3
ADL3 = 0d0
ELSE
! Follow the same logic for L3S as described in
! Jintai Lin's note above (bmy, 4/28/10)
IF ( XX > 0.d0 ) THEN
! fwd:
!L3S = O3
! adj:
ADO3 = ADO3 + ADL3S
ADL3S = 0d0
ELSE
! fwd:
!L3S = SO2_ss
! adj:
ADSO2_CD = ADSO2_CD + ADL3S
ADL3S = 0d0
ENDIF
ENDIF
! fwd:
!XX = ( SO2_ss - O3 ) * KaqO3 * DTCHEM
! adj:
ADSO2_CD = ADSO2_CD + XX_ADJ * KaqO3 * DTCHEM
ADO3 = ADO3 - XX_ADJ * KaqO3 * DTCHEM
! dkh debug
IF ( LPRINTFD .and. I == IFD .and.
& J == JFD .and. L == LFD ) THEN
print*, ' ADJ_CHEM_SO2: ADSO2_CD = ', ADSO2_CD
print*, ' ADJ_CHEM_SO2: XX_ADJ = ', XX_ADJ
ENDIF
XX_ADJ = 0d0
! Argument of the exponential
XX = ( SO2_ss - H2O20 ) * KaqH2O2 * DTCHEM
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 ) THEN
! Aqueous phase SO2 loss rate w/ H2O2 [v/v/timestep]
L2 = EXP( XX )
! Loss by H2O2
L2S = SO2_ss * H2O20 * ( L2 - 1.D0 ) /
& ( (SO2_ss * L2) - H2O20 )
ELSE
! NOTE from Jintai Lin (4/28/10):
! However, in the case of a negative XX, L2S should be
! approximated as SO2_ss, instead of H2O20. In other words,
! L2S = SO2_ss * H2O20 * ( L2 - 1.D0 ) / ( (SO2_ss*L2) - H2O20 )
! reaches different limits when XX reaches positive infinity
! and negative infinity.
IF ( XX > 0.d0 ) THEN
L2S = H2O20
ELSE
L2S = SO2_ss
ENDIF
ENDIF
IF ( IS_SAFE_EXP( XX ) .and. ABS( XX ) > 0d0 .and.
& (SO2_CD * L2 - H2O20) .ne. 0d0 ) THEN
! fwd:
!L2S = SO2_ss * H2O20 * ( L2 - 1.D0 ) /
! ( (SO2_ss * L2) - H2O20 )
! adj: original TAMC code
! adh2o20 = adh2o20+adl2s*(so2_cd*(l2-1.d0)/(so2_cd*l2-h2o20)+
! $so2_cd*h2o20*(l2-1.d0)/((so2_cd*l2-h2o20)*(so2_cd*l2-h2o20)))
! adl2 = adl2+adl2s*(so2_cd*h2o20/(so2_cd*l2-h2o20)-so2_cd*h2o20*
! $(l2-1.d0)*so2_cd/((so2_cd*l2-h2o20)*(so2_cd*l2-h2o20)))
! adso2_cd = adso2_cd+adl2s*(h2o20*(l2-1.d0)/(so2_cd*l2-h2o20)-
! $so2_cd*h2o20*(l2-1.d0)*l2/((so2_cd*l2-h2o20)*(so2_cd*l2-h2o20)))
! adj: numerically stable code avoids L2^2 terms.
TMP1 = ( L2 - 1D0 ) / ( SO2_cd * L2 - H2O20 )
TMP2 = 1D0 / ( SO2_cd * L2 - H2O20 )
ADH2O20 = ADH2O20 + ADL2S *
& ( SO2_cd * TMP1 + SO2_cd * H2O20 * TMP1 * TMP2 )
ADL2 = ADL2 + ADL2S *
& ( SO2_CD * H2O20 * TMP2
& - SO2_CD * H2O20 * SO2_cd * TMP1 * TMP2 )
ADSO2_cd = ADSO2_cd + ADL2S *
& ( H2O20 * TMP1
& - SO2_cd * H2O20 * L2 * TMP1 * TMP2 )
! dkh debug
IF ( LPRINTFD .and. I == IFD .and.
& J == JFD .and. L == LFD ) THEN
print*, ' ADJ_CHEM_SO2: adl2s = ', adl2s
print*, ' ADJ_CHEM_SO2: adh2o20 = ', adh2o20
print*, ' ADJ_CHEM_SO2: adl2 = ', adl2
print*, ' ADJ_CHEM_SO2: adso2_cd = ', adso2_cd
print*, ' ADJ_CHEM_SO2: SO2_ss = ', SO2_ss, so2_cd
print*, ' ADJ_CHEM_SO2: H2O20 = ', H2O20
print*, ' ADJ_CHEM_SO2: L2 = ', L2
ENDIF
ADL2S = 0.d0
! fwd:
!L2 = EXP( XX )
! adj:
XX_ADJ = XX_ADJ + ADL2 * L2
ADL2 = 0d0
ELSE
! and negative infinity.
IF ( XX > 0.d0 ) THEN
! fwd:
!L2S = H2O20
! adj:
ADH2O20 = ADH2O20 + ADL2S
ADL2S = 0d0
ELSE
! fwd:
!L2S = SO2_ss
! adj:
ADSO2_CD = ADSO2_CD + ADL2S
ADL2S = 0d0
ENDIF
ENDIF
! fwd:
!XX = ( SO2_ss - H2O20 ) * KaqH2O2 * DTCHEM
! adj:
ADSO2_CD = ADSO2_CD + XX_ADJ * KaqH2O2 * DTCHEM
ADH2O20 = ADH2O20 - XX_ADJ * KaqH2O2 * DTCHEM
XX_ADJ = 0d0
!-------------------------------------------------------------------------
else
! adso2_cd = adso2_cd+adso2s(i,j,l)*(0.5+sign(0.5d0,so2_cd-1.d-32)
! $)
! adso2s(i,j,l) = 0.d0
adso2_cd = adso2_cd+SO2s_ADJ(i,j,l)*
&(0.5+sign(0.5d0,so2_cd-1.d-32))
SO2s_ADJ(i,j,l) = 0.d0
!adh2o20 = adh2o20+adh2o2s(i,j,l)*(0.5+sign(0.5d0,h2o20-1.d-32))
!adh2o2s(i,j,l) = 0.d0
adh2o20 = adh2o20+H2O2s_ADJ(i,j,l)
& *(0.5+sign(0.5d0,h2o20-1.d-32))
H2O2s_ADJ(i,j,l) = 0.d0
! dkh debug
IF ( LPRINTFD .and. I == IFD .and.
& J == JFD .and. L == LFD ) THEN
print*, ' ADJ_CHEM_SO2: no aqchem ! '
ENDIF
endif
if (rk .gt. 0.d0) then
adso20 = adso20+adl1*(rk1/rk)
adso2_cd = adso2_cd-adl1*(rk1/rk)
adl1 = 0.d0
adso20 = adso20+adso2_cd*exp(-rkt)
adso2_cd = 0.d0
!fp
if (force) then
adso20 = adso20
& + (1D0 - exp(-rk2*dtchem))
& * AD(I,J,L)*FACT/GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTSO2)
endif
else
adso20 = adso20+adso2_cd
adso2_cd = 0.d0
!no forcing since no dry deposition (fp)
endif
IF ( IT_IS_NAN( ADSO20 ) .or. IT_IS_NAN( ADH2O20 ) ) THEN
print*, ' CHEM_SO2_ADJ error '
print*, ' ADSO20 = ', ADSO20
print*, ' ADH2O20 = ', ADH2O20
print*, ' SO2_ss = ', SO2_ss
print*, ' H2O20 = ', H2O20
print*, ' XX = ', ( SO2_ss - H2O20 ) * KaqH2O2 * DTCHEM
print*, ' I, J, L = ', I, J, L
CALL ERROR_STOP( 'sulfate_adj_mod.f', 'chem_so2_adj')
ENDIF
! Update global adjoint arrays and reset local variables to zero.
! ADJ_STT(IDADJSO2) should be zero at this point, as it will be zeroed
! after passing off values to ADSO2s ? -- NO, they both coexist. H2O2s
! and SO2s are just control variables. The actual running concentrations
! are kept in STT.
STT_ADJ(I,J,L,IDTSO2) = STT_ADJ(I,J,L,IDTSO2) + ADSO20
STT_ADJ(I,J,L,IDTH2O2) = STT_ADJ(I,J,L,IDTH2O2) + ADH2O20
CALL GET_O3_ADJ( ADO3, I, J, L )
ado3 = 0.d0
adh2o20 = 0.d0
adso20 = 0.d0
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_SO2_ADJ
!------------------------------------------------------------------------------
!
! SUBROUTINE SEASALT_CHEM ( I, J, L, ALK1, ALK2,
! & SO2_cd, Kt1, Kt2, Kt1N, Kt2N,
! & SO2_ss, PSO4E, PSO4F )
!!
!!******************************************************************************
!! Function SEASALT_CHEM computes SO4 formed from S(IV) + O3 on seasalt
!! aerosols as a function of seasalt alkalinity. (bec, bmy, 4/13/05, 10/7/08)
!!
!! Arguments as Input:
!! ============================================================================
!! (1 ) I (INTEGER) :
!! (2 ) J (INTEGER) :
!! (3 ) L (INTEGER) :
!! (4 ) O30 (REAL*8) : Initial O3 mixing ratio (v/v]
!! (5 ) ALK (REAL*8) : Alkalinity [kg] from seasalt from seasalt_mod
!! (6 ) SO2_cd (REAL*8) : SO2 mixing ratio [v/v] after gas phase chemistry
!! and dry deposition
!! (7 ) Kt1 (REAL*8) : Rate constant [s-1] for sulfate formation on
!! fine sea-salt aerosols from GET_ALK
!! (8 ) Kt2 (REAL*8) : Rate constant [s-1] for sulfate formation on
!! coarse sea-salt aerosols from GET_ALK
!!
!! Arguments as Output:
!! ============================================================================
!! (9 ) SO2_ss (REAL*8) : SO2 mixing ratio [v/v] updated after SS chemistry
!! (10) SO4E (REAL*8) : SO4E (sulfate produced by S(IV)+O3 on fine seasalt)
!! mixing ratio [v/v]
!! (11) SO4F (REAL*8) : SO4F(sulfate produced by S(IV)+O3 on coarse seasalt)
!! mixing ratio [v/v]
!! (12) O3 (REAL*8) : Updated O3 mixing ratio [v/v] for fullchem runs
!! only. Otherwise O30=O3.
!!
!! Chemical reactions:
!! ============================================================================
!! (R1) SO2 + O3 + ALK => SO4 + O2
!! Modeled after Chamedies and Stelson, 1992?
!!
!! NOTES:
!! (1 ) Now references XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
!! (2 ) Bug fix: now avoid seg fault error if IDTHNO3 is zero, as it would
!! be for an offline aerosol simulation. (bmy, 3/29/06)
!! (3 ) Fixed typo in FALK_A_SO2 equation: C_FLUX_C should be C_FLUX_A.
!! (havala, bec, bmy, 12/8/06)
!! (4 ) Bug fix for mass balance, replace TITR_HNO3 w/ HNO3_SSC in the
!! expression for HNO3_ss. Bug fix: now do equivalent computation
!! for GET_GNO3, which is now no longer called because it's in
!! "isoropiaii_adj_mod.f". (bec, bmy, 7/30/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME
! USE DAO_MOD, ONLY : AD, AIRDEN, AIRVOL
! USE TRACERID_MOD
! !----------------------------------------------------------------
! ! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
! !USE DIAG_MOD, ONLY : AD09
! !----------------------------------------------------------------
! USE ERROR_MOD, ONLY : GEOS_CHEM_STOP
! USE TIME_MOD, ONLY : GET_TS_CHEM, GET_ELAPSED_SEC
! USE ERROR_MOD, ONLY : IT_IS_NAN
! USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, STT
! USE TRACER_MOD, ONLY : TCVV, XNUMOLAIR
! USE GLOBAL_HNO3_MOD, ONLY : GET_HNO3_UGM3
! USE TIME_MOD, ONLY : GET_ELAPSED_SEC, GET_MONTH
! USE TIME_MOD, ONLY : ITS_A_NEW_MONTH
! USE ISOROPIAII_ADJ_MOD, ONLY : GET_GNO3
!
! ! Add these for GET_GNO3 fix (lyj, bmy, 10/7/08)
! USE GLOBAL_HNO3_MOD, ONLY : GET_HNO3_UGM3
! USE DAO_MOD, ONLY : AIRVOL
!
!# include "CMN_SIZE" ! Size parameters
!!---------------------------------------------------------------
!! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
!!# include "CMN_DIAG" ! ND19
!!---------------------------------------------------------------
!# include "CMN_GCTM" ! AIRMW
!
! ! Arguments
! INTEGER, INTENT(IN) :: I, J, L
! REAL*8, INTENT(IN) :: SO2_cd, Kt1, Kt2, Kt1N, Kt2N
! REAL*8, INTENT(IN) :: ALK1, ALK2
! REAL*8, INTENT(OUT) :: SO2_ss, PSO4E, PSO4F
!
! ! Local variables
! INTEGER :: JLOOP
! REAL*8 :: SO2_chem, DTCHEM
! REAL*8 :: O3_cspec, O3_lost
! REAL*8 :: EQ_1_C, EQ_2_C
! REAL*8 :: SO4E, SO2_new, SO4F
! REAL*8 :: SO2_eq, N_FLUX_A, N_FLUX_C
! REAL*8 :: END_ALK, L5A, L5C
! REAL*8 :: EQ1, EQ2, TITR_SO2
! REAL*8 :: TITR_HNO3, NIT_vv, NITs_vv
! REAL*8 :: NIT0, NITS0
! REAL*8 :: F_SO2, FALK_A_SO2, FALK_C_SO2
! REAL*8 :: EQ_BEG, F_SO2_A, F_SO2_C
! REAL*8 :: ALKA, ALKC, TOTAL_ACID_FLUX
! REAL*8 :: HNO3_EQ, TOT_FLUX_A, TOT_FLUX_C
! REAL*8 :: FALK_A_HNO3, HNO3_vv
! REAL*8 :: FALK_C_HNO3, F_HNO3_A, F_HNO3_C
! REAL*8 :: EQ_1_N, EQ_2_N, F_HNO3
! REAL*8 :: HNO3_SSA, HNO3_SSC, N_FLUX
! REAL*8 :: HNO3_EQ_C, L6A, L6C
! REAL*8 :: C_FLUX_A, C_FLUX_C, C_FLUX
! REAL*8 :: HNO3_ss, HNO3_kg
! REAL*8, PARAMETER :: MINDAT = 1.0d-20
! REAL*8, PARAMETER :: TCVV_HNO3 = 28.97d0 / 63.0d0
!
! !=================================================================
! ! SEASALT_CHEM begins here!
! !=================================================================
!
! ! DTCHEM is the chemistry timestep in seconds
! DTCHEM = GET_TS_CHEM() * 60d0
!
! ! Convert SO2 [v/v] to [eq/gridbox]
! SO2_eq = ( 2.d0 * SO2_cd * AD(I,J,L) ) / ( TCVV(IDTSO2) * 0.064d0)
! SO2_eq = MAX( SO2_eq, MINDAT )
!
! IF ( ITS_A_FULLCHEM_SIM() ) THEN
!
! ! Convert HNO3 [v/v] to [equivalents]
! HNO3_vv = STT(I,J,L,IDTHNO3)
! HNO3_eq = HNO3_vv * AD(I,J,L) / ( 28.97d0 / 63d0 ) / 63.d-3
!
! ELSE
!
! !--------------------------------------------------------------------
! ! Prior to 10/7/08:
! ! Now that we have switched from ISORROPIA to RPMARES, GET_GNO3
! ! is no longer defined. We therefore need to do the equivalent
! ! computation. NOTE: This is only an issue for the offline
! ! aerosol simulation. (lyj, bmy, 10/7/08)
! !
! ! For more information, please see this Wiki post:
! ! http://wiki.seas.harvard.edu/geos-chem/index.php/Aerosol_thermodynamical_equilibrium#Bug_in_sulfate_mod.f_caused_by_switch_to_RPMARES
! !
! !! Get gas-phase HNO3 from ISORROPIA code
! !CALL GET_GNO3( I, J, L, HNO3_kg )
! !--------------------------------------------------------------------
!
! ! Get HNO3 in ug/m3, then multiply by volume in m3
! ! and 1e-6 kg/ug to get HNO3 in kg
! HNO3_kg = GET_HNO3_UGM3( I, J, L ) * AIRVOL(I,J,L) * 1e-6
!
! ! Convert HNO3 [kg] first to [v/v]
! HNO3_vv = HNO3_kg * ( 28.97d0 / 63d0 ) / AD(I,J,L)
!
! ! Then convert HNO3 [kg] to [equivalents]
! HNO3_eq = HNO3_kg / 63d-3
!
! ENDIF
!
! !-----------
! ! SO2
! !-----------
!
! ! Available flux of SO2 to accum sea salt aerosols [v/v/timestep]
! L5A = EXP( -Kt1 * DTCHEM )
! F_SO2_A = SO2_cd * ( 1.d0 - L5A )
! F_SO2_A = MAX( F_SO2_A, 1.d-32 )
!
! ! Convert to [eq/timestep]
! C_FLUX_A = 2.d0 * F_SO2_A * AD(I,J,L) / TCVV(IDTSO2) / 0.064d0
!
! ! Available flux of SO2 to coarse sea salt aerosols [v/v/timestep]
! L5C = EXP( - Kt2 * DTCHEM )
! F_SO2_C = SO2_cd * ( 1.d0 - L5C )
! F_SO2_C = MAX( F_SO2_C, 1.0d-32 )
!
! ! Convert to [eq/timestep]
! C_FLUX_C = 2.d0 * F_SO2_C * AD(I,J,L) / TCVV(IDTSO2) / 0.064d0
!
! ! Total flux of SO2 [v/v/timestep]
! F_SO2 = F_SO2_A + F_SO2_C
!
! ! Total flux of SO2 [eq/timestep]
! C_FLUX = C_FLUX_A + C_FLUX_C
!
! !-----------
! ! HNO3
! !-----------
!
! ! Available flux of HNO3 to accum sea salt aerosols [v/v/timestep]
! L6A = EXP( - Kt1N * DTCHEM )
! F_HNO3_A = HNO3_vv * ( 1.D0 - L6A )
! F_HNO3_A = MAX( F_HNO3_A, 1.0D-32 )
!
! ! Convert to [eq/timestep]
! N_FLUX_A = F_HNO3_A * AD(I,J,L)/( 28.97d0 / 63d0 )/0.063d0
!
! ! Available flux of HNO3 to coarse sea salt aerosols [v/v/timestep]
! L6C = EXP( - Kt2N * DTCHEM )
! F_HNO3_C = HNO3_vv * ( 1.D0 - L6C )
! F_HNO3_C = MAX( F_HNO3_C, 1.0D-32 )
!
! ! convert to [eq/timestep]
! N_FLUX_C = F_HNO3_C * AD(I,J,L)/( 28.97d0 / 63d0 )/0.063d0
!
! ! Total flux of HNO3
! F_HNO3 = F_HNO3_A + F_HNO3_C ![v/v/timestep]
! N_FLUX = N_FLUX_A + N_FLUX_C ![eq/timestep]
!
! !-----------
! ! Acid
! !-----------
!
! ! Total acid flux to accum sea-salt aerosols [eq/box/timestep]
! TOT_FLUX_A = C_FLUX_A + N_FLUX_A
! TOT_FLUX_A = MAX( TOT_FLUX_A, MINDAT )
!
! ! Total acid flux to coarse sea-salt aerosols [eq/box/timestep]
! TOT_FLUX_C = C_FLUX_C + N_FLUX_C
! TOT_FLUX_C = MAX( TOT_FLUX_C, MINDAT )
!
! ! Total acid flux to sea salt aerosols
! TOTAL_ACID_FLUX = TOT_FLUX_A + TOT_FLUX_C
!
! ! Total available alkalinity [eq]
! EQ1 = ALK1 * 0.07d0
! EQ2 = ALK2 * 0.07d0
!
! !----------------------------------------------------------------------
! ! NOTE: This was a sensitivity simulation, keep for future reference
! ! cf Alexander et al 2005 (bec, bmy, 4/13/05)
! !! Total available alkalinity [eq] doubled for Sievering run
! !EQ1 = ALK1 * 0.14d0
! !EQ2 = ALK2 * 0.14d0
! !----------------------------------------------------------------------
!
! !----------------------------------------------------------------------
! ! DIAGNOSTIC -- leave uncommented for now (bec, bmy, 4/13/05)
! !! Write out beginning alkalinity [eq SO4]
! !EQ_BEG = EQ1 + EQ2
! !IF ( ND09 > 0 ) AD09(I,J,L,1) = AD09(I,J,L,1) + EQ_BEG
! !----------------------------------------------------------------------
!
! IF ( TOT_FLUX_A > EQ1 ) THEN
!
! ! Fraction of alkalinity available for each acid
! FALK_A_SO2 = C_FLUX_A / TOT_FLUX_A
! FALK_A_HNO3 = N_FLUX_A / TOT_FLUX_A
! FALK_A_SO2 = MAX( FALK_A_SO2, MINDAT )
! FALK_A_HNO3 = MAX( FALK_A_HNO3, MINDAT )
!
! ELSE
!
! FALK_A_SO2 = 1.0d0
! FALK_A_HNO3 = 1.0d0
!
! ENDIF
!
! IF ( TOT_FLUX_C > EQ2 ) THEN
!
! ! Fraction of flkalinity available for each acid
! FALK_C_SO2 = C_FLUX_C/TOT_FLUX_C
! FALK_C_HNO3 = N_FLUX_C/TOT_FLUX_C
! FALK_C_SO2 = MAX( FALK_C_SO2, MINDAT )
! FALK_C_HNO3 = MAX( FALK_C_HNO3, MINDAT )
!
! ELSE
!
! FALK_C_SO2 = 1.0d0
! FALK_C_HNO3 = 1.0d0
!
! ENDIF
!
! ! Alkalinity available for S(IV) --> S(VI)
! EQ_1_C = EQ1 * FALK_A_SO2
! EQ_1_C = MAX( EQ_1_C, MINDAT )
! EQ_1_N = EQ1 * FALK_A_HNO3
! EQ_1_N = MAX( EQ_1_N, MINDAT )
!
! EQ_2_C = EQ2 * FALK_C_SO2
! EQ_2_C = MAX( EQ_2_C, MINDAT )
! EQ_2_N = EQ2 * FALK_C_HNO3
! EQ_2_N = MAX( EQ_2_N, MINDAT )
!
! !-----------------
! ! Fine Seasalt
! !-----------------
!
! ! don't produce more SO4 than available ALK or SO2
! SO4E = MIN( C_FLUX_A, EQ_1_C, SO2_eq )
! SO4E = MAX( SO4E, MINDAT )
!
! ! Update SO2 concentration [eq/box]
! SO2_new = SO2_eq - SO4E
! SO2_new = MAX( SO2_new, MINDAT )
!
! !-----------------
! ! Coarse Seasalt
! !-----------------
! IF ( SO2_new > MINDAT ) THEN
!
! ! don't produce more SO4 than available ALK or SO2
! SO4F = MIN( C_FLUX_C, SO2_new, EQ_2_C )
! SO4F = MAX( SO4F, MINDAT )
!
! !Update SO2 concentration [eq]
! SO2_chem = SO2_new - SO4F
! SO2_chem = MAX( SO2_chem, MINDAT )
! ELSE
! SO4F = MINDAT
! SO2_chem = MINDAT
! ENDIF
!
! ! Alkalinity titrated by S(IV) --> S(VI) [eq]
! TITR_SO2 = SO4E + SO4F
!
! !-------------------------------------------------------------------
! ! DIAGNOSTIC -- leave uncommented for now
! !! write out in diagnostic
! !IF ( ND09 > 0 ) AD09(I,J,L,2) = AD09(I,J,L,2) + TITR_SO2
! !-------------------------------------------------------------------
!
! !Modified SO2 [eq] converted back to [v/v]
! SO2_ss = SO2_chem * 0.064 * TCVV(IDTSO2)/AD(I,J,L)/2.0d0
! SO2_ss = MAX( SO2_ss, MINDAT )
!
! !SO4E produced converted from [eq/timestep] to [v/v/timestep]
! PSO4E = SO4E * 0.096 * TCVV(IDTSO4)/AD(I,J,L)/2.0d0
!
! !SO4F produced converted from [eq/timestep] to [v/v/timestep]
! PSO4F = SO4F * 0.096 * TCVV(IDTSO4S)/AD(I,J,L)/2.0d0
!
! ! Alkalinity titrated by HNO3
! HNO3_SSA = MIN(N_FLUX_A, HNO3_EQ, EQ_1_N)
! HNO3_SSA = MAX(HNO3_SSA, MINDAT)
! HNO3_EQ_C = HNO3_EQ - HNO3_SSA
! HNO3_EQ_C = MAX(HNO3_EQ_C, MINDAT)
! HNO3_SSC = MIN(N_FLUX_C, HNO3_EQ_C, EQ_2_N)
! HNO3_SSC = MAX(HNO3_SSC, MINDAT)
! TITR_HNO3 = HNO3_SSA + HNO3_SSC
!
! !----------------------------------------------------------------------
! ! DIAGNOSTIC -- leave commented out for now
! ! !write out alkalinity titrated by HNO3(g)
! !IF ( ND09 > 0 ) AD09(I,J,L,3) = AD09(I,J,L,3) + TITR_HNO3
! !----------------------------------------------------------------------
!
! ! HNO3 lost [eq/timestep] converted back to [v/v/timestep]
! IF ( IDTHNO3 > 0 ) THEN
!
! ! Coupled sim: IDTHNO3 is defined, so use it
! HNO3_ss = HNO3_SSC * 0.063 * TCVV(IDTHNO3)/AD(I,J,L)
! STT(I,J,L,IDTHNO3) = MAX( HNO3_vv - HNO3_ss, MINDAT )
!
! ELSE
!
! ! Offline aerosol sim: IDTHNO3 isn't defined, use TCVV_HNO3
! HNO3_ss = TITR_HNO3 * 0.063 * TCVV_HNO3 / AD(I,J,L)
!
! ENDIF
!
! ! NITS produced converted from [eq/timestep] to [v/v/timestep]
! PNITs(I,J,L) = HNO3_SSC * 0.063 * TCVV(IDTNITS)/AD(I,J,L)
!
! ! Modified accum alkalinity
! ALKA = EQ1 - (SO4E + HNO3_SSA)
! ALKA = MAX( ALKA, MINDAT )
!
! !------------------------------------------------------------------------
! ! Uncomment this if you want to transport alkalinity (bec, bmy, 4/13/05)
! ![eq] --> [kg] --> [v/v] use this only if transporting alkalinity
! !ALKAvv = (ALKA * TCVV(IDTSAL1))/(7.0d-2 * AD(I,J,L))
! !ALKAvv = MAX( ALKAvv, MINDAT )
! !------------------------------------------------------------------------
!
! ! Modified accum alkalinity
! ALKC = EQ2 - (SO4F + HNO3_SSC)
! ALKC = MAX( ALKC, MINDAT )
!
! !------------------------------------------------------------------------
! ! Uncomment this if you want to transport alkalinity (bec, bmy, 4/13/05)
! !! [eq] --> [kg] --> [v/v] use this only if transporting alkalinity
! !ALKCvv = (ALKC * TCVV(IDTSAL2))/(7.0d-2 * AD(I,J,L))
! !ALKCvv = MAX(ALKCvv, MINDAT)
! !------------------------------------------------------------------------
!
! !------------------------------------------------------------------------
! ! DIAGNOSTIC -- leave commented out for now (bec, bmy, 4/13/05)
! !! write out ending alkalinity
! !END_ALK = ALKA + ALKC
! !IF ( ND09 > 0 ) AD09(I,J,L,4) = AD09(I,J,L,4) + END_ALK
! !------------------------------------------------------------------------
!
! ! Return to calling program
! END SUBROUTINE SEASALT_CHEM
!
!!------------------------------------------------------------------------------
SUBROUTINE AQCHEM_SO2( LWC, T, P, SO2, H2O2,
& O3, Hplus, KaqH2O2, KaqO3 )
!
!******************************************************************************
! Function AQCHEM_SO2 computes the reaction rates for aqueous SO2 chemistry.
! (rjp, bmy, 10/31/02, 12/12/02)
!
! Arguments as Input:
! ============================================================================
! (1 ) LWC (REAL*8) : Liquid water content [m3/m3] = 1.E-6*L [g/m3]
! (2 ) T (REAL*8) : Temperature [K]
! (3 ) P (REAL*8) : Pressure [atm]
! (4 ) SO2 (REAL*8) : SO2 mixing ratio [v/v]
! (5 ) H2O2 (REAL*8) : H2O2 mixing ratio [v/v]
! (6 ) O3 (REAL*8) : O3 mixing ratio [v/v]
! (7 ) HPLUS (REAL*8) : Concentration of H+ ion (i.e. the pH) [v/v]
!
! Arguments as Output:
! ============================================================================
! (8 ) KaqH2O2 (REAL*8) : Reaction rate for H2O2
! (9 ) KaqO3 (REAL*8) : Reaction rate for O3
!
! Chemical Reactions:
! ============================================================================
! (R1) HSO3- + H2O2(aq) + H+ => SO4-- + 2H+ + H2O [Jacob, 1986]
!
! d[S(VI)]/dt = k[H+][H2O2(aq)][HSO3-]/(1 + K[H+])
! [Seinfeld and Pandis, 1998, page 366]
!
! (R2) SO2(aq) + O3(aq) =>
! HSO3- + O3(aq) =>
! SO3-- + O3(aq) =>
! [Jacob, 1986; Jacobson, 1999]
!
! d[S(VI)]/dt = (k0[SO2(aq)] + k1[HSO3-] + K2[SO3--])[O3(aq)]
! [Seinfeld and Pandis, 1998, page 363]
!
! Reaction rates can be given as
! Ra = k [H2O2(ag)] [S(IV)] [mole/liter*s] OR
! Krate = Ra LWC R T / P [1/s]
!
! Where:
! LWC = Liquid water content(g/m3)*10-6 [m3(water)/m3(gas)]
! R = 0.08205 (atm L / mol-K), Universal gas const.
! T = Temperature (K)
! P = Pressure (atm)
!
! Procedure:
! ============================================================================
! (a ) Given [SO2] which is assumed to be total SO2 (gas+liquid) in
! equilibrium between gas and liquid phase.
!
! (b ) We can compute SO2(g) using Henry's law
! P(so2(g)) = Xg * [SO2]
! Xg = 1/(1 + Faq), Fraction of SO2 in gas
! where:
! Faq = Kheff * R * T * LWC,
! KHeff = Effective Henry's constant
!
! (c ) Then Calculate Aquous phase, S[IV] concentrations
! S[IV] = Kheff * P(so2(g) in atm) [M]
!
! (d ) The exact same procedure is applied to calculate H2O2(aq)
!
! NOTES:
! (1 ) Updated by Rokjin Park (rjp, bmy, 12/12/02)
!******************************************************************************
!
! Arguments
REAL*8, INTENT(IN) :: LWC, T, P, SO2, H2O2, O3, HPLUS
REAL*8, INTENT(OUT) :: KaqH2O2, KaqO3
! Local variables
REAL*8, PARAMETER :: R = 0.08205d0
REAL*8 :: KH2O2, RA, KS1, KS2, HCSO2
REAL*8 :: FHCSO2, XSO2G, SIV, HSO3, XSO2AQ
REAL*8 :: XHSO3, XSO3, KH1, HCH2O2, FHCH2O2
REAL*8 :: XH2O2G, H2O2aq, KO0, KO1, KO2
REAL*8 :: HCO3, XO3g, O3aq
!=================================================================
! AQCHEM_SO2 begins here!
!
! Aqueous reaction rate
! HSO3- + H2O2 + H+ => SO4-- + 2H+ + H2O [Jacob, 1986]
!=================================================================
! [Jacob, 1986]
KH2O2 = 6.31d14 * EXP( -4.76d3 / T )
! ! [Jacobson, 1999]
! KH2O2 = 7.45d07 * EXP( -15.96d0 * ( (298.15/T) - 1.) ) /
! & ( 1.d0 + 13.d0 * Hplus)
!=================================================================
! Equilibrium reaction of SO2-H2O
! SO2 + H2O = SO2(aq) (s0)
! SO2(ag) = HSO3- + H+ (s1)
! HSO3- = SO3-- + H+ (s2)
!
! Reaction constant for Aqueous chemistry -- No big difference
! between Jacob and Jacobson, choose one of them.
!
! Reaction rate dependent on Temperature is given
! H = A exp ( B (T./T - 1) )
!
! For equilibrium reactions of SO2:
! As1 Bs1 As2 Bs2
! Seinfeld 1.30d-2 7.02 6.60d-8 3.76 [1998]
! Jacob 1.30d-2 6.75 6.31d-8 5.05 [1986]
! Jacobson 1.71d-2 7.04 5.99d-8 3.74 [1996]
!=================================================================
Ks1 = 1.30d-2 * EXP( 6.75d0 * ( 298.15d0 / T - 1.d0 ) )
Ks2 = 6.31d-8 * EXP( 5.05d0 * ( 298.15d0 / T - 1.d0 ) )
! SIV Fraction
XSO2aq = 1.d0/(1.d0 + Ks1/Hplus + Ks1*Ks2/(Hplus*Hplus))
XHSO3 = 1.d0/(1.d0 + Hplus/Ks1 + Ks2/Hplus)
XSO3 = 1.d0/(1.d0 + Hplus/Ks2 + Hplus*Hplus/(Ks1*Ks2))
! Henry's constant [mol/l-atm] and Effective Henry's constant for SO2
HCSO2 = 1.22d0 * EXP( 10.55d0 * ( 298.15d0 / T - 1.d0) )
FHCSO2 = HCSO2 * (1.d0 + (Ks1/Hplus) + (Ks1*Ks2 / (Hplus*Hplus)))
XSO2g = 1.d0 / ( 1.d0 + ( FHCSO2 * R * T * LWC ) )
SIV = FHCSO2 * XSO2g * SO2 * P
! HSO3 = Ks1 * HCSO2 * XSO2g * SO2 * P
!=================================================================
! H2O2 equilibrium reaction
! H2O2 + H2O = H2O2.H2O
! H2O2.H2O = HO2- + H+ 1)
!
! Reaction rate dependent on Temperature is given
! H = A exp ( B (T./T - 1) )
!
! For equilibrium reactions of SO2
! Ah1 Bh1
! Jacob 1.58E-12 -12.49 [1986]
! Jacobson 2.20E-12 -12.52 [1996]
!=================================================================
Kh1 = 2.20d-12 * EXP( -12.52d0 * ( 298.15d0 / T - 1.d0 ) )
! Henry's constant [mol/l-atm] and Effective Henry's constant for H2O2
! [Seinfeld and Pandis, 1998]
! HCH2O2 = 7.45D4 * EXP( 24.48d0 * ( 298.15d0 / T - 1.d0) )
! [Jacobson,1999]
HCH2O2 = 7.45D4 * EXP( 22.21d0 * (298.15d0 / T - 1.d0) )
FHCH2O2 = HCH2O2 * (1.d0 + (Kh1 / Hplus))
XH2O2g = 1.d0 / ( 1.d0 + ( FHCH2O2 * R * T * LWC ) )
! H2O2aq = FHCH2O2 * XH2O2g * H2O2 * P
! Conversion rate from SO2 to SO4 via reaction with H2O2
KaqH2O2 = kh2o2 * Ks1 * FHCH2O2 * HCSO2 * XH2O2g * XSO2g
& * P * LWC * R * T ! [v/v/s]
!=================================================================
! Aqueous reactions of SO2 with O3
! SO2(aq) + O3 => (0)
! HSO3- + O3 => SO4-- + H+ + O2 (1)
! SO3-- + O3 => SO4-- + O2 (2)
!
! NOTE
! [Jacob, 1986]
! KO1 = 3.49E12 * EXP( -4.83E3 / T )
! KO2 = 7.32E14 * EXP( -4.03E3 / T )
!
! [Jacobson, 1999]
! KO0 = 2.40E+4
! KO1 = 3.70E+5 * EXP( -18.56 * ((298.15/T) - 1.))
! KO2 = 1.50E+9 * EXP( -17.72 * ((298.15/T) - 1.))
!
! Rate constants from Jacobson is larger than those of Jacob
! and results in faster conversion from S(IV) to S(VI)
! We choose Jacob 1) 2) and Jacobson 0) here
!=================================================================
KO0 = 2.40d+4
KO1 = 3.49d12 * EXP( -4.83d3 / T )
KO2 = 7.32d14 * EXP( -4.03d3 / T )
!=================================================================
! H2O2 equilibrium reaction
! O3 + H2O = O3.H2O
! HCO3 = 1.13E-2 * EXP( 8.51 * (298.15/T -1.) ), S & P
! HCO3 = 1.13E-2 * EXP( 7.72 * (298.15/T -1.) ), Jacobson
!=================================================================
! Calculate Henry's Law constant for atmospheric temperature
HCO3 = 1.13d-2 * EXP( 8.51d0 * ( 298.15d0 / T - 1.d0 ) )
XO3g = 1.d0 / ( 1.d0 + ( HCO3 * R * T * LWC ) )
! O3aq = HCO3 * XO3g * O3 * P
! Conversion rate from SO2 to SO4 via reaction with O3
KaqO3 = (KO0*XSO2AQ + KO1*XHSO3 + KO2*XSO3) * FHCSO2 * XSO2g
& * P * HCO3 * XO3g * LWC * R * T ! [v/v/s]
! Return to calling program
END SUBROUTINE AQCHEM_SO2
!------------------------------------------------------------------------------
SUBROUTINE CHEM_SO4_ADJ
!
!******************************************************************************
! Subroutine CHEM_SO4_ADJ is the adjoint SO4 chemistry subroutine for the
! fwd routine CHEM_SO4. (dkh, 10/13/05)
!
! * Does not yet include seasalt sulfate *
!
! See original routine for notes. (rjp, bdf, cas, bmy, 5/31/00, 5/23/06)
!
! Module Variables Used:
! ============================================================================
! (1 ) ADPSO4_SO2 (REAL*8 ) : Array for adjoint of P(SO4) from SO2
!
! 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:
!
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
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
!fp
USE LOGICAL_ADJ_MOD, ONLY : LMAX_OBS, LADJ_DDEP_TRACER
USE ADJ_ARRAYS_MOD, ONLY : GET_CF_REGION, ADJOINT_AREA_M2
USE ADJ_ARRAYS_MOD, ONLY : OBS_THIS_TRACER, DEP_UNIT
USE ADJ_ARRAYS_MOD, ONLY : NSPAN, TR_DDEP_CONV
# 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 :: ADJ_SO4, ADJ_SO40
REAL*8, SAVE :: NTSCHEM
REAL*8, SAVE :: FACT
LOGICAL :: FORCE
LOGICAL, SAVE :: FIRST = .TRUE.
INTEGER, SAVE :: OBS_COUNT = 0
!=================================================================
! CHEM_SO4_ADJ begins here!
!=================================================================
! Return if tracers are not defined
IF ( IDTSO4 == 0 .or. IDTSO4s == 0 ) RETURN
IF ( DRYSO4 == 0 .or. DRYSO4s == 0 ) RETURN
!for dry dep forcing (fp)
! Determine if it is time to apply deposition forcing
FORCE = .FALSE.
IF ( LMAX_OBS ) THEN
OBS_COUNT = OBS_COUNT + 1
IF ( OBS_COUNT <= NSPAN
& .and. LADJ_DDEP_TRACER
& .and. OBS_THIS_TRACER(IDTSO4) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'SO4' , TRIM( DEP_UNIT )
ENDIF
ELSEIF ( LADJ_DDEP_TRACER .and. OBS_THIS_TRACER(IDTSO4) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'SO4' , TRIM( DEP_UNIT )
ENDIF
100 FORMAT('Forcing ',a,' drydep (', a,')')
! DTCHEM is the chemistry timestep in seconds
DTCHEM = GET_TS_CHEM() * 60d0
! initialize some constants for depostion forcing
IF ( FORCE .and. FIRST ) THEN
! here we aren't assuming that TS_CHEM is necessarily 1 hr
NTSCHEM = NSPAN / ( GET_TS_CHEM() / 60D0 )
!default is molec/cm2/s
FACT = XNUMOL(IDTSO4) / DTCHEM
& / TCVV(IDTSO4) / NTSCHEM
FIRST = .FALSE.
ENDIF
! Loop over tropospheric grid boxes
!$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+PRIVATE( ADJ_SO40, ADJ_SO4 )
!$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
! Skip stratospheric boxes
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
!==============================================================
! Initial concentrations before chemistry
!==============================================================
! Initial ADJ_SO4
ADJ_SO4 = STT_ADJ(I,J,L,IDTSO4)
! 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 )
! Adjoint of SO4 change due to deposition
ADJ_SO40 = ADJ_SO4 * E_RKT
! Adjoint of SO4 change due to SO2 production
ADPSO4_SO2(I,J,L) =
& ADJ_SO4 / RKT * ( 1.d0 - E_RKT )
!add forcings (fp)
IF ( FORCE ) THEN
ADJ_SO40 = ADJ_SO40
& + ( 1d0 - E_RKT )
& * AD(I,J,L) * FACT / GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTSO4)
ADPSO4_SO2(I,J,L) = ADPSO4_SO2(I,J,L)
& + ( 1D0 - ( 1D0 - E_RKT ) / RKT )
& * AD(I,J,L) * FACT / GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTSO4)
ENDIF
ELSE
!-----------------------------------------------------------
! CASE 2: Production of SO4 from SO2; no SO4 drydep loss
!-----------------------------------------------------------
! Adjoint of SO4 change due to SO2 production
ADJ_SO40 = ADJ_SO4
ADPSO4_SO2(I,J,L) = ADJ_SO4
!no dry deposition so no forcing for wet dep sensitivity
ENDIF
! Update global array
STT_ADJ(I,J,L,IDTSO4) = ADJ_SO40
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_SO4_ADJ
!!------------------------------------------------------------------------------
!
! !SUBROUTINE PHASE_SO4
! !
! ! *** Currently under development ***
! !
! !END SUBROUTINE PHASE_SO4
!
!!------------------------------------------------------------------------------
!
! !SUBROUTINE PHASE_RADIATIVE
! !
! ! *** Currently under development ***
! !
! !END SUBROUTINE PHASE_RADIATIVE
!
!!------------------------------------------------------------------------------
SUBROUTINE CHEM_MSA_ADJ
!
!******************************************************************************
! Subroutine ADJ_CHEM_MSA is the adjoint MSA chemistry subroutine for the
! fwd routine CHEM_MSA. See original routine for notes. (dkh, 10/13/05)
!
! See original routine (rjp, bdf, bmy, 5/31/00, 10/25/05) for notes.
!
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
! ============================================================================
!
! MSA = MSA_0 * exp(-kt)
! where k = dry deposition.
!
! NOTES:
! (1 ) Updated to GCv8 adjoint (dkh, 09/28/09)
!
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
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 :: ADJ_MSA, ADJ_MSA0
!=================================================================
! CHEM_MSA_ADJ 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()
! 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+PRIVATE( ADJ_MSA0, ADJ_MSA )
!$OMP+SCHEDULE( DYNAMIC )
DO L = 1, PBL_MAX
DO J = 1, JJPAR
DO I = 1, IIPAR
! Initialize for safety's sake
RKT = 0d0
! Fraction of box (I,J,L) underneath the PBL top [unitless]
F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
! Initial ADJ_MSA
ADJ_MSA = STT_ADJ(I,J,L,IDTMSA)
! Only apply drydep loss to boxes w/in the PBL
IF ( F_UNDER_TOP > 0 ) THEN
! 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
! Adjoint of MSA change due to deposition
ADJ_MSA0 = ADJ_MSA * EXP( -RKT )
ELSE
ADJ_MSA0 = ADJ_MSA
ENDIF
! Update global array
STT_ADJ(I,J,L,IDTMSA) = ADJ_MSA0
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_MSA_ADJ
!------------------------------------------------------------------------------
SUBROUTINE CHEM_NH3_ADJ
!
!******************************************************************************
! Subroutine ADJ_CHEM_NH3 is the adjoint NH3 chemistry subroutine for the
! fwd routine CHEM_NH3. (dkh, 10/13/05)
!
! See originat routine (rjp, bdf, bmy, 1/2/02, 10/25/05) for notes.
!
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
! ============================================================================
!
! NH3 = NH3_0 * exp(-kt)
! where k = dry deposition.
!
! NOTES:
! (1 ) Updated to GCv8 adjoint (dkh, 09/28/09)
! (2 ) Now support deposition cost function (fp, dkh, 03/04/13)
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
USE ADJ_ARRAYS_MOD, ONLY : NSPAN
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
USE LOGICAL_ADJ_MOD, ONLY : LADJ_DDEP_TRACER
USE LOGICAL_ADJ_MOD, ONLY : LMAX_OBS
USE ADJ_ARRAYS_MOD, ONLY : GET_CF_REGION, ADJOINT_AREA_M2
USE ADJ_ARRAYS_MOD, ONLY : OBS_THIS_TRACER, DEP_UNIT
USE ADJ_ARRAYS_MOD, ONLY : TR_DDEP_CONV
# include "CMN_SIZE" ! Size parameters
! Local variables
INTEGER :: I, J, L, PBL_MAX
REAL*8 :: DTCHEM, NH30, NH3
REAL*8 :: FREQ, AREA_CM2, FLUX, F_UNDER_TOP
REAL*8 :: ADJ_NH3, ADJ_NH30
REAL*8, SAVE :: NTSCHEM
REAL*8, SAVE :: FACT
LOGICAL :: FORCE
LOGICAL, SAVE :: FIRST = .TRUE.
INTEGER, SAVE :: OBS_COUNT = 0
!=================================================================
! CHEM_NH3_ADJ 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()
! Determine if it is time to apply deposition forcing
FORCE = .FALSE.
IF ( LMAX_OBS ) THEN
OBS_COUNT = OBS_COUNT + 1
IF ( OBS_COUNT <= NSPAN
& .and. LADJ_DDEP_TRACER
& .and. OBS_THIS_TRACER(IDTNH3) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'NH3' , TRIM( DEP_UNIT )
ENDIF
ELSEIF ( LADJ_DDEP_TRACER .and. OBS_THIS_TRACER(IDTNH3) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'NH3' , TRIM( DEP_UNIT )
ENDIF
100 FORMAT('Forcing ',a,' drydep (', a,')')
! initialize some constants for depostion forcing
IF ( FORCE .and. FIRST ) THEN
! here we aren't assuming that TS_CHEM is necessarily 1 hr
NTSCHEM = NSPAN / ( GET_TS_CHEM() / 60D0 )
!default is molec/cm2/s
FACT = XNUMOL(IDTNH3) / DTCHEM
& / TCVV(IDTNH3) / NTSCHEM
! FACT = 1d0 / DTCHEM
! & / 1d0 / NTSCHEM
FIRST = .FALSE.
ENDIF
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ, NH30, NH3, AREA_CM2, FLUX )
!$OMP+PRIVATE( ADJ_NH30, ADJ_NH3 )
!$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 ADJ_NH3
ADJ_NH3 = STT_ADJ(I,J,L,IDTNH3)
ADJ_NH30 = ADJ_NH3 * EXP( -FREQ * DTCHEM )
STT_ADJ(I,J,L,IDTNH3) = ADJ_NH30
IF ( FORCE ) THEN
! note: the forcing corresponds to this cost function:
! COST_FUNC = SUM ( STT * ( 1 - EXP( - FREQ * DTCHEM) )
! * AD(I,J,L) * FACT / GET_AREA_CM2(J)
! the forcing is thus:
STT_ADJ(I,J,L,IDTNH3) = STT_ADJ(I,J,L,IDTNH3)
& + ( 1d0 - EXP( - FREQ * DTCHEM ) )
& * AD(I,J,L) * FACT / GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTNH3)
ENDIF
ENDIF
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_NH3_ADJ
!------------------------------------------------------------------------------
SUBROUTINE CHEM_NH4_ADJ
!
!******************************************************************************
! Subroutine CHEM_NH4_ADJ is the adjoint NH4 chemistry subroutine for the
! fwd routine CHEM_NH4. (dkh, 10/13/05)
!
! See original (rjp, bdf, bmy, 1/2/02, 10/25/05) for notes.
!
! Reaction List (by Mian Chin, chin@rondo.gsfc.nasa.gov)
! ============================================================================
!
! NH4 = NH4_0 * exp(-kt)
! where k = dry deposition.
!
! NOTES:
! (1 ) Updated to GCv8 adjoint
! (2 ) Now support deposition cost function (fp, dkh, 03/04/13)
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
USE ADJ_ARRAYS_MOD, ONLY : GET_CF_REGION, ADJOINT_AREA_M2
USE ADJ_ARRAYS_MOD, ONLY : OBS_THIS_TRACER, DEP_UNIT
USE ADJ_ARRAYS_MOD, ONLY : NSPAN
USE DAO_MOD, ONLY : AD
USE DIAG_MOD, ONLY : AD44
USE DRYDEP_MOD, ONLY : DEPSAV
USE GRID_MOD, ONLY : GET_AREA_CM2
USE LOGICAL_ADJ_MOD,ONLY : LADJ_DDEP_TRACER
USE LOGICAL_ADJ_MOD,ONLY : LMAX_OBS
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
USE ADJ_ARRAYS_MOD, ONLY : TR_DDEP_CONV
# include "CMN_SIZE" ! Size parameters
! Local variables
INTEGER :: I, J, L, PBL_MAX
REAL*8 :: DTCHEM, NH4, NH40
REAL*8 :: FREQ, FLUX, AREA_CM2, F_UNDER_TOP
REAL*8 :: ADJ_NH4, ADJ_NH40
REAL*8, SAVE :: FACT
REAL*8, SAVE :: NTSCHEM
INTEGER, SAVE :: OBS_COUNT = 0
LOGICAL, SAVE :: FIRST = .TRUE.
LOGICAL :: FORCE
!=================================================================
! CHEM_NH4_ADJ 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()
FORCE = .FALSE.
IF ( LMAX_OBS ) THEN
OBS_COUNT = OBS_COUNT + 1
IF ( OBS_COUNT <= NSPAN
& .and. LADJ_DDEP_TRACER
& .and. OBS_THIS_TRACER(IDTNH4) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'NH4' , TRIM( DEP_UNIT )
ENDIF
ELSEIF ( LADJ_DDEP_TRACER .and. OBS_THIS_TRACER(IDTNH4) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'NH4' , TRIM( DEP_UNIT )
ENDIF
100 FORMAT('Forcing ',a,' drydep (', a,')')
IF ( FORCE .and. FIRST ) THEN
! here we aren't assuming that TS_CHEM is necessarily 1 hr
NTSCHEM = NSPAN / ( GET_TS_CHEM() / 60D0 )
! default is molec/cm2/s
FACT = XNUMOL(IDTNH4) / DTCHEM
& / TCVV(IDTNH4) / NTSCHEM
FIRST = .FALSE.
ENDIF
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ, NH40, NH4, AREA_CM2, FLUX )
!$OMP+PRIVATE( ADJ_NH40, ADJ_NH4 )
!$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 ADJ_NH4
ADJ_NH4 = STT_ADJ(I,J,L,IDTNH4)
! Adjoint of NH4 change due to deposition
ADJ_NH40 = ADJ_NH4 * EXP( -FREQ * DTCHEM )
! Update global array
STT_ADJ(I,J,L,IDTNH4) = ADJ_NH40
IF ( FORCE ) THEN
! note: the forcing corresponds to this cost function:
! COST_FUNC = SUM ( STT * ( 1 - EXP( - FREQ * DTCHEM) )
! * AD(I,J,L) * FACT / GET_AREA_CM2(J)
! the forcing is thu:
STT_ADJ(I,J,L,IDTNH4) = STT_ADJ(I,J,L,IDTNH4)
& + ( 1d0 - EXP( - FREQ * DTCHEM ) )
& * AD(I,J,L) * FACT / GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTNH4)
ENDIF
ENDIF
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_NH4_ADJ
!!------------------------------------------------------------------------------
!
! SUBROUTINE CHEM_NH4aq
!!
!!******************************************************************************
!! Subroutine CHEM_NH4aq removes NH4aq from the surface via dry deposition.
!! (cas, bmy, 1/6/05, 10/25/05)
!!
!! Reaction List:
!! ============================================================================
!! (1 ) NH4aq = NH4_0aq * EXP( -dt ) where d = dry deposition rate [s-1]
!!
!! NOTES:
!! (1 ) Replace PBLFRAC from "drydep_mod.f" with GET_FRAC_UNDER_PBLTOP from
!! "pbl_mix_mod.f". Also reference GET_PBL_MAX_L from "pbl_mix_mod.f"
!! Vertical DO-loops can run up to PBL_MAX and not LLTROP. (bmy, 2/22/05)
!! (31) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
!!******************************************************************************
!!
! ! References to F90 modules
! USE DAO_MOD, ONLY : AD
! USE DIAG_MOD, ONLY : AD44
! USE DRYDEP_MOD, ONLY : DEPSAV
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
! USE TIME_MOD, ONLY : GET_TS_CHEM
! USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
! USE TRACERID_MOD, ONLY : IDTNH4aq
!
!# include "CMN_SIZE" ! Size parameters
!# include "CMN_DIAG" ! ND44
!
! ! Local variables
! INTEGER :: I, J, L, PBL_MAX
! REAL*8 :: DTCHEM, NH4aq, NH4aq0
! REAL*8 :: FREQ, FLUX, AREA_CM2, F_UNDER_TOP
! REAL*8 :: T44(IIPAR,JJPAR,LLTROP)
!
! !=================================================================
! ! CHEM_NH4 begins here!
! !=================================================================
! IF ( IDTNH4aq == 0 .or. DRYNH4aq == 0 ) RETURN
!
! ! DTCHEM is the chemistry interval in seconds
! DTCHEM = GET_TS_CHEM() * 60d0
!
! ! Model level where maximum PBL height occurs
! PBL_MAX = GET_PBL_MAX_L()
!
! ! Zero T44 array
! IF ( ND44 > 0 ) THEN
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, L )
! DO L = 1, LLTROP
! DO J = 1, JJPAR
! DO I = 1, IIPAR
! T44(I,J,L) = 0d0
! ENDDO
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
! ENDIF
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, L, F_UNDER_TOP, FREQ )
!!$OMP+PRIVATE( NH4aq0, NH4aq, AREA_CM2, FLUX )
!!$OMP+SCHEDULE( DYNAMIC )
! DO L = 1, PBL_MAX
! DO J = 1, JJPAR
! DO I = 1, IIPAR
!
! ! Fraction of box (I,J,L) underneath the PBL top [unitless]
! F_UNDER_TOP = GET_FRAC_UNDER_PBLTOP( I, J, L )
!
! ! Only apply drydep to boxes w/in the PBL
! IF ( F_UNDER_TOP > 0d0 ) THEN
!
! ! NH4 drydep frequency [1/s] -- PBLFRAC accounts for the fraction
! ! of each grid box (I,J,L) that is located beneath the PBL top
! FREQ = DEPSAV(I,J,DRYNH4aq) * F_UNDER_TOP
!
! ! Only apply drydep loss if FREQ is nonzero
! IF ( FREQ > 0d0 ) THEN
!
! ! Initial NH4 [v/v]
! NH4aq0 = STT(I,J,L,IDTNH4aq)
!
! ! Amount of NH4 lost to drydep [v/v]
! NH4aq = NH4aq0 * ( 1d0 - EXP( -FREQ * DTCHEM ) )
!
! ! Prevent underflow condition
! IF ( NH4aq < SMALLNUM ) NH4aq = 0d0
!
! ! Subtract NH4 lost to drydep from initial NH4 [v/v]
! STT(I,J,L,IDTNH4aq) = NH4aq0 - NH4aq
!
! !========================================================
! ! ND44 diagnostic: Drydep flux of NH4 [molec/cm2/s]
! !========================================================
! IF ( ND44 > 0 .and. NH4aq > 0d0 ) THEN
!
! ! Surface area [cm2]
! AREA_CM2 = GET_AREA_CM2( J )
!
! ! Convert drydep loss from [v/v/timestep] to [molec/cm2/s]
! FLUX = NH4aq * AD(I,J,L) / TCVV(IDTNH4aq)
! FLUX = FLUX * XNUMOL(IDTNH4aq) / AREA_CM2 / DTCHEM
!
! ! Store dryd flx in ND44_TMP as a placeholder
! T44(I,J,L) = T44(I,J,L) + FLUX
! ENDIF
! ENDIF
! ENDIF
! ENDDO
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! !===============================================================
! ! ND44: Sum drydep fluxes by level into the AD44 array in
! ! order to ensure that we get the same results w/ sp or mp
! !===============================================================
! IF ( ND44 > 0 ) THEN
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, L )
! DO J = 1, JJPAR
! DO I = 1, IIPAR
! DO L = 1, PBL_MAX
! AD44(I,J,DRYNH4aq,1) = AD44(I,J,DRYNH4aq,1) + T44(I,J,L)
! ENDDO
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE CHEM_NH4aq
!
!!------------------------------------------------------------------------------
SUBROUTINE CHEM_NIT_ADJ
!
!******************************************************************************
! Subroutine ADJ_CHEM_NIT is the adjoint NIT chemistry subroutine for the
! fwd routine CHEM_NIT. See original routine for notes. (dkh, 10/13/05)
!
! * Does not deal with NITs *
!
! See original (rjp, bdf, bmy, 1/2/02, 5/23/06) for notes.
!
! Reaction List:
! ============================================================================
! (1 ) NIT = NIT_0 * EXP( -dt ) where d = dry deposition rate [s-1]
!
! NOTES:
! (1 ) Updates to GCv8 adjoint (dkh, 09/28/09)
! (2 ) Now support deposition cost function (fp, dkh, 03/04/13)
!
!******************************************************************************
!
! References to F90 modules
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
USE ADJ_ARRAYS_MOD, ONLY : GET_CF_REGION
USE ADJ_ARRAYS_MOD, ONLY : OBS_THIS_TRACER
USE ADJ_ARRAYS_MOD, ONLY : NSPAN
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 LOGICAL_ADJ_MOD,ONLY : LADJ_DDEP_TRACER
USE LOGICAL_ADJ_MOD,ONLY : LMAX_OBS
USE PBL_MIX_MOD, ONLY : GET_FRAC_UNDER_PBLTOP, GET_PBL_MAX_L
USE TIME_MOD, ONLY : GET_TS_CHEM
USE TIME_MOD, ONLY : GET_TAU
USE TRACER_MOD, ONLY : STT, TCVV, XNUMOL
USE TRACERID_MOD, ONLY : IDTNIT, IDTNITs
USE ADJ_ARRAYS_MOD, ONLY : TR_DDEP_CONV, DEP_UNIT
# include "CMN_SIZE" ! Size parameters
! 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 :: ADJ_NIT, ADJ_NIT0
REAL*8, SAVE :: NTSCHEM
REAL*8, SAVE :: FACT
LOGICAL,SAVE :: FIRST = .TRUE.
LOGICAL :: FORCE
INTEGER, SAVE :: OBS_COUNT = 0
!=================================================================
! CHEM_NIT_ADJ begins here!
!=================================================================
! Return if tracers are not defined
!IF ( IDTNIT == 0 .or. IDTNITs == 0 ) RETURN
!IF ( DRYNIT == 0 .or. DRYNITs == 0 ) RETURN
IF ( IDTNIT == 0 ) RETURN
IF ( DRYNIT == 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()
! Model level where maximum PBL height occurs
PBL_MAX = GET_PBL_MAX_L()
! Determine if it is time to apply deposition forcing 判断加不加强迫取决于有没有观测
FORCE = .FALSE.
IF ( LMAX_OBS ) THEN
OBS_COUNT = OBS_COUNT + 1
IF ( OBS_COUNT <= NSPAN
& .and. LADJ_DDEP_TRACER
& .and. OBS_THIS_TRACER(IDTNIT) ) THEN
FORCE = .TRUE.
WRITE(6,100) , 'NIT' ,
& TRIM( DEP_UNIT )
100 FORMAT('Forcing ',a,' drydep (', a,')')
ENDIF
ENDIF
! initialize some constants for depostion forcing
IF ( FORCE .and. FIRST ) THEN
! here we aren't assuming that TS_CHEM is necessarily 1 hr
NTSCHEM = NSPAN / ( GET_TS_CHEM() / 60D0 )
!default is molec/cm2/s
FACT = XNUMOL(IDTNIT) / DTCHEM
& / TCVV(IDTNIT) / NTSCHEM
FIRST = .FALSE.
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+PRIVATE( ADJ_NIT0, ADJ_NIT )
!$OMP+SCHEDULE( DYNAMIC )
DO L = 1, PBL_MAX ! 这部分开始逐个网格计算了, 也就是伴随的部分还是逐网格的
DO J = 1, JJPAR
DO I = 1, IIPAR
! 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 )
! Initial ADJ_NIT
ADJ_NIT = STT_ADJ(I,J,L,IDTNIT)
! Adjoint of NIT change due to deposition
ADJ_NIT0 = ADJ_NIT * E_RKT
! Update global array
STT_ADJ(I,J,L,IDTNIT) = ADJ_NIT0
IF ( FORCE ) THEN
! note: the forcing corresponds to this cost function:
! COST_FUNC = SUM ( STT * ( 1 - EXP( - FREQ * DTCHEM) )
! * AD(I,J,L) * FACT / GET_AREA_CM2(J)
! the forcing is thu:
STT_ADJ(I,J,L,IDTNIT) = STT_ADJ(I,J,L,IDTNIT)
& + ( 1d0 - EXP( - RKT ) )
& * AD(I,J,L) * FACT / GET_AREA_CM2(J)
& * GET_CF_REGION(I,J,L)
& * TR_DDEP_CONV(J,IDTNIT)
ENDIF
ENDIF
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE CHEM_NIT_ADJ
!-----------------------------------------------------------------------------
SUBROUTINE EMISSSULFATE_ADJ
!
!******************************************************************************
! Subroutine EMISSSULFATE_ADJ is the interface between the adjoint
! of GEOS-CHEM and the adjoint of the sulfate emission routines.
! (dkh, 04/19/06)
!
! Based on forward routine EMISSSULFATE (bmy, 6/7/00, 10/3/05)
!
! NOTES:
! (1 ) Update to GCv8 (dkh, 11/03/09)
!
!******************************************************************************
!
! References to F90 modules
USE ERROR_MOD, ONLY : DEBUG_MSG
USE LOGICAL_MOD, ONLY : LSHIPSO2, LPRT, LBIOMASS !(win,5/1/09)
USE TIME_MOD, ONLY : GET_SEASON, GET_MONTH
USE TIME_MOD, ONLY : GET_YEAR, ITS_A_NEW_MONTH
USE TRACER_MOD, ONLY : STT, ITS_AN_AEROSOL_SIM
USE TRACERID_MOD, ONLY : IDTNITs, IDTSO4s
USE TRACERID_MOD, ONLY : IDTDMS, IDTSO2
USE TRACERID_MOD, ONLY : IDTSO4, IDTNH3
USE GFED2_BIOMASS_MOD, ONLY : GFED2_IS_NEW
USE LOGICAL_MOD, ONLY : LANTHRO
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
# include "CMN_SIZE" ! Size parameters
! Local variables
LOGICAL, SAVE :: FIRSTEMISS = .TRUE.
INTEGER :: NSEASON, MONTH, YEAR
!=================================================================
! EMISSSULFATE_ADJ begins here!
!=================================================================
! Get the season and month
NSEASON = GET_SEASON()
MONTH = GET_MONTH()
YEAR = GET_YEAR()
! fwd code:
!!=================================================================
!! 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) )
! adj code:
IF ( IDTNH3 /= 0 ) CALL SRCNH3_ADJ( STT_ADJ(:,:,:,IDTNH3) )
! add these later as needed
!IF ( IDTSO4 /= 0 ) CALL SRCSO4_ADJ( STT_ADJ(:,:,:,IDTSO4) )
IF ( IDTSO2 /= 0 ) CALL SRCSO2_ADJ( STT_ADJ(:,:,:,IDTSO2),NSEASON)
!IF ( IDTDMS /= 0 ) CALL SRCDMS_ADJ( STT_ADJ(:,:,:,IDTDMS) )
! If we wanted to pass sensitivities all the way back to specific
! emissions inventories, we could carry on like so...
! IF( ( GFED2_IS_NEW() .or. ITS_A_NEW_MONTH_ADJ() ) .AND.
! & ( LBIOMASS ) ) THEN
!
! ! fwd code:
! !CALL GET_BIOMASS_NH3
! ! adj code:
! print*, ' need to add GET_BIOMASS_NH3_ADJ '
! !CALL GET_BIOMASS_NH3_ADJ
! !IF ( LPRT ) CALL DEBUG_MSG('### EMISSSULFATE: GET_BM_NH3_ADJ')
!
! ! fwd code:
! !CALL GET_BIOMASS_SO2
! ! adj code:
! print*, ' need to add GET_BIOMASS_SO2_ADJ'
! !CALL GET_BIOMASS_SO2_ADJ
! !IF ( LPRT ) CALL DEBUG_MSG('### EMISSSULFATE: GET_BM_SO2_ADJ')
!
! ENDIF
!
! !=================================================================
! ! If this is a new month, read in the monthly mean quantities
! !=================================================================
! IF ( ITS_A_NEW_MONTH() ) THEN
!
! ! fwd code:
! !! Read oxidants for the offline simulation only
! !IF ( ITS_AN_AEROSOL_SIM() ) CALL READ_OXIDANT( MONTH )
! ! adj code: not supported
!
! ! fwd code:
! !! Also read ship exhaust SO2 if necessary
! !CALL READ_SHIP_SO2( MONTH )
! ! adj code:
! CALL READ_SHIP_SO2_ADJ( MONTH )
!
!
! ! Add LANTHRO switch to turn off anthropogenic emissions.
! ! (ccc, 4/15/09)
! IF ( LANTHRO ) THEN
!
! ! fwd code:
! !CALL READ_AIRCRAFT_SO2( MONTH )
! !CALL READ_ANTHRO_SOx( MONTH, NSEASON )
! !CALL READ_ANTHRO_NH3( MONTH )
! ! adj code:
! CALL READ_ANTHRO_NH3_ADJ( MONTH )
! CALL READ_ANTHRO_SOx_ADJ( MONTH, NSEASON )
! CALL READ_AIRCRAFT_SO2_ADJ( MONTH )
!
! ENDIF
!
! ! fwd code:
! !! Read monthly mean data
! !CALL READ_SST( MONTH, YEAR )
! !CALL READ_OCEAN_DMS( MONTH )
! !CALL READ_BIOFUEL_SO2( MONTH )
! !CALL READ_BIOFUEL_NH3( MONTH )
! !CALL READ_NATURAL_NH3( MONTH )
! ! adj code:
! CALL READ_NATURAL_NH3_ADJ( MONTH )
! CALL READ_BIOFUEL_NH3_ADJ( MONTH )
! CALL READ_BIOFUEL_SO2_ADJ( MONTH )
! CALL READ_OCEAN_DMS_ADJ( MONTH )
! CALL READ_SST_ADJ( MONTH, YEAR )
!
!
! ENDIF
! Return to calling program
END SUBROUTINE EMISSSULFATE_ADJ
!-----------------------------------------------------------------------------
SUBROUTINE SRCNH3_ADJ( TC_ADJ )
!
!******************************************************************************
! Subroutine ADJ_SRCNH3 computes adjoint of emission from adjoint of tracer
! (dkh, 05/05/06)
!
! Based on forward routine SRCNH3 (rjp, bmy, 12/17/01, 2/22/05)
!
! Arguments as Input
! ============================================================================
! (1 ) TC_ADJ (REAL*8 ) : Array for adjoint of NH3 tracer mass in kg
!
! NOTES:
! (1 ) Update to GCv8
! (2 ) Now adjoints are w.r.t. NH3an, ENH3_bb, NH3bf and ENH3_na
! (3 ) Add LEMS_ABS option (dkh, 02/17/11)
! (4 ) Add support for LNEI05 (dkh, 02/19/11)
!******************************************************************************
!
! References to F90 modules
USE CAC_ANTHRO_MOD, ONLY : GET_CANADA_MASK
USE CAC_ANTHRO_MOD, ONLY : GET_CAC_ANTHRO
USE DIAG_MOD, ONLY : AD13_NH3_an, AD13_NH3_bb
USE DIAG_MOD, ONLY : AD13_NH3_bf, AD13_NH3_na
USE DAO_MOD, ONLY : PBL
USE GRID_MOD, ONLY : GET_AREA_CM2
USE EPA_NEI_MOD, ONLY : GET_EPA_ANTHRO, GET_EPA_BIOFUEL
USE EPA_NEI_MOD, ONLY : GET_USA_MASK
USE ERROR_MOD, ONLY : ERROR_STOP
USE LOGICAL_MOD, ONLY : LNEI99, LCAC, LNEI05, LNEI08
USE LOGICAL_MOD, ONLY : LRCP
USE NEI2005_ANTHRO_MOD, ONLY : GET_NEI2005_ANTHRO
USE NEI2005_ANTHRO_MOD, ONLY : NEI05_MASK => USA_MASK
USE NEI2008_ANTHRO_MOD, ONLY : GET_NEI2008_ANTHRO
USE NEI2008_ANTHRO_MOD, ONLY : NEI08_MASK => USA_MASK
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK, GET_TS_EMIS, GET_HOUR
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK_LT
USE TRACER_MOD, ONLY : XNUMOL
USE TRACERID_MOD, ONLY : IDTNH3
USE ADJ_ARRAYS_MOD, ONLY : EMS_SF_ADJ
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_an
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_na
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_bb
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ENH3_bf
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
USE ADJ_ARRAYS_MOD, ONLY : EMS_ADJ
USE LOGICAL_ADJ_MOD,ONLY : LPRINTFD
USE LOGICAL_ADJ_MOD,ONLY : LEMS_ABS
USE LOGICAL_MOD, ONLY : LHTAP
USE SULFATE_MOD, ONLY : ENH3_an
USE SULFATE_MOD, ONLY : ENH3_bb
USE SULFATE_MOD, ONLY : ENH3_bf
USE SULFATE_MOD, ONLY : ENH3_na
# include "CMN_SIZE" ! Size parameters
# include "CMN_DIAG" ! ND13
# include "CMN_GCTM" ! SCALE_HEIGHT
! Argumetns
REAL*8, INTENT(IN) :: TC_ADJ(IIPAR,JJPAR,LLPAR)
! Local variables
LOGICAL :: WEEKDAY
INTEGER :: I, J, L, K, NTOP, DAY_NUM, IH, DOW_LT
REAL*8 :: FEMIS, DTSRCE
REAL*8 :: AREA_CM2, EPA_AN, EPA_BF
REAL*8 :: CAC_AN
REAL*8 :: NH3an(IIPAR,JJPAR)
REAL*8 :: NH3bf(IIPAR,JJPAR)
REAL*8 :: TNH3_ADJ
!=================================================================
! SRCNH3_ADJ begins here!
!=================================================================
! Emission timestep [s]
DTSRCE = GET_TS_EMIS() * 60d0
! Get current day of the week
DAY_NUM = GET_DAY_OF_WEEK()
! Is it a weekday?
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
! Get hour (for NEI08)
IH = GET_HOUR() + 1
!=================================================================
! Overwrite USA with EPA/NEI NH3 emissions (if necessary)
! Store emissions into local arrays NH3an, NH3bf
!=================================================================
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF, CAC_AN )
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, AREA_CM2, EPA_AN, EPA_BF, CAC_AN, L )
!$OMP+PRIVATE( DOW_LT, WEEKDAY )
DO J = 1, JJPAR
!-------------------------------------------------------------------
! NOTE: There seems to be some problems with the EPA/NEI NH3
! emissions. Therefore we will use the existing emissions for NH3
! until further notice. Comment out the lines below until
! further notice. (bmy, 11/17/04)
!! Grid box surface area [cm2]
AREA_CM2 = GET_AREA_CM2( J )
!-------------------------------------------------------------------
DO I = 1, IIPAR
!-----------------------------------------------------------------
! NOTE: There seems to be some problems with the EPA/NEI NH3
! emissions. Therefore we will use the existing emissions for
! NH3 until further notice. Comment out the lines below until
! further notice. (bmy, 11/17/04)
!
!! If we are using EPA/NEI99 emissions ...
!IF ( LNEI99 ) THEN
!
! ! If we are over the USA ...
! IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
!
! ! Read NH3 anthro emissions in [molec NH3/cm2/s]
! EPA_AN = GET_EPA_ANTHRO( I, J, IDTNH3, WEEKDAY )
! EPA_BF = GET_EPA_BIOFUEL( I, J, IDTNH3, WEEKDAY )
!
! ! Convert from [molec NH3/cm2/s] to [kg NH3/box/sec]
! NH3an(I,J) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
! NH3bf(I,J) = EPA_BF * AREA_CM2 / XNUMOL(IDTNH3)
!
! ELSE
!
! ! If we are not over the USA, just use the regular
! ! emissions in NH3_an and NH3bf (bmy, 11/16/04)
! NH3an(I,J) = ENH3_an(I,J)
! NH3bf(I,J) = ENH3_bf(I,J)
!
! ENDIF
!
!ELSE
!-----------------------------------------------------------------
! If we are not using the EPA/NEI emissions, just copy the
! regular ENH3_an and ENH3_bf to local arrays. (bmy, 11/16/04)
NH3an(I,J) = ENH3_an(I,J)
NH3bf(I,J) = ENH3_bf(I,J)
! The RCP anthropogenic emission inventory already includes
! biofuel emissions, so we turn off the additional biofuel
! inventory (cdh, 8/31/12)
IF ( LRCP ) NH3bf(I,J) = 0d0
!-----------------------------------------------------------------
! NOTE: There seems to be some problems with the EPA/NEI NH3
! emissions. Therefore we will use the existing emissions for
! NH3 until further notice. Comment out the lines below until
! further notice. (bmy, 11/17/04)
!ENDIF
!-----------------------------------------------------------------
! If we are using CAC emissions and over CANADA
IF ( LCAC .and. .not. LHTAP .and. .not. LRCP ) THEN
IF ( GET_CANADA_MASK( I, J ) > 0d0 ) THEN
! Read NH3 anthro emissions in [molec NH3/cm2/s]
CAC_AN = GET_CAC_ANTHRO( I, J, IDTNH3,
& MOLEC_CM2_S=.TRUE.)
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
NH3an(I,J) = CAC_AN * AREA_CM2 / XNUMOL(IDTNH3)
ENDIF
ENDIF
! If we are using NEI 2005 over North America
IF ( LNEI05 .and. .not. LHTAP .and. .not. LRCP ) THEN
IF ( NEI05_MASK( I, J ) > 0d0 ) THEN
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
! For 2D NH3an (dkh, 02/19/11)
NH3an(I,J) = 0d0
DO L = 1, NOXLEVELS
! Read NH3 anthro emissions in [molec NH3/cm2/s]
EPA_AN = GET_NEI2005_ANTHRO( I, J, L, IDTNH3,
& WEEKDAY, MOLEC_CM2_S=.TRUE.)
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
! Keep NH3an 2D for now. (dkh, 02/19/11)
!NH3an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
NH3an(I,J) = NH3an(I,J)
& + EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
ENDDO
ENDIF
ENDIF
! If we are using NEI 2008 over North America
IF ( LNEI08 .and. .not. LHTAP .and. .not. LRCP ) THEN
IF ( NEI08_MASK( I, J ) > 0d0 ) THEN
DOW_LT = GET_DAY_OF_WEEK_LT( I, J, 1 )
WEEKDAY = ( DOW_LT > 0 .and. DOW_LT < 6 )
NH3an(I,J) = 0d0
DO L = 1, NOXLEVELS
! Read NH3 anthro emissions in [molec NH3/cm2/s]
EPA_AN = GET_NEI2008_ANTHRO( I, J, L, IH, IDTNH3,
& WEEKDAY )
! Convert from [molec NH3/cm2/c] to [kg NH3/box/sec]
! same as daven keep NH3an 2d
! NH3an(I,J,L) = EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
NH3an(I,J) = NH3an(I,J)
& + EPA_AN * AREA_CM2 / XNUMOL(IDTNH3)
ENDDO
ENDIF
ENDIF
ENDDO
ENDDO
!$OMP END PARALLEL DO
!=================================================================
! Partition NH3 emissions into the STT tracer array
!=================================================================
! Loop over surface grid boxes
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, NTOP, L, FEMIS )
!$OMP+PRIVATE( TNH3_ADJ )
!$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 ) )
!==============================================================
! Add NH3 emissions [kg NH3/box] into the tracer array
! Partition total NH3 throughout the entire boundary layer
!==============================================================
TNH3_ADJ = 0d0
! 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 )
! fwd code:
!! Add NH3 emissions into tracer array [kg NH3/timestep]
!TC(I,J,L) = TC(I,J,L) + ( TNH3 * FEMIS * DTSRCE )
! adj code:
TNH3_ADJ = TNH3_ADJ + ( TC_ADJ(I,J,L) * FEMIS * DTSRCE )
ENDDO
! fwd code:
!! Sum all types of NH3 emission [kg/box/s]
!TNH3 = NH3an(I,J) + ENH3_bb(I,J) +
& ! NH3bf(I,J) + ENH3_na(I,J)
! adj code:
EMS_SF_ADJ(I,J,1,IDADJ_ENH3_an) =
& EMS_SF_ADJ(I,J,1,IDADJ_ENH3_an) + TNH3_ADJ * NH3an(I,J)
EMS_SF_ADJ(I,J,1,IDADJ_ENH3_bb) =
& EMS_SF_ADJ(I,J,1,IDADJ_ENH3_bb) + TNH3_ADJ * ENH3_bb(I,J)
EMS_SF_ADJ(I,J,1,IDADJ_ENH3_bf) =
& EMS_SF_ADJ(I,J,1,IDADJ_ENH3_bf) + TNH3_ADJ * NH3bf(I,J)
EMS_SF_ADJ(I,J,1,IDADJ_ENH3_na) =
& EMS_SF_ADJ(I,J,1,IDADJ_ENH3_na) + TNH3_ADJ * ENH3_na(I,J)
! dkh debug
IF ( I == IFD .and. J == JFD .AND. LPRINTFD ) THEN
print*, ' SRCNH3 adj : NH3an = ', NH3an(I,J)
print*, ' SRCNH3 adj : ENH3_bb= ', ENH3_bb(I,J)
print*, ' SRCNH3 adj : NH3bf = ', NH3bf(I,J)
print*, ' SRCNH3 adj : ENH3_na= ', ENH3_na(I,J)
print*, ' SRCNH3 adj : TNH3_ADJ = ', TNH3_ADJ
print*, ' EMS_SF_ADJ(ENH3_an) = ',
& EMS_SF_ADJ(I,J,1,IDADJ_ENH3_an)
ENDIF
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Optional diagnostic -- add sensitivity w.r.t to absolute emissions (dkh, 02/17/11)
IF ( LEMS_ABS ) THEN
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, NTOP, L, FEMIS )
!$OMP+PRIVATE( TNH3_ADJ )
!$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 ) )
!==============================================================
! Add NH3 emissions [kg NH3/box] into the tracer array
! Partition total NH3 throughout the entire boundary layer
!==============================================================
TNH3_ADJ = 0d0
! 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 )
! fwd code:
!! Add NH3 emissions into tracer array [kg NH3/timestep]
!TC(I,J,L) = TC(I,J,L) + ( TNH3 * FEMIS * DTSRCE )
! adj code:
TNH3_ADJ = TNH3_ADJ + ( TC_ADJ(I,J,L) * FEMIS * DTSRCE )
ENDDO
! fwd code:
!! Sum all types of NH3 emission [kg/box/s]
!TNH3 = NH3an(I,J) + ENH3_bb(I,J) +
& ! NH3bf(I,J) + ENH3_na(I,J)
! adj code: also convert to J / (kg/box/timestep)
EMS_ADJ(I,J,1,IDADJ_ENH3_an)
& = EMS_ADJ(I,J,1,IDADJ_ENH3_an) + TNH3_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ENH3_bb)
& = EMS_ADJ(I,J,1,IDADJ_ENH3_bb) + TNH3_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ENH3_bf)
& = EMS_ADJ(I,J,1,IDADJ_ENH3_bf) + TNH3_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ENH3_na)
& = EMS_ADJ(I,J,1,IDADJ_ENH3_na) + TNH3_ADJ / DTSRCE
ENDDO
ENDDO
!$OMP END PARALLEL DO
ENDIF
! Return to calling program
END SUBROUTINE SRCNH3_ADJ
!------------------------------------------------------------------------------
SUBROUTINE SRCSO2_ADJ( TC_ADJ, NSEASON )
!
!******************************************************************************
! Subroutine SRCSO2_ADJ computes the adjoint of SO2 emisson scaling factors.
! (dkh, 05/04/06, 02/04/10)
!
! Based on forward model code SRCSO2 (rjp, bdf, bmy, 6/2/00, 2/27/09)
!
! Arguments as Input/Output:
! ===========================================================================
! (1 ) NSEASON (INTEGER) : Season number: 1=DJF; 2=MAM; 3=JJA; 4=SON
! (2 ) TC_ADJ (REAL*8 ) : adoint of SO2 tracer mass
!
! NOTES:
! (1 ) Doesn't deal with aircraft or volcanoe source yet.
! (2 ) Updated to GCv8 (dkh, 02/04/10)
! (3 ) Add support for LEMS_ABS
!******************************************************************************
!
! Reference to diagnostic arrays
USE BRAVO_MOD, ONLY : GET_BRAVO_ANTHRO, GET_BRAVO_MASK
USE CAC_ANTHRO_MOD, ONLY : GET_CANADA_MASK, GET_CAC_ANTHRO
USE DIAG_MOD, ONLY : AD13_SO2_an, AD13_SO2_ac
USE DIAG_MOD, ONLY : AD13_SO2_bb, AD13_SO2_nv
USE DIAG_MOD, ONLY : AD13_SO2_ev, AD13_SO2_bf
USE DIAG_MOD, ONLY : AD13_SO2_sh
USE DAO_MOD, ONLY : BXHEIGHT, PBL
USE EPA_NEI_MOD, ONLY : GET_EPA_ANTHRO, GET_EPA_BIOFUEL
USE EPA_NEI_MOD, ONLY : GET_USA_MASK
USE ERROR_MOD, ONLY : ERROR_STOP
USE GRID_MOD, ONLY : GET_AREA_CM2
USE LOGICAL_MOD, ONLY : LBRAVO, LNEI99, LSHIPSO2
USE LOGICAL_MOD, ONLY : LCAC, LNEI05, LNEI08
USE NEI2005_ANTHRO_MOD, ONLY : GET_NEI2005_ANTHRO
USE NEI2005_ANTHRO_MOD, ONLY : NEI05_MASK => USA_MASK
USE NEI2008_ANTHRO_MOD, ONLY : GET_NEI2008_ANTHRO
USE NEI2008_ANTHRO_MOD, ONLY : NEI08_MASK => USA_MASK
USE PBL_MIX_MOD, ONLY : GET_FRAC_OF_PBL, GET_PBL_TOP_L
USE TIME_MOD, ONLY : GET_TS_EMIS, GET_DAY_OF_YEAR
USE TIME_MOD, ONLY : GET_DAY_OF_WEEK, GET_HOUR
USE TRACER_MOD, ONLY : XNUMOL
USE TRACERID_MOD, ONLY : IDTSO2
USE LOGICAL_MOD, ONLY : LHTAP
USE HTAP_MOD, ONLY : GET_HTAP
! adj_group
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_an1, IDADJ_ESO2_an2
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_bb, IDADJ_ESO2_bf
USE ADJ_ARRAYS_MOD, ONLY : IDADJ_ESO2_sh
USE ADJ_ARRAYS_MOD, ONLY : EMS_SF_ADJ
USE ADJ_ARRAYS_MOD, ONLY : EMS_ADJ
USE LOGICAL_ADJ_MOD,ONLY : LEMS_ABS
USE SULFATE_MOD, ONLY : ESO2_an
USE SULFATE_MOD, ONLY : ESO2_bb
USE SULFATE_MOD, ONLY : ESO2_bf
USE SULFATE_MOD, ONLY : ESO2_sh
# 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_ADJ(IIPAR,JJPAR,LLPAR)
! Local variables
LOGICAL :: WEEKDAY
INTEGER :: I, J, K, L, LV1, LV2, NTOP, JDAY
INTEGER :: DAY_NUM, IH
REAL*8 :: ZH(0:LLPAR), DZ(LLPAR), SO2(LLPAR)
REAL*8 :: DTSRCE, HGHT, SO2SRC
REAL*8 :: SLAB, SLAB1
REAL*8 :: TSO2, FEMIS
REAL*8 :: AREA_CM2, AN, BF
REAL*8 :: SO2an(IIPAR,JJPAR,2)
REAL*8 :: SO2bf(IIPAR,JJPAR)
REAL*8 :: HTAP
! for adjoint
REAL*8 :: SO2SRC_ADJ
REAL*8 :: SO2_ADJ(LLPAR)
REAL*8 :: TSO2_ADJ
! Ratio of molecular weights: S/SO2
REAL*8, PARAMETER :: S_SO2 = 32d0 / 64d0
!=================================================================
! SRCSO2_ADJ begins here!
!================================================================
! DTSRCE is the emission timestep in seconds
DTSRCE = GET_TS_EMIS() * 60d0
! JDAY is the day of year (0-365 or 0-366)
JDAY = GET_DAY_OF_YEAR()
! Get current day of the week
DAY_NUM = GET_DAY_OF_WEEK()
! Get hour (for NEI08)
IH = GET_HOUR() + 1
! Is it a weekday?
WEEKDAY = ( DAY_NUM > 0 .and. DAY_NUM < 6 )
!=================================================================
! First we recalculate fwd model emissions
!=================================================================
! Adjoint of LENV not supported yet
! !=================================================================
! ! SO2 emissions from non-eruptive volcanoes [kg SO2/box/s].
! ! Assume that emission only occurs at the crater altitude.
! !=================================================================
! IF ( LENV ) THEN
!
! ! Initialize
! ESO2_nv = 0.d0
!
! ! Loop thru each non-erupting volcano
! DO K = 1, NNVOL
!
! ! Elevation of volcano crater
! HGHT = DBLE( IELVn(k) )
!
! ! Altitude of crater from the ground
! ZH(0) = 0.d0
!
! ! Loop over levels
! DO L = 1, LLPAR
!
! ! Thickness of layer [m] w/ crater
! DZ(L) = BXHEIGHT(INV(K),JNV(K),L)
!
! ! Increment altitude
! ZH(L) = ZH(L-1) + DZ(L)
!
! ! If we are at the crater altitude, add emissions and exit
! IF ( ZH(L-1) <= HGHT .AND. ZH(L) > HGHT ) THEN
! ESO2_nv(INV(K),JNV(K),L) =
! & ESO2_nv(INV(K),JNV(K),L) + Env(K)
! EXIT
! ENDIF
! ENDDO
! ENDDO
! ENDIF
!
! !=================================================================
! ! Calculate eruptive volcanic emission of SO2.
! !=================================================================
! IF ( LEEV ) THEN
!
! ! Initialize
! ESO2_ev = 0.D0
!
! ! Loop thru each erupting volcano
! DO K = 1, NEVOL
!
! ! Test to see if the volcano is erupting
! IF ( JDAY < IDAYS(K) .OR. JDAY > IDAYe(K) ) GOTO 20
!
! !===========================================================
! ! Define a slab at the top 1/3 of the volcano plume.
! !===========================================================
! HGHT = DBLE( IHGHT(K) )
!
! ! slab bottom height
! SLAB1 = HGHT - ( HGHT - DBLE ( IELVe(K) ) ) / 3.d0
!
! ! Slab thickness
! SLAB = HGHT - SLAB1
! ZH(0) = 0.d0
!
! ! Loop over each level
! DO L = 1, LLPAR
!
! ! DZ is the thickness of level L [m]
! DZ(L) = BXHEIGHT(IEV(K),JEV(K),L)
!
! ! ZH is the height of the top edge of
! ! level L, measured from the ground up [m]
! ZH(L) = ZH(L-1) + DZ(L)
!
! ! max model erup.height
! IF ( L == LLPAR .AND. HGHT > ZH(L) ) THEN
! LV2 = LLPAR
! !HGHT = ZH(L)
! !SLAB1 = SLAB1 - ( HGHT - ZH(L) )
! ENDIF
!
! !========================================================
! ! If Zh(l) <= bottom of the slab, go to next level.
! !========================================================
! IF ( ZH(L) <= SLAB1 ) GOTO 22
!
! !========================================================
! ! If the slab is only in current level: CASE 1
! ! ---------------------------------- ZH(L)
! ! HGHT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
! ! SLAB1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
! ! ---------------------------------- ZH(L-1)
! !========================================================
! IF ( ZH(L-1) <= SLAB1 .AND. ZH(L) >= HGHT ) THEN
! LV1 = L
! LV2 = L
! DZ(L) = SLAB
!
! !========================================================
! ! The slab extends more then one level. Find the
! ! lowest (lv1) and the highest (lv2) levels:
! ! --------------------------------- ZH(L)
! ! HGHT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
! ! --------------------------------- ZH(L-1)
! !
! ! --------------------------------- ZH(L)
! ! SLAB1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
! ! --------------------------------- ZH(L-1)
! !========================================================
! ELSE IF (ZH(L-1) <= SLAB1 .AND. ZH(L) > SLAB1) THEN
! LV1 = L
! DZ(L) = ZH(L) - SLAB1
!
! ELSE IF (ZH(L-1) < HGHT .AND. ZH(L) > HGHT ) THEN
! LV2 = L
! DZ(L) = HGHT - ZH(L-1)
! EXIT ! do 20
!
! ENDIF
!
! ! Go to next level
! 22 CONTINUE
! ENDDO
!
! !===========================================================
! ! Calculate SO2 emission in the levels between LV1 and LV2.
! ! Convert Eev from [kg SO2/box/event] to [kg SO2/box/s].
! ! ESO2_ev is distributed evenly with altitude among the slab.
! !===========================================================
! DO L = LV1, LV2
! ESO2_ev(IEV(K),JEV(K),L) = ESO2_ev(IEV(K),JEV(K),L) +
! & EEV(K) / ( (IDAYe(K)-IDAYs(K)+1) * 24.d0 * 3600.d0 )
! & * DZ(L) / SLAB
! ENDDO
!
! ! Go to next volcano
! 20 CONTINUE
! ENDDO
!
! ENDIF
!=================================================================
! Overwrite USA w/ EPA/NEI99 (anthro+biofuel) SO2 emissions
! Overwrite MEXICO w/ BRAVO (anthro only ) SO2 emissions
! Overwrite CANADA w/ CAC (anthro only ) SO2 emissions
!-----------------------------------------------------------------
! Note that we:
! Overwrite ASIA w/ STREETS and EUROPE w/ EMEP
! in READ_ANTHRO_SOx.
!
! In both cases, SO4 is a fraction of provided SO2 (except for
! EPA). It is done in READ_ANTHRO_SOX in the 1st case, and in
! SRCSO4 for inventories dealt with here. EPA is the only one to
! provide direct SO4, which is why we deal with it here, even
! though it does not have to be like that. Historical.
!
! So, since we have EPA here, we have to deal with BRAVO and
! CAC here to deal with their overlaping mask.
!
! (amv, phs, 3/12/08, 8/24/09)
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, AREA_CM2, AN, BF )
!$OMP+PRIVATE( HTAP )
!$OMP+SCHEDULE( DYNAMIC )
DO J = 1, JJPAR
! Initialize
AN = 0d0
BF = 0d0
! Grid box surface area [cm2]
AREA_CM2 = GET_AREA_CM2(J)
DO I = 1, IIPAR
!------- Prior to 3/8/07 (phs)
!!-----------------------------------------------------------
!! If we are using EPA/NEI99 (anthro + biofuel) ...
!!-----------------------------------------------------------
!IF ( LNEI99 ) THEN
!
! ! If we are over the USA ...
! IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
!
! ! Read EPA/NEI99 SO2 emissions in [molec/cm2/s]
! AN = GET_EPA_ANTHRO( I, J, IDTSO2, WEEKDAY )
! BF = GET_EPA_BIOFUEL(I, J, IDTSO2, WEEKDAY )
!
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! ! Place all anthro SO2 into surface layer
! SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
! SO2an(I,J,2) = 0d0
!
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! SO2bf(I,J) = BF * AREA_CM2 / XNUMOL(IDTSO2)
!
! ELSE
!
! ! If we are not over the USA, then just use the regular
! ! emissions from ESO2_an and ESO2_bf (bmy, 11/16/04)
! SO2an(I,J,1) = ESO2_an(I,J,1)
! SO2an(I,J,2) = ESO2_an(I,J,2)
! SO2bf(I,J) = ESO2_bf(I,J)
!
! ENDIF
!
!ELSE
!
! ! If we are not using EPA/NEI99 emissions, then just copy
! ! ESO2_an and ESO2_bf into local arrays (bmy, 11/16/04)
! SO2an(I,J,1) = ESO2_an(I,J,1)
! SO2an(I,J,2) = ESO2_an(I,J,2)
! SO2bf(I,J) = ESO2_bf(I,J)
!
!ENDIF
!
!!-----------------------------------------------------------
!! If we are using BRAVO emissions over Mexico ...
!!-----------------------------------------------------------
!IF ( LBRAVO ) THEN
!
! ! If we are over Mexico ...
! IF ( GET_BRAVO_MASK( I, J ) > 0d0 ) THEN
!
! ! Read BRAVO SO2 emissions in [molec/cm2/s]
! AN = GET_BRAVO_ANTHRO( I, J, IDTSO2 )
!
! ! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! ! Place all anthro SO2 into surface layer
! SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
! SO2an(I,J,2) = 0d0
!
! ELSE
!
! ! If we are not over MEXICO, then just use
! ! the regular emissions from ESO2_an
! SO2an(I,J,1) = ESO2_an(I,J,1)
! SO2an(I,J,2) = ESO2_an(I,J,2)
!
! ENDIF
!
!ELSE
!
! ! If we are not using BRAVO emissions, then just copy
! ! ESO2_an and ESO2_bf into local arrays
! SO2an(I,J,1) = ESO2_an(I,J,1)
! SO2an(I,J,2) = ESO2_an(I,J,2)
! SO2bf(I,J) = ESO2_bf(I,J)
!
!ENDIF
!-----------------------------------------------------------
! Default SO2 from GEIA or EDGAR (w/ optional STREETS for
! ASIA, and EMEP for Europe)
!-----------------------------------------------------------
SO2an(I,J,1) = ESO2_an(I,J,1)
SO2an(I,J,2) = ESO2_an(I,J,2)
SO2bf(I,J) = ESO2_bf(I,J)
!-----------------------------------------------------------
! If we are using EPA/NEI99 over the USA (anthro + biofuel)
!-----------------------------------------------------------
IF ( LNEI99 ) THEN
IF ( GET_USA_MASK( I, J ) > 0d0 ) THEN
! Read EPA/NEI99 SO2 emissions in [molec/cm2/s]
AN = GET_EPA_ANTHRO( I, J, IDTSO2, WEEKDAY )
BF = GET_EPA_BIOFUEL(I, J, IDTSO2, WEEKDAY )
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! Place all anthro SO2 into surface layer
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
SO2an(I,J,2) = 0d0
! Convert biofuel SO2 from [molec/cm2/s] to [kg/box/s]
SO2bf(I,J) = BF * AREA_CM2 / XNUMOL(IDTSO2)
ENDIF
ENDIF
!-----------------------------------------------------------
! If we are using BRAVO emissions over Mexico (anthro)
!-----------------------------------------------------------
IF ( LBRAVO ) THEN
IF ( GET_BRAVO_MASK( I, J ) > 0d0 ) THEN
! Read BRAVO SO2 emissions in [molec/cm2/s]
AN = GET_BRAVO_ANTHRO( I, J, IDTSO2 )
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! Place all anthro SO2 into surface layer.
! Add to USA emissions if on the border.
IF ( LNEI99 .and. GET_USA_MASK( I, J) > 0d0 ) THEN
SO2an(I,J,1) = SO2an(I,J,1) +
& AN * AREA_CM2 / XNUMOL(IDTSO2)
ELSE
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
ENDIF
SO2an(I,J,2) = 0d0
ENDIF
ENDIF
!-----------------------------------------------------------
! If we are using CAC emissions over Canada ...
!-----------------------------------------------------------
IF ( LCAC ) THEN
IF ( GET_CANADA_MASK( I, J ) > 0d0 ) THEN
! Read CAC SO2 emissions in [molec/cm2/s]
AN = GET_CAC_ANTHRO( I, J, IDTSO2,
& MOLEC_CM2_s=.TRUE. )
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
! Place all anthro SO2 into surface layer.
! Add to USA emissions if on the border.
IF ( LNEI99 .and. GET_USA_MASK( I, J) > 0d0 ) THEN
SO2an(I,J,1) = SO2an(I,J,1) +
& AN * AREA_CM2 / XNUMOL(IDTSO2)
ELSE
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
ENDIF
SO2an(I,J,2) = 0d0
ENDIF
ENDIF
!-----------------------------------------------------------
! If we are using EPA/NEI 2005 over USA.
! Must be called after CAC and BRAVO to simply overwrite
! where they overlap
! Modify for use with 2-level SO2an (dkh, 02/19/11)
!-----------------------------------------------------------
IF ( LNEI05 ) THEN
IF ( NEI05_MASK( I, J ) > 0d0 ) THEN
! Read USA SO2 emissions in [molec/cm2/s]
! Level L=1 (dkh, 02/19/11)
AN = GET_NEI2005_ANTHRO( I, J, 1, IDTSO2, WEEKDAY,
& MOLEC_CM2_s=.TRUE. )
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
SO2an(I,J,1) = AN * AREA_CM2 / XNUMOL(IDTSO2)
SO2an(I,J,2) = 0d0
! Read USA SO2 emissions in [molec/cm2/s]
DO L = 2, NOXLEVELS
AN = GET_NEI2005_ANTHRO( I, J, L, IDTSO2, WEEKDAY,
& MOLEC_CM2_s=.TRUE. )
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
!SO2an(I,J,L) = AN * AREA_CM2 / XNUMOL(IDTSO2)
SO2an(I,J,2) = SO2an(I,J,2)
& + AN * AREA_CM2 / XNUMOL(IDTSO2)
ENDDO
ENDIF
ENDIF
! updated to NEI08
! IF ( LNEI08 .and. .not. LHIST ) THEN
IF ( LNEI08 ) THEN
IF ( NEI08_MASK( I, J ) > 0d0 ) THEN
SO2an(I,J,:) = 0d0
! Read USA SO2 emissions in [molec/cm2/s]
DO L = 1, NOXLEVELS
AN = GET_NEI2008_ANTHRO( I, J, L, IH, IDTSO2, WEEKDAY )
!fp for compatibility
IF ( L == 1 ) THEN
! Convert anthro SO2 from [molec/cm2/s] to [kg/box/s]
SO2an(I,J,L) = AN * AREA_CM2 / XNUMOL(IDTSO2)
ELSE
SO2an(I,J,2) = SO2an(I,J,2) +
& AN * AREA_CM2 / XNUMOL(IDTSO2) !put everything in level 2
ENDIF
ENDDO
ENDIF
ENDIF
IF ( LHTAP ) THEN
DO L = 1, NOXLEVELS
HTAP = GET_HTAP( I, J, IDTSO2 )
IF ( L == 1 ) THEN
! Convert anthro SO2 from [kg/m2/s] to [kg/box/s]
SO2an(I,J,1) = HTAP * AREA_CM2 * 1d-4
ELSE
! SO2an(I,J,2) = SO2an(I,J,2) + HTAP(I,J)
! & * AREA_CM2 * 1d-4
SO2an(I,J,2) = 0d0
ENDIF
ENDDO
ENDIF
ENDDO
ENDDO
!$OMP END PARALLEL DO
!=================================================================
! Adjoint of Add SO2 emissions into model levels
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, NTOP, L, SO2, TSO2, FEMIS, SO2SRC )
!$OMP+PRIVATE( SO2SRC_ADJ, SO2_ADJ, TSO2_ADJ )
!$OMP+SCHEDULE( DYNAMIC )
DO J = 1, JJPAR
DO I = 1, IIPAR
! Top of the boundary layer
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
DO L = 1, LLPAR
! Add SO2 to TC array [kg/box/timestep]
! fwd code:
!TC(I,J,L) = TC(I,J,L) + ( SO2SRC * DTSRCE )
! adj code:
SO2SRC_ADJ = TC_ADJ(I,J,L) * DTSRCE
! SO2 emissions [kg/box/s]
! fwd code:
!SO2SRC = SO2(L) + ESO2_ac(I,J,L) +
! ESO2_nv(I,J,L) + ESO2_ev(I,J,L)
! adj code:
SO2_ADJ(L) = SO2SRC_ADJ
! adj code not implemented yet
! ESO2_ac_ADJ(I,J,L) = ... etc
ENDDO
!===============================================================
! 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
TSO2_ADJ = 0d0
! 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
! fwd_code:
!SO2(L) = FEMIS * TSO2
! adj_code:
TSO2_ADJ = TSO2_ADJ + SO2_ADJ(L) * FEMIS
ENDDO
! Also add SO2 from ship exhaust if necessary (bec, bmy, 5/20/04)
! fwd code:
!TSO2 = TSO2 + ESO2_sh(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_sh)
! adj code:
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_sh) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_sh) + ESO2_sh(I,J) * TSO2_ADJ
! Sum of anthro (surface + 100m), biomass, biofuel SO2 at (I,J)
! fwd code:
!TSO2 = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
! + SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
! + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
! + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
! adj code:
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an1) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an1)
& + SO2an(I,J,1) * TSO2_ADJ
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an2) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an2)
& + SO2an(I,J,2) * TSO2_ADJ
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bb) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bb)
& + ESO2_bb(I,J) * TSO2_ADJ
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bf) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bf)
& + SO2bf(I,J) * TSO2_ADJ
!===============================================================
! 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
! Also add ship exhaust SO2 into surface if necessary
! (bec, bmy, 5/20/04)
! fwd code:
!SO2(1) = SO2(1)
! + ESO2_sh(I,J) * EMS_SF(I,J,IDADJ_ESO2_sh)
! adj code:
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_sh) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_sh) +
& ESO2_sh(I,J) * SO2_ADJ(1)
! fwd code:
!SO2(1) = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
! + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
! + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
!SO2(2) = SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
! adj code:
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an1) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an1) +
& SO2an(I,J,1) * SO2_ADJ(1)
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bb) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bb) +
& ESO2_bb(I,J) * SO2_ADJ(1)
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bf) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_bf) +
& SO2bf(I,J) * SO2_ADJ(1)
EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an2) =
& EMS_SF_ADJ(I,J,1,IDADJ_ESO2_an2) +
& SO2an(I,J,2) * SO2_ADJ(2)
ENDIF
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Optional diagnostic -- sensitivity w.r.t. absolute emissions (dkh, 02/17/11)
IF ( LEMS_ABS ) THEN
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, NTOP, L, SO2, TSO2, FEMIS, SO2SRC )
!$OMP+PRIVATE( SO2SRC_ADJ, SO2_ADJ, TSO2_ADJ )
!$OMP+SCHEDULE( DYNAMIC )
DO J = 1, JJPAR
DO I = 1, IIPAR
! Top of the boundary layer
NTOP = CEILING( GET_PBL_TOP_L( I, J ) )
DO L = 1, LLPAR
! Add SO2 to TC array [kg/box/timestep]
! fwd code:
!TC(I,J,L) = TC(I,J,L) + ( SO2SRC * DTSRCE )
! adj code:
SO2SRC_ADJ = TC_ADJ(I,J,L) * DTSRCE
! SO2 emissions [kg/box/s]
! fwd code:
!SO2SRC = SO2(L) + ESO2_ac(I,J,L) +
! ESO2_nv(I,J,L) + ESO2_ev(I,J,L)
! adj code:
SO2_ADJ(L) = SO2SRC_ADJ
! adj code not implemented yet
! ESO2_ac_ADJ(I,J,L) = ... etc
ENDDO
!===============================================================
! 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
TSO2_ADJ = 0d0
! 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
! fwd_code:
!SO2(L) = FEMIS * TSO2
! adj_code:
TSO2_ADJ = TSO2_ADJ + SO2_ADJ(L) * FEMIS
ENDDO
! Also add SO2 from ship exhaust if necessary (bec, bmy, 5/20/04)
! fwd code:
!TSO2 = TSO2 + ESO2_sh(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_sh)
! adj code: also convert to ( J / kg / box / timestep )
EMS_ADJ(I,J,1,IDADJ_ESO2_sh)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_sh)
& + TSO2_ADJ / DTSRCE
! Sum of anthro (surface + 100m), biomass, biofuel SO2 at (I,J)
! fwd code:
!TSO2 = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
! + SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
! + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
! + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
! adj code: also convert to J / ( kg/box/timestep )
EMS_ADJ(I,J,1,IDADJ_ESO2_an1)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_an1)
& + TSO2_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_an2)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_an2)
& + TSO2_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_bb)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_bb)
& + TSO2_ADJ / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_bf)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_bf)
& + TSO2_ADJ / DTSRCE
!===============================================================
! 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
! Also add ship exhaust SO2 into surface if necessary
! (bec, bmy, 5/20/04)
! fwd code:
!SO2(1) = SO2(1)
! + ESO2_sh(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_sh)
! adj code: also convert to J / (kg/box/timestep)
EMS_ADJ(I,J,1,IDADJ_ESO2_sh)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_sh)
& + SO2_ADJ(1) / DTSRCE
! fwd code:
!SO2(1) = SO2an(I,J,1) * EMS_SF(I,J,1,IDADJ_ESO2_an1)
! + ESO2_bb(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bb)
! + SO2bf(I,J) * EMS_SF(I,J,1,IDADJ_ESO2_bf)
!SO2(2) = SO2an(I,J,2) * EMS_SF(I,J,1,IDADJ_ESO2_an2)
! adj code: also convert to kg/box/timestep
EMS_ADJ(I,J,1,IDADJ_ESO2_an1)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_an1)
& + SO2_ADJ(1) / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_bb)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_bb)
& + SO2_ADJ(1) / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_bf)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_bf)
& + SO2_ADJ(1) / DTSRCE
EMS_ADJ(I,J,1,IDADJ_ESO2_an2)
& = EMS_ADJ(I,J,1,IDADJ_ESO2_an2)
& + SO2_ADJ(2) / DTSRCE
ENDIF
ENDDO
ENDDO
!$OMP END PARALLEL DO
ENDIF
! Return to calling program
END SUBROUTINE SRCSO2_ADJ
!------------------------------------------------------------------------------
!
! FUNCTION GET_OH( I, J, L ) RESULT( OH_MOLEC_CM3 )
!!
!!******************************************************************************
!! Function GET_OH returns OH from SMVGEAR's CSPEC array (for coupled runs)
!! or monthly mean OH (for offline runs). Imposes a diurnal variation on
!! OH for offline simulations. (bmy, 12/16/02, 7/20/04)
!!
!! Arguments as Input:
!! ============================================================================
!! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!!
!! NOTES:
!! (1 ) We assume SETTRACE has been called to define IDOH (bmy, 11/1/02)
!! (2 ) Now use function GET_TS_CHEM from "time_mod.f" (bmy, 3/27/03)
!! (3 ) Now reference ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM from
!! "tracer_mod.f". Also replace IJSURF w/ an analytic function.
!! (bmy, 7/20/04)
!!******************************************************************************
!!
! ! References to F90 modules
! USE COMODE_MOD, ONLY : CSPEC, JLOP
! USE DAO_MOD, ONLY : SUNCOS
! USE ERROR_MOD, ONLY : ERROR_STOP
! USE GLOBAL_OH_MOD, ONLY : OH
! USE TIME_MOD, ONLY : GET_TS_CHEM
! USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
! USE TRACERID_MOD, ONLY : IDOH
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: I, J, L
!
! ! Local variables
! INTEGER :: JLOOP
! REAL*8 :: OH_MOLEC_CM3
!
! !=================================================================
! ! GET_OH begins here!
! !=================================================================
! IF ( ITS_A_FULLCHEM_SIM() ) THEN
!
! !---------------------
! ! Coupled simulation
! !---------------------
!
! ! JLOOP = SMVGEAR 1-D grid box index
! JLOOP = JLOP(I,J,L)
!
! ! Take OH from the SMVGEAR array CSPEC
! ! OH is defined only in the troposphere
! IF ( JLOOP > 0 ) THEN
! OH_MOLEC_CM3 = CSPEC(JLOOP,IDOH)
! ELSE
! OH_MOLEC_CM3 = 0d0
! ENDIF
!
! ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
!
! !---------------------
! ! Offline simulation
! !---------------------
!
! ! 1-D grid box index for SUNCOS
! JLOOP = ( (J-1) * IIPAR ) + I
!
! ! Test for sunlight...
! IF ( SUNCOS(JLOOP) > 0d0 .and. TCOSZ(I,J) > 0d0 ) THEN
!
! ! Impose a diurnal variation on OH during the day
! OH_MOLEC_CM3 = OH(I,J,L) *
! & ( SUNCOS(JLOOP) / TCOSZ(I,J) ) *
! & ( 1440d0 / GET_TS_CHEM() )
!
! ! Make sure OH is not negative
! OH_MOLEC_CM3 = MAX( OH_MOLEC_CM3, 0d0 )
!
! ELSE
!
! ! At night, OH goes to zero
! OH_MOLEC_CM3 = 0d0
!
! ENDIF
!
! ELSE
!
! !---------------------
! ! Invalid simulation
! !---------------------
! CALL ERROR_STOP( 'Invalid NSRCX!', 'GET_OH (sulfate_mod.f)')
!
! ENDIF
!
! ! Return to calling program
! END FUNCTION GET_OH
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE SET_OH( I, J, L, OH )
!!
!!******************************************************************************
!! Function SET_OH saves the modified OH value back to SMVGEAR's CSPEC array
!! for coupled sulfate/aerosol simulations. (bmy, 12/16/02)
!!
!! Arguments as Input:
!! ============================================================================
!! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!! (4 ) OH (REAL*8 ) : OH at grid box (I,J,L) to be saved into CSPEC
!!
!! NOTES:
!! (1 ) We assume SETTRACE has been called to define IDOH (bmy, 12/16/02)
!!******************************************************************************
!!
! ! References to F90 modules
! USE COMODE_MOD, ONLY : CSPEC, JLOP
! USE TRACERID_MOD, ONLY : IDOH
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: I, J, L
! REAL*8, INTENT(IN) :: OH
!
! ! Local variables
! INTEGER :: JLOOP
!
! !=================================================================
! ! SET_OH begins here!
! !=================================================================
!
! ! JLOOP = SMVGEAR 1-D grid box index
! JLOOP = JLOP(I,J,L)
!
! ! Replace OH into CSPEC(troposphere only)
! IF ( JLOOP > 0 ) THEN
! CSPEC(JLOOP,IDOH) = OH
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE SET_OH
!
!!------------------------------------------------------------------------------
!
! FUNCTION GET_NO3( I, J, L ) RESULT( NO3_MOLEC_CM3 )
!!
!!******************************************************************************
!! Function GET_NO3 returns NO3 from SMVGEAR's CSPEC array (for coupled runs)
!! or monthly mean OH (for offline runs). For offline runs, the concentration
!! of NO3 is set to zero during the day. (rjp, bmy, 12/16/02)
!!
!! Arguments as Input:
!! ============================================================================
!! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!!
!! NOTES:
!! (1 ) Now references ERROR_STOP from "error_mod.f". We also assume that
!! SETTRACE has been called to define IDNO3. Now also set NO3 to
!! zero during the day. (rjp, bmy, 12/16/02)
!! (2 ) Now reference ITS_A_FULLCHEM_SIM and ITS_AN_AEROSOL_SIM from
!! "tracer_mod.f". Also remove reference to CMN. Also replace
!! IJSURF with an analytic function. (bmy, 7/20/04)
!!******************************************************************************
!!
! ! References to F90 modules
! USE COMODE_MOD, ONLY : CSPEC, JLOP
! USE DAO_MOD, ONLY : AD, SUNCOS
! USE ERROR_MOD, ONLY : ERROR_STOP
! USE GLOBAL_NO3_MOD, ONLY : NO3
! USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
! USE TRACERID_MOD, ONLY : IDNO3
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: I, J, L
!
! ! Local variables
! INTEGER :: JLOOP
! REAL*8 :: NO3_MOLEC_CM3
!
! ! External functions
! REAL*8, EXTERNAL :: BOXVL
!
! !=================================================================
! ! GET_NO3 begins here!
! !=================================================================
! IF ( ITS_A_FULLCHEM_SIM() ) THEN
!
! !--------------------
! ! Coupled simulation
! !--------------------
!
! ! 1-D SMVGEAR grid box index
! JLOOP = JLOP(I,J,L)
!
! ! Take NO3 from the SMVGEAR array CSPEC
! ! NO3 is defined only in the troposphere
! IF ( JLOOP > 0 ) THEN
! NO3_MOLEC_CM3 = CSPEC(JLOOP,IDNO3)
! ELSE
! NO3_MOLEC_CM3 = 0d0
! ENDIF
!
! ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
!
! !==============================================================
! ! Offline simulation: Read monthly mean GEOS-CHEM NO3 fields
! ! in [v/v]. Convert these to [molec/cm3] as follows:
! !
! ! vol NO3 moles NO3 kg air kg NO3/mole NO3
! ! ------- = --------- * -------- * ---------------- = kg NO3
! ! vol air moles air 1 kg air/mole air
! !
! ! And then we convert [kg NO3] to [molec NO3/cm3] by:
! !
! ! kg NO3 molec NO3 mole NO3 1 molec NO3
! ! ------ * --------- * -------- * ----- = ---------
! ! 1 mole NO3 kg NO3 cm3 cm3
! ! ^ ^
! ! |____________________|
! ! this is XNUMOL_NO3
! !
! ! If at nighttime, use the monthly mean NO3 concentration from
! ! the NO3 array of "global_no3_mod.f". If during the daytime,
! ! set the NO3 concentration to zero. We don't have to relax to
! ! the monthly mean concentration every 3 hours (as for HNO3)
! ! since NO3 has a very short lifetime. (rjp, bmy, 12/16/02)
! !==============================================================
!
! ! 1-D grid box index for SUNCOS
! JLOOP = ( (J-1) * IIPAR ) + I
!
! ! Test if daylight
! IF ( SUNCOS(JLOOP) > 0d0 ) THEN
!
! ! NO3 goes to zero during the day
! NO3_MOLEC_CM3 = 0d0
!
! ELSE
!
! ! At night: Get NO3 [v/v] and convert it to [kg]
! NO3_MOLEC_CM3 = NO3(I,J,L) * AD(I,J,L) * ( 62d0/28.97d0 )
!
! ! Convert NO3 from [kg] to [molec/cm3]
! NO3_MOLEC_CM3 = NO3_MOLEC_CM3 * XNUMOL_NO3 / BOXVL(I,J,L)
!
! ENDIF
!
! ! Make sure NO3 is not negative
! NO3_MOLEC_CM3 = MAX( NO3_MOLEC_CM3, 0d0 )
!
! ELSE
!
! !--------------------
! ! Invalid simulation
! !--------------------
! CALL ERROR_STOP( 'Invalid NSRCX!','GET_NO3 (sulfate_mod.f)')
!
! ENDIF
!
! ! Return to calling program
! END FUNCTION GET_NO3
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE SET_NO3( I, J, L, NO3 )
!!
!!******************************************************************************
!! Function SET_NO3 saves the modified NO3 value back to SMVGEAR's CSPEC array
!! for coupled lfate/aerosol simulations. (rjp, bmy, 12/16/02, 7/20/04)
!!
!! Arguments as Input:
!! ============================================================================
!! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!! (4 ) NO3 (REAL*8 ) : OH at grid box (I,J,L) to be saved into CSPEC
!!
!! NOTES:
!! (1 ) We assume SETTRACE has been called to define IDNO3. (bmy, 12/16/02)
!! (2 ) Remove references to "error_mod.f" and CMN (bmy, 7/20/04)
!!******************************************************************************
!!
! ! References to F90 modules
! USE COMODE_MOD, ONLY : CSPEC, JLOP
! USE TRACERID_MOD, ONLY : IDNO3
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: I, J, L
! REAL*8, INTENT(IN) :: NO3
!
! ! Local variables
! INTEGER :: JLOOP
!
! !=================================================================
! ! SET_NO3 begins here!
! !=================================================================
!
! ! 1-D grid box index for CSPEC
! JLOOP = JLOP(I,J,L)
!
! ! Replace OH into CSPEC (troposphere only)
! IF ( JLOOP > 0 ) THEN
! CSPEC(JLOOP,IDNO3) = NO3
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE SET_NO3
!
!!------------------------------------------------------------------------------
FUNCTION GET_O3( I, J, L ) RESULT( O3_VV )
!
!******************************************************************************
! Function GET_O3 returns monthly mean O3 for offline sulfate aerosol
! simulations. (bmy, 12/16/02, 10/25/05)
!
! Arguments as Input:
! ============================================================================
! (1-3) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!
! NOTES:
! (1 ) We assume SETTRACE has been called to define IDO3. (bmy, 12/16/02)
! (2 ) Now reference inquiry functions from "tracer_mod.f" (bmy, 7/20/04)
! (3 ) Now remove reference to CMN, it's obsolete. (bmy, 8/22/05)
! (4 ) Now references XNUMOLAIR from "tracer_mod.f" (bmy, 10/25/05)
!******************************************************************************
!
! References to F90 modules
USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME
USE DAO_MOD, ONLY : AIRDEN
USE ERROR_MOD, ONLY : ERROR_STOP
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM, ITS_AN_AEROSOL_SIM
USE TRACER_MOD, ONLY : XNUMOLAIR
USE TRACERID_MOD, ONLY : IDO3
# include "CMN_SIZE" ! Size parameters
! Arguments
INTEGER, INTENT(IN) :: I, J, L
! Local variables
INTEGER :: JLOOP
REAL*8 :: O3_VV
!=================================================================
! GET_O3 begins here!
!=================================================================
IF ( ITS_A_FULLCHEM_SIM() ) THEN
!--------------------
! Coupled simulation
!--------------------
! JLOOP = SMVGEAR 1-D grid box index
JLOOP = JLOP(I,J,L)
! Get O3 from CSPEC [molec/cm3] and convert it to [v/v]
! O3 data will only be defined below the tropopause
IF ( JLOOP > 0 ) THEN
O3_VV = ( CSPEC(JLOOP,IDO3) * 1d6 ) /
& ( AIRDEN(L,I,J) * XNUMOLAIR )
ELSE
O3_VV = 0d0
ENDIF
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
! !--------------------
! ! Offline simulation
! !--------------------
!
! ! Get O3 [v/v] for this gridbox & month
! ! O3 data will only be defined below the tropopause
! IF ( L <= LLTROP ) THEN
! O3_VV = O3m(I,J,L)
! ELSE
! O3_VV = 0d0
! ENDIF
!
!ELSE
!--------------------
! Invalid simulation
!--------------------
CALL ERROR_STOP( 'Invalid NSRCX!',
$ 'GET_O3 (sulfate_adj_mod.f)')
ENDIF
! Return to calling program
END FUNCTION GET_O3
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_NONERUP_VOLC
!!
!!******************************************************************************
!! Subroutine READ_NONERUP_VOLC reads SO2 emissions from non-eruptive
!! volcanoes. (rjp, bdf, bmy, 9/19/02, 10/3/05)
!!
!! NOTES:
!! (1 ) Split off from old module routine "sulfate_readyr" (bmy, 9/19/02)
!! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/" (bmy, 7/28/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE FILE_MOD, ONLY : IU_FILE, IOERROR
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Local variables
! INTEGER :: I, IOS, J, K, L
! REAL*8 :: EE
! CHARACTER(LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_NONERUP_VOLC begins here!
! !=================================================================
!
! ! Initialize
! K = 1
! Env = 0.d0
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/volcano.con.' // GET_RES_EXT()
!
! !=================================================================
! ! Read NON-eruptive volcanic SO2 emission (GEIA) into Env.
! ! Convert Env from [Mg SO2/box/day] to [kg SO2/box/s].
! !=================================================================
!
! ! Fancy output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_NONERUP_VOLC: Reading ', a )
!
! ! Open file
! OPEN( IU_FILE, FILE=TRIM( FILENAME ), STATUS='OLD', IOSTAT=IOS )
! IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:1' )
!
! ! Read header lines
! DO L = 1, 2
! READ( IU_FILE, '(a)', IOSTAT=IOS )
! IF ( IOS > 0 ) THEN
! CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:2' )
! ENDIF
! ENDDO
!
! ! Read data values
! DO
! READ( IU_FILE, '(49x,i4,e11.3,1x,2i4)', IOSTAT=IOS )
! & IELVn(k), EE, INV(K), JNV(k)
!
! ! Check for EOF
! IF ( IOS < 0 ) EXIT
!
! ! Trap I/O error
! IF ( IOS > 0 ) THEN
! CALL IOERROR( IOS, IU_FILE, 'read_nonerup_volc:3' )
! ENDIF
!
! ! Unit conversion: [Mg SO2/box/day] -> [kg SO2/box/s]
! Env(k) = EE * 1000.d0 / ( 24.d0 * 3600.d0 )
!
! ! Increment counter
! K = K + 1
! ENDDO
!
! ! Close file
! CLOSE( IU_FILE )
!
! ! NNVOL = Number of non-eruptive volcanoes
! NNVOL = K - 1
!
! ! Return to calling program
! END SUBROUTINE READ_NONERUP_VOLC
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_ERUP_VOLC
!!
!!*****************************************************************************
!! Subroutine READ_ERUP_VOLC reads SO2 emissions from eruptive
!! volcanoes. (rjp, bdf, bmy, 9/19/02, 10/3/05)
!!
!! NOTES:
!! (1 ) Split off from old module routine "sulfate_readyr" (bmy, 9/19/02)
!! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/" (bmy, 7/28/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!*****************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE FILE_MOD, ONLY : IU_FILE, IOERROR
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Local variables
! INTEGER :: I, IOS, IUNIT, J, K, L, M
! REAL*8 :: A, B, Fe, X, EE
! CHARACTER(LEN=255) :: FILENAME
!
! !==================================================================
! ! READ_ERUP_VOLC begins here
! !==================================================================
!
! ! Initialize
! K = 1
! Eev(:) = 0.d0
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/volcano.erup.1990.' //
! & GET_RES_EXT()
!
! !==================================================================
! ! Read eruptive volcanic SO2 emission (based on Smithsonian data
! ! base, SO2 emission and cloud height are a function of VEI.
! ! Data are over-written if TOMS observations are available.
! ! Also define a slab with a thickness of 1/3 of the cloud column,
! ! and SO2 are emitted uniformely within the slab.
! !
! ! Convert Ee from [kton SO2] to [kg SO2/box] and store in Eev.
! ! ESO2_ev(i,j,l) in [kg SO2/box/s] will be calculated in SRCSO2.
! !==================================================================
!
! ! Fancy output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_ERUP_VOLC: Reading ', a )
!
! ! Open file
! OPEN( IU_FILE, FILE=TRIM( FILENAME ), STATUS='OLD', IOSTAT=IOS )
! IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_erup_volc:1' )
!
! ! Read header lines
! DO L = 1, 2
! READ( IU_FILE, '(a)', IOSTAT=IOS )
! IF ( IOS > 0 ) THEN
! CALL IOERROR( IOS, IU_FILE, 'read_erup_volc:2' )
! ENDIF
! ENDDO
!
! ! Read data values
! DO
! READ( IU_FILE, '(47x,3i6,6x,i6,es11.3,1x,2i4)', IOSTAT=IOS )
! & IELVe(K), IDAYs(K), IDAYe(K), IHGHT(K),
! & Ee, IEV(K), JEV(K)
!
! ! Check for EOF
! IF ( IOS < 0 ) EXIT
!
! ! Trap I/O error
! IF ( IOS > 0 ) THEN
! CALL IOERROR( IOS, IU_FILE, 'sulfate_readyr:6' )
! ENDIF
!
! ! Unit conversion: [kton SO2/box/event] -> [kg SO2/box/event]
! Eev(k) = Ee * 1.d6
!
! ! Increment count
! K = K + 1
! ENDDO
!
! ! Close file
! CLOSE( IU_FILE )
!
! ! NEVOL = Number of eruptive volcanoes
! NEVOL = K - 1
!
! ! Return to calling program
! END SUBROUTINE READ_ERUP_VOLC
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_ANTHRO_SOx( THISMONTH, NSEASON )
!!
!!******************************************************************************
!! Suborutine READ_ANTHRO_SOx reads the anthropogenic SOx from disk,
!! and partitions it into anthropogenic SO2 and SO4.
!! (rjp, bdf, bmy, 9/20/02, 10/31/08)
!!
!! Arguments as Input:
!! ============================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Now use functions GET_XMID and GET_YMID to compute lon and lat
!! centers of grid box (I,J). Now replace DXYP(JREF)*1d4 with routine
!! GET_AREA_CM2 of "grid_mod.f". Now use functions GET_MONTH and
!! GET_YEAR of time_mod.f". Now call READ_BPCH2 with QUIET=.TRUE.
!! (bmy, 3/27/03)
!! (2 ) Now references DATA_DIR from "directory_mod.f". Also removed
!! reference to CMN, it's not needed. (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids (bmy, 8/16/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (5 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
!! (6 ) Now computes future SOx emissions (swu, bmy, 5/30/06)
!! (7 ) Now can read either EDGAR or GEIA emissions (avd, bmy, 7/14/06)
!! (8 ) Now overwrite David Streets' SO2, if necessary (yxw, bmy, 8/14/06)
!! (9 ) Now accounts for FSCLYR (phs, 3/17/08)
!! (9 ) Bug fix: Using tracer #30 in the call to GET_STREETS_ANTHRO can cause
!! problems when adding or removing species. Replace w/ IDTNH3.
!! (dkh, 10/31/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE EDGAR_MOD, ONLY : GET_EDGAR_ANTH_SO2
! USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO
! USE EMEP_MOD, ONLY : GET_EUROPE_MASK
! USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2ff
! USE GRID_MOD, ONLY : GET_XMID, GET_YMID
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE LOGICAL_MOD, ONLY : LFUTURE, LEDGARSOx
! USE LOGICAL_MOD, ONLY : LSTREETS, LEMEP
! USE STREETS_ANTHRO_MOD, ONLY : GET_SE_ASIA_MASK
! USE STREETS_ANTHRO_MOD, ONLY : GET_STREETS_ANTHRO
! USE TIME_MOD, ONLY : GET_YEAR
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTSO2, IDTSO4
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
! USE SCALE_ANTHRO_MOD, ONLY : GET_ANNUAL_SCALAR
!
!# include "CMN_SIZE" ! Size parameters
!# include "CMN_O3" ! FSCALYR
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH, NSEASON
!
! ! Local variables
! INTEGER :: I, J, L, IX, JX, IOS
! INTEGER, SAVE :: LASTYEAR = -99
! INTEGER :: SCALEYEAR
! REAL*4 :: E_SOx(IGLOB,JGLOB,2)
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: XTAU, Fe, X, Y, AREA_CM2
! REAL*8 :: EDG_SO2
! CHARACTER(LEN=4) :: SYEAR
! CHARACTER(LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_ANTHRO_SOx begins here!
! !=================================================================
!
! IF ( FSCALYR < 0 ) THEN
! SCALEYEAR = GET_YEAR()
! ELSE
! SCALEYEAR = FSCALYR
! ENDIF
!
!
! IF ( LEDGARSOx ) 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,
! & IDTSO2, KG_S=.TRUE. )
!
! ! Streets 2006 includes biofuels.
! IF ( SCALEYEAR >= 2006 ) ESO2_bf(I,J) = 0d0
!
! ENDIF
! ENDIF
!
! ! If we are using EMEP over Europe...
! IF ( LEMEP ) THEN
!
! IF (GET_EUROPE_MASK(I,J) > 0d0) THEN
!
!!-----------------------------------------------------------------------------
!! Prior to 11/14/08:
!! BUG FIX: Using tracer #26 in the call to GET_EMEP_ANTHRO can cause
!! problems when adding or removing species. Replace w/ IDTSO2.
!! (phs, 11/14/08)
!! EDG_SO2 = GET_EMEP_ANTHRO( I, J, 26, KG_S=.TRUE. )
!!-----------------------------------------------------------------------------
! EDG_SO2 = GET_EMEP_ANTHRO( I, J,
! $ IDTSO2, KG_S=.TRUE. )
!
! ENDIF
!
! ENDIF
!
! ! Compute SO4/SOx fraction for EUROPE
! IF ( ( X >= -12.5 .and. X <= 60.0 ) .and.
! & ( Y >= 36.0 .and. Y <= 78.0 ) ) THEN
! Fe = 0.05d0
!
! ! Compute SO4/SOx fraction for NORTH AMERICA
! ELSE IF ( ( X >= -167.5 .and. X <= -52.5 ) .and.
! & ( Y >= 26.0 .and. Y <= 74.0 ) ) THEN
! Fe = 0.014d0
!
! ! Compute SO4/SOx fraction for EVERYWHERE ELSE
! ELSE
! Fe = 0.03d0
!
! ENDIF
!
! ! Store SO2 emission [kg SO2/s]
! ESO2_an(I,J,1) = EDG_SO2
! ESO4_an(I,J,2) = 0d0
!
! ! Compute SO4 from SO2 [kg SO4/s]
! ESO4_an(I,J,1) = EDG_SO2 * Fe / ( 1.d0 - Fe )
! ESO4_an(I,J,2) = 0d0
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ELSE
!
! !==============================================================
! ! Use GEIA SOx emissions
! !==============================================================
!
! ! Define filename
! FILENAME = TRIM( DATA_DIR ) //
! & 'fossil_200104/merge_nobiofuels.' //
! & GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_ANTHRO_SOx: Reading ', a )
!
! ! Pick the right TAU value for the given season
! ! Seasons: 1=DJF, 2=MAM, 3=JJA, 4=SON
! SELECT CASE ( NSEASON )
! CASE ( 1 )
! XTAU = -744d0
! CASE ( 2 )
! XTAU = 1416d0
! CASE ( 3 )
! XTAU = 3624d0
! CASE ( 4 )
! XTAU = 5832d0
! END SELECT
!
! ! Read anthropogenic SOx [molec/cm2/s]
! CALL READ_BPCH2( FILENAME, 'ANTHSRCE', 27,
! & XTAU, IGLOB, JGLOB,
! & 2, E_SOx, QUIET=.TRUE. )
!
! !=================================================================
! ! Read in yearly SO2 scale factors here
! ! (For now we only have 1998, deal w/ other years later)
! !=================================================================
!!-- prior to 3/11/08
! !IF ( LASTYEAR < 0 ) THEN
! !
! ! ! put in SOX scale year here (hardwired to 1998 for now)
! ! SYEAR = '1998'
! ! FILENAME = TRIM( DATA_DIR ) //
! !& 'sulfate_sim_200508/scalefoss.SOx.' //
! !& GET_RES_EXT() // '.' // SYEAR
! !
! ! ! Echo output
! ! WRITE( 6, 100 ) TRIM( FILENAME )
! !
! ! ! Get TAU value (use Jan 1, 1998 for scale factors)
! ! XTAU = GET_TAU0( 1, 1, 1998 )
! !
! ! ! Read anthropogenic SOx [molec/cm2/s]
! ! CALL READ_BPCH2( FILENAME, 'SCALFOSS', 3,
! !& XTAU, IGLOB, JGLOB,
! !& 1, ARRAY, QUIET=.TRUE. )
! !
! ! ! Cast from REAL*4 to REAL*8
! ! CALL TRANSFER_2D( ARRAY(:,:,1), SOx_SCALE )
! !
! ! ! Reset LASTYEAR
! ! LASTYEAR = GET_YEAR()
! !ENDIF
!
!
! ! Get annual scalar factor (amv, 08/24/07)
! CALL GET_ANNUAL_SCALAR( 73, 1985, SCALEYEAR, SOx_SCALE )
!
! !==============================================================
! ! Partition SOx into SO2 and SO4, according to the following
! ! fractions (cf Chin et al, 2000):
! !
! ! Europe [ 36N-78N, 12.5W-60.0E ]: 5.0% of SOx is SO4
! ! 95.0% of SOx is SO2
! !
! ! N. America [ 26N-74N, 167.5W-52.5W ]: 1.4% of SOx is SO4
! ! 98.6% of SOx is SO2
! !
! ! Everywhere else: 3.0% of SOx is SO4
! ! 97.0% of SOx is SO2
! !==============================================================
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, L, AREA_CM2, Y, X, Fe )
! DO L = 1, 2
! DO J = 1, JJPAR
!
! ! Grid box surface area [cm2]
! AREA_CM2 = GET_AREA_CM2( J )
!
! ! Latitude [degrees]
! Y = GET_YMID( J )
!
! DO I = 1, IIPAR
!
! ! Longitude [degrees]
! X = GET_XMID( I )
!
! ! First scale SOx to the given fossil fuel year
! E_SOx(I,J,L) = E_SOx(I,J,L) * SOx_SCALE(I,J)
!
! ! Compute future SOx emissions (if necessary)
! IF ( LFUTURE ) THEN
! E_SOx(I,J,L) = E_SOx(I,J,L) *
! & GET_FUTURE_SCALE_SO2ff( I, J )
! ENDIF
!
! ! Compute SO4/SOx fraction for EUROPE
! IF ( ( X >= -12.5 .and. X <= 60.0 ) .and.
! & ( Y >= 36.0 .and. Y <= 78.0 ) ) THEN
! Fe = 0.05d0
!
! ! Compute SO4/SOx fraction for NORTH AMERICA
! ELSE IF ( ( X >= -167.5 .and. X <= -52.5 ) .and.
! & ( Y >= 26.0 .and. Y <= 74.0 ) ) THEN
! Fe = 0.014d0
!
! ! Compute SO4/SOx fraction for EVERYWHERE ELSE
! ELSE
! Fe = 0.03d0
!
! ENDIF
!
! ! Compute SO2 (tracer #2) from SOx
! ! Convert from [molec SOx/cm2/s] to [kg SO2/box/s]
! ESO2_an(I,J,L) = E_SOx(I,J,L) * ( 1.d0 - Fe ) *
! & AREA_CM2 / XNUMOL(IDTSO2)
!
! ! If we are using David Streets' emissions
! ! Remember: those include BF if Year is GE 2006
! IF ( LSTREETS ) THEN
!
! ! If we are over the SE Asia region
! IF ( GET_SE_ASIA_MASK( I, J ) > 0d0 ) THEN
!
! ! Overwrite GEIA SO2 w/ David Streets' SO2 [kg SO2/s]
! ESO2_an(I,J,1) = GET_STREETS_ANTHRO( I, J, IDTSO2,
! & KG_S=.TRUE. )
!
! ! Zero 2nd level of emissions
! ESO2_an(I,J,2) = 0d0
!
! ENDIF
! ENDIF
!
! IF ( LEMEP ) THEN
!
! IF (GET_EUROPE_MASK(I,J) > 0d0 ) THEN
!
! ESO2_an(I,J,1) = GET_EMEP_ANTHRO( I, J, IDTSO2,
! & KG_S=.TRUE. )
!
! ESO2_an(I,J,2) = 0d0
!
! ENDIF
!
! ENDIF
!
!!--- prior 6/23/08
!! Now calculate SO4 from SO2, since SOx not available with STREETS and EMEP
!! ! Compute SO4 (tracer #3) from SOx
!! ! Convert from [molec SOx/cm2/s] to [kg SO4/box/s]
!! ESO4_an(I,J,L) = E_SOx(I,J,L) * Fe *
!! & AREA_CM2 / XNUMOL(IDTSO4)
!
! ESO4_an(I,J,L) = ESO2_an(I,J,L) * Fe / (1.d0-Fe)
!
! ENDDO
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE READ_ANTHRO_SOx
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_OCEAN_DMS( THISMONTH )
!!
!!*****************************************************************************
!! Subroutine READ_OCEAN_DMS reads seawater concentrations of DMS (nmol/L).
!! (rjp, bdf, bmy, 9/20/02, 10/3/05)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
!! (2 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
!! (3 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (4 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids (bmy, 8/16/05)
!! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!*****************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: XTAU
! CHARACTER(LEN=255) :: FILENAME
!
! !==================================================================
! ! READ_OCEAN_DMS begins here!
! !==================================================================
!
! ! File name
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/DMS_seawater.' //
! & GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_OCEAN_DMS: Reading ', a )
!
! ! TAU value (use generic year 1985)
! XTAU = GET_TAU0( THISMONTH, 1, 1985 )
!
! ! Read ocean DMS [nmol/L]
! CALL READ_BPCH2( FILENAME, 'BIOGSRCE', 25,
! & XTAU, IGLOB, JGLOB,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8
! CALL TRANSFER_2D( ARRAY(:,:,1), DMSo )
!
! ! Return to calling program
! END SUBROUTINE READ_OCEAN_DMS
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_SST( THISMONTH, THISYEAR )
!!
!!*****************************************************************************
!! Subroutine READ_SST reads monthly mean sea surface temperatures.
!! (rjp, bdf, bmy, 9/18/02, 11/17/05)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!! (2 ) THISYEAR (INTEGER) : Current 4-digit year
!!
!! NOTES:
!! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
!! (2 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
!! (3 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (4 ) Now use interannual SST data from NOAA if present; otherwise use
!! climatological SST data. Now read data for both GCAP and GEOS
!! grids (bmy, 8/16/05)
!! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (6 ) Now read int'annual SST data on the GEOS 1x1 grid (bmy, 11/17/05)
!!*****************************************************************************
!!
! ! 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_BIOFUEL_SO2( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_BIOFUEL_SO2 reads monthly mean biomass burning
!! emissions for SO2. SOx is read in, and converted to SO2.
!! (rjp, bdf, bmy, phs, 1/16/03, 12/23/08)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
!! (2 ) Modified molar ratio of biomass burning SO2 per CO. Added SO2
!! emission from biofuel burning. (rjp, bmy, 1/16/03)
!! (3 ) Now replace DXYP(J+J0)*1d4 with routine GET_AREA_CM2 of "grid_mod.f"
!! Now replace MONTH with the argument THISMONTH. Now call READ_BPCH2
!! with QUIET=.TRUE. (bmy, 3/27/03)
!! (4 ) Now references DATA_DIR from "directory_mod.f". Also removed
!! references to CMN and CMN_SETUP. (bmy, 7/20/04)
!! (5 ) Now can read either seasonal or interannual biomass burning emissions.
!! Now references routines from both "logical_mod.f" and "time_mod.f".
!! Now reads SO2 biomass emissions directly rather than computing
!! it by mole fraction from CO. (rjp, bmy, 1/11/05)
!! (6 ) Now read data for both GCAP and GEOS grids (bmy, 8/16/05)
!! (7 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (8 ) Now computes future biomass emissions, if necessary (swu, bmy, 5/30/06)
!! (9 ) Now only read the biofuel, we have moved the biomass-reading code
!! to "gc_biomass_mod.f" for compatibility with GFED2 biomass emissions
!! (bmy, 9/27/06)
!! (10) Now prevent seg fault if BIOMASS emissions are turned off.
!! (bmy, 10/3/06)
!! (11) Renamed READ_BIOFUEL_SO2, and move all biomass code to GET_BIOMASS_SO2
!! to account for several GFED2 products (yc, phs, 12/23/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BIOMASS_MOD, ONLY : BIOMASS, IDBSO2
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2bf
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE LOGICAL_MOD, ONLY : LBIOMASS, LFUTURE
! USE TIME_MOD, ONLY : ITS_A_LEAPYEAR
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTSO2
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! INTEGER :: I, J, THISYEAR
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: BIOCO(IIPAR,JJPAR)
!!-- prior 12/23/08
!! REAL*8 :: CONV, XTAU
! REAL*8 :: XTAU
! CHARACTER(LEN=4 ) :: CYEAR
! CHARACTER(LEN=255) :: FILENAME
!
! ! Days per month
! REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0, 31d0, 30d0,
! & 31d0, 31d0, 30d0, 31d0, 30d0, 31d0/)
!
! !=================================================================
! ! READ_BIOFUEL_SO2 begins here!
! !=================================================================
!
! !=================================================================
! ! Compute biofuel SO2 from biofuel CO. Use a molar
! ! ratio of 0.0015 moles SO2/mole CO from biofuel burning.
! ! (Table 2, [Andreae and Merlet, 2001])
! !=================================================================
!
! ! File name for biofuel burning file
! FILENAME = TRIM( DATA_DIR ) //
! & 'biofuel_200202/biofuel.' // GET_NAME_EXT_2D() //
! & '.' // GET_RES_EXT()
!
! ! Echo info
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_BIOFUEL_SO2: Reading ', a )
!
! ! Get TAU0 value (use generic year 1985)
! XTAU = GET_TAU0( 1, 1, 1985 )
!
! ! Read Biofuel burning of CO [kg/yr]
! CALL READ_BPCH2( FILENAME, 'BIOFSRCE', 4,
! & XTAU, IGLOB, JGLOB,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8
! CALL TRANSFER_2D( ARRAY(:,:,1), BIOCO )
!
! !=================================================================
! ! Unit conversion to [kg SO2/s]
! !=================================================================
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!----------------------------------------------------------------------
!! Prior to 1/28/09:
!! Need to remove CONV from the PRIVATE statement (bmy, 1/28/09)
!!!$OMP+PRIVATE( I, J, CONV )
!!----------------------------------------------------------------------
!!$OMP+PRIVATE( I, J )
! ! Loop over longitudes
! DO J = 1, JJPAR
!
!!-- prior 12/23/08
!! ! Conversion factor for [cm2 * kg/molec]
!! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTSO2)
!
! ! Loop over latitudes
! DO I = 1, IIPAR
!
!!-- prior 12/23/08
!! ! Convert biomass SO2 from [molec SO2/cm2/s] -> [kg SO2/s]
!! ! NOTE: Future scale has already been applied by this point
!! IF ( LBIOMASS ) THEN
!! ESO2_bb(I,J) = BIOMASS(I,J,IDBSO2) * CONV
!! ELSE
!! ESO2_bb(I,J) = 0d0
!! ENDIF
!
! ! Convert biofuel SO2 from [kg CO/yr] to [kg SO2/s]
! ESO2_bf(I,J) = ( BIOCO(I,J) * 64d-3 * 0.0015d0 /
! & ( 28d-3 * 86400.d0 * 365.25d0 ) )
!
! ! Apply future emissions to biofuel SO2, if necessary
! IF ( LFUTURE ) THEN
! ESO2_bf(I,J) = ESO2_bf(I,J) *
! & GET_FUTURE_SCALE_SO2bf( I, J )
! ENDIF
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ! Return to calling program
! END SUBROUTINE READ_BIOFUEL_SO2
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE GET_BIOMASS_SO2
!!
!!******************************************************************************
!! Subroutine GET_BIOMASS_SO2 retrieve monthly/8-day/3hr biomass burning
!! emissions for SO2. (yc, phs, 12/23/08)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 )
!!
!! NOTES:
!! (1 ) Extracted from old module subroutine READ_BIOMASS_SO2
!! (yc, phs, 12/23/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BIOMASS_MOD, ONLY : BIOMASS, IDBSO2
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTSO2
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Local variables
! INTEGER :: I, J
! REAL*8 :: CONV
!
! !=================================================================
! ! GET_BIOMASS_SO2 begins here!
! !=================================================================
! ! Unit conversion to [kg SO2/s]
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, CONV )
!
! ! Loop over longitudes
! DO J = 1, JJPAR
!
! ! Conversion factor for [cm2 * kg/molec]
! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTSO2)
!
! ! Loop over latitudes
! DO I = 1, IIPAR
!
! ! Convert biomass SO2 from [molec SO2/cm2/s] -> [kg SO2/s]
! ! NOTE: Future scale has already been applied by this point
! ESO2_bb(I,J) = BIOMASS(I,J,IDBSO2) * CONV
!
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ! Return to calling program
! END SUBROUTINE GET_BIOMASS_SO2
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_AIRCRAFT_SO2( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_AIRCRAFT_SO2 reads monthly mean aircraft fuel emissions
!! and converts them to SO2 emissions. (rjp, bdf, bmy, 9/18/02, 10/3/05)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Extracted from old module routine SULFATE_READMON (bmy, 9/18/02)
!! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids (bmy, 8/16/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!******************************************************************************
!!
! ! Reference to F90 modules
! USE BPCH2_MOD, ONLY : GET_RES_EXT, GET_TAU0, READ_BPCH2
! USE DAO_MOD, ONLY : BXHEIGHT
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE FILE_MOD, ONLY : IU_FILE, IOERROR
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! INTEGER :: I, IOS, J, K, L
! REAL*8 :: ACSO2(IGLOB,JGLOB,20)
! REAL*8 :: FAC, FUEL, DZ(LLPAR), ZH(0:LLPAR)
! CHARACTER(LEN=255) :: FILENAME
!
! ! Month names
! CHARACTER(LEN=3) :: CMONTH(12) = (/'jan', 'feb', 'mar', 'apr',
! & 'may', 'jun', 'jul', 'aug',
! & 'sep', 'oct', 'nov', 'dec'/)
!
! !=================================================================
! ! READ_AIRCRAFT_SO2 begins here!
! !=================================================================
!
! ! Zero arrays
! ESO2_ac = 0d0
! ACSO2 = 0d0
!
! ! File name
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/aircraft.' // GET_RES_EXT() //
! & '.1992.' // CMONTH(THISMONTH)
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_AIRCRAFT_SO2: Reading ', a )
!
! !=================================================================
! ! Read aircraft emissions. These are fuel burned in [kg/box/day],
! ! from AEAP for 1992. SO2 emission is calculated by assuming
! ! an emission index EI of 1.0, i.e., 1g of SO2 emitted per kg
! ! of fuel burned. It is also assumed that there is no diurnal
! ! variation of emission rate. Convert to [kg SO2/box/s].
! !=================================================================
!
! ! Open file
! OPEN( IU_FILE, FILE=FILENAME, STATUS='OLD', IOSTAT=IOS )
! IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:1' )
!
! ! Read header line
! READ( IU_FILE, '(/)', IOSTAT=IOS )
! IF ( IOS > 0 ) CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:2' )
!
! ! Read data values until an EOF is found
! DO
! READ( IU_FILE, '(3i4,e11.3)', IOSTAT=IOS ) I, J, L, FUEL
!
! ! EOF encountered
! IF ( IOS < 0 ) EXIT
!
! ! I/O error condition
! IF ( IOS > 0 ) THEN
! CALL IOERROR( IOS, IU_FILE, 'read_aircraft_so2:3' )
! ENDIF
!
! ! Unit conversion: [kg Fuel/box/day] -> [kg SO2/box/s]
! ! Assuming an emission index of 1.0,
! ! 1 g SO2 / kg fuel burned [Weisenstein et al., 1996]
! ACSO2(I,J,L+1) = 1.d-3 * FUEL / ( 24.d0 * 3600d0 )
! ENDDO
!
! ! Close file
! CLOSE( IU_FILE )
!
! !=================================================================
! ! Interpolate from the 1-km grid to the given GEOS-CHEM grid
! ! NOTE: we need to account for window grids (bmy, 9/20/02)
! !=================================================================
! DO J = 1, JJPAR
! DO I = 1, IIPAR
!
! ! ACSO2 is the aircraft SO2 on the 1-km vertical grid
! FUEL = SUM( ACSO2(I,J,:) )
! IF ( FUEL < 1d-20 ) CYCLE
!
! ! There are 20 1-km levels
! DO K = 1, 20
!
! ! Initialize
! ZH(0) = 0.d0
!
! ! Loop over levels
! DO L = 1, LLPAR
!
! ! Altitude of top edge of level L, from ground [km]
! ZH(L) = ZH(L-1) + ( BXHEIGHT(I,J,L) * 1d-3 )
!
! IF ( ZH(L-1) > DBLE(K) ) EXIT
! IF ( ZH(L ) < DBLE(K-1) ) CYCLE
!
! IF ( ZH(L) < DBLE(K) ) THEN
! FAC = ZH(L) - MAX( ZH(L-1), DBLE(K-1) )
! ESO2_ac(I,J,L) = ESO2_ac(I,J,L) + ACSO2(I,J,K) * FAC
! ELSE
! FAC = DBLE(K) - MAX( ZH(L-1), DBLE(K-1) )
! ESO2_ac(I,J,L) = ESO2_ac(I,J,L) + ACSO2(I,J,K) * FAC
! EXIT
! ENDIF
! ENDDO
! ENDDO
! ENDDO
! ENDDO
!
! ! Return to calling program
! END SUBROUTINE READ_AIRCRAFT_SO2
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_SHIP_SO2( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_SHIP_SO2 reads in ship SO2 emissions, from either Corbett
!! et al or EDGAR inventories. (bec, qli, 10/01/03, 7/14/06)
!!
!! Arguments as Input:
!! ============================================================================
!! (1 ) THISMONTH (INTEGER) : Current month (1-12)
!!
!! NOTES:
!! (1 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (2 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids. (bmy, 8/16/05)
!! (3 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (4 ) Now references XNUMOL from "tracer_mod.f" (bmy, 10/25/05)
!! (5 ) Now get EDGAR ship SO2 emissions if necessary. Also apply future
!! emissions scale factors to the default Corbett et al ship emissions.
!! (avd, bmy, 7/14/06)
!! (6 ) Now references GET_ARCTAS_HIP from 'arctas_ship_emiss_mod.f" and
!! GET_EMEP_ANTHRO to get ARCTAS and EMEP SO2 ship emissions (phs, 12/5/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE ARCTAS_SHIP_EMISS_MOD,ONLY : GET_ARCTAS_SHIP
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE EDGAR_MOD, ONLY : GET_EDGAR_SHIP_SO2
! USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO, GET_EUROPE_MASK
! USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_SO2ff
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE LOGICAL_MOD, ONLY : LEDGARSHIP, LFUTURE,
! & LARCSHIP, LSHIPSO2,
! $ LEMEPSHIP
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTSO2
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! INTEGER :: I, J
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*4 :: SHIPSO2(IIPAR,JJPAR)
! REAL*8 :: XTAU, AREA_CM2
! CHARACTER (LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_SHIP_SO2 begins here!
! !=================================================================
!
! ! Reset
! ESO2_sh = 0D0
!
!
! ! Test for EDAGR last, since this is default inventory by design.
! ! So we can still use EDGAR SHIP to get ship-NOX and CO, and
! ! overwrite ship-SO2 with ARCTAS or Colbert (phs, 12/5/08)
!
! !-----------------------------------------------------------
! ! Use ARCTAS SHIP emissions (EDGAR 2006 update)
! !-----------------------------------------------------------
! IF ( LARCSHIP ) THEN
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J )
! DO J = 1, JJPAR
! DO I = 1, IIPAR
!
! ! Read ARCTAS SO2 emissions in [kg SO2/BOX/s]
! ESO2_sh(I,J) = GET_ARCTAS_SHIP( I, J, IDTSO2, KG_S=.TRUE. )
!
! IF ( LEMEPSHIP ) THEN
! IF ( GET_EUROPE_MASK(I,J) > 0d0 )
! $ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
! & KG_S=.TRUE.,
! $ SHIP=.TRUE.)
! ENDIF
!
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! !----------------------------------------
! ! Or Corbett et al ship SO2 emissions
! !----------------------------------------
! ELSE IF ( LSHIPSO2 ) THEN
!
! ! Filename
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/shipSOx.' // GET_NAME_EXT_2D() //
! & '.' // GET_RES_EXT()
!
! ! Echo some information to the standard output
! WRITE( 6, 110 ) TRIM( FILENAME )
! 110 FORMAT( ' - READ_SHIP_SO2 ', a )
!
! ! TAU value at the beginning of this month
! XTAU = GET_TAU0( THISMONTH, 1, 1985 )
!
! ! Read in this month's ship SO2 emissions [molec SO2/cm2/s]
! CALL READ_BPCH2( FILENAME, 'SO2-SHIP', 26,
! & XTAU, IIPAR, JJPAR,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8
! CALL TRANSFER_2D( ARRAY(:,:,1), SHIPSO2 )
!
! ! Loop over latitudes
! DO J = 1, JJPAR
!
! ! Grid box surface area [cm2]
! AREA_CM2 = GET_AREA_CM2( J )
!
! ! Loop over longitudes
! DO I = 1, IIPAR
!
! ! Convert [molec SO2/cm2/s] to [kg SO2/box/s]
! ESO2_sh(I,J) = SHIPSO2(I,J) * AREA_CM2 / XNUMOL(IDTSO2)
!
! ! Apply future emissions (if necessary)
! IF ( LFUTURE ) THEN
! ESO2_sh(I,J) = ESO2_sh(I,J) *
! & GET_FUTURE_SCALE_SO2ff( I, J )
! ENDIF
!
! IF ( LEMEPSHIP ) THEN
! IF ( GET_EUROPE_MASK(I,J) > 0d0 )
! $ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
! $ KG_S=.TRUE., SHIP=.TRUE.)
! ENDIF
!
! ENDDO
! ENDDO
!
! !-----------------------------------------------------------
! ! Test for EDGAR ship emissions
! !-----------------------------------------------------------
! ELSE IF ( LEDGARSHIP ) THEN
!
! !----------------------------------------
! ! Use EDGAR ship SO2 emissions
! !----------------------------------------
!
! ! Get EDGAR ship SO2 [kg SO2/box/s]
! ! NOTE: Future emissions have already been applied!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J )
! DO J = 1, JJPAR
! DO I = 1, IIPAR
!
! ESO2_sh(I,J) = GET_EDGAR_SHIP_SO2( I, J, KG_S=.TRUE. )
!
! IF ( LEMEPSHIP ) THEN
! IF ( GET_EUROPE_MASK(I,J) > 0d0 )
! $ ESO2_sh(I,J) = GET_EMEP_ANTHRO(I, J, IDTSO2,
! & KG_S=.TRUE.,
! $ SHIP=.TRUE.)
! ENDIF
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE READ_SHIP_SO2
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_ANTHRO_NH3( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_ANTHRO_NH3 reads the monthly mean anthropogenic
!! NH3 emissions from disk and converts to [kg NH3/box/s].
!! (rjp, bdf, bmy, 9/20/02, 10/31/08)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Renamed from NH3_READ to READ_ANTHRO_NH3. Also updated comments,
!! made cosmetic changes. (bmy, 9/20/02)
!! (2 ) Changed filename to NH3_anthsrce.geos.*. Also now reads data under
!! category name "NH3-ANTH". (rjp, bmy, 3/23/03)
!! (3 ) Now reads from NH3emis.monthly.geos.* files. Now call READ_BPCH2
!! with QUIET=.TRUE. (bmy, 3/27/03)
!! (4 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (5 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids. (bmy, 8/16/05)
!! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (6 ) Now compute future emissions, if necessary (swu, bmy, 5/30/06)
!! (7 ) Now overwrite w/ David Streets' NH3, if necessary (yxw, bmy, 8/17/06)
!! (8 ) Bug fix: Using tracer #30 in the call to GET_STREETS_ANTHRO can cause
!! problems when adding or removing species. Replace w/ IDTNH3.
!! (dkh, 10/31/08)
!! (9 ) Now check if NH3 Streets is available (phs, 12/10/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE EMEP_MOD, ONLY : GET_EMEP_ANTHRO
! USe EMEP_MOD, ONLY : GET_EUROPE_MASK
! USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_NH3an
! USE LOGICAL_MOD, ONLY : LFUTURE, LSTREETS
! USE LOGICAL_MOD, ONLY : LEMEP
! USE STREETS_ANTHRO_MOD, ONLY : GET_SE_ASIA_MASK
! USE STREETS_ANTHRO_MOD, ONLY : GET_STREETS_ANTHRO
! USE TRACERID_MOD, ONLY : IDTNH3
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! LOGICAL :: WEEKDAY
! INTEGER :: I, J, DAY_NUM
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: AREA_CM2, EPA_NEI, XTAU
! REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0,
! & 31d0, 30d0, 31d0, 31d0,
! & 30d0, 31d0, 30d0, 31d0 /)
! CHARACTER(LEN=255) :: FILENAME
! REAL*8 :: STREETS
!
! !=================================================================
! ! READ_ANTHRO_NH3 begins here!
! !=================================================================
!
! ! File name
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/NH3_anthsrce.' //
! & GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_ANTHRO_NH3: Reading ', a )
!
! ! Get TAU value (use year 1990, the year of the data!)
! XTAU = GET_TAU0( THISMONTH, 1, 1990 )
!
! ! Read 1990 NH3 emissions [kg N/box/mon]
! CALL READ_BPCH2( FILENAME, 'NH3-ANTH', 29,
! & XTAU, IGLOB, JGLOB,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8
! CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_an )
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J )
! DO J = 1, JJPAR
! DO I = 1, IIPAR
!
! ! Convert from [kg N/box/mon] to [kg NH3/box/s]
! ENH3_an(I,J) = ENH3_an(I,J) * ( 17.d0 / 14.d0 )
! & / ( NMDAY(THISMONTH) * 86400.d0 )
!
! ! Compute future NH3an emissions, if necessary
! ! Moved here since Streets and EMEP should have already
! ! applied FUTURE scale factors if needed
! IF ( LFUTURE ) THEN
! ENH3_an(I,J) = ENH3_an(I,J) * GET_FUTURE_SCALE_NH3an( I, J )
! ENDIF
!
! ! If we are using David Streets' emissions ...
! IF ( LSTREETS ) THEN
!
! ! If we are over the SE Asia region ...
! IF ( GET_SE_ASIA_MASK( I, J ) > 0d0 ) THEN
!
! ! Overwrite with David Streets emissions [kg NH3/s]
!!------------------------------------------------------------------------------
!! Prior to 12/10/08:
!! Now check first that NH3 is available (phs, 12/10/08)
!! ENH3_an(I,J) = GET_STREETS_ANTHRO( I, J,
!! & IDTNH3, KG_S=.TRUE.)
! STREETS = GET_STREETS_ANTHRO( I, J,
! & IDTNH3, KG_S=.TRUE.)
!
! IF ( .not. ( STREETS < 0d0 ) )
! $ ENH3_an(I,J) = STREETS
!
! ENDIF
! ENDIF
!
! IF ( LEMEP ) THEN
! IF ( GET_EUROPE_MASK(I,J) > 0d0) THEN
! ENH3_an(I,J) = GET_EMEP_ANTHRO(I,J,IDTNH3,KG_S=.TRUE.)
! ENDIF
! ENDIF
!
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ! Return to calling program
! END SUBROUTINE READ_ANTHRO_NH3
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_NATURAL_NH3( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_NATURAL_NH3 reads the monthly mean natural
!! NH3 emissions from disk and converts to [kg NH3/box/s].
!! (rjp, bdf, bmy, 9/20/02, 10/3/05)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Updated FORMAT string. Now also call READ_BPCH2 with QUIET=.TRUE.
!! (bmy, 4/8/03)
!! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids. (bmy, 8/16/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: XTAU
! REAL*8 :: NMDAY(12) = (/ 31d0, 28d0, 31d0, 30d0,
! & 31d0, 30d0, 31d0, 31d0,
! & 30d0, 31d0, 30d0, 31d0 /)
! CHARACTER(LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_NATURAL_NH3 begins here!
! !=================================================================
!
! ! File name
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/NH3_natusrce.' //
! & GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_NATURAL_NH3: Reading ', a )
!
! ! Get TAU value (use year 1990, the year of the data!)
! XTAU = GET_TAU0( THISMONTH, 1, 1990 )
!
! ! Read 1990 NH3 emissions [kg N/box/mon]
! CALL READ_BPCH2( FILENAME, 'NH3-NATU', 29,
! & XTAU, IGLOB, JGLOB,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8
! CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_na )
!
! ! Convert from [kg N/box/mon] to [kg NH3/box/s]
! ENH3_na = ENH3_na * ( 17.d0 / 14.d0 ) /
! & ( NMDAY(THISMONTH) * 86400.d0 )
!
! ! Return to calling program
! END SUBROUTINE READ_NATURAL_NH3
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_BIOFUEL_NH3( THISMONTH )
!!
!!******************************************************************************
!! Subroutine READ_BIOFUEL_NH3 reads the monthly mean biomass NH3
!! and biofuel emissions from disk and converts to [kg NH3/box/s].
!! (rjp, bdf, bmy, phs, 9/20/02, 12/23/08)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 ) THISMONTH (INTEGER) : Current month number (1-12)
!!
!! NOTES:
!! (1 ) Renamed from NH3_READ to READ_BIOMASS_NH3. Also updated comments,
!! made cosmetic changes. Now reads in both biomass and biofuel
!! emissions. (rjp, bmy, 12/13/02)
!! (2 ) Now replace DXYP(J+J0) with routine GET_AREA_M2 of "grid_mod.f"
!! Now use function GET_YEAR from "time_mod.f". Replace MONTH with
!! THISMONTH when referencing the NMDAY variable. Now call READ_BPCH2
!! with QUIET=.TRUE. (bmy, 3/27/03)
!! (3 ) If using interannual biomass emissions, substitute seasonal emissions
!! for years where internannual emissions do not exist. Now also
!! reference GET_TAU from "time_mod.f" (bmy, 5/15/03)
!! (4 ) Now use ENCODE statement for PGI/F90 on Linux (bmy, 9/29/03)
!! (5 ) Changed cpp switch name from LINUX to LINUX_PGI (bmy, 12/2/03)
!! (6 ) Now references DATA_DIR from "directory_mod.f". Now references LBBSEA
!! from "logical_mod.f". Removed references to CMN and CMN_SETUP.
!! (bmy, 7/20/04)
!! (7 ) Now can read either seasonal or interannual biomass burning emissions.
!! Now references routines from both and "time_mod.f". Now reads SO2
!! biomass emissions directly rather than computing it by mole fraction
!! from CO. (rjp, bmy, 1/11/05)
!! (8 ) Now read files from "sulfate_sim_200508/". Now read data for both
!! GCAP and GEOS grids. (bmy, 8/16/05)
!! (9 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!! (10) Now only read the biofuel, we have moved the biomass-reading code to
!! "gc_biomass_mod.f" for compatibility with GFED2 biomass emissions
!! (bmy, 9/27/06)
!! (11) Prevent seg fault error when LBIOMASS=F (bmy, 11/3/06)
!! (12) Renamed READ_BIOFUEL_NH3, and move all biomass code to GET_BIOMASS_NH3
!! to account for several GFED2 products (yc, phs, 12/23/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BIOMASS_MOD, ONLY : BIOMASS, IDBNH3
! USE BPCH2_MOD, ONLY : GET_NAME_EXT_2D, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE FUTURE_EMISSIONS_MOD, ONLY : GET_FUTURE_SCALE_NH3bf
! USE LOGICAL_MOD, ONLY : LBIOMASS, LFUTURE
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE TIME_MOD, ONLY : ITS_A_LEAPYEAR
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTNH3
! USE TRANSFER_MOD, ONLY : TRANSFER_2D
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: THISMONTH
!
! ! Local variables
! INTEGER :: I, J, THISYEAR
! REAL*4 :: ARRAY(IGLOB,JGLOB,1)
! REAL*8 :: XTAU, DMASS!, CONV
! REAL*8 :: NMDAY(12) = (/31d0, 28d0, 31d0,
! & 30d0, 31d0, 30d0,
! & 31d0, 31d0, 30d0,
! & 31d0, 30d0, 31d0/)
! CHARACTER(LEN=4 ) :: CYEAR
! CHARACTER(LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_BIOFUEL_NH3 begins here!
! !=================================================================
!
! !=================================================================
! ! Read NH3 biofuel emissions
! !=================================================================
!
! ! File name
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/NH3_biofuel.' //
! & GET_NAME_EXT_2D() // '.' // GET_RES_EXT()
!
! ! Echo output
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_BIOFUEL_NH3: Reading ', a )
!
! ! Get TAU0 value for 1998
! XTAU = GET_TAU0( THISMONTH, 1, 1998 )
!
! ! Read NH3 biofuel data [kg NH3/box/month]
! CALL READ_BPCH2( FILENAME, 'BIOFSRCE', 29,
! & XTAU, IGLOB, JGLOB,
! & 1, ARRAY(:,:,1), QUIET=.TRUE. )
!
! ! Cast from REAL*4 to REAL*8 and resize if necesary
! CALL TRANSFER_2D( ARRAY(:,:,1), ENH3_bf )
!
! ! Store NH3 in ENH3_bf array [kg NH3/box/s]
! ENH3_bf = ENH3_bf / ( NMDAY(THISMONTH) * 86400.d0 )
!
! !=================================================================
! ! Convert units and apply IPCC future emissions (if necessary)
! !=================================================================
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!------------------------------------------------------------------
!! Prior to 1/28/09:
!! Need to remove CONV from the PRIVATE statement (bmy, 1/28/09)
!!!$OMP+PRIVATE( I, J, CONV )
!!------------------------------------------------------------------
!!$OMP+PRIVATE( I, J )
!
! ! Loop over latitudes
! DO J = 1, JJPAR
!
!!-- prior 12/23/08
!! ! Conversion factor for [cm2 * kg/molec]
!! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTNH3)
!
! ! Loop over longitudes
! DO I = 1, IIPAR
!
!!-- prior 12/23/08
!! ! Convert biomass NH3 from [molec NH3/cm2/s] -> [kg NH3/s]
!! ! NOTE: Future scale is applied by this point (if necessary)
!! IF ( LBIOMASS ) THEN
!! ENH3_bb(I,J) = BIOMASS(I,J,IDBNH3) * CONV
!! ELSE
!! ENH3_bb(I,J) = 0d0
!! ENDIF
!
! ! Scale biofuel NH3 to IPCC future scenario (if necessary)
! IF ( LFUTURE ) THEN
! ENH3_bf(I,J) = ENH3_bf(I,J) *
! & GET_FUTURE_SCALE_NH3bf( I, J )
! ENDIF
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ! Return to calling program
! END SUBROUTINE READ_BIOFUEL_NH3
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE GET_BIOMASS_NH3
!!
!!******************************************************************************
!! Subroutine GET_BIOMASS_NH3 retrieve the monthly/8days/3hr mean biomass NH3
!! (yc, phs, 12/23/08)
!!
!! Arguments as input:
!! ===========================================================================
!! (1 )
!!
!! NOTES:
!! (1 ) Extracted from old module subroutine READ_BIOMASS_NH3
!! (yc, phs, 12/23/08)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BIOMASS_MOD, ONLY : BIOMASS, IDBNH3
! USE GRID_MOD, ONLY : GET_AREA_CM2
! USE TRACER_MOD, ONLY : XNUMOL
! USE TRACERID_MOD, ONLY : IDTNH3
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Local variables
! INTEGER :: I, J
! REAL*8 :: CONV
!
! !=================================================================
! ! READ_BIOMASSBURN_NH3 begins here!
! !=================================================================
! ! Convert units
!
!!$OMP PARALLEL DO
!!$OMP+DEFAULT( SHARED )
!!$OMP+PRIVATE( I, J, CONV )
!
! ! Loop over latitudes
! DO J = 1, JJPAR
!
! ! Conversion factor for [cm2 * kg/molec]
! CONV = GET_AREA_CM2( J ) / XNUMOL(IDTNH3)
!
! ! Loop over longitudes
! DO I = 1, IIPAR
!
! ! Convert biomass NH3 from [molec NH3/cm2/s] -> [kg NH3/s]
! ! NOTE: Future scale is applied by this point (if necessary)
! ENH3_bb(I,J) = BIOMASS(I,J,IDBNH3) * CONV
!
! ENDDO
! ENDDO
!!$OMP END PARALLEL DO
!
! ! Return to calling program
! END SUBROUTINE GET_BIOMASS_NH3
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE READ_OXIDANT( MONTH )
!!
!!******************************************************************************
!! Subroutine READ_OXIDANT reads in monthly mean H2O2 and O3 fields for the
!! offline sulfate + aerosol simulation. (rjp, bdf, bmy, 11/1/02, 10/3/05)
!!
!! Arguments as input:
!! ============================================================================
!! (1 ) MONTH (INTEGER ) : Emission timestep in minutes
!!
!! NOTES:
!! (1 ) Now call READ_BPCH2 with QUIET=.TRUE. (bmy, 3/27/03)
!! (2 ) Now references DATA_DIR from "directory_mod.f" (bmy, 7/20/04)
!! (3 ) Now read files from "sulfate_sim_200508/offline/". Now read data
!! for both GEOS and GCAP grids (bmy, 8/16/05)
!! (4 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
!!******************************************************************************
!!
! ! References to F90 modules
! USE BPCH2_MOD, ONLY : GET_NAME_EXT, GET_RES_EXT
! USE BPCH2_MOD, ONLY : GET_TAU0, READ_BPCH2
! USE DIRECTORY_MOD, ONLY : DATA_DIR
! USE TRANSFER_MOD, ONLY : TRANSFER_3D_TROP
!
!# include "CMN_SIZE" ! Size parameters
!
! ! Arguments
! INTEGER, INTENT(IN) :: MONTH
!
! ! Local variables
! INTEGER :: I, J, L, K
! REAL*4 :: ARRAY(IGLOB,JGLOB,LLTROP)
! REAL*8 :: XTAU
! CHARACTER(LEN=255) :: FILENAME
!
! !=================================================================
! ! READ_OXIDANT begins here !
! !
! ! Oxidant fields were computed for 1998 using coupled aerosol
! ! and gas chemistry GEOS-CHEM by Brendan Field (bdf, 5/23/02).
! ! Bob Yantosca has regridded these fields to all GEOS-CHEM grids.
! ! Data is saved from the surface to the tropopause.
! !=================================================================
!
! ! Use generic year 1985
! XTAU = GET_TAU0( MONTH, 1, 1985 )
!
! !=================================================================
! ! Read monthly mean PH2O2 (from HO2 + HO2 = H2O2) [molec/cm3/s]
! !=================================================================
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/offline/PH2O2.' //
! & GET_NAME_EXT() // '.' // GET_RES_EXT()
!
! ! Echo filename
! WRITE( 6, 100 ) TRIM( FILENAME )
! 100 FORMAT( ' - READ_OXIDANT: Reading ', a )
!
! ! Read data
! CALL READ_BPCH2( FILENAME, 'PORL-L=$', 5,
! ! limit array 3d dimension to LLTROP_FIX, i.e, case of annual mean
! ! tropopause. This is backward compatibility with
! ! offline data set.
! & XTAU, IGLOB, JGLOB,
! & LLTROP_FIX, ARRAY(:,:,1:LLTROP_FIX), QUIET=.TRUE. )
!! & XTAU, IGLOB, JGLOB,
!! & LLTROP, ARRAY, QUIET=.TRUE. )
!
! ! Cast to REAL*8 and resize if necessary
! CALL TRANSFER_3D_TROP( ARRAY, PH2O2m )
!
! !=================================================================
! ! Read monthly mean O3 [v/v]
! !=================================================================
! FILENAME = TRIM( DATA_DIR ) //
! & 'sulfate_sim_200508/offline/O3.' //
! & GET_NAME_EXT() // '.' // GET_RES_EXT()
!
! ! Echo filename
! WRITE( 6, 100 ) TRIM( FILENAME )
!
! ! Read data
! ! limit array 3d dimension to LLTROP_FIX, i.e, case of annual mean
! ! tropopause. This is backward compatibility with
! ! offline data set.
! CALL READ_BPCH2( FILENAME, 'IJ-AVG-$', 51,
! & XTAU, IGLOB, JGLOB,
! & LLTROP_FIX, ARRAY(:,:,1:LLTROP_FIX), QUIET=.TRUE. )
!! & XTAU, IGLOB, JGLOB,
!! & LLTROP, ARRAY, QUIET=.TRUE. )
!
! ! Cast to REAL*8 and resize if necessary
! CALL TRANSFER_3D_TROP( ARRAY, O3m )
!
! ! Return to calling program
! END SUBROUTINE READ_OXIDANT
!
!!------------------------------------------------------------------------------
!
! SUBROUTINE OHNO3TIME
!!
!!******************************************************************************
!! Subroutine OHNO3TIME computes the sum of cosine of the solar zenith
!! angle over a 24 hour day, as well as the total length of daylight.
!! This is needed to scale the offline OH and NO3 concentrations.
!! (rjp, bmy, 12/16/02, 3/30/04)
!!
!! NOTES:
!! (1 ) Copy code from COSSZA directly for now, so that we don't get NaN
!! values. Figure this out later (rjp, bmy, 1/10/03)
!! (2 ) Now replace XMID(I) with routine GET_XMID from "grid_mod.f".
!! Now replace RLAT(J) with routine GET_YMID_R from "grid_mod.f".
!! Removed NTIME, NHMSb from the arg list. Now use GET_NHMSb,
!! GET_ELAPSED_SEC, GET_TS_CHEM, GET_DAY_OF_YEAR, GET_GMT from
!! "time_mod.f". (bmy, 3/27/03)
!! (3 ) Now store the peak SUNCOS value for each surface grid box (I,J) in
!! the COSZM array. (rjp, bmy, 3/30/04)
!!******************************************************************************
!!
! ! References to F90 modules
! USE GRID_MOD, ONLY : GET_XMID, GET_YMID_R
! USE TIME_MOD, ONLY : GET_NHMSb, GET_ELAPSED_SEC
! USE TIME_MOD, ONLY : GET_TS_CHEM, GET_DAY_OF_YEAR, GET_GMT
!
!# include "CMN_SIZE" ! Size parameters
!# include "CMN_GCTM"
!
! ! Local variables
! LOGICAL, SAVE :: FIRST = .TRUE.
! INTEGER :: I, IJLOOP, J, L, N, NT, NDYSTEP
! REAL*8 :: A0, A1, A2, A3, B1, B2, B3
! REAL*8 :: LHR0, R, AHR, DEC, TIMLOC, YMID_R
! REAL*8 :: SUNTMP(MAXIJ)
!
! !=================================================================
! ! OHNO3TIME begins here!
! !=================================================================
!
! ! Solar declination angle (low precision formula, good enough for us):
! A0 = 0.006918
! A1 = 0.399912
! A2 = 0.006758
! A3 = 0.002697
! B1 = 0.070257
! B2 = 0.000907
! B3 = 0.000148
! R = 2.* PI * float( GET_DAY_OF_YEAR() - 1 ) / 365.
!
! DEC = A0 - A1*cos( R) + B1*sin( R)
! & - A2*cos(2*R) + B2*sin(2*R)
! & - A3*cos(3*R) + B3*sin(3*R)
!
! LHR0 = int(float( GET_NHMSb() )/10000.)
!
! ! Only do the following at the start of a new day
! IF ( FIRST .or. GET_GMT() < 1e-5 ) THEN
!
! ! Zero arrays
! TTDAY(:,:) = 0d0
! TCOSZ(:,:) = 0d0
! COSZM(:,:) = 0d0
!
! ! NDYSTEP is # of chemistry time steps in this day
! NDYSTEP = ( 24 - INT( GET_GMT() ) ) * 60 / GET_TS_CHEM()
!
! ! NT is the elapsed time [s] since the beginning of the run
! NT = GET_ELAPSED_SEC()
!
! ! Loop forward through NDYSTEP "fake" timesteps for this day
! DO N = 1, NDYSTEP
!
! ! Zero SUNTMP array
! SUNTMP(:) = 0d0
!
! ! IJLOOP is the 1-D loop index for SUNCOS
! IJLOOP = 0
!
! ! Loop over surface grid boxes
! DO J = 1, JJPAR
!
! ! Grid box latitude center [radians]
! YMID_R = GET_YMID_R( J )
!
! DO I = 1, IIPAR
!
! ! Increment IJLOOP
! IJLOOP = IJLOOP + 1
! TIMLOC = real(LHR0) + real(NT)/3600.0 + GET_XMID(I)/15.0
!
! DO WHILE (TIMLOC .lt. 0)
! TIMLOC = TIMLOC + 24.0
! ENDDO
!
! DO WHILE (TIMLOC .gt. 24.0)
! TIMLOC = TIMLOC - 24.0
! ENDDO
!
! AHR = abs(TIMLOC - 12.) * 15.0 * PI_180
!
! !===========================================================
! ! The cosine of the solar zenith angle (SZA) is given by:
! !
! ! cos(SZA) = sin(LAT)*sin(DEC) + cos(LAT)*cos(DEC)*cos(AHR)
! !
! ! where LAT = the latitude angle,
! ! DEC = the solar declination angle,
! ! AHR = the hour angle, all in radians.
! !
! ! If SUNCOS < 0, then the sun is below the horizon, and
! ! therefore does not contribute to any solar heating.
! !===========================================================
!
! ! Compute Cos(SZA)
! SUNTMP(IJLOOP) = sin(YMID_R) * sin(DEC) +
! & cos(YMID_R) * cos(DEC) * cos(AHR)
!
! ! TCOSZ is the sum of SUNTMP at location (I,J)
! ! Do not include negative values of SUNTMP
! TCOSZ(I,J) = TCOSZ(I,J) + MAX( SUNTMP(IJLOOP), 0d0 )
!
! ! COSZM is the peak value of SUMTMP during a day at (I,J)
! ! (rjp, bmy, 3/30/04)
! COSZM(I,J) = MAX( COSZM(I,J), SUNTMP(IJLOOP) )
!
! ! TTDAY is the total daylight time at location (I,J)
! IF ( SUNTMP(IJLOOP) > 0d0 ) THEN
! TTDAY(I,J) = TTDAY(I,J) + DBLE( GET_TS_CHEM() )
! ENDIF
! ENDDO
! ENDDO
!
! !### Debug
! !PRINT*, '### IN OHNO3TIME'
! !PRINT*, '### N : ', N
! !PRINT*, '### NDYSTEP : ', NDYSTEP
! !PRINT*, '### NT : ', NT
! !PRINT*, '### JDAY : ', JDAY
! !PRINT*, '### RLAT : ', RLAT
! !PRINT*, '### XMID : ', XMID
! !PRINT*, '### SUNTMP : ', SUNTMP
! !PRINT*, '### TCOSZ : ', MINVAL( TCOSZ ), MAXVAL( TCOSZ )
! !PRINT*, '### TTDAY : ', MINVAL( TCOSZ ), MAXVAL( TCOSZ )
!
! ! Increment elapsed time [sec]
! NT = NT + ( GET_TS_CHEM() * 60 )
! ENDDO
!
! ! Reset first-time flag
! FIRST = .FALSE.
! ENDIF
!
! ! Return to calling program
! END SUBROUTINE OHNO3TIME
!
!!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
SUBROUTINE GET_O3_ADJ( ADO3, I, J, L )
!
!******************************************************************************
! Subroutine GET_O3_ADJ is the adjoint of GET_O3.
! (dkh, 10/12/05)
!
! Arguments as Input:
! ============================================================================
! (1 ) (REAL*8) : Local adjoint of ozone conc
! (2-4) I, J, L (INTEGER) : Grid box indices for lon, lat, vertical level
!
! NOTES:
! (1 ) The only reason we can just add the new value of ADO3 to the pre-existing
! adjoint of ozone is that ADO3 is not involved in any equations in
! ADJ_CHEM_SO2 other than ado3 = ado3 + ...
! Otherwise we would have to initialize ado3 with ADCSPEC, then replace
! ADCSPEC directly here. (dkh, 10/24/05)
! (2 ) Updated to GCv8 adjoint (dkh, 09/28/09)
!******************************************************************************
!
! References to F90 modules
USE COMODE_MOD, ONLY : CSPEC, JLOP, VOLUME, CSPEC_ADJ
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
REAL*8, INTENT(IN) :: ADO3
! Local variables
INTEGER :: JLOOP
!=================================================================
! GET_O3_ADJ begins here!
!=================================================================
IF ( ITS_A_FULLCHEM_SIM() ) THEN
! JLOOP = SMVGEAR 1-D grid box index
JLOOP = JLOP(I,J,L)
! Add additional sensitivity gleaned from sulfate
! chemistry to previous adjoint ozone value.
IF ( JLOOP > 0 ) THEN
CSPEC_ADJ(JLOOP,IDO3) = CSPEC_ADJ(JLOOP,IDO3) +
& ( ADO3 * 1d6 ) / ( AIRDEN(L,I,J) * XNUMOLAIR )
ENDIF
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
CALL ERROR_STOP( 'Invalid NSRCX!',
& 'GET_O3_ADJ (sulfate_adj_mod.f)')
ENDIF
! Return to calling program
END SUBROUTINE GET_O3_ADJ
!------------------------------------------------------------------------------
SUBROUTINE INIT_SULFATE_ADJ
!
!******************************************************************************
! Subroutine INIT_ADJ_SULFATE initializes and zeros all allocatable arrays
! declared in "adj_sulfate_mod.f" (dkh, 10/12/05)
!
! NOTES:
! (1 ) Updated for GCv8 adjoint (dkh, 09/28/09)
!
!******************************************************************************
!
! Reference to f90 modules
USE DRYDEP_MOD, ONLY : DEPNAME, NUMDEP
USE ERROR_MOD, ONLY : ALLOC_ERR
USE LOGICAL_MOD, ONLY : LDRYD
# include "CMN_SIZE" ! Size parameters
! Local variables
LOGICAL, SAVE :: IS_INIT = .FALSE.
INTEGER :: AS, I, J, N, IJLOOP
!=================================================================
! INIT_SULFATE_ADJ begins here!
!=================================================================
! Return if we have already initialized
IF ( IS_INIT ) RETURN
ALLOCATE( VCLDF( IIPAR, JJPAR, LLTROP ), STAT=AS )
IF ( AS /= 0 ) CALL ALLOC_ERR( 'VCLDF' )
VCLDF = 0d0
ALLOCATE( ADPSO4_SO2( IIPAR, JJPAR, LLTROP ), STAT=AS )
IF ( AS /= 0 ) CALL ALLOC_ERR( 'ADPSO4_SO2' )
ADPSO4_SO2 = 0d0
! Initialize flags
DRYH2O2 = 0
DRYSO2 = 0
DRYSO4 = 0
DRYSO4s = 0
DRYMSA = 0
DRYNH3 = 0
DRYNH4 = 0
DRYNIT = 0
DRYSO4s = 0
DRYAS = 0
DRYAHS = 0
DRYLET = 0
DRYSO4aq = 0
DRYNH4aq = 0
IF ( LDRYD ) THEN
! Locate position of each tracer in DEPSAV
DO N = 1, NUMDEP
SELECT CASE ( TRIM( DEPNAME(N) ) )
CASE ( 'H2O2' )
DRYH2O2 = N
CASE ( 'SO2' )
DRYSO2 = N
CASE ( 'SO4' )
DRYSO4 = N
CASE ( 'SO4S' )
DRYSO4s = N
CASE ( 'MSA' )
DRYMSA = N
CASE ( 'NH3' )
DRYNH3 = N
CASE ( 'NH4' )
DRYNH4 = N
CASE ( 'NIT' )
DRYNIT = N
CASE ( 'NITS' )
DRYNITs = N
CASE ( 'AS' )
DRYAS = N
CASE ( 'AHS' )
DRYAHS = N
CASE ( 'LET' )
DRYLET = N
CASE ( 'SO4aq' )
DRYSO4aq = N
CASE ( 'NH4aq' )
DRYNH4aq = N
CASE DEFAULT
! Nothing
END SELECT
ENDDO
ENDIF
! Reset IS_INIT so we do not allocate arrays again
IS_INIT = .TRUE.
! Return to calling program
END SUBROUTINE INIT_SULFATE_ADJ
!-----------------------------------------------------------------------------
SUBROUTINE CLEANUP_SULFATE_ADJ
!
!******************************************************************************
! Subroutine CLEANUP_SULFATE_ADJ deallocates all previously allocated arrays
! for sulfate emissions -- call at the end of the run (bmy, 6/1/00, 5/3/06)
!
! NOTES:
! (1 ) Updated for GCv8 adjoint (dkh, 09/28/09)
!******************************************************************************
!
!=================================================================
! CLEANUP_SULFATE_ADJ begins here!
!=================================================================
IF ( ALLOCATED( ADPSO4_SO2 ) ) DEALLOCATE( ADPSO4_SO2 )
IF ( ALLOCATED( VCLDF ) ) DEALLOCATE( VCLDF )
! Return to calling program
END SUBROUTINE CLEANUP_SULFATE_ADJ
!------------------------------------------------------------------------------
END MODULE SULFATE_ADJ_MOD