3 ! module_cam_mam_gasaerexch.F
4 ! adapted from cam3 modal_aero_gasaerexch.F90 by r.c.easter, august 2010
5 ! Updated to CESM1.0.3 (CAM5.1.01) by Balwinder.Singh@pnnl.gov
8 ! > change pcnstxx to a subr argument because gas_pcnst is
9 ! not a constant/parameter in wrf-chem
10 !--------------------------------------------------------------
12 ! modal_aero_gasaerexch.F90
15 !----------------------------------------------------------------------
16 !----------------------------------------------------------------------
19 ! !MODULE: modal_aero_gasaerexch --- does modal aerosol gas-aerosol exchange
22 module modal_aero_gasaerexch
25 use shr_kind_mod, only: r8 => shr_kind_r8
27 use chem_mods, only: gas_pcnst
29 use module_cam_support, only: gas_pcnst => gas_pcnst_modal_aero
31 use modal_aero_data, only: maxd_aspectype
37 ! !PUBLIC MEMBER FUNCTIONS:
38 public modal_aero_gasaerexch_sub, modal_aero_gasaerexch_init
40 ! !PUBLIC DATA MEMBERS:
42 integer, parameter :: pcnstxx = gas_pcnst
44 integer, parameter, public :: maxspec_pcage = maxd_aspectype
46 integer, public :: npair_pcage
47 integer, public :: modefrm_pcage
48 integer, public :: modetoo_pcage
49 integer, public :: nspecfrm_pcage
50 integer, public :: lspecfrm_pcage(maxspec_pcage)
51 integer, public :: lspectoo_pcage(maxspec_pcage)
54 ! real(r8), parameter, public :: n_so4_monolayers_pcage = 1.0_r8
55 real(r8), parameter, public :: n_so4_monolayers_pcage = 3.0_r8
56 ! number of so4(+nh4) monolayers needed to "age" a carbon particle
58 real(r8), parameter, public :: &
59 dr_so4_monolayers_pcage = n_so4_monolayers_pcage * 4.76e-10
60 ! thickness of the so4 monolayers (m)
61 ! for so4(+nh4), use bi-sulfate mw and 1.77 g/cm3,
62 ! --> 1 mol so4(+nh4) = 65 cm^3 --> 1 molecule = (4.76e-10 m)^3
63 ! aging criterion is approximate so do not try to distinguish
64 ! sulfuric acid, bisulfate, ammonium sulfate
66 real(r8), save, public :: soa_equivso4_factor
67 ! this factor converts an soa volume to a volume of so4(+nh4)
68 ! having same hygroscopicity as the soa
71 ! !DESCRIPTION: This module implements ...
75 ! RCE 07.04.13: Adapted from MIRAGE2 code
78 !----------------------------------------------------------------------
81 ! list private module data here
84 !----------------------------------------------------------------------
90 !----------------------------------------------------------------------
91 !----------------------------------------------------------------------
93 ! !ROUTINE: modal_aero_gasaerexch_sub --- ...
96 subroutine modal_aero_gasaerexch_sub( &
102 dqdt_other, dqqcwdt_other, &
103 dgncur_a, dgncur_awet &
111 use modal_aero_rename, only: modal_aero_rename_sub
113 use cam_history, only: outfld, fieldname_len
114 use chem_mods, only: adv_mass
115 use constituents, only: pcnst, cnst_name, cnst_get_ind
116 use mo_tracname, only: solsym
118 use physconst, only: gravit, mwdry, rair
120 use ppgrid, only: pcols, pver
122 use abortutils, only : endrun
123 use spmd_utils, only : iam, masterproc
125 use module_cam_support, only: outfld, fieldname_len, pcnst => pcnst_runtime, &
126 pcols, pver, endrun, iam, masterproc
127 use constituents, only: cnst_name, cnst_get_ind
128 use module_data_cam_mam_asect, only: adv_mass => mw_q_mo_array
137 integer, intent(in) :: pcnstxx ! number of species in "incoming q array"
139 integer, intent(in) :: lchnk ! chunk identifier
140 integer, intent(in) :: ncol ! number of atmospheric column
141 integer, intent(in) :: nstep ! model time-step number
142 integer, intent(in) :: loffset ! offset applied to modal aero "ptrs"
143 integer, intent(in) :: latndx(pcols), lonndx(pcols)
144 real(r8), intent(in) :: deltat ! time step (s)
146 real(r8), intent(inout) :: q(ncol,pver,pcnstxx) ! tracer mixing ratio (TMR) array
147 ! *** MUST BE #/kmol-air for number
148 ! *** MUST BE mol/mol-air for mass
149 ! *** NOTE ncol dimension
150 real(r8), intent(inout) :: qqcw(ncol,pver,pcnstxx)
151 ! like q but for cloud-borner tracers
152 real(r8), intent(in) :: dqdt_other(ncol,pver,pcnstxx)
153 ! TMR tendency from other continuous
154 ! growth processes (aqchem, soa??)
155 ! *** NOTE ncol dimension
156 real(r8), intent(in) :: dqqcwdt_other(ncol,pver,pcnstxx)
157 ! like dqdt_other but for cloud-borner tracers
158 real(r8), intent(in) :: t(pcols,pver) ! temperature at model levels (K)
159 real(r8), intent(in) :: pmid(pcols,pver) ! pressure at model levels (Pa)
160 real(r8), intent(in) :: pdel(pcols,pver) ! pressure thickness of levels (Pa)
161 real(r8), intent(in) :: dgncur_a(pcols,pver,ntot_amode)
162 real(r8), intent(in) :: dgncur_awet(pcols,pver,ntot_amode)
163 ! dry & wet geo. mean dia. (m) of number distrib.
166 ! computes TMR (tracer mixing ratio) tendencies for gas condensation
167 ! onto aerosol particles
169 ! this version does condensation of H2SO4, NH3, and MSA, both treated as
170 ! completely non-volatile (gas --> aerosol, but no aerosol --> gas)
171 ! gas H2SO4 goes to aerosol SO4
172 ! gas MSA (if present) goes to aerosol SO4
173 ! aerosol MSA is not distinguished from aerosol SO4
174 ! gas NH3 (if present) goes to aerosol NH4
175 ! if gas NH3 is not present, then ????
179 ! RCE 07.04.13: Adapted from MIRAGE2 code
182 !----------------------------------------------------------------------
186 integer, parameter :: jsrflx_gaexch = 1
187 integer, parameter :: jsrflx_rename = 2
188 integer, parameter :: ldiag1=-1, ldiag2=-1, ldiag3=-1, ldiag4=-1
189 integer, parameter :: method_soa = 2
190 ! method_soa=0 is no uptake
191 ! method_soa=1 is irreversible uptake done like h2so4 uptake
192 ! method_soa=2 is reversible uptake using subr modal_aero_soaexch
194 integer :: i, icol_diag, iq
196 integer :: ido_so4a(ntot_amode), ido_nh4a(ntot_amode), ido_soaa(ntot_amode)
199 integer :: l, l2, lb, lsfrm, lstoo
200 integer :: l_so4g, l_nh4g, l_msag, l_soag
201 integer :: n, niter, niter_max, ntot_soamode
203 logical :: is_dorename_atik, dorename_atik(ncol,pver)
205 character(len=fieldname_len+3) :: fieldname
207 real (r8) :: avg_uprt_nh4, avg_uprt_so4, avg_uprt_soa
208 real (r8) :: deltatxx
209 real (r8) :: dqdt_nh4(ntot_amode), dqdt_so4(ntot_amode), dqdt_soa(ntot_amode)
210 real (r8) :: fac_m2v_nh4, fac_m2v_so4, fac_m2v_soa
211 real (r8) :: fac_m2v_pcarbon(maxd_aspectype)
212 real (r8) :: fac_volsfc_pcarbon
213 real (r8) :: fgain_nh4(ntot_amode), fgain_so4(ntot_amode), fgain_soa(ntot_amode)
215 real (r8) :: pdel_fac
216 real (r8) :: qmax_nh4, qnew_nh4, qnew_so4
217 real (r8) :: qold_nh4(ntot_amode), qold_so4(ntot_amode)
218 real (r8) :: qold_soa(ntot_amode), qold_poa(ntot_amode)
219 real (r8) :: sum_dqdt_msa, sum_dqdt_so4, sum_dqdt_soa
220 real (r8) :: sum_dqdt_nh4, sum_dqdt_nh4_b
221 real (r8) :: sum_uprt_msa, sum_uprt_nh4, sum_uprt_so4, sum_uprt_soa
222 real (r8) :: tmp1, tmp2
223 real (r8) :: uptkrate(ntot_amode,pcols,pver)
224 real (r8) :: uptkratebb(ntot_amode), uptkrate_soa(ntot_amode)
225 ! gas-to-aerosol mass transfer rates (1/s)
226 real (r8) :: vol_core, vol_shell
227 real (r8) :: xferfrac_pcage, xferfrac_max
228 real (r8) :: xferrate
230 logical :: do_msag ! true if msa gas is a species
231 logical :: do_nh4g ! true if nh3 gas is a species
232 logical :: do_soag ! true if soa gas is a species
234 logical :: dotend(pcnstxx) ! identifies species directly involved in
235 ! gas-aerosol exchange (gas condensation)
236 logical :: dotendqqcw(pcnstxx) ! like dotend but for cloud-borner tracers
237 logical :: dotendrn(pcnstxx), dotendqqcwrn(pcnstxx)
238 ! identifies species involved in renaming
239 ! after "continuous growth"
240 ! (gas-aerosol exchange and aqchem)
242 integer, parameter :: nsrflx = 2 ! last dimension of qsrflx
243 real(r8) :: dqdt(ncol,pver,pcnstxx) ! TMR "delta q" array - NOTE dims
244 real(r8) :: dqqcwdt(ncol,pver,pcnstxx) ! like dqdt but for cloud-borner tracers
245 real(r8) :: qsrflx(pcols,pcnstxx,nsrflx)
246 ! process-specific column tracer tendencies
247 ! (1=renaming, 2=gas condensation)
248 real(r8) :: qqcwsrflx(pcols,pcnstxx,nsrflx)
250 ! following only needed for diagnostics
251 real(r8) :: qold(ncol,pver,pcnstxx) ! NOTE dims
252 real(r8) :: qnew(ncol,pver,pcnstxx) ! NOTE dims
253 real(r8) :: qdel(ncol,pver,pcnstxx) ! NOTE dims
254 real(r8) :: dumavec(1000), dumbvec(1000), dumcvec(1000)
255 real(r8) :: qqcwold(ncol,pver,pcnstxx)
256 real(r8) :: dqdtsv1(ncol,pver,pcnstxx)
257 real(r8) :: dqqcwdtsv1(ncol,pver,pcnstxx)
260 !----------------------------------------------------------------------
267 if ((latndx(i) == 23) .and. (lonndx(i) == 37)) icol_diag = i
273 ! set gas species indices
274 call cnst_get_ind( 'H2SO4', l_so4g, .false. )
275 call cnst_get_ind( 'NH3', l_nh4g, .false. )
276 call cnst_get_ind( 'MSA', l_msag, .false. )
277 call cnst_get_ind( 'SOAG', l_soag, .false. )
278 l_so4g = l_so4g - loffset
279 l_nh4g = l_nh4g - loffset
280 l_msag = l_msag - loffset
281 l_soag = l_soag - loffset
282 if ((l_so4g <= 0) .or. (l_so4g > pcnstxx)) then
283 write( *, '(/a/a,2i7)' ) &
284 '*** modal_aero_gasaerexch_sub -- cannot find H2SO4 species', &
285 ' l_so4g, loffset =', l_so4g, loffset
286 call endrun( 'modal_aero_gasaerexch_sub error' )
290 if ((l_nh4g > 0) .and. (l_nh4g <= pcnstxx)) do_nh4g = .true.
291 if ((l_msag > 0) .and. (l_msag <= pcnstxx)) do_msag = .true.
293 if ((method_soa == 1) .or. (method_soa == 2)) then
294 if ((l_soag > 0) .and. (l_soag <= pcnstxx)) do_soag = .true.
295 else if (method_soa /= 0) then
296 write(*,'(/a,1x,i10)') '*** modal_aero_gasaerexch_sub - bad method_soa =', method_soa
297 call endrun( 'modal_aero_gasaerexch_sub error' )
302 dotendqqcw(:) = .false.
307 dotend(l_so4g) = .true.
308 if ( do_nh4g ) dotend(l_nh4g) = .true.
309 if ( do_msag ) dotend(l_msag) = .true.
310 if ( do_soag ) dotend(l_soag) = .true.
313 l = lptr_so4_a_amode(n)-loffset
314 if ((l > 0) .and. (l <= pcnstxx)) then
318 l = lptr_nh4_a_amode(n)-loffset
319 if ((l > 0) .and. (l <= pcnstxx)) then
326 l = lptr_soa_a_amode(n)-loffset
327 if ((l > 0) .and. (l <= pcnstxx)) then
334 if ( do_soag ) ntot_soamode = max( ntot_soamode, modefrm_pcage )
336 if (modefrm_pcage > 0) then
337 ido_so4a(modefrm_pcage) = 2
338 if (ido_nh4a(modetoo_pcage) == 1) ido_nh4a(modefrm_pcage) = 2
339 if (ido_soaa(modetoo_pcage) == 1) ido_soaa(modefrm_pcage) = 2
340 do iq = 1, nspecfrm_pcage
341 lsfrm = lspecfrm_pcage(iq)-loffset
342 lstoo = lspectoo_pcage(iq)-loffset
343 if ((lsfrm > 0) .and. (lsfrm <= pcnst)) then
344 dotend(lsfrm) = .true.
345 if ((lstoo > 0) .and. (lstoo <= pcnst)) then
346 dotend(lstoo) = .true.
352 fac_m2v_so4 = specmw_so4_amode / specdens_so4_amode
353 fac_m2v_nh4 = specmw_nh4_amode / specdens_nh4_amode
354 fac_m2v_soa = specmw_soa_amode / specdens_soa_amode
355 fac_m2v_pcarbon(:) = 0.0
357 do l = 1, nspec_amode(n)
358 l2 = lspectype_amode(l,n)
359 ! fac_m2v converts (kmol-AP/kmol-air) to (m3-AP/kmol-air)
360 ! [m3-AP/kmol-AP] = [kg-AP/kmol-AP] / [kg-AP/m3-AP]
361 fac_m2v_pcarbon(l) = specmw_amode(l2) / specdens_amode(l2)
363 fac_volsfc_pcarbon = exp( 2.5*(alnsg_amode(n)**2) )
364 xferfrac_max = 1.0_r8 - 10.0_r8*epsilon(1.0_r8) ! 1-eps
368 ! zero out tendencies and other
372 qqcwsrflx(:,:,:) = 0.0
374 ! compute gas-to-aerosol mass transfer rates
375 call gas_aer_uptkrates( ncol, loffset, &
377 dgncur_awet, uptkrate &
384 ! use this for tendency calcs to avoid generating very small negative values
385 deltatxx = deltat * (1.0d0 + 1.0d-15)
392 ! fgain_so4(n) = fraction of total h2so4 uptake going to mode n
393 ! fgain_nh4(n) = fraction of total nh3 uptake going to mode n
398 uptkratebb(n) = uptkrate(n,i,k)
399 if (ido_so4a(n) > 0) then
400 fgain_so4(n) = uptkratebb(n)
401 sum_uprt_so4 = sum_uprt_so4 + fgain_so4(n)
402 if (ido_so4a(n) == 1) then
403 qold_so4(n) = q(i,k,lptr_so4_a_amode(n)-loffset)
412 if (ido_nh4a(n) > 0) then
413 ! 2.08 factor is for gas diffusivity (nh3/h2so4)
414 ! differences in fuch-sutugin and accom coef ignored
415 fgain_nh4(n) = uptkratebb(n)*2.08
416 sum_uprt_nh4 = sum_uprt_nh4 + fgain_nh4(n)
417 if (ido_nh4a(n) == 1) then
418 qold_nh4(n) = q(i,k,lptr_nh4_a_amode(n)-loffset)
427 if (ido_soaa(n) > 0) then
428 ! 0.81 factor is for gas diffusivity (soa/h2so4)
429 ! (differences in fuch-sutugin and accom coef ignored)
430 fgain_soa(n) = uptkratebb(n)*0.81
431 sum_uprt_soa = sum_uprt_soa + fgain_soa(n)
432 if (ido_soaa(n) == 1) then
433 qold_soa(n) = q(i,k,lptr_soa_a_amode(n)-loffset)
434 l = lptr_pom_a_amode(n)-loffset
436 qold_poa(n) = q(i,k,l)
449 uptkrate_soa(n) = fgain_soa(n)
452 if (sum_uprt_so4 > 0.0) then
454 fgain_so4(n) = fgain_so4(n) / sum_uprt_so4
457 ! at this point (sum_uprt_so4 <= 0.0) only when all the fgain_so4 are zero
458 if (sum_uprt_nh4 > 0.0) then
460 fgain_nh4(n) = fgain_nh4(n) / sum_uprt_nh4
463 if (sum_uprt_soa > 0.0) then
465 fgain_soa(n) = fgain_soa(n) / sum_uprt_soa
469 ! uptake amount (fraction of gas uptaken) over deltat
470 avg_uprt_so4 = (1.0 - exp(-deltatxx*sum_uprt_so4))/deltatxx
471 avg_uprt_nh4 = (1.0 - exp(-deltatxx*sum_uprt_nh4))/deltatxx
472 avg_uprt_soa = (1.0 - exp(-deltatxx*sum_uprt_soa))/deltatxx
474 ! sum_dqdt_so4 = so4_a tendency from h2so4 gas uptake (mol/mol/s)
475 ! sum_dqdt_msa = msa_a tendency from msa gas uptake (mol/mol/s)
476 ! sum_dqdt_nh4 = nh4_a tendency from nh3 gas uptake (mol/mol/s)
477 ! sum_dqdt_soa = soa_a tendency from soa gas uptake (mol/mol/s)
478 sum_dqdt_so4 = q(i,k,l_so4g) * avg_uprt_so4
480 sum_dqdt_msa = q(i,k,l_msag) * avg_uprt_so4
485 sum_dqdt_nh4 = q(i,k,l_nh4g) * avg_uprt_nh4
490 sum_dqdt_soa = q(i,k,l_soag) * avg_uprt_soa
495 ! compute TMR tendencies for so4, nh4, msa interstial aerosol
496 ! due to simple gas uptake
497 pdel_fac = pdel(i,k)/gravit
500 dqdt_so4(n) = fgain_so4(n)*(sum_dqdt_so4 + sum_dqdt_msa)
503 dqdt_nh4(n) = fgain_nh4(n)*sum_dqdt_nh4
504 qnew_nh4 = qold_nh4(n) + dqdt_nh4(n)*deltat
505 qnew_so4 = qold_so4(n) + dqdt_so4(n)*deltat
506 qmax_nh4 = 2.0*qnew_so4
507 if (qnew_nh4 > qmax_nh4) then
508 dqdt_nh4(n) = (qmax_nh4 - qold_nh4(n))/deltatxx
510 sum_dqdt_nh4_b = sum_dqdt_nh4_b + dqdt_nh4(n)
514 if (( do_soag ) .and. (method_soa > 1)) then
515 ! compute TMR tendencies for soag and soa interstial aerosol
516 ! using soa parameterization
521 ! if (ldiag2 > 0) then
522 ! if ((i == icol_diag) .and. (mod(k-1,5) == 0)) then
527 ! call modal_aero_soaexch( dtfull, temp, pres, &
528 ! niter, niter_max, ntot_soamode, &
529 ! g_soa_in, a_soa_in, a_poa_in, xferrate, &
530 ! g_soa_tend, a_soa_tend )
531 call modal_aero_soaexch( deltat, t(i,k), pmid(i,k), &
532 niter, niter_max, ntot_soamode, &
533 q(i,k,l_soag), qold_soa, qold_poa, uptkrate_soa, &
535 ! tmp1, dqdt_soa, g0_soa, idiagss )
538 else if ( do_soag ) then
539 ! compute TMR tendencies for soa interstial aerosol
540 ! due to simple gas uptake
542 dqdt_soa(n) = fgain_soa(n)*sum_dqdt_soa
549 if (ido_so4a(n) == 1) then
550 l = lptr_so4_a_amode(n)-loffset
551 dqdt(i,k,l) = dqdt_so4(n)
552 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_so4(n)*pdel_fac
556 if (ido_nh4a(n) == 1) then
557 l = lptr_nh4_a_amode(n)-loffset
558 dqdt(i,k,l) = dqdt_nh4(n)
559 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_nh4(n)*pdel_fac
564 if (ido_soaa(n) == 1) then
565 l = lptr_soa_a_amode(n)-loffset
566 dqdt(i,k,l) = dqdt_soa(n)
567 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_soa(n)*pdel_fac
572 ! compute TMR tendencies for h2so4, nh3, and msa gas
573 ! due to simple gas uptake
575 dqdt(i,k,l) = -sum_dqdt_so4
576 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt(i,k,l)*pdel_fac
580 dqdt(i,k,l) = -sum_dqdt_msa
581 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt(i,k,l)*pdel_fac
586 dqdt(i,k,l) = -sum_dqdt_nh4_b
587 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt(i,k,l)*pdel_fac
592 dqdt(i,k,l) = -sum_dqdt_soa
593 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt(i,k,l)*pdel_fac
596 ! compute TMR tendencies associated with primary carbon aging
597 if (modefrm_pcage > 0) then
599 vol_shell = deltat * &
600 ( dqdt_so4(n)*fac_m2v_so4 + dqdt_nh4(n)*fac_m2v_nh4 + &
601 dqdt_soa(n)*fac_m2v_soa*soa_equivso4_factor )
603 do l = 1, nspec_amode(n)
604 vol_core = vol_core + &
605 q(i,k,lmassptr_amode(l,n)-loffset)*fac_m2v_pcarbon(l)
607 ! ratio1 = vol_shell/vol_core =
608 ! actual hygroscopic-shell-volume/carbon-core-volume after gas uptake
609 ! ratio2 = 6.0_r8*dr_so4_monolayers_pcage/(dgncur_a*fac_volsfc_pcarbon)
610 ! = (shell-volume corresponding to n_so4_monolayers_pcage)/core-volume
611 ! The 6.0/(dgncur_a*fac_volsfc_pcarbon) = (mode-surface-area/mode-volume)
612 ! Note that vol_shell includes both so4+nh4 AND soa as "equivalent so4",
613 ! The soa_equivso4_factor accounts for the lower hygroscopicity of soa.
615 ! Define xferfrac_pcage = min( 1.0, ratio1/ratio2)
616 ! But ratio1/ratio2 == tmp1/tmp2, and coding below avoids possible overflow
618 tmp1 = vol_shell*dgncur_a(i,k,n)*fac_volsfc_pcarbon
619 tmp2 = max( 6.0_r8*dr_so4_monolayers_pcage*vol_core, 0.0_r8 )
620 if (tmp1 >= tmp2) then
621 xferfrac_pcage = xferfrac_max
623 xferfrac_pcage = min( tmp1/tmp2, xferfrac_max )
626 if (xferfrac_pcage > 0.0_r8) then
627 do iq = 1, nspecfrm_pcage
628 lsfrm = lspecfrm_pcage(iq)-loffset
629 lstoo = lspectoo_pcage(iq)-loffset
630 xferrate = (xferfrac_pcage/deltat)*q(i,k,lsfrm)
631 dqdt(i,k,lsfrm) = dqdt(i,k,lsfrm) - xferrate
632 qsrflx(i,lsfrm,jsrf) = qsrflx(i,lsfrm,jsrf) - xferrate*pdel_fac
633 if ((lstoo > 0) .and. (lstoo <= pcnst)) then
634 dqdt(i,k,lstoo) = dqdt(i,k,lstoo) + xferrate
635 qsrflx(i,lstoo,jsrf) = qsrflx(i,lstoo,jsrf) + xferrate*pdel_fac
639 if (ido_so4a(modetoo_pcage) > 0) then
640 l = lptr_so4_a_amode(modetoo_pcage)-loffset
641 dqdt(i,k,l) = dqdt(i,k,l) + dqdt_so4(modefrm_pcage)
642 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_so4(modefrm_pcage)*pdel_fac
645 if (ido_nh4a(modetoo_pcage) > 0) then
646 l = lptr_nh4_a_amode(modetoo_pcage)-loffset
647 dqdt(i,k,l) = dqdt(i,k,l) + dqdt_nh4(modefrm_pcage)
648 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_nh4(modefrm_pcage)*pdel_fac
651 if (ido_soaa(modetoo_pcage) > 0) then
652 l = lptr_soa_a_amode(modetoo_pcage)-loffset
653 dqdt(i,k,l) = dqdt(i,k,l) + dqdt_soa(modefrm_pcage)
654 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf) + dqdt_soa(modefrm_pcage)*pdel_fac
661 ! diagnostics start -------------------------------------------------------
663 if (i == icol_diag) then
664 if (mod(k-1,5) == 0) then
665 write(*,'(a,43i5)') 'gasaerexch aaa nstep,lat,lon,k', nstep, latndx(i), lonndx(i), k
666 write(*,'(a,1p,10e12.4)') 'uptkratebb ', uptkratebb(:)
667 write(*,'(a,1p,10e12.4)') 'sum_uprt_so4 ', sum_uprt_so4
668 write(*,'(a,1p,10e12.4)') 'fgain_so4 ', fgain_so4(:)
669 write(*,'(a,1p,10e12.4)') 'sum_uprt_nh4 ', sum_uprt_nh4
670 write(*,'(a,1p,10e12.4)') 'fgain_nh4 ', fgain_nh4(:)
671 write(*,'(a,1p,10e12.4)') 'sum_uprt_soa ', sum_uprt_soa
672 write(*,'(a,1p,10e12.4)') 'fgain_soa ', fgain_soa(:)
673 write(*,'(a,1p,10e12.4)') 'so4g o,dqdt,n', q(i,k,l_so4g), sum_dqdt_so4, &
674 (q(i,k,l_so4g)-deltat*sum_dqdt_so4)
675 write(*,'(a,1p,10e12.4)') 'nh3g o,dqdt,n', q(i,k,l_nh4g), sum_dqdt_nh4, sum_dqdt_nh4_b, &
676 (q(i,k,l_nh4g)-deltat*sum_dqdt_nh4_b)
677 write(*,'(a,1p,10e12.4)') 'soag o,dqdt,n', q(i,k,l_soag), sum_dqdt_soa, &
678 (q(i,k,l_soag)-deltat*sum_dqdt_soa)
679 write(*,'(a,i12,1p,10e12.4)') &
680 'method,g0,t,p', method_soa, g0_soa, t(i,k), pmid(i,k)
681 write(*,'(a,1p,10e12.4)') 'so4 old ', qold_so4(:)
682 write(*,'(a,1p,10e12.4)') 'so4 dqdt ', dqdt_so4(:)
683 write(*,'(a,1p,10e12.4)') 'so4 new ', (qold_so4(:)+deltat*dqdt_so4(:))
684 write(*,'(a,1p,10e12.4)') 'nh4 old ', qold_nh4(:)
685 write(*,'(a,1p,10e12.4)') 'nh4 dqdt ', dqdt_nh4(:)
686 write(*,'(a,1p,10e12.4)') 'nh4 new ', (qold_nh4(:)+deltat*dqdt_nh4(:))
687 write(*,'(a,1p,10e12.4)') 'soa old ', qold_soa(:)
688 write(*,'(a,1p,10e12.4)') 'soa dqdt ', dqdt_soa(:)
689 write(*,'(a,1p,10e12.4)') 'soa new ', (qold_soa(:)+deltat*dqdt_soa(:))
690 write(*,'(a,1p,10e12.4)') 'vshell, core ', vol_shell, vol_core
691 write(*,'(a,1p,10e12.4)') 'dr_mono, ... ', dr_so4_monolayers_pcage, &
693 write(*,'(a,1p,10e12.4)') 'dgn, ... ', dgncur_a(i,k,modefrm_pcage), &
695 write(*,'(a,1p,10e12.4)') 'tmp1, tmp2 ', tmp1, tmp2
696 write(*,'(a,1p,10e12.4)') 'xferfrac_age ', xferfrac_pcage
700 ! diagnostics end ---------------------------------------------------------
703 end do ! "i = 1, ncol"
704 end do ! "k = 1, pver"
707 ! set "temporary testing arrays"
708 qold(:,:,:) = q(:,:,:)
709 qqcwold(:,:,:) = qqcw(:,:,:)
710 dqdtsv1(:,:,:) = dqdt(:,:,:)
711 dqqcwdtsv1(:,:,:) = dqqcwdt(:,:,:)
717 dotendrn(:) = .false.
718 dotendqqcwrn(:) = .false.
719 dorename_atik(1:ncol,:) = .true.
720 is_dorename_atik = .true.
721 if (ncol >= -13579) then
722 call modal_aero_rename_sub( &
723 'modal_aero_gasaerexch_sub', &
724 lchnk, ncol, nstep, &
730 dotendqqcwrn, qqcw, &
731 dqqcwdt, dqqcwdt_other, &
732 is_dorename_atik, dorename_atik, &
733 jsrflx_rename, nsrflx, &
739 ! apply the dqdt to update q (and same for qqcw)
742 if ( dotend(l) .or. dotendrn(l) ) then
745 q(i,k,l) = q(i,k,l) + dqdt(i,k,l)*deltat
749 if ( dotendqqcw(l) .or. dotendqqcwrn(l) ) then
752 qqcw(i,k,l) = qqcw(i,k,l) + dqqcwdt(i,k,l)*deltat
759 ! diagnostics start -------------------------------------------------------
761 if (icol_diag > 0) then
763 write(*,'(a,3i5)') 'gasaerexch ppp nstep,lat,lon', nstep, latndx(i), lonndx(i)
764 write(*,'(2i5,3(2x,a))') 0, 0, 'ppp', 'pdel for all k'
765 write(*,'(1p,7e12.4)') (pdel(i,k), k=1,pver)
767 write(*,'(a,3i5)') 'gasaerexch ddd nstep,lat,lon', nstep, latndx(i), lonndx(i)
771 if ( dotend(l) .or. dotendrn(l) ) then
772 write(*,'(2i5,3(2x,a))') 1, l, 'ddd1', cnst_name(lb), 'qold for all k'
773 write(*,'(1p,7e12.4)') (qold(i,k,l), k=1,pver)
774 write(*,'(2i5,3(2x,a))') 1, l, 'ddd2', cnst_name(lb), 'qnew for all k'
775 write(*,'(1p,7e12.4)') (q(i,k,l), k=1,pver)
776 write(*,'(2i5,3(2x,a))') 1, l, 'ddd3', cnst_name(lb), 'dqdt from conden for all k'
777 write(*,'(1p,7e12.4)') (dqdtsv1(i,k,l), k=1,pver)
778 write(*,'(2i5,3(2x,a))') 1, l, 'ddd4', cnst_name(lb), 'dqdt from rename for all k'
779 write(*,'(1p,7e12.4)') ((dqdt(i,k,l)-dqdtsv1(i,k,l)), k=1,pver)
780 write(*,'(2i5,3(2x,a))') 1, l, 'ddd5', cnst_name(lb), 'dqdt other for all k'
781 write(*,'(1p,7e12.4)') (dqdt_other(i,k,l), k=1,pver)
784 if ( dotendqqcw(l) .or. dotendqqcwrn(l) ) then
785 write(*,'(2i5,3(2x,a))') 2, l, 'ddd1', cnst_name_cw(lb), 'qold for all k'
786 write(*,'(1p,7e12.4)') (qqcwold(i,k,l), k=1,pver)
787 write(*,'(2i5,3(2x,a))') 2, l, 'ddd2', cnst_name_cw(lb), 'qnew for all k'
788 write(*,'(1p,7e12.4)') (qqcw(i,k,l), k=1,pver)
789 write(*,'(2i5,3(2x,a))') 2, l, 'ddd3', cnst_name_cw(lb), 'dqdt from conden for all k'
790 write(*,'(1p,7e12.4)') (dqqcwdtsv1(i,k,l), k=1,pver)
791 write(*,'(2i5,3(2x,a))') 2, l, 'ddd4', cnst_name_cw(lb), 'dqdt from rename for all k'
792 write(*,'(1p,7e12.4)') ((dqqcwdt(i,k,l)-dqqcwdtsv1(i,k,l)), k=1,pver)
793 write(*,'(2i5,3(2x,a))') 2, l, 'ddd5', cnst_name_cw(lb), 'dqdt other for all k'
794 write(*,'(1p,7e12.4)') (dqqcwdt_other(i,k,l), k=1,pver)
799 write(*,'(a,3i5)') 'gasaerexch fff nstep,lat,lon', nstep, latndx(i), lonndx(i)
802 if ( dotend(l) .or. dotendrn(l) .or. dotendqqcw(l) .or. dotendqqcwrn(l) ) then
803 write(*,'(i5,2(2x,a,2l3))') l, &
804 cnst_name(lb), dotend(l), dotendrn(l), &
805 cnst_name_cw(lb), dotendqqcw(l), dotendqqcwrn(l)
811 ! diagnostics end ---------------------------------------------------------
814 ! do history file column-tendency fields
823 if (jsrf == jsrflx_gaexch) then
824 if ( .not. dotend(l) ) cycle
825 fieldname = trim(cnst_name(lb)) // '_sfgaex1'
826 else if (jsrf == jsrflx_rename) then
827 if ( .not. dotendrn(l) ) cycle
828 fieldname = trim(cnst_name(lb)) // '_sfgaex2'
833 qsrflx(i,l,jsrf) = qsrflx(i,l,jsrf)*(adv_mass(l)/mwdry)
835 call outfld( fieldname, qsrflx(:,l,jsrf), pcols, lchnk )
838 if (jsrf == jsrflx_gaexch) then
840 else if (jsrf == jsrflx_rename) then
841 if ( .not. dotendqqcwrn(l) ) cycle
842 fieldname = trim(cnst_name_cw(lb)) // '_sfgaex2'
847 qqcwsrflx(i,l,jsrf) = qqcwsrflx(i,l,jsrf)*(adv_mass(l)/mwdry)
849 call outfld( fieldname, qqcwsrflx(:,l,jsrf), pcols, lchnk )
852 ! if (( masterproc ) .and. (nstep < 1)) &
853 ! write(*,'(2(a,2x),1p,e11.3)') &
854 ! 'modal_aero_newnuc_sub outfld', fieldname, adv_mass(l)
857 if (icol_diag > 0) then
860 tmp1 = qsrflx(i,l,jsrf)
862 tmp1 = qqcwsrflx(i,l,jsrf)
864 write(*,'(a,4i5,2x,a,1p,2e12.4)') &
865 'gasaerexch nstep,lat,lon,l,fieldname,qsrflx,adv_mass', &
866 nstep, latndx(i), lonndx(i), l, fieldname, tmp1, adv_mass(l)
877 end subroutine modal_aero_gasaerexch_sub
880 !----------------------------------------------------------------------
881 !----------------------------------------------------------------------
882 subroutine gas_aer_uptkrates( ncol, loffset, &
884 dgncur_awet, uptkrate &
892 ! computes uptkrate = | dx dN/dx gas_conden_rate(Dp(x))
894 ! using Gauss-Hermite quadrature of order nghq=2
896 ! Dp = particle diameter (cm)
898 ! dN/dx = log-normal particle number density distribution
899 ! gas_conden_rate(Dp) = 2 * pi * gasdiffus * Dp * F(Kn,ac)
900 ! F(Kn,ac) = Fuchs-Sutugin correction factor
901 ! Kn = Knudsen number
902 ! ac = accomodation coefficient
905 !use modal_aero_data, only: ntot_amode, ntot_amode, nspec_amode, &
906 ! lspectype_amode, lmassptr_amode, &
908 ! specdens_amode, specmw_amode
909 use modal_aero_data, only: ntot_amode, ntot_amode, &
914 use constituents, only: pcnst, cnst_name
916 use module_cam_support, only: pcnst => pcnst_runtime, &
918 use constituents, only: cnst_name
920 use physconst, only: mwdry, rair
924 integer, intent(in) :: pcnstxx
925 integer, intent(in) :: ncol ! number of atmospheric column
926 integer, intent(in) :: loffset
927 real(r8), intent(in) :: q(ncol,pver,pcnstxx) ! Tracer array (mol,#/mol-air)
928 real(r8), intent(in) :: t(pcols,pver) ! Temperature in Kelvin
929 real(r8), intent(in) :: pmid(pcols,pver) ! Air pressure in Pa
930 real(r8), intent(in) :: dgncur_awet(pcols,pver,ntot_amode)
932 real(r8), intent(out) :: uptkrate(ntot_amode,pcols,pver)
933 ! gas-to-aerosol mass transfer rates (1/s)
937 integer, parameter :: nghq = 2
938 integer :: i, iq, k, l1, l2, la, n
940 real(r8), parameter :: tworootpi = 3.5449077
941 real(r8), parameter :: root2 = 1.4142135
942 real(r8), parameter :: beta = 2.0
946 real(r8) :: dp, dum_m2v
947 real(r8) :: dryvol_a(pcols,pver)
948 real(r8) :: gasdiffus, gasspeed
949 real(r8) :: freepathx2, fuchs_sutugin
951 real(r8) :: lndp, lndpgn, lnsg
955 real(r8), save :: xghq(nghq), wghq(nghq) ! quadrature abscissae and weights
957 data xghq / 0.70710678, -0.70710678 /
958 data wghq / 0.88622693, 0.88622693 /
961 ! outermost loop over all modes
964 ! 22-aug-2007 rc easter - get number from q array rather
965 ! than computing a "bounded" number conc.
966 !! compute dry volume = sum_over_components{ component_mass / density }
968 !! compute it for all i,k to improve accessing q array
969 ! dryvol_a(1:ncol,:) = 0.0_r8
970 ! do l1 = 1, nspec_amode(n)
971 ! l2 = lspectype_amode(l1,n)
972 !! dum_m2v converts (kmol-AP/kmol-air) to (m3-AP/kmol-air)
973 !! [m3-AP/kmol-AP]= [kg-AP/kmol-AP] / [kg-AP/m3-AP]
974 ! dum_m2v = specmw_amode(l2) / specdens_amode(l2)
975 ! la = lmassptr_amode(l1,n)
976 ! dryvol_a(1:ncol,:) = dryvol_a(1:ncol,:) &
977 ! + max(0.0_r8,q(1:ncol,:,la))*dum_m2v
984 rhoair = pmid(i,k)/(rair*t(i,k)) ! (kg-air/m3)
985 ! aircon = 1.0e3*rhoair/mwdry ! (mol-air/m3)
987 !! "bounded" number conc. (#/m3)
988 ! num_a = dryvol_a(i,k)*v2ncur_a(i,k,n)*aircon
990 ! number conc. (#/m3) -- note q(i,k,numptr) is (#/kmol-air)
991 ! so need aircon in (kmol-air/m3)
992 aircon = rhoair/mwdry ! (kmol-air/m3)
993 num_a = q(i,k,numptr_amode(n)-loffset)*aircon
995 ! gasdiffus = h2so4 gas diffusivity from mosaic code (m^2/s)
997 gasdiffus = 0.557e-4 * (t(i,k)**1.75) / pmid(i,k)
998 ! gasspeed = h2so4 gas mean molecular speed from mosaic code (m/s)
999 gasspeed = 1.470e1 * sqrt(t(i,k))
1000 ! freepathx2 = 2 * (h2so4 mean free path) (m)
1001 freepathx2 = 6.0*gasdiffus/gasspeed
1003 lnsg = log( sigmag_amode(n) )
1004 lndpgn = log( dgncur_awet(i,k,n) ) ! (m)
1005 const = tworootpi * num_a * exp(beta*lndpgn + 0.5*(beta*lnsg)**2)
1007 ! sum over gauss-hermite quadrature points
1010 lndp = lndpgn + beta*lnsg**2 + root2*lnsg*xghq(iq)
1014 knudsen = freepathx2/dp
1015 ! following assumes accomodation coefficient = ac = 0.65
1016 ! (Adams & Seinfeld, 2002, JGR, and references therein)
1017 ! fuchs_sutugin = (0.75*ac*(1. + knudsen)) /
1018 ! (knudsen*(1.0 + knudsen + 0.283*ac) + 0.75*ac)
1019 fuchs_sutugin = (0.4875*(1. + knudsen)) / &
1020 (knudsen*(1.184 + knudsen) + 0.4875)
1022 sumghq = sumghq + wghq(iq)*dp*fuchs_sutugin/(dp**beta)
1024 uptkrate(n,i,k) = const * gasdiffus * sumghq
1026 end do ! "do i = 1, ncol"
1027 end do ! "do k = 1, pver"
1029 end do ! "do n = 1, ntot_soamode"
1033 end subroutine gas_aer_uptkrates
1035 !----------------------------------------------------------------------
1038 subroutine modal_aero_soaexch( dtfull, temp, pres, &
1039 niter, niter_max, ntot_soamode, &
1040 g_soa_in, a_soa_in, a_poa_in, xferrate, &
1041 g_soa_tend, a_soa_tend )
1042 ! g_soa_tend, a_soa_tend, g0_soa, idiagss )
1044 !-----------------------------------------------------------------------
1048 ! calculates condensation/evaporation of "soa gas"
1049 ! to/from multiple aerosol modes in 1 grid cell
1052 ! (1) ambient equilibrium vapor pressure of soa gas
1053 ! is given by p0_soa_298 and delh_vap_soa
1054 ! (2) equilibrium vapor pressure of soa gas at aerosol
1055 ! particle surface is given by raoults law in the form
1056 ! g_star = g0_soa*[a_soa/(a_soa + a_opoa)]
1057 ! (3) (oxidized poa)/(total poa) is equal to frac_opoa (constant)
1060 ! Author: R. Easter and R. Zaveri
1062 !-----------------------------------------------------------------------
1065 real(r8), intent(in) :: dtfull ! full integration time step (s)
1066 real(r8), intent(in) :: temp ! air temperature (K)
1067 real(r8), intent(in) :: pres ! air pressure (Pa)
1068 integer, intent(out) :: niter ! number of iterations performed
1069 integer, intent(in) :: niter_max ! max allowed number of iterations
1070 integer, intent(in) :: ntot_soamode ! number of modes having soa
1071 real(r8), intent(in) :: g_soa_in ! initial soa gas mixrat (mol/mol)
1072 real(r8), intent(in) :: a_soa_in(ntot_soamode) ! initial soa aerosol mixrat (mol/mol)
1073 real(r8), intent(in) :: a_poa_in(ntot_soamode) ! initial poa aerosol mixrat (mol/mol)
1074 real(r8), intent(in) :: xferrate(ntot_soamode) ! gas-aerosol mass transfer rate (1/s)
1075 real(r8), intent(out) :: g_soa_tend ! soa gas mixrat tendency (mol/mol/s)
1076 real(r8), intent(out) :: a_soa_tend(ntot_soamode) ! soa aerosol mixrat tendency (mol/mol/s)
1077 ! real(r8), intent(out) :: g0_soa ! ambient soa gas equilib mixrat (mol/mol)
1078 ! integer, intent(in) :: idiagss
1083 real(r8), parameter :: alpha = 0.05 ! parameter used in calc of time step
1084 real(r8), parameter :: g_min1 = 1.0e-20
1085 real(r8), parameter :: opoa_frac = 0.1 ! fraction of poa that is opoa
1086 real(r8), parameter :: delh_vap_soa = 156.0e3
1087 ! delh_vap_soa = heat of vaporization for gas soa (J/mol)
1088 real(r8), parameter :: p0_soa_298 = 1.0e-10
1089 ! p0_soa_298 = soa gas equilib vapor presssure (atm) at 298 k
1090 real(r8), parameter :: rgas = 8.3144 ! gas constant in J/K/mol
1092 real(r8) :: a_opoa(ntot_soamode) ! oxidized-poa aerosol mixrat (mol/mol)
1093 real(r8) :: a_soa(ntot_soamode) ! soa aerosol mixrat (mol/mol)
1094 real(r8) :: a_soa_tmp ! temporary soa aerosol mixrat (mol/mol)
1095 real(r8) :: beta(ntot_soamode) ! dtcur*xferrate
1096 real(r8) :: dtcur ! current time step (s)
1097 real(r8) :: dtmax ! = (dtfull-tcur)
1098 real(r8) :: g_soa ! soa gas mixrat (mol/mol)
1099 real(r8) :: g0_soa ! ambient soa gas equilib mixrat (mol/mol)
1100 real(r8) :: g_star(ntot_soamode) ! soa gas mixrat that is in equilib
1101 ! with each aerosol mode (mol/mol)
1102 real(r8) :: phi(ntot_soamode) ! "relative driving force"
1103 real(r8) :: p0_soa ! soa gas equilib vapor presssure (atm)
1104 real(r8) :: sat(ntot_soamode)
1105 real(r8) :: tcur ! current integration time (from 0 s)
1106 real(r8) :: tmpa, tmpb
1107 real(r8) :: tot_soa ! g_soa + sum( a_soa(:) )
1110 ! force things to be non-negative and calc tot_soa
1111 ! calc a_opoa (always slightly >0)
1112 g_soa = max( g_soa_in, 0.0_r8 )
1114 do m = 1, ntot_soamode
1115 a_soa(m) = max( a_soa_in(m), 0.0_r8 )
1116 tot_soa = tot_soa + a_soa(m)
1117 a_opoa(m) = opoa_frac*a_poa_in(m)
1118 a_opoa(m) = max( a_opoa(m), 1.0e-20_r8 ) ! force to small non-zero value
1121 ! calc ambient equilibrium soa gas
1122 p0_soa = p0_soa_298 * &
1123 exp( -(delh_vap_soa/rgas)*((1.0/temp)-(1.0/298.0)) )
1124 g0_soa = 1.01325e5*p0_soa/pres
1125 ! molecular weight adjustment
1126 ! the soa parameterization assumes that real gsoa and asoa have mw=150
1127 ! currently in cam3,
1128 ! mw=12 is used (this has to do with the mozart preprocessor)
1129 ! soag emission files (molec/cm2/s units) are set to give the desired
1130 ! mass emissions (kg/m2/s) and mass mixing ratios (kg/kg)
1131 ! when mw=12 is applied
1132 ! as a result, the molar mixing ratios for both gsoa and asoa
1133 ! are artificially scaled up by (150/12)
1134 ! and g0_soa must be similarly scaled up
1135 g0_soa = g0_soa*(150.0/12.0)
1136 ! g0_soa = 0.0 ! force irreversible uptake
1144 ! if (idiagss > 0) then
1145 ! write(luna,'(a,1p,10e11.3)') 'p0, g0_soa', p0_soa, g0_soa
1146 ! write(luna,'(3a)') &
1147 ! 'niter, tcur, dtcur, phi(:), ', &
1150 ! write(luna,'(3a)') &
1152 ! 'sat(:)*a_soa(:) ', &
1154 ! write(luna,'(i3,1p,20e10.2)') niter, tcur, dtcur, &
1155 ! phi(:), g_star(:), a_soa(:), g_soa
1159 ! integration loop -- does multiple substeps to reach dtfull
1160 timeloop: do while (tcur < dtfull-1.0e-3_r8 )
1163 if (niter > niter_max) exit
1166 do m = 1, ntot_soamode
1167 sat(m) = g0_soa/(a_soa(m) + a_opoa(m))
1168 g_star(m) = sat(m)*a_soa(m)
1169 phi(m) = (g_soa - g_star(m))/max(g_soa,g_star(m),g_min1)
1170 tmpa = tmpa + xferrate(m)*abs(phi(m))
1174 if (dtmax*tmpa <= alpha) then
1175 ! here alpha/tmpa >= dtmax, so this is final substep
1183 ! step 1 - for modes where soa is condensing, estimate "new" a_soa(m)
1184 ! using an explicit calculation with "old" g_soa
1185 ! and g_star(m) calculated using "old" a_soa(m)
1186 ! do this to get better estimate of "new" a_soa(m) and sat(m)
1187 do m = 1, ntot_soamode
1188 beta(m) = dtcur*xferrate(m)
1189 tmpa = g_soa - g_star(m)
1190 if (tmpa > 0.0_r8) then
1191 a_soa_tmp = a_soa(m) + beta(m)*tmpa
1192 sat(m) = g0_soa/(a_soa_tmp + a_opoa(m))
1193 g_star(m) = sat(m)*a_soa_tmp ! this just needed for diagnostics
1197 ! step 2 - implicit in g_soa and semi-implicit in a_soa,
1198 ! with g_star(m) calculated semi-implicitly
1201 do m = 1, ntot_soamode
1202 tmpa = tmpa + a_soa(m)/(1.0_r8 + beta(m)*sat(m))
1203 tmpb = tmpb + beta(m)/(1.0_r8 + beta(m)*sat(m))
1206 g_soa = (tot_soa - tmpa)/(1.0_r8 + tmpb)
1207 g_soa = max( 0.0_r8, g_soa )
1208 do m = 1, ntot_soamode
1209 a_soa(m) = (a_soa(m) + beta(m)*g_soa)/ &
1210 (1.0_r8 + beta(m)*sat(m))
1213 ! if (idiagss > 0) then
1214 ! write(luna,'(i3,1p,20e10.2)') niter, tcur, dtcur, &
1215 ! phi(:), g_star(:), a_soa(:), g_soa
1216 ! write(luna,'(23x,1p,20e10.2)') &
1217 ! sat(:), sat(:)*a_soa(:), a_opoa(:)
1220 ! if (niter > 9992000) then
1221 ! write(luna,'(a)') '*** to many iterations'
1228 g_soa_tend = (g_soa - g_soa_in)/dtfull
1229 do m = 1, ntot_soamode
1230 a_soa_tend(m) = (a_soa(m) - a_soa_in(m))/dtfull
1235 end subroutine modal_aero_soaexch
1237 !----------------------------------------------------------------------
1240 subroutine modal_aero_gasaerexch_init
1242 !-----------------------------------------------------------------------
1245 ! set do_adjust and do_aitken flags
1246 ! create history fields for column tendencies associated with
1247 ! modal_aero_calcsize
1251 !-----------------------------------------------------------------------
1254 use modal_aero_rename
1256 use abortutils, only : endrun
1257 use cam_history, only : addfld, add_default, fieldname_len, phys_decomp
1258 use constituents, only : pcnst, cnst_get_ind, cnst_name
1259 use spmd_utils, only : masterproc
1260 use phys_control,only : phys_getopts
1262 use module_cam_support, only: pcnst => pcnst_runtime, &
1264 endrun, masterproc, phys_decomp, &
1266 use constituents, only : cnst_name, cnst_get_ind
1272 !-----------------------------------------------------------------------
1275 !-----------------------------------------------------------------------
1277 integer :: ipair, iq, iqfrm, iqfrm_aa, iqtoo, iqtoo_aa
1279 integer :: l, lsfrm, lstoo, lunout
1280 integer :: l_so4g, l_nh4g, l_msag, l_soag
1281 integer :: m, mfrm, mtoo
1282 integer :: nsamefrm, nsametoo, nspec
1283 integer :: n, nacc, nait
1285 logical :: do_msag, do_nh4g, do_soag
1286 logical :: dotend(pcnst), dotendqqcw(pcnst)
1288 real(r8) :: tmp1, tmp2
1290 character(len=fieldname_len) :: tmpnamea, tmpnameb
1291 character(len=fieldname_len+3) :: fieldname
1292 character(128) :: long_name
1293 character(8) :: unit
1295 logical :: history_aerosol ! Output the MAM aerosol tendencies
1297 !-----------------------------------------------------------------------
1299 call phys_getopts( history_aerosol_out = history_aerosol )
1301 history_aerosol = .FALSE.
1306 ! define "from mode" and "to mode" for primary carbon aging
1308 ! skip (turn off) aging if either is absent,
1309 ! or if accum mode so4 is absent
1311 modefrm_pcage = -999888777
1312 modetoo_pcage = -999888777
1313 if ((modeptr_pcarbon <= 0) .or. (modeptr_accum <= 0)) goto 15000
1314 l = lptr_so4_a_amode(modeptr_accum)
1315 if ((l < 1) .or. (l > pcnst)) goto 15000
1317 modefrm_pcage = modeptr_pcarbon
1318 modetoo_pcage = modeptr_accum
1321 ! define species involved in each primary carbon aging pairing
1322 ! (include aerosol water)
1325 mfrm = modefrm_pcage
1326 mtoo = modetoo_pcage
1329 aa_iqfrm: do iqfrm = -1, nspec_amode(mfrm)
1331 if (iqfrm == -1) then
1332 lsfrm = numptr_amode(mfrm)
1333 lstoo = numptr_amode(mtoo)
1334 else if (iqfrm == 0) then
1335 ! bypass transfer of aerosol water due to primary-carbon aging
1337 ! lsfrm = lwaterptr_amode(mfrm)
1338 ! lstoo = lwaterptr_amode(mtoo)
1340 lsfrm = lmassptr_amode(iqfrm,mfrm)
1343 if ((lsfrm < 1) .or. (lsfrm > pcnst)) cycle aa_iqfrm
1345 if (lsfrm>0 .and. iqfrm>0 ) then
1346 ! find "too" species having same lspectype_amode as the "frm" species
1347 do iqtoo = 1, nspec_amode(mtoo)
1348 if ( lspectype_amode(iqtoo,mtoo) .eq. &
1349 lspectype_amode(iqfrm,mfrm) ) then
1350 lstoo = lmassptr_amode(iqtoo,mtoo)
1356 if ((lstoo < 1) .or. (lstoo > pcnst)) lstoo = 0
1358 lspecfrm_pcage(nspec) = lsfrm
1359 lspectoo_pcage(nspec) = lstoo
1362 nspecfrm_pcage = nspec
1367 if ( masterproc ) then
1371 mfrm = modefrm_pcage
1372 mtoo = modetoo_pcage
1373 write(lunout,9320) 1, mfrm, mtoo
1375 do iq = 1, nspecfrm_pcage
1376 lsfrm = lspecfrm_pcage(iq)
1377 lstoo = lspectoo_pcage(iq)
1378 if (lstoo .gt. 0) then
1379 write(lunout,9330) lsfrm, cnst_name(lsfrm), &
1380 lstoo, cnst_name(lstoo)
1382 write(lunout,9340) lsfrm, cnst_name(lsfrm)
1388 end if ! ( masterproc )
1390 9310 format( / 'subr. modal_aero_gasaerexch_init - primary carbon aging pointers' )
1391 9320 format( 'pair', i3, 5x, 'mode', i3, ' ---> mode', i3 )
1392 9330 format( 5x, 'spec', i3, '=', a, ' ---> spec', i3, '=', a )
1393 9340 format( 5x, 'spec', i3, '=', a, ' ---> LOSS' )
1398 ! set gas species indices
1399 call cnst_get_ind( 'H2SO4', l_so4g, .false. )
1400 call cnst_get_ind( 'NH3', l_nh4g, .false. )
1401 call cnst_get_ind( 'MSA', l_msag, .false. )
1402 call cnst_get_ind( 'SOAG', l_soag, .false. )
1403 if ((l_so4g <= 0) .or. (l_so4g > pcnst)) then
1404 write( *, '(/a/a,2i7)' ) &
1405 '*** modal_aero_gasaerexch_init -- cannot find H2SO4 species', &
1407 call endrun( 'modal_aero_gasaerexch_init error' )
1412 if ((l_nh4g > 0) .and. (l_nh4g <= pcnst)) do_nh4g = .true.
1413 if ((l_msag > 0) .and. (l_msag <= pcnst)) do_msag = .true.
1414 if ((l_soag > 0) .and. (l_soag <= pcnst)) do_soag = .true.
1416 ! set tendency flags
1418 dotend(l_so4g) = .true.
1419 if ( do_nh4g ) dotend(l_nh4g) = .true.
1420 if ( do_msag ) dotend(l_msag) = .true.
1421 if ( do_soag ) dotend(l_soag) = .true.
1422 do n = 1, ntot_amode
1423 l = lptr_so4_a_amode(n)
1424 if ((l > 0) .and. (l <= pcnst)) then
1427 l = lptr_nh4_a_amode(n)
1428 if ((l > 0) .and. (l <= pcnst)) dotend(l) = .true.
1431 l = lptr_soa_a_amode(n)
1432 if ((l > 0) .and. (l <= pcnst)) then
1437 if (modefrm_pcage > 0) then
1438 do iq = 1, nspecfrm_pcage
1439 lsfrm = lspecfrm_pcage(iq)
1440 lstoo = lspectoo_pcage(iq)
1441 if ((lsfrm > 0) .and. (lsfrm <= pcnst)) then
1442 dotend(lsfrm) = .true.
1443 if ((lstoo > 0) .and. (lstoo <= pcnst)) then
1444 dotend(lstoo) = .true.
1451 ! define history fields for basic gas-aer exchange
1452 ! and primary carbon aging from that
1454 if ( .not. dotend(l) ) cycle
1456 tmpnamea = cnst_name(l)
1457 fieldname = trim(tmpnamea) // '_sfgaex1'
1458 long_name = trim(tmpnamea) // ' gas-aerosol-exchange primary column tendency'
1460 call addfld( fieldname, unit, 1, 'A', long_name, phys_decomp )
1461 if ( history_aerosol ) then
1462 call add_default( fieldname, 1, ' ' )
1464 if ( masterproc ) write(*,'(3(a,3x))') 'gasaerexch addfld', fieldname, unit
1469 ! define history fields for aitken-->accum renaming
1471 dotendqqcw(:) = .false.
1472 do ipair = 1, npair_renamexf
1473 do iq = 1, nspecfrm_renamexf(ipair)
1474 lsfrm = lspecfrma_renamexf(iq,ipair)
1475 lstoo = lspectooa_renamexf(iq,ipair)
1476 if ((lsfrm > 0) .and. (lsfrm <= pcnst)) then
1477 dotend(lsfrm) = .true.
1478 if ((lstoo > 0) .and. (lstoo <= pcnst)) then
1479 dotend(lstoo) = .true.
1483 lsfrm = lspecfrmc_renamexf(iq,ipair)
1484 lstoo = lspectooc_renamexf(iq,ipair)
1485 if ((lsfrm > 0) .and. (lsfrm <= pcnst)) then
1486 dotendqqcw(lsfrm) = .true.
1487 if ((lstoo > 0) .and. (lstoo <= pcnst)) then
1488 dotendqqcw(lstoo) = .true.
1492 end do ! ipair = ...
1497 if ( .not. dotend(l) ) cycle
1498 tmpnamea = cnst_name(l)
1500 if ( .not. dotendqqcw(l) ) cycle
1501 tmpnamea = cnst_name_cw(l)
1504 fieldname = trim(tmpnamea) // '_sfgaex2'
1505 long_name = trim(tmpnamea) // ' gas-aerosol-exchange renaming column tendency'
1507 if ((tmpnamea(1:3) == 'num') .or. &
1508 (tmpnamea(1:3) == 'NUM')) unit = '#/m2/s'
1509 call addfld( fieldname, unit, 1, 'A', long_name, phys_decomp )
1510 if ( history_aerosol ) then
1511 call add_default( fieldname, 1, ' ' )
1513 if ( masterproc ) write(*,'(3(a,3x))') 'gasaerexch addfld', fieldname, unit
1518 ! calculate soa_equivso4_factor
1519 ! if do_soag == .false., then set it to zero as a safety measure
1520 soa_equivso4_factor = 0.0
1522 tmp1 = -1.0 ; tmp2 = -1.0
1523 do l = 1, ntot_aspectype
1524 if (specname_amode(l) == 's-organic') tmp1 = spechygro(l)
1525 if (specname_amode(l) == 'sulfate' ) tmp2 = spechygro(l)
1527 if ((tmp1 > 0.0_r8) .and. (tmp2 > 0.0_r8)) then
1528 soa_equivso4_factor = tmp1/tmp2
1530 write(*,'(a/a,1p,2e10.2)') &
1531 '*** subr modal_aero_gasaerexch_init', &
1532 ' cannot find hygros - tmp1/2 =', tmp1, tmp2
1538 end subroutine modal_aero_gasaerexch_init
1541 !----------------------------------------------------------------------
1543 end module modal_aero_gasaerexch