Files
2018-08-28 00:37:54 -04:00

3066 lines
124 KiB
Fortran

! $Id: rpmares_mod.f,v 1.5 2012/03/01 22:00:27 daven Exp $
MODULE RPMARES_MOD
!
!******************************************************************************
! Module RPMARES_MOD contains the RPMARES routines, which compute the aerosol
! thermodynamical equilibrium. (rjp, bdf, bmy, 11/6/02, 6/11/08)
!
! Module Variables:
! ============================================================================
! (1 ) HNO3_SAV (REAL*8 ) : Array to save evolving HNO3 concentrations
!
! Module Routines:
! ============================================================================
! (1 ) DO_RPMARES : Bridge between GEOS-CHEM and RPMARES
! (2 ) GET_HNO3 : Gets evolving HNO3; relaxes to monthly mean every 3h
! (3 ) SET_HNO3 : Saves HNO3 in an array for the next timestep
! (4 ) RPMARES : Driver for RPMARES code
! (5 ) AWATER : Computes thermodynamical equilibrium (?)
! (6 ) POLY4 : Evaluates a 4th order polynomial expression
! (7 ) POLY6 : Evaluates a 6th order polynomial expression
! (8 ) CUBIC : Solver to find cubic roots
! (9 ) ACTCOF : Computes activity coefficients
! (10) INIT_RPMARES : Initializes and allocates all module arrays
! (11) CLEANUP_RPMARES : Deallocates all module arrays
!
! GEOS-CHEM modules referenced by rpmares_mod.f
! ============================================================================
! (1 ) dao_mod.f : Module w/ arrays for DAO met fields
! (2 ) error_mod.f : Module w/ NaN and other error check routines
! (3 ) time_mod.f : Module w/ routines to compute date & time
! (4 ) tracer_mod.f : Module w/ GEOS-CHEM tracer array STT etc.
! (5 ) tracerid_mod.f : Module w/ pointers to tracers & emissions
! (6 ) tropopause_mod.f : Module
!
! NOTES:
! (1 ) Added module variables ELAPSED_SEC and HNO3_sav. Added module routines
! GET_HNO3, SET_HNO3, INIT_RPMARES, CLEANUP_RPMARES. (bmy, 12/16/02)
! (2 ) Replace ALOG with F90 intrinsic LOG to facilitate compilation on
! COMPAQ/Alpha platform. (bmy, 3/23/03)
! (3 ) Now references "time_mod.f". Now removed ELAPSED_SEC module variable
! since we can get this info from "time_mod.f". (bmy, 3/24/03)
! (4 ) Now references "tracer_mod.f" (bmy, 7/20/04)
! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
! (6 ) Now only apply RPMARES to boxes in the troposphere. (bmy, 4/3/08)
! (7 ) Add bug fix for low ammonia case in RPMARES (phs, bmy, 4/10/08)
!******************************************************************************
!
IMPLICIT NONE
!=================================================================
! MODULE PRIVATE DECLARATIONS -- keep certain internal variables
! and routines from being seen outside "rpmares_mod.f"
!=================================================================
! Make everything PUBLIC
PUBLIC
! ... except these variables ...
PRIVATE :: HNO3_sav
! ... and these routines
! adj_group: these are needed in rpmares_adj_mod
!PRIVATE :: POLY4, POLY6, CUBIC, ACTCOF
!PRIVATE :: GET_HNO3, SET_HNO3, RPMARES, AWATER
PRIVATE :: GET_HNO3, SET_HNO3, RPMARES
PRIVATE :: INIT_RPMARES
!=================================================================
! MODULE VARIABLES
!=================================================================
REAL*8, ALLOCATABLE :: HNO3_sav(:,:,:)
!=================================================================
! MODULE ROUTINES -- follow below the "CONTAINS" statement
!=================================================================
CONTAINS
!------------------------------------------------------------------------------
SUBROUTINE DO_RPMARES
!
!******************************************************************************
! Subroutine DO_RPMARES is the interface between the GEOS-CHEM model
! and the aerosol thermodynamical equilibrium routine in "rpmares.f"
! (rjp, bdf, bmy, 12/17/01, 4/10/08)
!
! NOTES
! (1 ) Bundled into "rpmares_mod.f" (bmy, 11/15/02)
! (2 ) Now let HNO3 concentration evolve, but relax to monthly mean values
! every 3 hours, via routines GET_HNO3 and SET_HNO3. (bmy, 12/16/02)
! (3 ) Now removed NSEC from the arg list -- use GET_ELAPSED_SEC() function
! from the new "time_mod.f". Also use GET_MONTH from "time_mod.f".
! (bmy, 3/24/03)
! (4 ) Now reference STT, ITS_A_FULLCHEM_SIM, and ITS_AN_AEROSOL_SIM
! from "tracer_mod.f". Now references ITS_A_NEW_MONTH from
! "time_mod.f" (bmy, 7/20/04)
! (5 ) Now make sure all USE statements are USE, ONLY (bmy, 10/3/05)
! (6 ) Now limit RPMARES to the tropopause. (bmy, 4/10/08)
!******************************************************************************
!
! References to F90 modules
USE DAO_MOD, ONLY : AIRVOL, RH, T
USE GLOBAL_HNO3_MOD, ONLY : GET_GLOBAL_HNO3
USE ERROR_MOD, ONLY : ERROR_STOP
USE TIME_MOD, ONLY : GET_ELAPSED_SEC, GET_MONTH
USE TIME_MOD, ONLY : ITS_A_NEW_MONTH
USE TRACER_MOD, ONLY : ITS_A_FULLCHEM_SIM
USE TRACER_MOD, ONLY : ITS_AN_AEROSOL_SIM, STT
USE TRACERID_MOD, ONLY : IDTSO4, IDTNH3, IDTNH4
USE TRACERID_MOD, ONLY : IDTNIT, IDTHNO3
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
! adj_group: (dkh, 09/07/09)
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD, NFD
USE CHECKPT_MOD, ONLY : RP_IN
USE CHECKPT_MOD, ONLY : RP_OUT
USE CHECKPT_MOD, ONLY : NITR_MAX
USE LOGICAL_ADJ_MOD, ONLY : LADJ
USE LOGICAL_ADJ_MOD, ONLY : LPRINTFD
# include "CMN_SIZE" ! Size parameters
! Local variables
LOGICAL, SAVE :: FIRST = .TRUE.
INTEGER, SAVE :: LASTMONTH = -99
INTEGER :: I, J, L
REAL*8 :: ARH, ATEMP, AVOL, SO4, ASO4, ANO3
REAL*8 :: AH2O, ANH4, GNH3, GNO3, AHSO4
CHARACTER(LEN=255) :: X
! adj_group: need to track EXIT status (dkh, 09/07/09)
INTEGER :: EXIT
! concentration lower limit [ug/m3 ]
REAL*8, PARAMETER :: CONMIN = 1.0D-30
!=================================================================
! DO_RPMARES begins here!
!=================================================================
! Initialize on first call
IF ( FIRST ) THEN
CALL INIT_RPMARES
FIRST = .FALSE.
ENDIF
! Error check tracer ID's
X = 'DO_RPMARES (rpmares_mod.f)'
IF ( IDTSO4 == 0 ) CALL ERROR_STOP( 'IDTSO4 is not defined!', X )
IF ( IDTNH3 == 0 ) CALL ERROR_STOP( 'IDTNH3 is not defined!', X )
IF ( IDTNH4 == 0 ) CALL ERROR_STOP( 'IDTNH4 is not defined!', X )
IF ( IDTNIT == 0 ) CALL ERROR_STOP( 'IDTNIT is not defined!', X )
! Check to see if we have to read in monthly mean HNO3
IF ( IDTHNO3 == 0 ) THEN
IF ( ITS_A_FULLCHEM_SIM() ) THEN
! Coupled simulation: stop w/ error since we need HNO3
CALL ERROR_STOP( 'IDTHNO3 is not defined!', X )
ELSE IF ( ITS_AN_AEROSOL_SIM() ) THEN
! Offline simulation: read monthly mean HNO3
IF ( ITS_A_NEW_MONTH() ) THEN
CALL GET_GLOBAL_HNO3( GET_MONTH() )
ENDIF
ELSE
! Otherwise stop w/ error
CALL ERROR_STOP( 'Invalid simulation type!', X )
ENDIF
ENDIF
! adj_group: reset iteration counter to 1 (dkh, 9/10/04, 09/07/09)
IF ( LADJ ) NITR_MAX(:,:,:) = 1
!=================================================================
! Get equilibrium values of water, ammonium and nitrate content
!=================================================================
! adj_group: add EXIT
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, ATEMP, ARH, AVOL, SO4 )
!$OMP+PRIVATE( ANH4, ANO3, GNH3, GNO3, ASO4, AHSO4, AH2O )
!$OMP+PRIVATE( EXIT )
DO L = 1, LLTROP
DO J = 1, JJPAR
DO I = 1, IIPAR
! Skip if we are in the stratosphere (bmy, 4/3/08)
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
! Temperature [K], RH [unitless], and volume [m3]
ATEMP = T(I,J,L)
ARH = RH(I,J,L) * 1.d-2
AVOL = AIRVOL(I,J,L)
! Convert sulfate, ammonimum, gaseous NH3, gaseous HNO3,
! and aerosol NO3 from [kg] to [ug/m3].
SO4 = MAX( STT(I,J,L,IDTSO4) * 1.d9 / AVOL, CONMIN )
GNH3 = MAX( STT(I,J,L,IDTNH3) * 1.d9 / AVOL, CONMIN )
ANH4 = MAX( STT(I,J,L,IDTNH4) * 1.d9 / AVOL, CONMIN )
ANO3 = MAX( STT(I,J,L,IDTNIT) * 1.d9 / AVOL, CONMIN )
! For coupled simulations, use HNO3 tracer from STT array.
! For offline simulations, call GET_HNO3, which lets HNO3
! conc's evolve, but relaxes to monthly mean values every 3h.
IF ( IDTHNO3 > 0 ) THEN
GNO3 = MAX( STT(I,J,L,IDTHNO3) * 1.d9 / AVOL, CONMIN )
ELSE
GNO3 = MAX( GET_HNO3( I, J, L ), CONMIN )
ENDIF
!==============================================================
! Call the RPMARES code with the following quantities:
!
! SO4 : Total sulfate as sulfate [ug/m3]
! GNO3 : Nitric Acid vapor (actually gaseous HNO3) [ug/m3]
! GNH3 : Gas phase ammonia [ug/m3]
! ARH : Fractional relative humidity [unitless]
! ATEMP : Temperature [K]
! ASO4 : Aerosol phase sulfate [ug/m3]
! AHSO4 : Aerosol phase in bisulfate [ug/m3]
! ANO3 : Aerosol phase nitrate [ug/m3]
! AH2O : Aerosol phase water [ug/m3]
! ANH4 : Aerosol phase ammonium [ug/m3]
!==============================================================
! adj_group: call special version for adjoint (dkh, 9/10/04, 09/07/09)
! Now always use RPMARES_FORADJ, and check LADJ therein (dkh, 02/12/12, adj32_001)
!IF ( .not. LADJ ) THEN
! CALL RPMARES( SO4, GNO3, GNH3, ARH, ATEMP,
! ASO4, AHSO4, ANO3, AH2O, ANH4 )
! ELSE
IF ( LADJ ) THEN
! adj_group: Checkpoint inputs to RPMARES
RP_IN(I,J,L,1) = SO4
RP_IN(I,J,L,2) = GNO3
RP_IN(I,J,L,3) = GNH3
RP_IN(I,J,L,4) = ANO3
RP_IN(I,J,L,5) = ANH4
RP_IN(I,J,L,6) = ARH
RP_IN(I,J,L,7) = ATEMP
ENDIF
! adj_group: call modified version
CALL RPMARES_FORADJ( SO4, GNO3, GNH3, ARH, ATEMP,
& ASO4, AHSO4, ANO3, AH2O, ANH4,
& I, J, L, EXIT )
IF ( LADJ ) THEN
! adj_group: checkpoint outputs
RP_OUT(I,J,L,1) = ASO4
RP_OUT(I,J,L,2) = AHSO4
RP_OUT(I,J,L,3) = ANO3
RP_OUT(I,J,L,4) = AH2O
RP_OUT(I,J,L,5) = ANH4
RP_OUT(I,J,L,6) = SO4
RP_OUT(I,J,L,7) = GNO3
RP_OUT(I,J,L,8) = GNH3
RP_OUT(I,J,L,9) = EXIT
IF ( LPRINTFD
& .and. J == JFD .AND. L == LFD .AND. I == IFD) THEN
print*, ' After RECOMP_RPMARES ', I, J, L
print*, ' RP_IN = ', RP_IN(I,J,L,:)
print*, ' RP_OUT = ', RP_OUT(I,J,L,:)
print*, ' EXIT = ', RP_OUT(I,J,L,9), L
ENDIF
ENDIF
! Convert modified concentrations from [ug/m3] to [kg]
! for ammonium, ammonia, nitric acid (g), and Nitrate
! NOTE: We don't modify the total sulfate mass.
STT(I,J,L,IDTNH3) = MAX( GNH3 * AVOL * 1.d-9, CONMIN )
STT(I,J,L,IDTNH4) = MAX( ANH4 * AVOL * 1.d-9, CONMIN )
STT(I,J,L,IDTNIT) = MAX( ANO3 * AVOL * 1.d-9, CONMIN )
! For coupled runs, convert HNO3 [kg] and store in STT.
! For offline runs, save evolving HNO3 [ug/m3] for next timestep.
IF ( IDTHNO3 > 0 ) THEN
STT(I,J,L,IDTHNO3) = MAX( GNO3 * AVOL * 1.d-9, CONMIN )
ELSE
CALL SET_HNO3( I, J, L, GNO3 )
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE DO_RPMARES
!------------------------------------------------------------------------------
SUBROUTINE RECOMP_RPMARES
!
!******************************************************************************
! Subroutine RECOMP_RPMARES recomputes the resuls of the aerosol thermo
! calculation in order to be used in the adjoint routins, adrpmares. This
! MAY be faster than saving these values to a checkpt file during forward
! integration. (dkh, 2/08/05)
!
! NOTES
! (1 ) Based on DO_RPMARES
! (2 ) Updated to GCv8 (dkh, 09/08/09)
!******************************************************************************
!
! References to F90 modules
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_STRAT
! adj_group: (dkh, 09/07/09)
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD, NFD
USE CHECKPT_MOD, ONLY : RP_IN
USE CHECKPT_MOD, ONLY : RP_OUT
USE CHECKPT_MOD, ONLY : NITR_MAX
USE LOGICAL_ADJ_MOD, ONLY : LADJ
USE LOGICAL_ADJ_MOD, ONLY : LPRINTFD
# include "CMN_SIZE" ! Size parameters
! Local variables
LOGICAL, SAVE :: FIRST = .TRUE.
INTEGER, SAVE :: LASTMONTH = -99
INTEGER :: I, J, L
REAL*8 :: ARH, ATEMP, AVOL, SO4, ASO4, ANO3
REAL*8 :: AH2O, ANH4, GNH3, GNO3, AHSO4
CHARACTER(LEN=255) :: X
! adj_group: need to track EXIT status (dkh, 09/07/09)
INTEGER :: EXIT
! concentration lower limit [ug/m3 ]
REAL*8, PARAMETER :: CONMIN = 1.0D-30
!=================================================================
! RECOMP_RPMARES begins here!
!=================================================================
! adj_group: reset iteration counter to 1 (dkh, 9/10/04, 09/07/09)
IF ( LADJ ) NITR_MAX(:,:,:) = 1
!=================================================================
! Get equilibrium values of water, ammonium and nitrate content
!=================================================================
!$OMP PARALLEL DO
!$OMP+DEFAULT( SHARED )
!$OMP+PRIVATE( I, J, L, ATEMP, ARH, AVOL, SO4 )
!$OMP+PRIVATE( ANH4, ANO3, GNH3, GNO3, ASO4, AHSO4, AH2O )
!$OMP+PRIVATE( EXIT )
DO L = 1, LLTROP
DO J = 1, JJPAR
DO I = 1, IIPAR
! Skip if we are in the stratosphere (bmy, 4/3/08)
IF ( ITS_IN_THE_STRAT( I, J, L ) ) CYCLE
SO4 = RP_IN(I,J,L,1)
GNO3 = RP_IN(I,J,L,2)
GNH3 = RP_IN(I,J,L,3)
ANO3 = RP_IN(I,J,L,4)
ANH4 = RP_IN(I,J,L,5)
ARH = RP_IN(I,J,L,6)
ATEMP = RP_IN(I,J,L,7)
!==============================================================
! Call the RPMARES_FORADJ code with the following quantities:
!
! SO4 : Total sulfate as sulfate [ug/m3]
! GNO3 : Nitric Acid vapor (actually gaseous HNO3) [ug/m3]
! GNH3 : Gas phase ammonia [ug/m3]
! ARH : Fractional relative humidity [unitless]
! ATEMP : Temperature [K]
! ASO4 : Aerosol phase sulfate [ug/m3]
! AHSO4 : Aerosol phase in bisulfate [ug/m3]
! ANO3 : Aerosol phase nitrate [ug/m3]
! AH2O : Aerosol phase water [ug/m3]
! ANH4 : Aerosol phase ammonium [ug/m3]
!==============================================================
CALL RPMARES_FORADJ( SO4, GNO3, GNH3, ARH, ATEMP,
& ASO4, AHSO4, ANO3, AH2O, ANH4,
& I, J, L, EXIT )
RP_OUT(I,J,L,1) = ASO4
RP_OUT(I,J,L,2) = AHSO4
RP_OUT(I,J,L,3) = ANO3
RP_OUT(I,J,L,4) = AH2O
RP_OUT(I,J,L,5) = ANH4
RP_OUT(I,J,L,6) = SO4
RP_OUT(I,J,L,7) = GNO3
RP_OUT(I,J,L,8) = GNH3
RP_OUT(I,J,L,9) = EXIT
IF ( LPRINTFD
& .and. J == JFD .AND. L == LFD .AND. I == IFD) THEN
print*, ' After RECOMP_RPMARES ', I, J, L
print*, ' RP_IN = ', RP_IN(I,J,L,:)
print*, ' RP_OUT = ', RP_OUT(I,J,L,:)
print*, ' EXIT = ', RP_OUT(I,J,L,9), L
ENDIF
ENDDO
ENDDO
ENDDO
!$OMP END PARALLEL DO
! Return to calling program
END SUBROUTINE RECOMP_RPMARES
!------------------------------------------------------------------------------
FUNCTION GET_HNO3( I, J, L ) RESULT ( HNO3_UGM3 )
!
!******************************************************************************
! Subroutine GET_HNO3 allows the HNO3 concentrations to evolve with time,
! but relaxes back to the monthly mean concentrations every 3 hours.
! (bmy, 12/16/02, 3/24/03)
!
! Arguments as Input:
! ============================================================================
! (1-3) I, J, L (INTEGER) : Grid box lon, lat, alt indices
!
! Function Value:
! ============================================================================
! (1 ) HNO3_UGM3 (REAL*8 ) : HNO3 concentration in ug/m3
!
! NOTES:
! (1 ) Now use function GET_ELAPSED_MIN() from the new "time_mod.f" to
! get the elapsed minutes since the start of run. (bmy, 3/24/03)
!******************************************************************************
!
! References to F90 modules
USE GLOBAL_HNO3_MOD, ONLY : GET_HNO3_UGM3
USE TIME_MOD, ONLY : GET_ELAPSED_MIN
! Arguments
INTEGER, INTENT(IN) :: I, J, L
! Local variables
REAL*8 :: HNO3_UGM3
!=================================================================
! GET_HNO3 begins here!
!=================================================================
! Relax to monthly mean HNO3 concentrations every 3 hours
! Otherwise just return the concentration in HNO3_sav
IF ( MOD( GET_ELAPSED_MIN(), 180 ) == 0 ) THEN
HNO3_UGM3 = GET_HNO3_UGM3( I, J, L )
ELSE
HNO3_UGM3 = HNO3_sav(I,J,L)
ENDIF
! Return to calling program
END FUNCTION GET_HNO3
!------------------------------------------------------------------------------
SUBROUTINE SET_HNO3( I, J, L, HNO3_UGM3 )
!
!******************************************************************************
! Subroutine SET_HNO3 stores the modified HNO3 value back into the HNO3_sav
! array for the next timestep. (bmy, 12/16/02)
!
! Arguments as Input:
! ============================================================================
! (1-3) I, J, L (INTEGER) : Grid box lon, lat, alt indices
! (4 ) HNO3_UGM3 (REAL*8 ) : HNO3 concentration in ug/m3
!
! NOTES:
!******************************************************************************
!
! Arguments
INTEGER, INTENT(IN) :: I, J, L
REAL*8, INTENT(IN) :: HNO3_UGM3
!=================================================================
! SET_HNO3 begins here!
!=================================================================
HNO3_sav(I,J,L) = HNO3_UGM3
! Return to calling program
END SUBROUTINE SET_HNO3
!------------------------------------------------------------------------------
SUBROUTINE RPMARES( SO4, GNO3, GNH3, RH, TEMP,
& ASO4, AHSO4, ANO3, AH2O, ANH4 )
!
!******************************************************************************
!
! Description:
!
! ARES calculates the chemical composition of a sulfate/nitrate/
! ammonium/water aerosol based on equilibrium thermodynamics.
!
! This code considers two regimes depending upon the molar ratio
! of ammonium to sulfate.
!
! For values of this ratio less than 2,the code solves a cubic for
! hydrogen ion molality, H+, and if enough ammonium and liquid
! water are present calculates the dissolved nitric acid. For molal
! ionic strengths greater than 50, nitrate is assumed not to be present.
!
! For values of the molar ratio of 2 or greater, all sulfate is assumed
! to be ammonium sulfate and a calculation is made for the presence of
! ammonium nitrate.
!
! The Pitzer multicomponent approach is used in subroutine ACTCOF to
! obtain the activity coefficients. Abandoned -7/30/97 FSB
!
! The Bromley method of calculating the multicomponent activity coefficients
! is used in this version 7/30/97 SJR/FSB
!
! The calculation of liquid water
! is done in subroutine water. Details for both calculations are given
! in the respective subroutines.
!
! Based upon MARS due to
! P. Saxena, A.B. Hudischewskyj, C. Seigneur, and J.H. Seinfeld,
! Atmos. Environ., vol. 20, Number 7, Pages 1471-1483, 1986.
!
! and SCAPE due to
! Kim, Seinfeld, and Saxeena, Aerosol Sience and Technology,
! Vol 19, number 2, pages 157-181 and pages 182-198, 1993.
!
! NOTE: All concentrations supplied to this subroutine are TOTAL
! over gas and aerosol phases
!
! Parameters:
!
! SO4 : Total sulfate in MICROGRAMS/M**3 as sulfate
! GNO3 : Nitric Acid vapor in MICROGRAMS/M**3 as nitric acid
! GNH3 : Gas phase ammonia in MICROGRAMS/M**3
! RH : Fractional relative humidity
! TEMP : Temperature in Kelvin
! ASO4 : Aerosol phase sulfate in MICROGRAMS/M**3
! AHSO4 : Aerosol phase in bisulfate in MICROGRAMS/M**3 [rjp, 12/12/01]
! ANO3 : Aerosol phase nitrate in MICROGRAMS/M**3
! ANH4 : Aerosol phase ammonium in MICROGRAMS/M**3
! AH2O : Aerosol phase water in MICROGRAMS/M**3
!
! Revision History:
! Who When Detailed description of changes
! --------- -------- -------------------------------------------
! S.Roselle 11/10/87 Received the first version of the MARS code
! S.Roselle 12/30/87 Restructured code
! S.Roselle 2/12/88 Made correction to compute liquid-phase
! concentration of H2O2.
! S.Roselle 5/26/88 Made correction as advised by SAI, for
! computing H+ concentration.
! S.Roselle 3/1/89 Modified to operate with EM2
! S.Roselle 5/19/89 Changed the maximum ionic strength from
! 100 to 20, for numerical stability.
! F.Binkowski 3/3/91 Incorporate new method for ammonia rich case
! using equations for nitrate budget.
! F.Binkowski 6/18/91 New ammonia poor case which
! omits letovicite.
! F.Binkowski 7/25/91 Rearranged entire code, restructured
! ammonia poor case.
! F.Binkowski 9/9/91 Reconciled all cases of ASO4 to be output
! as SO4--
! F.Binkowski 12/6/91 Changed the ammonia defficient case so that
! there is only neutralized sulfate (ammonium
! sulfate) and sulfuric acid.
! F.Binkowski 3/5/92 Set RH bound on AWAS to 37 % to be in agreement
! with the Cohen et al. (1987) maximum molality
! of 36.2 in Table III.( J. Phys Chem (91) page
! 4569, and Table IV p 4587.)
! F.Binkowski 3/9/92 Redid logic for ammonia defficient case to remove
! possibility for denomenator becoming zero;
! this involved solving for H+ first.
! Note that for a relative humidity
! less than 50%, the model assumes that there is no
! aerosol nitrate.
! F.Binkowski 4/17/95 Code renamed ARES (AeRosol Equilibrium System)
! Redid logic as follows
! 1. Water algorithm now follows Spann & Richardson
! 2. Pitzer Multicomponent method used
! 3. Multicomponent practical osmotic coefficient
! use to close iterations.
! 4. The model now assumes that for a water
! mass fraction WFRAC less than 50% there is
! no aerosol nitrate.
! F.Binkowski 7/20/95 Changed how nitrate is calculated in ammonia poor
! case, and changed the WFRAC criterion to 40%.
! For ammonium to sulfate ratio less than 1.0
! all ammonium is aerosol and no nitrate aerosol
! exists.
! F.Binkowski 7/21/95 Changed ammonia-ammonium in ammonia poor case to
! allow gas-phase ammonia to exist.
! F.Binkowski 7/26/95 Changed equilibrium constants to values from
! Kim et al. (1993)
! F.Binkowski 6/27/96 Changed to new water format
! F.Binkowski 7/30/97 Changed to Bromley method for multicomponent
! activity coefficients. The binary activity
! coefficients
! are the same as the previous version
! F.Binkowski 8/1/97 Changed minimum sulfate from 0.0 to 1.0e-6 i.e.
! 1 picogram per cubic meter
! F.Binkowski 2/23/98 Changes to code made by Ingmar Ackermann to
! deal with precision problems on workstations
! incorporated in to this version. Also included
! are his improved descriptions of variables.
! F. Binkowski 8/28/98 changed logic as follows:
! If iterations fail, initial values of nitrate
! are retained.
! Total mass budgets are changed to account for gas
! phase returned.
! F.Binkowski 10/01/98 Removed setting RATIO to 5 for low to
! to zero sulfate sulfate case.
! F.Binkowski 01/10/2000 reconcile versions
!
! F.Binkowski 05/17/2000 change to logic for calculating RATIO
! F.Binkowski 04/09/2001 change for very low values of RATIO,
! RATIO < 0.5, no iterative calculations are done
! in low ammonia case a MAX(1.0e-10, MSO4) IS
! applied, and the iteration count is
! reduced to fifty for each iteration loop.
! R. Yantosca 09/25/2002 Bundled into "rpmares_mod.f". Declared all REALs
! as REAL*8's. Cleaned up comments. Also now force
! double precision explicitly with "D" exponents.
! P. Le Sager and Bug fix for low ammonia case -- prevent floating
! R. Yantosca 04/10/2008 point underflow and NaN's.
! P. Le Sager 06/10/2008 Better catch of over/underflow for low ammonia case
!******************************************************************************
!
! References to F90 modules
USE ERROR_MOD, ONLY : GEOS_CHEM_STOP, IS_SAFE_DIV
!=================================================================
! ARGUMENTS and their descriptions
!=================================================================
REAL*8 :: SO4 ! Total sulfate in micrograms / m**3
REAL*8 :: GNO3 ! Gas-phase nitric acid in micrograms / m**3
REAL*8 :: GNH3 ! Gas-phase ammonia in micrograms / m**3
REAL*8 :: RH ! Fractional relative humidity
REAL*8 :: TEMP ! Temperature in Kelvin
REAL*8 :: ASO4 ! Aerosol sulfate in micrograms / m**3
REAL*8 :: AHSO4 ! Aerosol bisulfate in micrograms / m**3
REAL*8 :: ANO3 ! Aerosol nitrate in micrograms / m**3
REAL*8 :: AH2O ! Aerosol liquid water content water in
! micrograms / m**3
REAL*8 :: ANH4 ! Aerosol ammonium in micrograms / m**3
!=================================================================
! PARAMETERS and their descriptions:
!=================================================================
! Molecular weights
REAL*8, PARAMETER :: MWNACL = 58.44277d0 ! NaCl
REAL*8, PARAMETER :: MWNO3 = 62.0049d0 ! NO3
REAL*8, PARAMETER :: MWHNO3 = 63.01287d0 ! HNO3
REAL*8, PARAMETER :: MWSO4 = 96.0576d0 ! SO4
REAL*8, PARAMETER :: MWHSO4 = MWSO4 + 1.0080d0 ! HSO4
REAL*8, PARAMETER :: MH2SO4 = 98.07354d0 ! H2SO4
REAL*8, PARAMETER :: MWNH3 = 17.03061d0 ! NH3
REAL*8, PARAMETER :: MWNH4 = 18.03858d0 ! NH4
REAL*8, PARAMETER :: MWORG = 16.0d0 ! Organic Species
REAL*8, PARAMETER :: MWCL = 35.453d0 ! Chloride
REAL*8, PARAMETER :: MWAIR = 28.964d0 ! AIR
REAL*8, PARAMETER :: MWLCT = 3.0d0 * MWNH4 + ! Letovicite
& 2.0d0 * MWSO4 + 1.0080d0
REAL*8, PARAMETER :: MWAS = 2.0d0 * MWNH4 + MWSO4 ! Amm. Sulfate
REAL*8, PARAMETER :: MWABS = MWNH4 + MWSO4 + 1.0080d0 ! Amm. Bisulfate
! Minimum value of sulfate aerosol concentration
REAL*8, PARAMETER :: MINSO4 = 1.0d-6 / MWSO4
! Minimum total nitrate cncentration
REAL*8, PARAMETER :: MINNO3 = 1.0d-6 / MWNO3
! Force a minimum concentration
REAL*8, PARAMETER :: FLOOR = 1.0d-30
! Tolerances for convergence test. NOTE: We now have made these
! parameters so they don't lose their values (phs, bmy, 4/10/08)
REAL*8, PARAMETER :: TOLER1 = 0.00001d0
REAL*8, PARAMETER :: TOLER2 = 0.001d0
!=================================================================
! SCRATCH LOCAL VARIABLES and their descriptions:
!=================================================================
INTEGER :: IRH ! Index set to percent relative humidity
INTEGER :: NITR ! Number of iterations for activity
! coefficients
INTEGER :: NNN ! Loop index for iterations
INTEGER :: NR ! Number of roots to cubic equation for
! H+ ciaprecision
REAL*8 :: A0 ! Coefficients and roots of
REAL*8 :: A1 ! Coefficients and roots of
REAL*8 :: A2 ! Coefficients and roots of
REAL*8 :: AA ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: BAL ! internal variables ( high ammonia case)
REAL*8 :: BB ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: BHAT ! Variables used for ammonia solubility
REAL*8 :: CC ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: CONVT ! Factor for conversion of units
REAL*8 :: DD ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: DISC ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: EROR ! Relative error used for convergence test
REAL*8 :: FNH3 ! "Free ammonia concentration", that
! which exceeds TWOSO4
REAL*8 :: GAMAAB ! Activity Coefficient for (NH4+,
! HSO4-)GAMS( 2,3 )
REAL*8 :: GAMAAN ! Activity coefficient for (NH4+, NO3-)
! GAMS( 2,2 )
REAL*8 :: GAMAHAT ! Variables used for ammonia solubility
REAL*8 :: GAMANA ! Activity coefficient for (H+ ,NO3-)
! GAMS( 1,2 )
REAL*8 :: GAMAS1 ! Activity coefficient for (2H+, SO4--)
! GAMS( 1,1 )
REAL*8 :: GAMAS2 ! Activity coefficient for (H+, HSO4-)
! GAMS( 1,3 )
REAL*8 :: GAMOLD ! used for convergence of iteration
REAL*8 :: GASQD ! internal variables ( high ammonia case)
REAL*8 :: HPLUS ! Hydrogen ion (low ammonia case) (moles
! / kg water)
REAL*8 :: K1A ! Equilibrium constant for ammonia to
! ammonium
REAL*8 :: K2SA ! Equilibrium constant for
! sulfate-bisulfate (aqueous)
REAL*8 :: K3 ! Dissociation constant for ammonium
! nitrate
REAL*8 :: KAN ! Equilibrium constant for ammonium
! nitrate (aqueous)
REAL*8 :: KHAT ! Variables used for ammonia solubility
REAL*8 :: KNA ! Equilibrium constant for nitric acid
! (aqueous)
REAL*8 :: KPH ! Henry's Law Constant for ammonia
REAL*8 :: KW ! Equilibrium constant for water
! dissociation
REAL*8 :: KW2 ! Internal variable using KAN
REAL*8 :: MAN ! Nitrate (high ammonia case) (moles /
! kg water)
REAL*8 :: MAS ! Sulfate (high ammonia case) (moles /
! kg water)
REAL*8 :: MHSO4 ! Bisulfate (low ammonia case) (moles /
! kg water)
REAL*8 :: MNA ! Nitrate (low ammonia case) (moles / kg
! water)
REAL*8 :: MNH4 ! Ammonium (moles / kg water)
REAL*8 :: MOLNU ! Total number of moles of all ions
REAL*8 :: MSO4 ! Sulfate (low ammonia case) (moles / kg
! water)
REAL*8 :: PHIBAR ! Practical osmotic coefficient
REAL*8 :: PHIOLD ! Previous value of practical osmotic
! coefficient used for convergence of
! iteration
REAL*8 :: RATIO ! Molar ratio of ammonium to sulfate
REAL*8 :: RK2SA ! Internal variable using K2SA
REAL*8 :: RKNA ! Internal variables using KNA
REAL*8 :: RKNWET ! Internal variables using KNA
REAL*8 :: RR1
REAL*8 :: RR2
REAL*8 :: STION ! Ionic strength
REAL*8 :: T1 ! Internal variables for temperature
! corrections
REAL*8 :: T2 ! Internal variables for temperature
! corrections
REAL*8 :: T21 ! Internal variables of convenience (low
! ammonia case)
REAL*8 :: T221 ! Internal variables of convenience (low
! ammonia case)
REAL*8 :: T3 ! Internal variables for temperature
! corrections
REAL*8 :: T4 ! Internal variables for temperature
! corrections
REAL*8 :: T6 ! Internal variables for temperature
! corrections
REAL*8 :: TNH4 ! Total ammonia and ammonium in
! micromoles / meter ** 3
REAL*8 :: TNO3 ! Total nitrate in micromoles / meter ** 3
REAL*8 :: TSO4 ! Total sulfate in micromoles / meter ** 3
REAL*8 :: TWOSO4 ! 2.0 * TSO4 (high ammonia case) (moles
! / kg water)
REAL*8 :: WFRAC ! Water mass fraction
REAL*8 :: WH2O ! Aerosol liquid water content (internally)
! micrograms / meter **3 on output
! internally it is 10 ** (-6) kg (water)
! / meter ** 3
! the conversion factor (1000 g = 1 kg)
! is applied for AH2O output
REAL*8 :: WSQD ! internal variables ( high ammonia case)
REAL*8 :: XNO3 ! Nitrate aerosol concentration in
! micromoles / meter ** 3
REAL*8 :: XXQ ! Variable used in quadratic solution
REAL*8 :: YNH4 ! Ammonium aerosol concentration in
! micromoles / meter** 3
REAL*8 :: ZH2O ! Water variable saved in case ionic
! strength too high.
REAL*8 :: ZSO4 ! Total sulfate molality - mso4 + mhso4
! (low ammonia case) (moles / kg water)
REAL*8 :: CAT( 2 ) ! Array for cations (1, H+); (2, NH4+)
! (moles / kg water)
REAL*8 :: AN ( 3 ) ! Array for anions (1, SO4--); (2,
! NO3-); (3, HSO4-) (moles / kg water)
REAL*8 :: CRUTES( 3 ) ! Coefficients and roots of
REAL*8 :: GAMS( 2, 3 ) ! Array of activity coefficients
REAL*8 :: TMASSHNO3 ! Total nitrate (vapor and particle)
REAL*8 :: GNO3_IN, ANO3_IN
!=================================================================
! RPMARES begins here!
! convert into micromoles/m**3
!=================================================================
! For extremely low relative humidity ( less than 1% ) set the
! water content to a minimum and skip the calculation.
IF ( RH .LT. 0.01 ) THEN
AH2O = FLOOR
RETURN
ENDIF
! total sulfate concentration
TSO4 = MAX( FLOOR, SO4 / MWSO4 )
ASO4 = SO4
!Cia models3 merge NH3/NH4 , HNO3,NO3 here
!c *** recommended by Dr. Ingmar Ackermann
! total nitrate
TNO3 = MAX( 0.0d0, ( ANO3 / MWNO3 + GNO3 / MWHNO3 ) )
! total ammonia
TNH4 = MAX( 0.0d0, ( GNH3 / MWNH3 + ANH4 / MWNH4 ) )
GNO3_IN = GNO3
ANO3_IN = ANO3
TMASSHNO3 = MAX( 0.0d0, GNO3 + ANO3 )
! set the molar ratio of ammonium to sulfate
RATIO = TNH4 / TSO4
! validity check for negative concentration
IF ( TSO4 < 0.0d0 .OR. TNO3 < 0.0d0 .OR. TNH4 < 0.0d0 ) THEN
PRINT*, 'TSO4 : ', TSO4
PRINT*, 'TNO3 : ', TNO3
PRINT*, 'TNH4 : ', TNH4
CALL GEOS_CHEM_STOP
ENDIF
! now set humidity index IRH as a percent
IRH = NINT( 100.0 * RH )
! now set humidity index IRH as a percent
IRH = MAX( 1, IRH )
IRH = MIN( 99, IRH )
!=================================================================
! Specify the equilibrium constants at correct temperature.
! Also change units from ATM to MICROMOLE/M**3 (for KAN, KPH, and K3 )
! Values from Kim et al. (1993) except as noted.
! Equilibrium constant in Kim et al. (1993)
! K = K0 exp[ a(T0/T -1) + b(1+log(T0/T)-T0/T) ], T0 = 298.15 K
! K = K0 EXP[ a T3 + b T4 ] in the code here.
!=================================================================
CONVT = 1.0d0 / ( 0.082d0 * TEMP )
T6 = 0.082d-9 * TEMP
T1 = 298.0d0 / TEMP
T2 = LOG( T1 )
T3 = T1 - 1.0d0
T4 = 1.0d0 + T2 - T1
!=================================================================
! Equilibrium Relation
!
! HSO4-(aq) = H+(aq) + SO4--(aq) ; K2SA
! NH3(g) = NH3(aq) ; KPH
! NH3(aq) + H2O(aq) = NH4+(aq) + OH-(aq) ; K1A
! HNO3(g) = H+(aq) + NO3-(aq) ; KNA
! NH3(g) + HNO3(g) = NH4NO3(s) ; K3
! H2O(aq) = H+(aq) + OH-(aq) ; KW
!=================================================================
KNA = 2.511d+06 * EXP( 29.17d0 * T3 + 16.83d0 * T4 ) * T6
K1A = 1.805d-05 * EXP( -1.50d0 * T3 + 26.92d0 * T4 )
K2SA = 1.015d-02 * EXP( 8.85d0 * T3 + 25.14d0 * T4 )
KW = 1.010d-14 * EXP( -22.52d0 * T3 + 26.92d0 * T4 )
KPH = 57.639d0 * EXP( 13.79d0 * T3 - 5.39d0 * T4 ) * T6
!K3 = 5.746E-17 * EXP( -74.38 * T3 + 6.12 * T4 ) * T6 * T6
KHAT = KPH * K1A / KW
KAN = KNA * KHAT
! Compute temperature dependent equilibrium constant for NH4NO3
! (from Mozurkewich, 1993)
K3 = EXP( 118.87d0 - 24084.0d0 / TEMP - 6.025d0 * LOG( TEMP ) )
! Convert to (micromoles/m**3) **2
K3 = K3 * CONVT * CONVT
WH2O = 0.0d0
STION = 0.0d0
AH2O = 0.0d0
MAS = 0.0d0
MAN = 0.0d0
HPLUS = 0.0d0
NITR = 0
NR = 0
GAMAAN = 1.0d0
GAMOLD = 1.0d0
! If there is very little sulfate and nitrate
! set concentrations to a very small value and return.
IF ( ( TSO4 .LT. MINSO4 ) .AND. ( TNO3 .LT. MINNO3 ) ) THEN
ASO4 = MAX( FLOOR, ASO4 )
AHSO4 = MAX( FLOOR, AHSO4 ) ! [rjp, 12/12/01]
ANO3 = MAX( FLOOR, ANO3 )
ANH4 = MAX( FLOOR, ANH4 )
WH2O = FLOOR
AH2O = FLOOR
GNH3 = MAX( FLOOR, GNH3 )
GNO3 = MAX( FLOOR, GNO3 )
RETURN
ENDIF
!=================================================================
! High Ammonia Case
!=================================================================
IF ( RATIO .GT. 2.0d0 ) THEN
GAMAAN = 0.1d0
! Set up twice the sulfate for future use.
TWOSO4 = 2.0d0 * TSO4
XNO3 = 0.0d0
YNH4 = TWOSO4
! Treat different regimes of relative humidity
!
! ZSR relationship is used to set water levels. Units are
! 10**(-6) kg water/ (cubic meter of air)
! start with ammomium sulfate solution without nitrate
CALL AWATER( IRH, TSO4, YNH4, TNO3, AH2O ) !**** note TNO3
WH2O = 1.0d-3 * AH2O
ASO4 = TSO4 * MWSO4
! In sulfate poor case, Sulfate ion is preferred
! Set bisulfate equal to zero [rjp, 12/12/01]
AHSO4 = 0.0d0
ANO3 = 0.0d0
ANH4 = YNH4 * MWNH4
WFRAC = AH2O / ( ASO4 + ANH4 + AH2O )
!IF ( WFRAC .EQ. 0.0 ) RETURN ! No water
IF ( WFRAC .LT. 0.2d0 ) THEN
! "dry" ammonium sulfate and ammonium nitrate
! compute free ammonia
FNH3 = TNH4 - TWOSO4
CC = TNO3 * FNH3 - K3
! check for not enough to support aerosol
IF ( CC .LE. 0.0d0 ) THEN
XNO3 = 0.0d0
ELSE
AA = 1.0d0
BB = -( TNO3 + FNH3 )
DISC = BB * BB - 4.0d0 * CC
! Check for complex roots of the quadratic
! set retain initial values of nitrate and RETURN
! if complex roots are found
IF ( DISC .LT. 0.0d0 ) THEN
XNO3 = 0.0d0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4
ASO4 = TSO4 * MWSO4
AHSO4 = 0.0d0
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
RETURN
ENDIF
! to get here, BB .lt. 0.0, CC .gt. 0.0 always
DD = SQRT( DISC )
XXQ = -0.5d0 * ( BB + SIGN ( 1.0d0, BB ) * DD )
! Since both roots are positive, select smaller root.
XNO3 = MIN( XXQ / AA, CC / XXQ )
ENDIF ! CC .LE. 0.0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4 + XNO3
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR
ANO3 = XNO3 * MWNO3
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
GNO3 = MAX( FLOOR, ( TMASSHNO3 - ANO3 ) )
RETURN
ENDIF ! WFRAC .LT. 0.2
! liquid phase containing completely neutralized sulfate and
! some nitrate. Solve for composition and quantity.
MAS = TSO4 / WH2O
MAN = 0.0d0
XNO3 = 0.0d0
YNH4 = TWOSO4
PHIOLD = 1.0d0
!===============================================================
! Start loop for iteration
!
! The assumption here is that all sulfate is ammonium sulfate,
! and is supersaturated at lower relative humidities.
!===============================================================
DO NNN = 1, 50 ! loop count reduced 0409/2001 by FSB
NITR = NNN
GASQD = GAMAAN * GAMAAN
WSQD = WH2O * WH2O
KW2 = KAN * WSQD / GASQD
AA = 1.0 - KW2
BB = TWOSO4 + KW2 * ( TNO3 + TNH4 - TWOSO4 )
CC = -KW2 * TNO3 * ( TNH4 - TWOSO4 )
! This is a quadratic for XNO3 [MICROMOLES / M**3]
! of nitrate in solution
DISC = BB * BB - 4.0d0 * AA * CC
! Check for complex roots, retain inital values and RETURN
IF ( DISC .LT. 0.0 ) THEN
XNO3 = 0.0d0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR ! [rjp, 12/12/01]
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, (TNH4 - YNH4 ) )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
RETURN
ENDIF
! Deal with degenerate case (yoj)
IF ( AA .NE. 0.0d0 ) THEN
DD = SQRT( DISC )
XXQ = -0.5d0 * ( BB + SIGN( 1.0d0, BB ) * DD )
RR1 = XXQ / AA
RR2 = CC / XXQ
! choose minimum positve root
IF ( ( RR1 * RR2 ) .LT. 0.0d0 ) THEN
XNO3 = MAX( RR1, RR2 )
ELSE
XNO3 = MIN( RR1, RR2 )
ENDIF
ELSE
XNO3 = - CC / BB ! AA equals zero here.
ENDIF
XNO3 = MIN( XNO3, TNO3 )
! This version assumes no solid sulfate forms (supersaturated )
! Now update water
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
! ZSR relationship is used to set water levels. Units are
! 10**(-6) kg water/ (cubic meter of air). The conversion
! from micromoles to moles is done by the units of WH2O.
WH2O = 1.0d-3 * AH2O
! Ionic balance determines the ammonium in solution.
MAN = XNO3 / WH2O
MAS = TSO4 / WH2O
MNH4 = 2.0d0 * MAS + MAN
YNH4 = MNH4 * WH2O
! MAS, MAN and MNH4 are the aqueous concentrations of sulfate,
! nitrate, and ammonium in molal units (moles/(kg water) ).
STION = 3.0d0 * MAS + MAN
CAT( 1 ) = 0.0d0
CAT( 2 ) = MNH4
AN ( 1 ) = MAS
AN ( 2 ) = MAN
AN ( 3 ) = 0.0d0
CALL ACTCOF ( CAT, AN, GAMS, MOLNU, PHIBAR )
GAMAAN = GAMS( 2, 2 )
! Use GAMAAN for convergence control
EROR = ABS( GAMOLD - GAMAAN ) / GAMOLD
GAMOLD = GAMAAN
! Check to see if we have a solution
IF ( EROR .LE. TOLER1 ) THEN
ASO4 = TSO4 * MWSO4
AHSO4 = 0.0d0 ! [rjp, 12/12/01]
ANO3 = XNO3 * MWNO3
ANH4 = YNH4 * MWNH4
GNO3 = MAX( FLOOR, ( TMASSHNO3 - ANO3 ) )
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
AH2O = 1000.0d0 * WH2O
RETURN
ENDIF
ENDDO
! If after NITR iterations no solution is found, then:
! FSB retain the initial values of nitrate particle and vapor
! note whether or not convert all bisulfate to sulfate
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR
XNO3 = TNO3 / MWNO3
YNH4 = TWOSO4
ANH4 = YNH4 * MWNH4
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
GNH3 = MAX( FLOOR, MWNH3 * (TNH4 - YNH4 ) )
RETURN
!================================================================
! Low Ammonia Case
!
! Coded by Dr. Francis S. Binkowski 12/8/91.(4/26/95)
! modified 8/28/98
! modified 04/09/2001
!
! All cases covered by this logic
!=================================================================
ELSE
WH2O = 0.0d0
CALL AWATER ( IRH, TSO4, TNH4, TNO3, AH2O )
WH2O = 1.0d-3 * AH2O
ZH2O = AH2O
! convert 10**(-6) kg water/(cubic meter of air) to micrograms
! of water per cubic meter of air (1000 g = 1 kg)
! in sulfate rich case, preferred form is HSO4-
!ASO4 = TSO4 * MWSO4
ASO4 = FLOOR ![rjp, 12/12/01]
AHSO4 = TSO4 * MWSO4 ![rjp, 12/12/01]
ANH4 = TNH4 * MWNH4
ANO3 = ANO3_IN
GNO3 = TMASSHNO3 - ANO3
GNH3 = FLOOR
!==============================================================
! *** Examine special cases and return if necessary.
!
! FSB For values of RATIO less than 0.5 do no further
! calculations. The code will cycle and still predict the
! same amount of ASO4, ANH4, ANO3, AH2O so terminate early
! to swame computation
!==============================================================
IF ( RATIO .LT. 0.5d0 ) RETURN ! FSB 04/09/2001
! Check for zero water.
IF ( WH2O .EQ. 0.0d0 ) RETURN
ZSO4 = TSO4 / WH2O
! ZSO4 is the molality of total sulfate i.e. MSO4 + MHSO4
! do not solve for aerosol nitrate for total sulfate molality
! greater than 11.0 because the model parameters break down
!### IF ( ZSO4 .GT. 11.0 ) THEN
IF ( ZSO4 .GT. 9.0 ) THEN ! 18 June 97
RETURN
ENDIF
! *** Calculation may now proceed.
!
! First solve with activity coeffs of 1.0, then iterate.
PHIOLD = 1.0d0
GAMANA = 1.0d0
GAMAS1 = 1.0d0
GAMAS2 = 1.0d0
GAMAAB = 1.0d0
GAMOLD = 1.0d0
! All ammonia is considered to be aerosol ammonium.
MNH4 = TNH4 / WH2O
! MNH4 is the molality of ammonium ion.
YNH4 = TNH4
! loop for iteration
DO NNN = 1, 50 ! loop count reduced 04/09/2001 by FSB
NITR = NNN
!------------------------------------------------------------
! Add robustness: now check if GAMANA or GAMAS1 is too small
! for the division in RKNA and RK2SA. If they are, return w/
! original values: basically replicate the procedure used
! after the current DO-loop in case of no-convergence
! (phs, bmy, rjp, 4/10/08)
! Now uses IS_SAFE_DIV to avoid compiler/machine dependency
! and to check for both underlow and overflow. Also
! use REAL4 flag to avoid under/overflow when computing A0
! and A1 from RKNA and RK2SA (phs, 5/28/08)
!------------------------------------------------------------
IF ( .NOT. (
& IS_SAFE_DIV( GAMAS2, GAMAS1*GAMAS1*GAMAS1, R4=.TRUE. )
& .AND. IS_SAFE_DIV( KNA, GAMANA*GAMANA, R4=.TRUE. )
& ) ) THEN
WRITE(6,*) 'RPMARES: not safe to divide...exit'
CALL flush(6)
GOTO 100
ENDIF
! set up equilibrium constants including activities
! solve the system for hplus first then sulfate & nitrate
RK2SA = K2SA * GAMAS2 * GAMAS2 / (GAMAS1 * GAMAS1 * GAMAS1)
RKNA = KNA / ( GAMANA * GAMANA )
RKNWET = RKNA * WH2O
T21 = ZSO4 - MNH4
T221 = ZSO4 + T21
! set up coefficients for cubic
A2 = RK2SA + RKNWET - T21
A1 = RK2SA * RKNWET - T21 * ( RK2SA + RKNWET )
& - RK2SA * ZSO4 - RKNA * TNO3
A0 = - (T21 * RK2SA * RKNWET
& + RK2SA * RKNWET * ZSO4 + RK2SA * RKNA * TNO3 )
CALL CUBIC ( A2, A1, A0, NR, CRUTES )
! Code assumes the smallest positive root is in CRUTES(1)
! But, it can be negative (see CUBIC, case of one real root,
! but can also be propagated by over/underflown)... if it is
! the case then return with original values (phs, 5/27/08)
HPLUS = CRUTES( 1 )
IF (HPLUS <= 0d0) GOTO 100
BAL = HPLUS **3 + A2 * HPLUS**2 + A1 * HPLUS + A0
! molality of sulfate ion
MSO4 = RK2SA * ZSO4 / ( HPLUS + RK2SA )
! molality of bisulfate ion
! MAX added 04/09/2001 by FSB
MHSO4 = MAX( 1.0d-10, ZSO4 - MSO4 )
! molality of nitrate ion
MNA = RKNA * TNO3 / ( HPLUS + RKNWET )
MNA = MAX( 0.0d0, MNA )
MNA = MIN( MNA, TNO3 / WH2O )
XNO3 = MNA * WH2O
ANO3 = MNA * WH2O * MWNO3
GNO3 = MAX( FLOOR, TMASSHNO3 - ANO3 )
ASO4 = MSO4 * WH2O * MWSO4 ![rjp, 12/12/01]
AHSO4 = MHSO4 * WH2O * MWSO4 ![rjp, 12/12/01]
! Calculate ionic strength
STION = 0.5d0 * ( HPLUS + MNA + MNH4 + MHSO4 + 4.0d0 * MSO4)
! Update water
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
! Convert 10**(-6) kg water/(cubic meter of air) to micrograms
! of water per cubic meter of air (1000 g = 1 kg)
WH2O = 1.0d-3 * AH2O
CAT( 1 ) = HPLUS
CAT( 2 ) = MNH4
AN ( 1 ) = MSO4
AN ( 2 ) = MNA
AN ( 3 ) = MHSO4
CALL ACTCOF ( CAT, AN, GAMS, MOLNU, PHIBAR )
GAMANA = GAMS( 1, 2 )
GAMAS1 = GAMS( 1, 1 )
GAMAS2 = GAMS( 1, 3 )
GAMAAN = GAMS( 2, 2 )
! NOTE: Improved for robustness!
GAMAHAT = ( GAMAS2 * GAMAS2 / ( GAMAAB * GAMAAB ) )
BHAT = KHAT * GAMAHAT
!### EROR = ABS ( ( PHIOLD - PHIBAR ) / PHIOLD )
!### PHIOLD = PHIBAR
EROR = ABS ( GAMOLD - GAMAHAT ) / GAMOLD
GAMOLD = GAMAHAT
! return with good solution
IF ( EROR .LE. TOLER2 ) THEN
RETURN
ENDIF
ENDDO
! after NITR iterations, failure to solve the system
! convert all ammonia to aerosol ammonium and return input
! values of NO3 and HNO3
100 ANH4 = TNH4 * MWNH4
GNH3 = FLOOR
GNO3 = GNO3_IN
ANO3 = ANO3_IN
ASO4 = TSO4 * MWSO4 ! [rjp, 12/17/01]
AHSO4= FLOOR ! [rjp, 12/17/01]
CALL AWATER ( IRH, TSO4, TNH4, TNO3, AH2O )
RETURN
ENDIF ! ratio .gt. 2.0
! Return to calling program
END SUBROUTINE RPMARES
!------------------------------------------------------------------------------
! adj_group: just like RPMARES_FORADJ but with checkpointing needed
! for the adjoint (dkh, 9/10/04, 09/07/09)
SUBROUTINE RPMARES_FORADJ( SO4, GNO3, GNH3, RH, TEMP,
& ASO4, AHSO4, ANO3, AH2O, ANH4,
& I, J, L, EXIT )
!
!******************************************************************************
!
! Description:
!
! ARES calculates the chemical composition of a sulfate/nitrate/
! ammonium/water aerosol based on equilibrium thermodynamics.
!
! This code considers two regimes depending upon the molar ratio
! of ammonium to sulfate.
!
! For values of this ratio less than 2,the code solves a cubic for
! hydrogen ion molality, H+, and if enough ammonium and liquid
! water are present calculates the dissolved nitric acid. For molal
! ionic strengths greater than 50, nitrate is assumed not to be present.
!
! For values of the molar ratio of 2 or greater, all sulfate is assumed
! to be ammonium sulfate and a calculation is made for the presence of
! ammonium nitrate.
!
! The Pitzer multicomponent approach is used in subroutine ACTCOF to
! obtain the activity coefficients. Abandoned -7/30/97 FSB
!
! The Bromley method of calculating the multicomponent activity coefficients
! is used in this version 7/30/97 SJR/FSB
!
! The calculation of liquid water
! is done in subroutine water. Details for both calculations are given
! in the respective subroutines.
!
! Based upon MARS due to
! P. Saxena, A.B. Hudischewskyj, C. Seigneur, and J.H. Seinfeld,
! Atmos. Environ., vol. 20, Number 7, Pages 1471-1483, 1986.
!
! and SCAPE due to
! Kim, Seinfeld, and Saxeena, Aerosol Sience and Technology,
! Vol 19, number 2, pages 157-181 and pages 182-198, 1993.
!
! NOTE: All concentrations supplied to this subroutine are TOTAL
! over gas and aerosol phases
!
! Parameters:
!
! SO4 : Total sulfate in MICROGRAMS/M**3 as sulfate
! GNO3 : Nitric Acid vapor in MICROGRAMS/M**3 as nitric acid
! GNH3 : Gas phase ammonia in MICROGRAMS/M**3
! RH : Fractional relative humidity
! TEMP : Temperature in Kelvin
! ASO4 : Aerosol phase sulfate in MICROGRAMS/M**3
! AHSO4 : Aerosol phase in bisulfate in MICROGRAMS/M**3 [rjp, 12/12/01]
! ANO3 : Aerosol phase nitrate in MICROGRAMS/M**3
! ANH4 : Aerosol phase ammonium in MICROGRAMS/M**3
! AH2O : Aerosol phase water in MICROGRAMS/M**3
!
! Revision History:
! Who When Detailed description of changes
! --------- -------- -------------------------------------------
! S.Roselle 11/10/87 Received the first version of the MARS code
! S.Roselle 12/30/87 Restructured code
! S.Roselle 2/12/88 Made correction to compute liquid-phase
! concentration of H2O2.
! S.Roselle 5/26/88 Made correction as advised by SAI, for
! computing H+ concentration.
! S.Roselle 3/1/89 Modified to operate with EM2
! S.Roselle 5/19/89 Changed the maximum ionic strength from
! 100 to 20, for numerical stability.
! F.Binkowski 3/3/91 Incorporate new method for ammonia rich case
! using equations for nitrate budget.
! F.Binkowski 6/18/91 New ammonia poor case which
! omits letovicite.
! F.Binkowski 7/25/91 Rearranged entire code, restructured
! ammonia poor case.
! F.Binkowski 9/9/91 Reconciled all cases of ASO4 to be output
! as SO4--
! F.Binkowski 12/6/91 Changed the ammonia defficient case so that
! there is only neutralized sulfate (ammonium
! sulfate) and sulfuric acid.
! F.Binkowski 3/5/92 Set RH bound on AWAS to 37 % to be in agreement
! with the Cohen et al. (1987) maximum molality
! of 36.2 in Table III.( J. Phys Chem (91) page
! 4569, and Table IV p 4587.)
! F.Binkowski 3/9/92 Redid logic for ammonia defficient case to remove
! possibility for denomenator becoming zero;
! this involved solving for H+ first.
! Note that for a relative humidity
! less than 50%, the model assumes that there is no
! aerosol nitrate.
! F.Binkowski 4/17/95 Code renamed ARES (AeRosol Equilibrium System)
! Redid logic as follows
! 1. Water algorithm now follows Spann & Richardson
! 2. Pitzer Multicomponent method used
! 3. Multicomponent practical osmotic coefficient
! use to close iterations.
! 4. The model now assumes that for a water
! mass fraction WFRAC less than 50% there is
! no aerosol nitrate.
! F.Binkowski 7/20/95 Changed how nitrate is calculated in ammonia poor
! case, and changed the WFRAC criterion to 40%.
! For ammonium to sulfate ratio less than 1.0
! all ammonium is aerosol and no nitrate aerosol
! exists.
! F.Binkowski 7/21/95 Changed ammonia-ammonium in ammonia poor case to
! allow gas-phase ammonia to exist.
! F.Binkowski 7/26/95 Changed equilibrium constants to values from
! Kim et al. (1993)
! F.Binkowski 6/27/96 Changed to new water format
! F.Binkowski 7/30/97 Changed to Bromley method for multicomponent
! activity coefficients. The binary activity
! coefficients
! are the same as the previous version
! F.Binkowski 8/1/97 Changed minimum sulfate from 0.0 to 1.0e-6 i.e.
! 1 picogram per cubic meter
! F.Binkowski 2/23/98 Changes to code made by Ingmar Ackermann to
! deal with precision problems on workstations
! incorporated in to this version. Also included
! are his improved descriptions of variables.
! F. Binkowski 8/28/98 changed logic as follows:
! If iterations fail, initial values of nitrate
! are retained.
! Total mass budgets are changed to account for gas
! phase returned.
! F.Binkowski 10/01/98 Removed setting RATIO to 5 for low to
! to zero sulfate sulfate case.
! F.Binkowski 01/10/2000 reconcile versions
!
! F.Binkowski 05/17/2000 change to logic for calculating RATIO
! F.Binkowski 04/09/2001 change for very low values of RATIO,
! RATIO < 0.5, no iterative calculations are done
! in low ammonia case a MAX(1.0e-10, MSO4) IS
! applied, and the iteration count is
! reduced to fifty for each iteration loop.
! R. Yantosca 09/25/2002 Bundled into "rpmares_mod.f". Declared all REALs
! as REAL*8's. Cleaned up comments. Also now force
! double precision explicitly with "D" exponents.
! P. Le Sager and Bug fix for low ammonia case -- prevent floating
! R. Yantosca 04/10/2008 point underflow and NaN's.
! P. Le Sager 06/10/2008 Better catch of over/underflow for low ammonia case
!******************************************************************************
!
! References to F90 modules
USE ERROR_MOD, ONLY : GEOS_CHEM_STOP, IS_SAFE_DIV
! (dkh, 9/10/04, 09/07/09)
USE ERROR_MOD, ONLY : ERROR_STOP
USE CHECKPT_MOD, ONLY : nitr_max
USE CHECKPT_MOD, ONLY : gamaan_fwd
USE CHECKPT_MOD, ONLY : gamold_fwd
USE CHECKPT_MOD, ONLY : wh2o_fwd
USE CHECKPT_MOD, ONLY : ynh4_fwd
USE CHECKPT_MOD, ONLY : eror_fwd
USE CHECKPT_MOD, ONLY : exit_fwd
USE CHECKPT_MOD, ONLY : gamana_fwd
USE CHECKPT_MOD, ONLY : gamas1_fwd
USE CHECKPT_MOD, ONLY : gamas2_fwd
USE CHECKPT_MOD, ONLY : NNNMAX
USE LOGICAL_ADJ_MOD, ONLY : LADJ
!=================================================================
! ARGUMENTS and their descriptions
!=================================================================
REAL*8 :: SO4 ! Total sulfate in micrograms / m**3
REAL*8 :: GNO3 ! Gas-phase nitric acid in micrograms / m**3
REAL*8 :: GNH3 ! Gas-phase ammonia in micrograms / m**3
REAL*8 :: RH ! Fractional relative humidity
REAL*8 :: TEMP ! Temperature in Kelvin
REAL*8 :: ASO4 ! Aerosol sulfate in micrograms / m**3
REAL*8 :: AHSO4 ! Aerosol bisulfate in micrograms / m**3
REAL*8 :: ANO3 ! Aerosol nitrate in micrograms / m**3
REAL*8 :: AH2O ! Aerosol liquid water content water in
! micrograms / m**3
REAL*8 :: ANH4 ! Aerosol ammonium in micrograms / m**3
! (dkh, 9/10/04, 09/07/09)
INTEGER :: I, J, L ! Grid cell coords
INTEGER EXIT
!=================================================================
! PARAMETERS and their descriptions:
!=================================================================
! Molecular weights
REAL*8, PARAMETER :: MWNACL = 58.44277d0 ! NaCl
REAL*8, PARAMETER :: MWNO3 = 62.0049d0 ! NO3
REAL*8, PARAMETER :: MWHNO3 = 63.01287d0 ! HNO3
REAL*8, PARAMETER :: MWSO4 = 96.0576d0 ! SO4
REAL*8, PARAMETER :: MWHSO4 = MWSO4 + 1.0080d0 ! HSO4
REAL*8, PARAMETER :: MH2SO4 = 98.07354d0 ! H2SO4
REAL*8, PARAMETER :: MWNH3 = 17.03061d0 ! NH3
REAL*8, PARAMETER :: MWNH4 = 18.03858d0 ! NH4
REAL*8, PARAMETER :: MWORG = 16.0d0 ! Organic Species
REAL*8, PARAMETER :: MWCL = 35.453d0 ! Chloride
REAL*8, PARAMETER :: MWAIR = 28.964d0 ! AIR
REAL*8, PARAMETER :: MWLCT = 3.0d0 * MWNH4 + ! Letovicite
& 2.0d0 * MWSO4 + 1.0080d0
REAL*8, PARAMETER :: MWAS = 2.0d0 * MWNH4 + MWSO4 ! Amm. Sulfate
REAL*8, PARAMETER :: MWABS = MWNH4 + MWSO4 + 1.0080d0 ! Amm. Bisulfate
! Minimum value of sulfate aerosol concentration
REAL*8, PARAMETER :: MINSO4 = 1.0d-6 / MWSO4
! Minimum total nitrate cncentration
REAL*8, PARAMETER :: MINNO3 = 1.0d-6 / MWNO3
! Force a minimum concentration
REAL*8, PARAMETER :: FLOOR = 1.0d-30
! Tolerances for convergence test. NOTE: We now have made these
! parameters so they don't lose their values (phs, bmy, 4/10/08)
REAL*8, PARAMETER :: TOLER1 = 0.00001d0
REAL*8, PARAMETER :: TOLER2 = 0.001d0
!=================================================================
! SCRATCH LOCAL VARIABLES and their descriptions:
!=================================================================
INTEGER :: IRH ! Index set to percent relative humidity
INTEGER :: NITR ! Number of iterations for activity
! coefficients
INTEGER :: NNN ! Loop index for iterations
INTEGER :: NR ! Number of roots to cubic equation for
! H+ ciaprecision
REAL*8 :: A0 ! Coefficients and roots of
REAL*8 :: A1 ! Coefficients and roots of
REAL*8 :: A2 ! Coefficients and roots of
REAL*8 :: AA ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: BAL ! internal variables ( high ammonia case)
REAL*8 :: BB ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: BHAT ! Variables used for ammonia solubility
REAL*8 :: CC ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: CONVT ! Factor for conversion of units
REAL*8 :: DD ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: DISC ! Coefficients and discriminant for
! quadratic equation for ammonium nitrate
REAL*8 :: EROR ! Relative error used for convergence test
REAL*8 :: FNH3 ! "Free ammonia concentration", that
! which exceeds TWOSO4
REAL*8 :: GAMAAB ! Activity Coefficient for (NH4+,
! HSO4-)GAMS( 2,3 )
REAL*8 :: GAMAAN ! Activity coefficient for (NH4+, NO3-)
! GAMS( 2,2 )
REAL*8 :: GAMAHAT ! Variables used for ammonia solubility
REAL*8 :: GAMANA ! Activity coefficient for (H+ ,NO3-)
! GAMS( 1,2 )
REAL*8 :: GAMAS1 ! Activity coefficient for (2H+, SO4--)
! GAMS( 1,1 )
REAL*8 :: GAMAS2 ! Activity coefficient for (H+, HSO4-)
! GAMS( 1,3 )
REAL*8 :: GAMOLD ! used for convergence of iteration
REAL*8 :: GASQD ! internal variables ( high ammonia case)
REAL*8 :: HPLUS ! Hydrogen ion (low ammonia case) (moles
! / kg water)
REAL*8 :: K1A ! Equilibrium constant for ammonia to
! ammonium
REAL*8 :: K2SA ! Equilibrium constant for
! sulfate-bisulfate (aqueous)
REAL*8 :: K3 ! Dissociation constant for ammonium
! nitrate
REAL*8 :: KAN ! Equilibrium constant for ammonium
! nitrate (aqueous)
REAL*8 :: KHAT ! Variables used for ammonia solubility
REAL*8 :: KNA ! Equilibrium constant for nitric acid
! (aqueous)
REAL*8 :: KPH ! Henry's Law Constant for ammonia
REAL*8 :: KW ! Equilibrium constant for water
! dissociation
REAL*8 :: KW2 ! Internal variable using KAN
REAL*8 :: MAN ! Nitrate (high ammonia case) (moles /
! kg water)
REAL*8 :: MAS ! Sulfate (high ammonia case) (moles /
! kg water)
REAL*8 :: MHSO4 ! Bisulfate (low ammonia case) (moles /
! kg water)
REAL*8 :: MNA ! Nitrate (low ammonia case) (moles / kg
! water)
REAL*8 :: MNH4 ! Ammonium (moles / kg water)
REAL*8 :: MOLNU ! Total number of moles of all ions
REAL*8 :: MSO4 ! Sulfate (low ammonia case) (moles / kg
! water)
REAL*8 :: PHIBAR ! Practical osmotic coefficient
REAL*8 :: PHIOLD ! Previous value of practical osmotic
! coefficient used for convergence of
! iteration
REAL*8 :: RATIO ! Molar ratio of ammonium to sulfate
REAL*8 :: RK2SA ! Internal variable using K2SA
REAL*8 :: RKNA ! Internal variables using KNA
REAL*8 :: RKNWET ! Internal variables using KNA
REAL*8 :: RR1
REAL*8 :: RR2
REAL*8 :: STION ! Ionic strength
REAL*8 :: T1 ! Internal variables for temperature
! corrections
REAL*8 :: T2 ! Internal variables for temperature
! corrections
REAL*8 :: T21 ! Internal variables of convenience (low
! ammonia case)
REAL*8 :: T221 ! Internal variables of convenience (low
! ammonia case)
REAL*8 :: T3 ! Internal variables for temperature
! corrections
REAL*8 :: T4 ! Internal variables for temperature
! corrections
REAL*8 :: T6 ! Internal variables for temperature
! corrections
REAL*8 :: TNH4 ! Total ammonia and ammonium in
! micromoles / meter ** 3
REAL*8 :: TNO3 ! Total nitrate in micromoles / meter ** 3
REAL*8 :: TSO4 ! Total sulfate in micromoles / meter ** 3
REAL*8 :: TWOSO4 ! 2.0 * TSO4 (high ammonia case) (moles
! / kg water)
REAL*8 :: WFRAC ! Water mass fraction
REAL*8 :: WH2O ! Aerosol liquid water content (internally)
! micrograms / meter **3 on output
! internally it is 10 ** (-6) kg (water)
! / meter ** 3
! the conversion factor (1000 g = 1 kg)
! is applied for AH2O output
REAL*8 :: WSQD ! internal variables ( high ammonia case)
REAL*8 :: XNO3 ! Nitrate aerosol concentration in
! micromoles / meter ** 3
REAL*8 :: XXQ ! Variable used in quadratic solution
REAL*8 :: YNH4 ! Ammonium aerosol concentration in
! micromoles / meter** 3
REAL*8 :: ZH2O ! Water variable saved in case ionic
! strength too high.
REAL*8 :: ZSO4 ! Total sulfate molality - mso4 + mhso4
! (low ammonia case) (moles / kg water)
REAL*8 :: CAT( 2 ) ! Array for cations (1, H+); (2, NH4+)
! (moles / kg water)
REAL*8 :: AN ( 3 ) ! Array for anions (1, SO4--); (2,
! NO3-); (3, HSO4-) (moles / kg water)
REAL*8 :: CRUTES( 3 ) ! Coefficients and roots of
REAL*8 :: GAMS( 2, 3 ) ! Array of activity coefficients
REAL*8 :: TMASSHNO3 ! Total nitrate (vapor and particle)
REAL*8 :: GNO3_IN, ANO3_IN
!=================================================================
! RPMARES_FORADJ begins here!
! convert into micromoles/m**3
!=================================================================
! Initialize EXIT to 0 (dkh, 9/10/04, 09/07/09)
EXIT = 0
! For extremely low relative humidity ( less than 1% ) set the
! water content to a minimum and skip the calculation.
IF ( RH .LT. 0.01 ) THEN
AH2O = FLOOR
! (dkh, 9/10/04, 09/07/09)
EXIT = 1
RETURN
ENDIF
! total sulfate concentration
TSO4 = MAX( FLOOR, SO4 / MWSO4 )
ASO4 = SO4
!Cia models3 merge NH3/NH4 , HNO3,NO3 here
!c *** recommended by Dr. Ingmar Ackermann
! total nitrate
TNO3 = MAX( 0.0d0, ( ANO3 / MWNO3 + GNO3 / MWHNO3 ) )
! total ammonia
TNH4 = MAX( 0.0d0, ( GNH3 / MWNH3 + ANH4 / MWNH4 ) )
GNO3_IN = GNO3
ANO3_IN = ANO3
TMASSHNO3 = MAX( 0.0d0, GNO3 + ANO3 )
! set the molar ratio of ammonium to sulfate
RATIO = TNH4 / TSO4
! validity check for negative concentration
IF ( TSO4 < 0.0d0 .OR. TNO3 < 0.0d0 .OR. TNH4 < 0.0d0 ) THEN
PRINT*, 'TSO4 : ', TSO4
PRINT*, 'TNO3 : ', TNO3
PRINT*, 'TNH4 : ', TNH4
CALL GEOS_CHEM_STOP
ENDIF
! now set humidity index IRH as a percent
IRH = NINT( 100.0 * RH )
! now set humidity index IRH as a percent
IRH = MAX( 1, IRH )
IRH = MIN( 99, IRH )
!=================================================================
! Specify the equilibrium constants at correct temperature.
! Also change units from ATM to MICROMOLE/M**3 (for KAN, KPH, and K3 )
! Values from Kim et al. (1993) except as noted.
! Equilibrium constant in Kim et al. (1993)
! K = K0 exp[ a(T0/T -1) + b(1+log(T0/T)-T0/T) ], T0 = 298.15 K
! K = K0 EXP[ a T3 + b T4 ] in the code here.
!=================================================================
CONVT = 1.0d0 / ( 0.082d0 * TEMP )
T6 = 0.082d-9 * TEMP
T1 = 298.0d0 / TEMP
T2 = LOG( T1 )
T3 = T1 - 1.0d0
T4 = 1.0d0 + T2 - T1
!=================================================================
! Equilibrium Relation
!
! HSO4-(aq) = H+(aq) + SO4--(aq) ; K2SA
! NH3(g) = NH3(aq) ; KPH
! NH3(aq) + H2O(aq) = NH4+(aq) + OH-(aq) ; K1A
! HNO3(g) = H+(aq) + NO3-(aq) ; KNA
! NH3(g) + HNO3(g) = NH4NO3(s) ; K3
! H2O(aq) = H+(aq) + OH-(aq) ; KW
!=================================================================
KNA = 2.511d+06 * EXP( 29.17d0 * T3 + 16.83d0 * T4 ) * T6
K1A = 1.805d-05 * EXP( -1.50d0 * T3 + 26.92d0 * T4 )
K2SA = 1.015d-02 * EXP( 8.85d0 * T3 + 25.14d0 * T4 )
KW = 1.010d-14 * EXP( -22.52d0 * T3 + 26.92d0 * T4 )
KPH = 57.639d0 * EXP( 13.79d0 * T3 - 5.39d0 * T4 ) * T6
!K3 = 5.746E-17 * EXP( -74.38 * T3 + 6.12 * T4 ) * T6 * T6
KHAT = KPH * K1A / KW
KAN = KNA * KHAT
! Compute temperature dependent equilibrium constant for NH4NO3
! (from Mozurkewich, 1993)
K3 = EXP( 118.87d0 - 24084.0d0 / TEMP - 6.025d0 * LOG( TEMP ) )
! Convert to (micromoles/m**3) **2
K3 = K3 * CONVT * CONVT
WH2O = 0.0d0
STION = 0.0d0
AH2O = 0.0d0
MAS = 0.0d0
MAN = 0.0d0
HPLUS = 0.0d0
NITR = 0
NR = 0
GAMAAN = 1.0d0
GAMOLD = 1.0d0
! If there is very little sulfate and nitrate
! set concentrations to a very small value and return.
IF ( ( TSO4 .LT. MINSO4 ) .AND. ( TNO3 .LT. MINNO3 ) ) THEN
ASO4 = MAX( FLOOR, ASO4 )
AHSO4 = MAX( FLOOR, AHSO4 ) ! [rjp, 12/12/01]
ANO3 = MAX( FLOOR, ANO3 )
ANH4 = MAX( FLOOR, ANH4 )
WH2O = FLOOR
AH2O = FLOOR
GNH3 = MAX( FLOOR, GNH3 )
GNO3 = MAX( FLOOR, GNO3 )
! (dkh, 9/10/04, 09/07/09)
EXIT = 2
RETURN
ENDIF
!=================================================================
! High Ammonia Case
!=================================================================
IF ( RATIO .GT. 2.0d0 ) THEN
GAMAAN = 0.1d0
! Set up twice the sulfate for future use.
TWOSO4 = 2.0d0 * TSO4
XNO3 = 0.0d0
YNH4 = TWOSO4
! Treat different regimes of relative humidity
!
! ZSR relationship is used to set water levels. Units are
! 10**(-6) kg water/ (cubic meter of air)
! start with ammomium sulfate solution without nitrate
CALL AWATER( IRH, TSO4, YNH4, TNO3, AH2O ) !**** note TNO3
WH2O = 1.0d-3 * AH2O
ASO4 = TSO4 * MWSO4
! In sulfate poor case, Sulfate ion is preferred
! Set bisulfate equal to zero [rjp, 12/12/01]
AHSO4 = 0.0d0
ANO3 = 0.0d0
ANH4 = YNH4 * MWNH4
WFRAC = AH2O / ( ASO4 + ANH4 + AH2O )
! This statement was commented out long ago, so
! no need to replace the RETURN with an EXIT = 1
!IF ( WFRAC .EQ. 0.0 ) RETURN ! No water
IF ( WFRAC .LT. 0.2d0 ) THEN
! "dry" ammonium sulfate and ammonium nitrate
! compute free ammonia
FNH3 = TNH4 - TWOSO4
CC = TNO3 * FNH3 - K3
! check for not enough to support aerosol
IF ( CC .LE. 0.0d0 ) THEN
XNO3 = 0.0d0
ELSE
AA = 1.0d0
BB = -( TNO3 + FNH3 )
DISC = BB * BB - 4.0d0 * CC
! Check for complex roots of the quadratic
! set retain initial values of nitrate and RETURN
! if complex roots are found
IF ( DISC .LT. 0.0d0 ) THEN
XNO3 = 0.0d0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4
ASO4 = TSO4 * MWSO4
AHSO4 = 0.0d0
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
! (dkh, 9/10/04, 09/07/09)
EXIT = 3
RETURN
ENDIF
! to get here, BB .lt. 0.0, CC .gt. 0.0 always
DD = SQRT( DISC )
XXQ = -0.5d0 * ( BB + SIGN ( 1.0d0, BB ) * DD )
! Since both roots are positive, select smaller root.
XNO3 = MIN( XXQ / AA, CC / XXQ )
ENDIF ! CC .LE. 0.0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4 + XNO3
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR
ANO3 = XNO3 * MWNO3
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
GNO3 = MAX( FLOOR, ( TMASSHNO3 - ANO3 ) )
! (dkh, 9/10/04, 09/07/09)
EXIT = 4
RETURN
ENDIF ! WFRAC .LT. 0.2
! liquid phase containing completely neutralized sulfate and
! some nitrate. Solve for composition and quantity.
MAS = TSO4 / WH2O
MAN = 0.0d0
XNO3 = 0.0d0
YNH4 = TWOSO4
PHIOLD = 1.0d0
!===============================================================
! Start loop for iteration
!
! The assumption here is that all sulfate is ammonium sulfate,
! and is supersaturated at lower relative humidities.
!===============================================================
! Define max iterations as NNNMAX (dkh, 9/10/04, 09/07/09)
!DO NNN = 1, 50 ! loop count reduced 0409/2001 by FSB
DO NNN = 1, NNNMAX ! loop count reduced 0409/2001 by FSB
NITR = NNN
GASQD = GAMAAN * GAMAAN
WSQD = WH2O * WH2O
KW2 = KAN * WSQD / GASQD
AA = 1.0 - KW2
BB = TWOSO4 + KW2 * ( TNO3 + TNH4 - TWOSO4 )
CC = -KW2 * TNO3 * ( TNH4 - TWOSO4 )
! This is a quadratic for XNO3 [MICROMOLES / M**3]
! of nitrate in solution
DISC = BB * BB - 4.0d0 * AA * CC
! Check for complex roots, retain inital values and RETURN
IF ( DISC .LT. 0.0 ) THEN
XNO3 = 0.0d0
AH2O = 1000.0d0 * WH2O
YNH4 = TWOSO4
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR ! [rjp, 12/12/01]
ANH4 = YNH4 * MWNH4
GNH3 = MWNH3 * MAX( FLOOR, (TNH4 - YNH4 ) )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
! (dkh, 9/10/04, 09/07/09)
EXIT = 5
RETURN
ENDIF
! Deal with degenerate case (yoj)
IF ( AA .NE. 0.0d0 ) THEN
DD = SQRT( DISC )
XXQ = -0.5d0 * ( BB + SIGN( 1.0d0, BB ) * DD )
RR1 = XXQ / AA
RR2 = CC / XXQ
! choose minimum positve root
IF ( ( RR1 * RR2 ) .LT. 0.0d0 ) THEN
XNO3 = MAX( RR1, RR2 )
ELSE
XNO3 = MIN( RR1, RR2 )
ENDIF
ELSE
XNO3 = - CC / BB ! AA equals zero here.
ENDIF
XNO3 = MIN( XNO3, TNO3 )
! This version assumes no solid sulfate forms (supersaturated )
! Now update water
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
! ZSR relationship is used to set water levels. Units are
! 10**(-6) kg water/ (cubic meter of air). The conversion
! from micromoles to moles is done by the units of WH2O.
WH2O = 1.0d-3 * AH2O
! Ionic balance determines the ammonium in solution.
MAN = XNO3 / WH2O
MAS = TSO4 / WH2O
MNH4 = 2.0d0 * MAS + MAN
YNH4 = MNH4 * WH2O
! MAS, MAN and MNH4 are the aqueous concentrations of sulfate,
! nitrate, and ammonium in molal units (moles/(kg water) ).
STION = 3.0d0 * MAS + MAN
CAT( 1 ) = 0.0d0
CAT( 2 ) = MNH4
AN ( 1 ) = MAS
AN ( 2 ) = MAN
AN ( 3 ) = 0.0d0
CALL ACTCOF ( CAT, AN, GAMS, MOLNU, PHIBAR )
GAMAAN = GAMS( 2, 2 )
! Use GAMAAN for convergence control
EROR = ABS( GAMOLD - GAMAAN ) / GAMOLD
GAMOLD = GAMAAN
! Now check here for adjoint run (dkh, 02/12/12, adj32_001)
IF ( LADJ ) THEN
!==================================================================
! CHECKPOINT (dkh, 9/10/04, 09/07/09)
! Save variables gamaan,wh2o,ynh4,gamold and exit for adjoint
! calculation
!==================================================================
gamaan_fwd (I,J,L,NNN) = GAMAAN
wh2o_fwd (I,J,L,NNN) = WH2O
ynh4_fwd (I,J,L,NNN) = YNH4
gamold_fwd (I,J,L,NNN) = GAMOLD
exit_fwd (I,J,L,NNN) = EXIT
ENDIF
! Check to see if we have a solution
IF ( EROR .LE. TOLER1 ) THEN
ASO4 = TSO4 * MWSO4
AHSO4 = 0.0d0 ! [rjp, 12/12/01]
ANO3 = XNO3 * MWNO3
ANH4 = YNH4 * MWNH4
GNO3 = MAX( FLOOR, ( TMASSHNO3 - ANO3 ) )
GNH3 = MWNH3 * MAX( FLOOR, ( TNH4 - YNH4 ) )
AH2O = 1000.0d0 * WH2O
! (dkh, 9/10/04, 09/07/09)
EXIT = 6
! check for out of bounds NITR
IF (NITR > NNNMAX) THEN
print*, I, J, L, nitr, nnn
CALL ERROR_STOP ( ' NITR > NNNMAX ',
& 'RPMARES_FORADJ' )
ENDIF
! Now check here for adjoint run (dkh, 02/12/12, adj32_001)
IF ( LADJ ) THEN
! Save more variables for adjoint calc
nitr_max (I,J,L) = NITR
exit_fwd (I,J,L,NNN) = exit
ENDIF
RETURN
ENDIF
ENDDO
! If after NITR iterations no solution is found, then:
! FSB retain the initial values of nitrate particle and vapor
! note whether or not convert all bisulfate to sulfate
ASO4 = TSO4 * MWSO4
AHSO4 = FLOOR
XNO3 = TNO3 / MWNO3
YNH4 = TWOSO4
ANH4 = YNH4 * MWNH4
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
GNO3 = GNO3_IN
ANO3 = ANO3_IN
GNH3 = MAX( FLOOR, MWNH3 * (TNH4 - YNH4 ) )
! (dkh, 9/10/04, 09/07/09)
EXIT = 7
RETURN
!================================================================
! Low Ammonia Case
!
! Coded by Dr. Francis S. Binkowski 12/8/91.(4/26/95)
! modified 8/28/98
! modified 04/09/2001
!
! All cases covered by this logic
!=================================================================
ELSE
WH2O = 0.0d0
CALL AWATER ( IRH, TSO4, TNH4, TNO3, AH2O )
WH2O = 1.0d-3 * AH2O
ZH2O = AH2O
! convert 10**(-6) kg water/(cubic meter of air) to micrograms
! of water per cubic meter of air (1000 g = 1 kg)
! in sulfate rich case, preferred form is HSO4-
!ASO4 = TSO4 * MWSO4
ASO4 = FLOOR ![rjp, 12/12/01]
AHSO4 = TSO4 * MWSO4 ![rjp, 12/12/01]
ANH4 = TNH4 * MWNH4
ANO3 = ANO3_IN
GNO3 = TMASSHNO3 - ANO3
GNH3 = FLOOR
!==============================================================
! *** Examine special cases and return if necessary.
!
! FSB For values of RATIO less than 0.5 do no further
! calculations. The code will cycle and still predict the
! same amount of ASO4, ANH4, ANO3, AH2O so terminate early
! to swame computation
!==============================================================
! (dkh, 9/10/04, 09/07/09)
!IF ( RATIO .LT. 0.5d0 ) RETURN ! FSB 04/09/2001
IF ( RATIO .LT. 0.5d0 ) THEN
EXIT = 8
RETURN ! FSB 04/09/2001
ENDIF
! Check for zero water.
! (dkh, 9/10/04, 09/07/09)
!IF ( WH2O .EQ. 0.0d0 ) RETURN
IF ( WH2O .EQ. 0.0d0 ) THEN
EXIT = 9
RETURN
ENDIF
ZSO4 = TSO4 / WH2O
! ZSO4 is the molality of total sulfate i.e. MSO4 + MHSO4
! do not solve for aerosol nitrate for total sulfate molality
! greater than 11.0 because the model parameters break down
!### IF ( ZSO4 .GT. 11.0 ) THEN
IF ( ZSO4 .GT. 9.0 ) THEN ! 18 June 97
! (dkh, 9/10/04, 09/07/09)
EXIT = 10
RETURN
ENDIF
! *** Calculation may now proceed.
!
! First solve with activity coeffs of 1.0, then iterate.
PHIOLD = 1.0d0
GAMANA = 1.0d0
GAMAS1 = 1.0d0
GAMAS2 = 1.0d0
GAMAAB = 1.0d0
GAMOLD = 1.0d0
! All ammonia is considered to be aerosol ammonium.
MNH4 = TNH4 / WH2O
! MNH4 is the molality of ammonium ion.
YNH4 = TNH4
! loop for iteration
! (dkh, 9/10/04, 09/07/09)
!DO NNN = 1, 50 ! loop count reduced 04/09/2001 by FSB
DO NNN = 1, NNNMAX ! loop count reduced 04/09/2001 by FSB
NITR = NNN
!------------------------------------------------------------
! Add robustness: now check if GAMANA or GAMAS1 is too small
! for the division in RKNA and RK2SA. If they are, return w/
! original values: basically replicate the procedure used
! after the current DO-loop in case of no-convergence
! (phs, bmy, rjp, 4/10/08)
! Now uses IS_SAFE_DIV to avoid compiler/machine dependency
! and to check for both underlow and overflow. Also
! use REAL4 flag to avoid under/overflow when computing A0
! and A1 from RKNA and RK2SA (phs, 5/28/08)
!------------------------------------------------------------
IF ( .NOT. (
& IS_SAFE_DIV( GAMAS2, GAMAS1*GAMAS1*GAMAS1, R4=.TRUE. )
& .AND. IS_SAFE_DIV( KNA, GAMANA*GAMANA, R4=.TRUE. )
& ) ) THEN
WRITE(6,*) 'RPMARES: not safe to divide...exit'
CALL flush(6)
GOTO 100
ENDIF
! set up equilibrium constants including activities
! solve the system for hplus first then sulfate & nitrate
RK2SA = K2SA * GAMAS2 * GAMAS2 / (GAMAS1 * GAMAS1 * GAMAS1)
RKNA = KNA / ( GAMANA * GAMANA )
RKNWET = RKNA * WH2O
T21 = ZSO4 - MNH4
T221 = ZSO4 + T21
! set up coefficients for cubic
A2 = RK2SA + RKNWET - T21
A1 = RK2SA * RKNWET - T21 * ( RK2SA + RKNWET )
& - RK2SA * ZSO4 - RKNA * TNO3
A0 = - (T21 * RK2SA * RKNWET
& + RK2SA * RKNWET * ZSO4 + RK2SA * RKNA * TNO3 )
CALL CUBIC ( A2, A1, A0, NR, CRUTES )
! Code assumes the smallest positive root is in CRUTES(1)
! But, it can be negative (see CUBIC, case of one real root,
! but can also be propagated by over/underflown)... if it is
! the case then return with original values (phs, 5/27/08)
HPLUS = CRUTES( 1 )
! (dkh, 9/10/04, 09/07/09)
! reinstate (dkh, 02/12/12, adj32_001)
IF (HPLUS <= 0d0) GOTO 100
BAL = HPLUS **3 + A2 * HPLUS**2 + A1 * HPLUS + A0
! molality of sulfate ion
MSO4 = RK2SA * ZSO4 / ( HPLUS + RK2SA )
! molality of bisulfate ion
! MAX added 04/09/2001 by FSB
MHSO4 = MAX( 1.0d-10, ZSO4 - MSO4 )
! molality of nitrate ion
MNA = RKNA * TNO3 / ( HPLUS + RKNWET )
MNA = MAX( 0.0d0, MNA )
MNA = MIN( MNA, TNO3 / WH2O )
XNO3 = MNA * WH2O
ANO3 = MNA * WH2O * MWNO3
GNO3 = MAX( FLOOR, TMASSHNO3 - ANO3 )
ASO4 = MSO4 * WH2O * MWSO4 ![rjp, 12/12/01]
AHSO4 = MHSO4 * WH2O * MWSO4 ![rjp, 12/12/01]
! Calculate ionic strength
STION = 0.5d0 * ( HPLUS + MNA + MNH4 + MHSO4 + 4.0d0 * MSO4)
! Update water
CALL AWATER ( IRH, TSO4, YNH4, XNO3, AH2O )
! Convert 10**(-6) kg water/(cubic meter of air) to micrograms
! of water per cubic meter of air (1000 g = 1 kg)
WH2O = 1.0d-3 * AH2O
CAT( 1 ) = HPLUS
CAT( 2 ) = MNH4
AN ( 1 ) = MSO4
AN ( 2 ) = MNA
AN ( 3 ) = MHSO4
CALL ACTCOF ( CAT, AN, GAMS, MOLNU, PHIBAR )
GAMANA = GAMS( 1, 2 )
GAMAS1 = GAMS( 1, 1 )
GAMAS2 = GAMS( 1, 3 )
GAMAAN = GAMS( 2, 2 )
! NOTE: Improved for robustness!
GAMAHAT = ( GAMAS2 * GAMAS2 / ( GAMAAB * GAMAAB ) )
BHAT = KHAT * GAMAHAT
!### EROR = ABS ( ( PHIOLD - PHIBAR ) / PHIOLD )
!### PHIOLD = PHIBAR
EROR = ABS ( GAMOLD - GAMAHAT ) / GAMOLD
GAMOLD = GAMAHAT
! Now check here for adjoint run (dkh, 02/12/12, adj32_001)
IF ( LADJ ) THEN
!==================================================================
! CHECKPOINT (dkh, 9/10/04, 09/07/09)
! Save variables error,gamana,gamas1,gamas2,gamold and wh2o for
! the adjoint calculation
!==================================================================
gamana_fwd(I,J,L,NNN) = GAMANA
gamas1_fwd(I,J,L,NNN) = GAMAS1
gamas2_fwd(I,J,L,NNN) = GAMAS2
gamold_fwd(I,J,L,NNN) = GAMOLD
wh2o_fwd(I,J,L,NNN) = WH2O
eror_fwd(I,J,L,NNN) = EROR
exit_fwd(I,J,L,NNN) = EXIT
ENDIF
! return with good solution
IF ( EROR .LE. TOLER2 ) THEN
! (dkh, 9/10/04, 09/07/09)
EXIT = 11
! Now check here for adjoint run (dkh, 02/12/12, adj32_001)
IF ( LADJ ) THEN
! Save more variables for adjoint
exit_fwd(I,J,L,NNN) = EXIT
nitr_max(I,J,L) = NITR
ENDIF
! check for out of bounds NITR
IF (NITR > NNNMAX) THEN
print*, I, J, L, nitr, nnn
CALL ERROR_STOP ( ' NITR > NNNMAX ',
& 'RPMARES_FORADJ' )
ENDIF
RETURN
ENDIF
ENDDO
! after NITR iterations, failure to solve the system
! convert all ammonia to aerosol ammonium and return input
! values of NO3 and HNO3
100 ANH4 = TNH4 * MWNH4
GNH3 = FLOOR
GNO3 = GNO3_IN
ANO3 = ANO3_IN
ASO4 = TSO4 * MWSO4 ! [rjp, 12/17/01]
AHSO4= FLOOR ! [rjp, 12/17/01]
CALL AWATER ( IRH, TSO4, TNH4, TNO3, AH2O )
! (dkh, 9/10/04, 09/07/09)
EXIT = 12
RETURN
ENDIF ! ratio .gt. 2.0
! Return to calling program
END SUBROUTINE RPMARES_FORADJ
!------------------------------------------------------------------------------
SUBROUTINE AWATER( IRHX, MSO4, MNH4, MNO3, WH2O )
!
!******************************************************************************
! NOTE!!! wh2o is returned in micrograms / cubic meter
! mso4,mnh4,mno3 are in microMOLES / cubic meter
!
! This version uses polynomials rather than tables, and uses empirical
! polynomials for the mass fraction of solute (mfs) as a function of water
! activity
! where:
!
! mfs = ms / ( ms + mw)
! ms is the mass of solute
! mw is the mass of water.
!
! Define y = mw/ ms
!
! then mfs = 1 / (1 + y)
!
! y can then be obtained from the values of mfs as
!
! y = (1 - mfs) / mfs
!
!
! the aerosol is assumed to be in a metastable state if the rh is
! is below the rh of deliquescence, but above the rh of crystallization.
!
! ZSR interpolation is used for sulfates with x ( the molar ratio of
! ammonium to sulfate in eh range 0 <= x <= 2, by sections.
! section 1: 0 <= x < 1
! section 2: 1 <= x < 1.5
! section 3: 1.5 <= x < 2.0
! section 4: 2 <= x
! In sections 1 through 3, only the sulfates can affect the amount of water
! on the particles.
! In section 4, we have fully neutralized sulfate, and extra ammonium which
! allows more nitrate to be present. Thus, the ammount of water is
! calculated
! using ZSR for ammonium sulfate and ammonium nitrate. Crystallization is
! assumed to occur in sections 2,3,and 4. See detailed discussion below.
!
!
!
! definitions:
! mso4, mnh4, and mno3 are the number of micromoles/(cubic meter of air)
! for sulfate, ammonium, and nitrate respectively
! irhx is the relative humidity (%)
! wh2o is the returned water amount in micrograms / cubic meter of air
! x is the molar ratio of ammonium to sulfate
! y0,y1,y1.5, y2 are the water contents in mass of water/mass of solute
! for pure aqueous solutions with x equal 1, 1.5, and 2 respectively.
! y3 is the value of the mass ratio of water to solute for
! a pure ammonium nitrate solution.
!
!
! coded by Dr. Francis S. Binkowski, 4/8/96.
!
! *** modified 05/30/2000
! The use of two values of mfs at an ammonium to sulfate ratio
! representative of ammonium sulfate led to an minor inconsistancy
! in nitrate behavior as the ratio went from a value less than two
! to a value greater than two and vice versa with either ammonium
! held constant and sulfate changing, or sulfate held constant and
! ammonium changing. the value of Chan et al. (1992) is the only value
! now used.
!
! *** Modified 09/25/2002
! Ported into "rpmares_mod.f". Now declare all variables with REAL*8.
! Also cleaned up comments and made cosmetic changes. Force double
! precision explicitly with "D" exponents.
!******************************************************************************
!
! Arguments
INTEGER :: IRHX
REAL*8 :: MSO4, MNH4, MNO3, WH2O
! Local variables
INTEGER :: IRH
REAL*8 :: TSO4, TNH4, TNO3, X, AW, AWC
REAL*8 :: MFS0, MFS1, MFS15, Y
REAL*8 :: Y0, Y1, Y15, Y2, Y3, Y40
REAL*8 :: Y140, Y1540, YC, MFSSO4, MFSNO3
! Molecular weight parameters
REAL*8, PARAMETER :: MWSO4 = 96.0636d0
REAL*8, PARAMETER :: MWNH4 = 18.0985d0
REAL*8, PARAMETER :: MWNO3 = 62.0649d0
REAL*8, PARAMETER :: MW2 = MWSO4 + 2.0d0 * MWNH4
REAL*8, PARAMETER :: MWANO3 = MWNO3 + MWNH4
!=================================================================
! The polynomials use data for aw as a function of mfs from Tang
! and Munkelwitz, JGR 99: 18801-18808, 1994. The polynomials were
! fit to Tang's values of water activity as a function of mfs.
!
! *** coefficients of polynomials fit to Tang and Munkelwitz data
! now give mfs as a function of water activity.
!=================================================================
REAL*8 :: C1(4) = (/ 0.9995178d0, -0.7952896d0,
& 0.99683673d0, -1.143874d0 /)
REAL*8 :: C15(4) = (/ 1.697092d0, -4.045936d0,
& 5.833688d0, -3.463783d0 /)
REAL*8 :: C2(4) = (/ 2.085067d0, -6.024139d0,
& 8.967967d0, -5.002934d0 /)
!=================================================================
! The following coefficients are a fit to the data in Table 1 of
! Nair & Vohra, J. Aerosol Sci., 6: 265-271, 1975
! data c0/0.8258941, -1.899205, 3.296905, -2.214749 /
!
! New data fit to data from
! Nair and Vohra J. Aerosol Sci., 6: 265-271, 1975
! Giaque et al. J.Am. Chem. Soc., 82: 62-70, 1960
! Zeleznik J. Phys. Chem. Ref. Data, 20: 157-1200
!=================================================================
REAL*8 :: C0(4) = (/ 0.798079d0, -1.574367d0,
& 2.536686d0, -1.735297d0 /)
!=================================================================
! Polynomials for ammonium nitrate and ammonium sulfate are from:
! Chan et al.1992, Atmospheric Environment (26A): 1661-1673.
!=================================================================
REAL*8 :: KNO3(6) = (/ 0.2906d0, 6.83665d0, -26.9093d0,
& 46.6983d0, -38.803d0, 11.8837d0 /)
REAL*8 :: KSO4(6) = (/ 2.27515d0, -11.147d0, 36.3369d0,
& -64.2134d0, 56.8341d0, -20.0953d0 /)
!=================================================================
! AWATER begins here!
!=================================================================
! Check range of per cent relative humidity
IRH = IRHX
IRH = MAX( 1, IRH )
IRH = MIN( IRH, 100 )
! Water activity = fractional relative humidity
AW = DBLE( IRH ) / 100.0d0
TSO4 = MAX( MSO4 , 0.0d0 )
TNH4 = MAX( MNH4 , 0.0d0 )
TNO3 = MAX( MNO3 , 0.0d0 )
X = 0.0d0
! If there is non-zero sulfate calculate the molar ratio
! otherwise check for non-zero nitrate and ammonium
IF ( TSO4 .GT. 0.0d0 ) THEN
X = TNH4 / TSO4
ELSE
IF ( TNO3 .GT. 0.0d0 .AND. TNH4 .GT. 0.0d0 ) X = 10.0d0
ENDIF
! *** begin screen on x for calculating wh2o
IF ( X .LT. 1.0d0 ) THEN
MFS0 = POLY4( C0, AW )
MFS1 = POLY4( C1, AW )
Y0 = ( 1.0d0 - MFS0 ) / MFS0
Y1 = ( 1.0d0 - MFS1 ) / MFS1
Y = ( 1.0d0 - X ) * Y0 + X * Y1
ELSE IF ( X .LT. 1.5d0 ) THEN
IF ( IRH .GE. 40 ) THEN
MFS1 = POLY4( C1, AW )
MFS15 = POLY4( C15, AW )
Y1 = ( 1.0d0 - MFS1 ) / MFS1
Y15 = ( 1.0d0 - MFS15 ) / MFS15
Y = 2.0d0 * ( Y1 * ( 1.5d0 - X ) + Y15 *( X - 1.0d0 ) )
!==============================================================
! Set up for crystalization
!
! Crystallization is done as follows:
!
! For 1.5 <= x, crystallization is assumed to occur
! at rh = 0.4
!
! For x <= 1.0, crystallization is assumed to occur at an
! rh < 0.01, and since the code does not allow ar rh < 0.01,
! crystallization is assumed not to occur in this range.
!
! For 1.0 <= x <= 1.5 the crystallization curve is a straignt
! line from a value of y15 at rh = 0.4 to a value of zero at
! y1. From point B to point A in the diagram. The algorithm
! does a double interpolation to calculate the amount of
! water.
!
! y1(0.40) y15(0.40)
! + + Point B
!
!
!
!
! +--------------------+
! x=1 x=1.5
! Point A
!==============================================================
ELSE
! rh along the crystallization curve.
AWC = 0.80d0 * ( X - 1.0d0 )
Y = 0.0d0
! interpolate using crystalization curve
IF ( AW .GE. AWC ) THEN
MFS1 = POLY4( C1, 0.40d0 )
MFS15 = POLY4( C15, 0.40d0 )
Y140 = ( 1.0d0 - MFS1 ) / MFS1
Y1540 = ( 1.0d0 - MFS15 ) / MFS15
Y40 = 2.0d0 * ( Y140 * ( 1.5d0 - X ) +
& Y1540 * ( X - 1.0d0 ) )
! Y along crystallization curve
YC = 2.0d0 * Y1540 * ( X - 1.0d0 )
Y = Y40 - (Y40 - YC) * (0.40d0 - AW) / (0.40d0 - AWC)
ENDIF
ENDIF
ELSE IF ( X .LT. 2.0d0 ) then ! changed 12/11/2000 by FSB
Y = 0.0D0
IF ( IRH .GE. 40 ) THEN
MFS15 = POLY4( C15, AW )
!MFS2 = POLY4( C2, AW )
Y15 = ( 1.0d0 - MFS15 ) / MFS15
!y2 = ( 1.0d0 - MFS2 ) / MFS2
MFSSO4 = POLY6( KSO4, AW ) ! Changed 05/30/2000 by FSB
Y2 = ( 1.0d0 - MFSSO4 ) / MFSSO4
Y = 2.0d0 * (Y15 * (2.0d0 - X) + Y2 * (X - 1.5d0) )
ENDIF
ELSE ! 2.0 <= x changed 12/11/2000 by FSB
!==============================================================
! Regime where ammonium sulfate and ammonium nitrate are
! in solution.
!
! following cf&s for both ammonium sulfate and ammonium nitrate
! check for crystallization here. their data indicate a 40%
! value is appropriate.
!==============================================================
Y2 = 0.0d0
Y3 = 0.0d0
IF ( IRH .GE. 40 ) THEN
MFSSO4 = POLY6( KSO4, AW )
MFSNO3 = POLY6( KNO3, AW )
Y2 = ( 1.0d0 - MFSSO4 ) / MFSSO4
Y3 = ( 1.0d0 - MFSNO3 ) / MFSNO3
ENDIF
ENDIF ! end of checking on x
!=================================================================
! Now set up output of WH2O
! WH2O units are micrograms (liquid water) / cubic meter of air
!=================================================================
IF ( X .LT. 2.0D0 ) THEN ! changed 12/11/2000 by FSB
WH2O = Y * ( TSO4 * MWSO4 + MWNH4 * TNH4 )
ELSE
! this is the case that all the sulfate is ammonium sulfate
! and the excess ammonium forms ammonum nitrate
WH2O = Y2 * TSO4 * MW2 + Y3 * TNO3 * MWANO3
ENDIF
! Return to calling program
END SUBROUTINE AWATER
!------------------------------------------------------------------------------
FUNCTION POLY4( A, X ) RESULT( Y )
! Arguments
REAL*8, INTENT(IN) :: A(4), X
! Return value
REAL*8 :: Y
!=================================================================
! POLY4 begins here!
!=================================================================
Y = A(1) + X * ( A(2) + X * ( A(3) + X * ( A(4) )))
! Return to calling program
END FUNCTION POLY4
!------------------------------------------------------------------------------
FUNCTION POLY6( A, X ) RESULT( Y )
! Arguments
REAL*8, INTENT(IN) :: A(6), X
! Return value
REAL*8 :: Y
!=================================================================
! POLY6 begins here!
!=================================================================
Y = A(1) + X * ( A(2) + X * ( A(3) + X * ( A(4) +
& X * ( A(5) + X * ( A(6) )))))
! Return to calling program
END FUNCTION POLY6
!------------------------------------------------------------------------------
SUBROUTINE CUBIC( A2, A1, A0, NR, CRUTES )
!
!******************************************************************************
! Subroutine to find the roots of a cubic equation / 3rd order polynomial
! Formulae can be found in numer. recip. on page 145
! kiran developed this version on 25/4/1990
! Dr. Francis S. Binkowski modified the routine on 6/24/91, 8/7/97
! ***
! *** modified 2/23/98 by fsb to incorporate Dr. Ingmar Ackermann's
! recommendations for setting a0, a1,a2 as real*8 variables.
!
! Modified by Bob Yantosca (10/15/02)
! - Now use upper case / white space
! - force double precision with "D" exponents
! - updated comments / cosmetic changes
! - now call ERROR_STOP from "error_mod.f" to stop the run safely
!******************************************************************************
!
! References to F90 modules
USE ERROR_MOD, ONLY : ERROR_STOP
! Arguments
INTEGER :: NR
REAL*8 :: A2, A1, A0
REAL*8 :: CRUTES(3)
! Local variables
REAL*8 :: QQ, RR, A2SQ, THETA, DUM1, DUM2
REAL*8 :: PART1, PART2, PART3, RRSQ, PHI, YY1
REAL*8 :: YY2, YY3, COSTH, SINTH
REAL*8, PARAMETER :: ONE = 1.0d0
REAL*8, PARAMETER :: SQRT3 = 1.732050808d0
REAL*8, PARAMETER :: ONE3RD = 0.333333333d0
!=================================================================
! CUBIC begins here!
!=================================================================
A2SQ = A2 * A2
QQ = ( A2SQ - 3.d0*A1 ) / 9.d0
RR = ( A2*( 2.d0*A2SQ - 9.d0*A1 ) + 27.d0*A0 ) / 54.d0
! CASE 1 THREE REAL ROOTS or CASE 2 ONLY ONE REAL ROOT
DUM1 = QQ * QQ * QQ
RRSQ = RR * RR
DUM2 = DUM1 - RRSQ
IF ( DUM2 .GE. 0.d0 ) THEN
! Now we have three real roots
PHI = SQRT( DUM1 )
IF ( ABS( PHI ) .LT. 1.d-20 ) THEN
CRUTES(1) = 0.0d0
CRUTES(2) = 0.0d0
CRUTES(3) = 0.0d0
NR = 0
CALL ERROR_STOP( 'PHI < 1d-20', 'CUBIC (rpmares_mod.f)' )
ENDIF
THETA = ACOS( RR / PHI ) / 3.0d0
COSTH = COS( THETA )
SINTH = SIN( THETA )
! Use trig identities to simplify the expressions
! Binkowski's modification
PART1 = SQRT( QQ )
YY1 = PART1 * COSTH
YY2 = YY1 - A2/3.0d0
YY3 = SQRT3 * PART1 * SINTH
CRUTES(3) = -2.0d0*YY1 - A2/3.0d0
CRUTES(2) = YY2 + YY3
CRUTES(1) = YY2 - YY3
! Set negative roots to a large positive value
IF ( CRUTES(1) .LT. 0.0d0 ) CRUTES(1) = 1.0d9
IF ( CRUTES(2) .LT. 0.0d0 ) CRUTES(2) = 1.0d9
IF ( CRUTES(3) .LT. 0.0d0 ) CRUTES(3) = 1.0d9
! Put smallest positive root in crutes(1)
CRUTES(1) = MIN( CRUTES(1), CRUTES(2), CRUTES(3) )
NR = 3
! Trap for negative CRUTES (dkh, 01/06/12, adj32_001))
IF ( CRUTES(1) < 0d0 ) THEN
IF ( CRUTES(1) .ne. ABS(CRUTES(1) ) ) CRUTES(1)=1d9
IF ( CRUTES(2) .ne. ABS(CRUTES(2) ) ) CRUTES(2)=1d9
IF ( CRUTES(3) .ne. ABS(CRUTES(3) ) ) CRUTES(3)=1d9
CRUTES(1) = MIN( CRUTES(1), CRUTES(2), CRUTES(3) )
IF ( CRUTES(1) < 0d0 ) THEN
print*, ' CRUTES = ', CRUTES , NR
CALL ERROR_STOP( ' checking for neg val failed',
& ' rpmares_mod.f ' )
ENDIF
ENDIF
ELSE
! Now here we have only one real root
PART1 = SQRT( RRSQ - DUM1 )
PART2 = ABS( RR )
PART3 = ( PART1 + PART2 )**ONE3RD
CRUTES(1) = -SIGN(ONE,RR) * ( PART3 + (QQ/PART3) ) - A2/3.D0
CRUTES(2) = 0.D0
CRUTES(3) = 0.D0
NR = 1
ENDIF
! Return to calling program
END SUBROUTINE CUBIC
!------------------------------------------------------------------------------
SUBROUTINE ACTCOF( CAT, AN, GAMA, MOLNU, PHIMULT )
!
!******************************************************************************
!
! DESCRIPTION:
!
! This subroutine computes the activity coefficients of (2NH4+,SO4--),
! (NH4+,NO3-),(2H+,SO4--),(H+,NO3-),AND (H+,HSO4-) in aqueous
! multicomponent solution, using Bromley's model and Pitzer's method.
!
! REFERENCES:
!
! Bromley, L.A. (1973) Thermodynamic properties of strong electrolytes
! in aqueous solutions. AIChE J. 19, 313-320.
!
! Chan, C.K. R.C. Flagen, & J.H. Seinfeld (1992) Water Activities of
! NH4NO3 / (NH4)2SO4 solutions, Atmos. Environ. (26A): 1661-1673.
!
! Clegg, S.L. & P. Brimblecombe (1988) Equilibrium partial pressures
! of strong acids over saline solutions - I HNO3,
! Atmos. Environ. (22): 91-100
!
! Clegg, S.L. & P. Brimblecombe (1990) Equilibrium partial pressures
! and mean activity and osmotic coefficients of 0-100% nitric acid
! as a function of temperature, J. Phys. Chem (94): 5369 - 5380
!
! Pilinis, C. and J.H. Seinfeld (1987) Continued development of a
! general equilibrium model for inorganic multicomponent atmospheric
! aerosols. Atmos. Environ. 21(11), 2453-2466.
!
!
!
!
! ARGUMENT DESCRIPTION:
!
! CAT(1) : conc. of H+ (moles/kg)
! CAT(2) : conc. of NH4+ (moles/kg)
! AN(1) : conc. of SO4-- (moles/kg)
! AN(2) : conc. of NO3- (moles/kg)
! AN(3) : conc. of HSO4- (moles/kg)
! GAMA(2,1) : mean molal ionic activity coeff for (2NH4+,SO4--)
! GAMA(2,2) : " " " " " " (NH4+,NO3-)
! GAMA(2,3) : " " " " " " (NH4+. HSO4-)
! GAMA(1,1) : " " " " " " (2H+,SO4--)
! GAMA(1,2) : " " " " " " (H+,NO3-)
! GAMA(1,3) : " " " " " " (H+,HSO4-)
! MOLNU : the total number of moles of all ions.
! PHIMULT : the multicomponent paractical osmotic coefficient.
!
! REVISION HISTORY:
! Who When Detailed description of changes
! --------- -------- -------------------------------------------
! S.Roselle 7/26/89 Copied parts of routine BROMLY, and began this
! new routine using a method described by Pilinis
! and Seinfeld 1987, Atmos. Envirn. 21 pp2453-2466.
! S.Roselle 7/30/97 Modified for use in Models-3
! F.Binkowski 8/7/97 Modified coefficients BETA0, BETA1, CGAMA
! R.Yantosca 9/25/02 Ported into "rpmares_mod.f" for GEOS-CHEM. Cleaned
! up comments, etc. Also force double precision by
! declaring REALs as REAL*8 and by using "D" exponents.
!******************************************************************************
!
! Error codes
!=================================================================
! PARAMETERS and their descriptions:
!=================================================================
INTEGER, PARAMETER :: NCAT = 2 ! number of cation
INTEGER, PARAMETER :: NAN = 3 ! number of anions
REAL*8, PARAMETER :: XSTAT0 = 0 ! Normal, successful completion
REAL*8, PARAMETER :: XSTAT1 = 1 ! File I/O error
REAL*8, PARAMETER :: XSTAT2 = 2 ! Execution error
REAL*8, PARAMETER :: XSTAT3 = 3 ! Special error
!=================================================================
! ARGUMENTS and their descriptions
!=================================================================
REAL*8 :: MOLNU ! tot # moles of all ions
REAL*8 :: PHIMULT ! multicomponent paractical
! osmotic coef
REAL*8 :: CAT(NCAT) ! cation conc in moles/kg (input)
REAL*8 :: AN(NAN) ! anion conc in moles/kg (input)
REAL*8 :: GAMA(NCAT,NAN) ! mean molal ionic activity coefs
!=================================================================
! SCRATCH LOCAL VARIABLES and their descriptions:
!=================================================================
INTEGER :: IAN ! anion indX
INTEGER :: ICAT ! cation indX
REAL*8 :: FGAMA !
REAL*8 :: I ! ionic strength
REAL*8 :: R !
REAL*8 :: S !
REAL*8 :: TA !
REAL*8 :: TB !
REAL*8 :: TC !
REAL*8 :: TEXPV !
REAL*8 :: TRM !
REAL*8 :: TWOI ! 2*ionic strength
REAL*8 :: TWOSRI ! 2*sqrt of ionic strength
REAL*8 :: ZBAR !
REAL*8 :: ZBAR2 !
REAL*8 :: ZOT1 !
REAL*8 :: SRI ! square root of ionic strength
REAL*8 :: F2(NCAT) !
REAL*8 :: F1(NAN) !
REAL*8 :: BGAMA (NCAT,NAN) !
REAL*8 :: X (NCAT,NAN) !
REAL*8 :: M (NCAT,NAN) ! molality of each electrolyte
REAL*8 :: LGAMA0(NCAT,NAN) ! binary activity coefficients
REAL*8 :: Y (NAN,NCAT) !
REAL*8 :: BETA0 (NCAT,NAN) ! binary activity coef parameter
REAL*8 :: BETA1 (NCAT,NAN) ! binary activity coef parameter
REAL*8 :: CGAMA (NCAT,NAN) ! binary activity coef parameter
REAL*8 :: V1 (NCAT,NAN) ! # of cations in electrolyte
! formula
REAL*8 :: V2 (NCAT,NAN) ! # of anions in electrolyte
! formula
! absolute value of charges of cation
REAL*8 :: ZP(NCAT) = (/ 1.0d0, 1.0d0 /)
! absolute value of charges of anion
REAL*8 :: ZM(NAN) = (/ 2.0d0, 1.0d0, 1.0d0 /)
! Character values.
CHARACTER(LEN=120) :: XMSG = ' '
CHARACTER(LEN=16), SAVE :: PNAME = ' driver program name'
!================================================================
! *** Sources for the coefficients BETA0, BETA1, CGAMA
! (1,1);(1,3) - Clegg & Brimblecombe (1988)
! (2,3) - Pilinis & Seinfeld (1987), cgama different
! (1,2) - Clegg & Brimblecombe (1990)
! (2,1);(2,2) - Chan, Flagen & Seinfeld (1992)
!================================================================
! now set the basic constants, BETA0, BETA1, CGAMA
DATA BETA0(1,1) /2.98d-2/, BETA1(1,1) / 0.0d0/,
& CGAMA(1,1) /4.38d-2/ ! 2H+SO4-
DATA BETA0(1,2) / 1.2556d-1/, BETA1(1,2) / 2.8778d-1/,
& CGAMA(1,2) / -5.59d-3/ ! HNO3
DATA BETA0(1,3) / 2.0651d-1/, BETA1(1,3) / 5.556d-1/,
& CGAMA(1,3) /0.0d0/ ! H+HSO4-
DATA BETA0(2,1) / 4.6465d-2/, BETA1(2,1) /-0.54196d0/,
& CGAMA(2,1) /-1.2683d-3/ ! (NH4)2SO4
DATA BETA0(2,2) /-7.26224d-3/, BETA1(2,2) /-1.168858d0/,
& CGAMA(2,2) / 3.51217d-5/ ! NH4NO3
DATA BETA0(2,3) / 4.494d-2/, BETA1(2,3) / 2.3594d-1/,
& CGAMA(2,3) /-2.962d-3/ ! NH4HSO4
DATA V1(1,1), V2(1,1) / 2.0d0, 1.0d0 / ! 2H+SO4-
DATA V1(2,1), V2(2,1) / 2.0d0, 1.0d0 / ! (NH4)2SO4
DATA V1(1,2), V2(1,2) / 1.0d0, 1.0d0 / ! HNO3
DATA V1(2,2), V2(2,2) / 1.0d0, 1.0d0 / ! NH4NO3
DATA V1(1,3), V2(1,3) / 1.0d0, 1.0d0 / ! H+HSO4-
DATA V1(2,3), V2(2,3) / 1.0d0, 1.0d0 / ! NH4HSO4
!=================================================================
! ACTCOF begins here!
!=================================================================
! Compute ionic strength
I = 0.0d0
DO ICAT = 1, NCAT
I = I + CAT( ICAT ) * ZP( ICAT ) * ZP( ICAT )
ENDDO
DO IAN = 1, NAN
I = I + AN( IAN ) * ZM( IAN ) * ZM( IAN )
ENDDO
I = 0.5d0 * I
! check for problems in the ionic strength
IF ( I .EQ. 0.0d0 ) THEN
DO IAN = 1, NAN
DO ICAT = 1, NCAT
GAMA( ICAT, IAN ) = 0.0d0
ENDDO
ENDDO
XMSG = 'Ionic strength is zero...returning zero activities'
!CALL M3WARN ( PNAME, 0, 0, XMSG )
RETURN
ELSE IF ( I .LT. 0.0d0 ) THEN
XMSG = 'Ionic strength below zero...negative concentrations'
! remove this on prospero (dkh, 11/18/10)
write(6,*)xmsg
call flush(6)
!CALL M3EXIT ( PNAME, 0, 0, XMSG, XSTAT1 )
ENDIF
! Compute some essential expressions
SRI = SQRT( I )
TWOSRI = 2.0d0 * SRI
TWOI = 2.0d0 * I
TEXPV = 1.0d0 - EXP( -TWOSRI ) * ( 1.0d0 + TWOSRI - TWOI )
R = 1.0d0 + 0.75d0 * I
S = 1.0d0 + 1.5d0 * I
ZOT1 = 0.511d0 * SRI / ( 1.0d0 + SRI )
! Compute binary activity coeffs
FGAMA = -0.392d0 * ( ( SRI / ( 1.0d0 + 1.2d0 * SRI )
& + ( 2.0d0 / 1.2d0 ) * LOG( 1.0d0 + 1.2d0 * SRI ) ) )
DO ICAT = 1, NCAT
DO IAN = 1, NAN
BGAMA( ICAT, IAN ) = 2.0d0 * BETA0( ICAT, IAN )
& + ( 2.0d0 * BETA1( ICAT, IAN ) / ( 4.0d0 * I ) )
& * TEXPV
! Compute the molality of each electrolyte for given ionic strength
M( ICAT, IAN ) = ( CAT( ICAT )**V1( ICAT, IAN )
& * AN( IAN )**V2( ICAT, IAN ) )**( 1.0d0
& / ( V1( ICAT, IAN ) + V2( ICAT, IAN ) ) )
! Calculate the binary activity coefficients
LGAMA0( ICAT, IAN ) = ( ZP( ICAT ) * ZM( IAN ) * FGAMA
& + M( ICAT, IAN )
& * ( 2.0d0 * V1( ICAT, IAN ) * V2( ICAT, IAN )
& / ( V1( ICAT, IAN ) + V2( ICAT, IAN ) )
& * BGAMA( ICAT, IAN ) )
& + M( ICAT, IAN ) * M( ICAT, IAN )
& * ( 2.0d0 * ( V1( ICAT, IAN )
& * V2( ICAT, IAN ) )**1.5d0
& / ( V1( ICAT, IAN ) + V2( ICAT, IAN ) )
& * CGAMA( ICAT, IAN ) ) ) / 2.302585093d0
ENDDO
ENDDO
! prepare variables for computing the multicomponent activity coeffs
DO IAN = 1, NAN
DO ICAT = 1, NCAT
ZBAR = ( ZP( ICAT ) + ZM( IAN ) ) * 0.5d0
ZBAR2 = ZBAR * ZBAR
Y( IAN, ICAT ) = ZBAR2 * AN( IAN ) / I
X( ICAT, IAN ) = ZBAR2 * CAT( ICAT ) / I
ENDDO
ENDDO
DO IAN = 1, NAN
F1( IAN ) = 0.0d0
DO ICAT = 1, NCAT
F1( IAN ) = F1( IAN ) + X( ICAT, IAN ) * LGAMA0( ICAT, IAN )
& + ZOT1 * ZP( ICAT ) * ZM( IAN ) * X( ICAT, IAN )
ENDDO
ENDDO
DO ICAT = 1, NCAT
F2( ICAT ) = 0.0d0
DO IAN = 1, NAN
F2( ICAT ) = F2( ICAT ) + Y( IAN, ICAT ) * LGAMA0(ICAT, IAN)
& + ZOT1 * ZP( ICAT ) * ZM( IAN ) * Y( IAN, ICAT )
ENDDO
ENDDO
! now calculate the multicomponent activity coefficients
DO IAN = 1, NAN
DO ICAT = 1, NCAT
TA = -ZOT1 * ZP( ICAT ) * ZM( IAN )
TB = ZP( ICAT ) * ZM( IAN ) / ( ZP( ICAT ) + ZM( IAN ) )
TC = ( F2( ICAT ) / ZP( ICAT ) + F1( IAN ) / ZM( IAN ) )
TRM = TA + TB * TC
IF ( TRM .GT. 30.0d0 ) THEN
GAMA( ICAT, IAN ) = 1.0d+30
ELSE
GAMA( ICAT, IAN ) = 10.0d0**TRM
ENDIF
ENDDO
ENDDO
! Return to calling program
END SUBROUTINE ACTCOF
!------------------------------------------------------------------------------
SUBROUTINE INIT_RPMARES
!
!*****************************************************************************
! Subroutine INIT_RPMARES initializes all module arrays (bmy, 12/16/02)
!
! NOTES:
!******************************************************************************
!
! F90 modules
USE ERROR_MOD, ONLY : ALLOC_ERR
# include "CMN_SIZE"
! Local variables
INTEGER :: AS
!=================================================================
! INIT_RPMARES begins here!
!=================================================================
ALLOCATE( HNO3_sav( IIPAR, JJPAR, LLPAR ) , STAT=AS )
IF ( AS /= 0 ) CALL ALLOC_ERR( 'HNO3_sav' )
HNO3_sav = 0d0
! Return to calling program
END SUBROUTINE INIT_RPMARES
!-----------------------------------------------------------------------------
SUBROUTINE CLEANUP_RPMARES
!
!*****************************************************************************
! Subroutine CLEANUP_RPMARES deallocates all module arrays (bmy, 12/16/02)
!
! NOTES:
!******************************************************************************
!
IF ( ALLOCATED( HNO3_sav ) ) DEALLOCATE( HNO3_sav )
! Return to calling program
END SUBROUTINE CLEANUP_RPMARES
!------------------------------------------------------------------------------
END MODULE RPMARES_MOD