-
Notifications
You must be signed in to change notification settings - Fork 0
Cloud chemistry module review #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop-1-cloud-chemistry
Are you sure you want to change the base?
Cloud chemistry module review #5
Conversation
modified: .gitmodules modified: src/physics/cam/carma_intr.F90 modified: src/physics/carma/base (new commits) modified: src/physics/carma/cam/carma_intr.F90 modified: src/physics/carma/cam/carma_precision_mod.F90
| mm = bin_idx(m, l) | ||
| call rad_cnst_get_bin_props_by_idx(0, m, l,spectype=spectype) | ||
| if (trim(spectype) == 'sulfate') then | ||
| so4mmr(i,k) = so4mmr(i,k) + qcw(i,k,mm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This loop can be condensed and re-ordered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure how this would work?
| !---------------------------------------------------------------------------------- | ||
| ! Update the mixing ratios | ||
| !---------------------------------------------------------------------------------- | ||
| subroutine sox_cldaero_update( state, & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could split subroutine into sox_cldaero_tend to compute tendencies and sox_cldaero_update to apply tendencies.
|
|
||
| conc_obj%no3c(:,:) = 0._r8 | ||
|
|
||
| if (mode7) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Index gymnastics is confusing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indexing can be removed, similar to what is done in carma_clouds.F90 Line 72 to 102.
K20shores
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewing cloud_aqueous_chemistry.F90
| logical :: modal_aerosols | ||
|
|
||
| call phys_getopts( prog_modal_aero_out=modal_aerosols ) | ||
| cloud_borne = modal_aerosols .or. carma_do_cloudborne |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does cloud_borne logically mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this needs to be described clearly in the source code. Recent conversations with people who have worked on CAM for years revealed that there is a lot of confusion about what this actually means.
| real(r8), parameter :: kh0 = 9.e3_r8 ! HO2(g) -> Ho2(a) | ||
| real(r8), parameter :: kh1 = 2.05e-5_r8 ! HO2(a) -> H+ + O2- | ||
| real(r8), parameter :: kh2 = 8.6e5_r8 ! HO2(a) + ho2(a) -> h2o2(a) + o2 | ||
| real(r8), parameter :: kh3 = 1.e8_r8 ! HO2(a) + o2- -> h2o2(a) + o2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a reference for these or is this just known in the ether of science? Is it applicable forever and always or only for a certain range of environmental conditions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this. This module is Mary's expertise and she can confirm and add references.
|
|
||
| if ( cloud_borne ) then | ||
| r2h2o2 = r1h2o2*xl & ! mole/L(w)/s * L(w)/fm3(a) = mole/fm3(a)/s | ||
| / const0*1.e+6_r8 & ! correct a bug here ???? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well did the bug get corrected? Is the correction const0 or the multiplication of const0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea about this. Someone needs to figure this out... Maybe in our regular Tue meetings.
| if ( .not. cloud_borne) then ! this seems to be specific to aerosols that are not cloud borne | ||
| xh2o2(i,k) = xh2o2(i,k) + r2h2o2*dtime ! updated h2o2 by het production | ||
| endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we sure it's specific? If so, why is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember Simone and Mary talked about this a while ago and nobody knew what happened here. I am not sure if they now have an updated view on this...
| rah2o2 = 8.e4_r8 * EXP( -3650._r8*work1(i) ) & | ||
| / (.1_r8 + xph(i,k)) | ||
|
|
||
| !------------------------------------------------------------------------ | ||
| ! ... S(IV)+ O3 | ||
| !------------------------------------------------------------------------ | ||
| rao3 = 4.39e11_r8 * EXP(-4131._r8/tz) & | ||
| + 2.56e3_r8 * EXP(-996._r8 /tz) /xph(i,k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have a citation for these values?
| pso4 = rah2o2 * 7.4e4_r8*EXP(6621._r8*work1(i)) * h2o2g * patm_x & | ||
| * 1.23_r8 *EXP(3120._r8*work1(i)) * so2g * patm_x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also these values
| knudsen = 3.0_r8*gasdiffus/(gasspeed*rad_cd) | ||
|
|
||
| ! following assumes accomodation coefficient = 0.65 | ||
| ! (Adams & Seinfeld, 2002, JGR, and references therein) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it this paper? If so, let's add a full bibliographical citation that includes the DOI
K20shores
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cloud_utilities.F90 reivew
| ! rad_cd = (drop radius in cm), computed from liquid water and drop number, | ||
| ! then bounded by 0.5 and 50.0 micrometers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but WHY is it bounded? Because a reference says we have to? Because numerically only values beteween 0.5 - 50 are valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to line 115 they applied the bounds at line 118 etc to avoid occasional unphysical values. I have no idea why that is the case though.
| !---------------------------------------------------------------------------------- | ||
|
|
||
| function cldaero_uptakerate( xl, cldnum, cfact, cldfrc, tfld, press ) result( uptkrate ) | ||
| use mo_constants, only : pi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use a constant from another module here, but in cloud_aqueous_chemistry.F90 we defined several constants within the code. We should probably push those constants into mo_constants if they don't exist
| ! radxnum_cd = (drop radius)*(drop number conc) | ||
| ! volx34pi_cd = (3/4*pi) * (liquid water volume in cm^3/cm^3) | ||
|
|
||
| volx34pi_cd = xl*0.75_r8/pi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the significance of 3/(4 pi)? WHY
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given xl (liquid water content) they want to estimate the droplet radius.
V = 4*pi/3 * R^3
So
V * 0.75/pi is related to the radius. See line 113 below.
| if (radxnum_cd .le. volx34pi_cd*4.0e4_r8) then | ||
| radxnum_cd = volx34pi_cd*4.0e4_r8 | ||
| rad_cd = 50.0e-4_r8 | ||
| else if (radxnum_cd .ge. volx34pi_cd*4.0e8_r8) then | ||
| radxnum_cd = volx34pi_cd*4.0e8_r8 | ||
| rad_cd = 0.5e-4_r8 | ||
| else | ||
| rad_cd = radxnum_cd/num_cd | ||
| end if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 4.0e4_r8 arbitrary? Why this value? what makes radxnum_cd and why is 4.0e4_r8 related to that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think theses are just bounds. They didn't want radxnum_cd to be smaller than volx34pi_cd*4.0e4 and bigger than volx34pi_cd*4.0e8. Again, I don't know why. This is a question for Mary.
| ! gasdiffus = h2so4 gas diffusivity from mosaic code (cm^2/s) | ||
| ! (pmid must be Pa) | ||
| gasdiffus = 0.557_r8 * (tfld**1.75_r8) / press | ||
|
|
||
| ! gasspeed = h2so4 gas mean molecular speed from mosaic code (cm/s) | ||
| gasspeed = 1.455e4_r8 * sqrt(tfld/98.0_r8) | ||
|
|
||
| ! knudsen number | ||
| knudsen = 3.0_r8*gasdiffus/(gasspeed*rad_cd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is from mosaic, do we have a reference for where these values come from and why? Do we know if they are always valid or does mosaic assume something we don't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can think of a reference for knudsen number (I am sure some textbooks will have this equation) but Mary probably knows better
| ! | ||
| ! first-order uptake rate is | ||
| ! 4*pi*(drop radius)*(drop number conc) | ||
| ! *(gas diffusivity)*(fuchs sutugin correction) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ! *(gas diffusivity)*(fuchs sutugin correction) | |
| ! *(gas diffusivity)*(fuchs sutugin correction) | |
| ! Fuchs Sutugin correction: | |
| ! Fuchs, N.A., Sutugin, A.G., 1971. HIGH-DISPERSED AEROSOLS, in: Hidy, G.M., Brock, J.R. (Eds.), | |
| ! Topics in Current Aerosol Research, International Reviews in Aerosol Physics and Chemistry. Pergamon, p. 1. | |
| ! https://doi.org/10.1016/B978-0-08-016674-2.50006-6 |
Is this a correct reference? Took me forever to track down
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is correct. A lot of papers on sulfur chemistry also used Fuchs' formulation. E.g., see
https://agupubs.onlinelibrary.wiley.com/doi/full/10.1029/2005jd005870
| real(r8), intent(out) :: aqso4(:,:) ! aqueous phase chemistry | ||
| real(r8), intent(out) :: aqh2so4(:,:) ! aqueous phase chemistry | ||
| real(r8), intent(out) :: aqso4_h2o2(:) ! SO4 aqueous phase chemistry due to H2O2 (kg/m2) | ||
| real(r8), intent(out) :: aqso4_o3(:) ! SO4 aqueous phase chemistry due to O3 (kg/m2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unit of this is also kg/m2/s
| real(r8), intent(out) :: aqso4_o3(:) ! SO4 aqueous phase chemistry due to O3 (kg/m2) | ||
| real(r8), intent(in), optional :: yph_in ! ph value | ||
| real(r8), intent(out), optional :: aqso4_h2o2_3d(:, :) ! 3D SO4 aqueous phase chemistry due to H2O2 (kg/m2) | ||
| real(r8), intent(out), optional :: aqso4_o3_3d(:, :) ! 3D SO4 aqueous phase chemistry due to O3 (kg/m2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two have a unit of kg/m2/s too.
K20shores
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
carma_clouds.F90
| !st use modal_aero_data, only : ntot_amode, modeptr_accum, lptr_so4_cw_amode, lptr_msa_cw_amode | ||
| !st use modal_aero_data, only : numptrcw_amode, lptr_nh4_cw_amode | ||
| !st use modal_aero_data, only : cnst_name_cw, specmw_so4_amode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just delete this since it's commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I think so
|
|
||
| integer :: id_msa, id_h2so4, id_so2, id_h2o2, id_nh3 | ||
|
|
||
| real(r8), parameter :: small_value = 1.e-20_r8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other places (the backward euler solver) small is set to 1e-40. I imagine there are other versions of small throughout CAM. Do we happen to know why this particular value of small is more useful for clouds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it depends on the order of magnitudes of the variables concerned. in the code here the order of magnitudes of chemical tracers (e.g., SO2, H2O2) are typically anywhere between 1e-14 (0.01 ppt) to 1e-5 or (10 ppm) in volume mixing ratios. People then want to disregard the reactions once the concentrations are low enough.
The small_value can definitely change depending on the situation and variable concerned. E.g., the small_value for relative humidity should be 0.1 instead of 1e-20. For solving differential equations, I think it makes sense that people try to make things as accurate as possible by using smaller small_values even for chemical tracers. But I think there's always wiggle room, e.g., setting 1e-30 in the solver probably doesn't hurt at all.
| integer :: i,k,mm | ||
|
|
||
| ! local indexing for bins | ||
| !integer, allocatable :: bin_idx(:,:) ! table for local indexing of modal aero number and mmr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can delete commented out code?
| !integer, allocatable :: bin_idx(:,:) ! table for local indexing of modal aero number and mmr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess Mary is the best to answer this. Mary needs to review the code changes...
| !st if (id_nh3>0) then | ||
| !st delnh3 = nh3g(i,k) - xnh3(i,k) | ||
| !st delnh4 = - delnh3 | ||
| !st endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| !st if (id_nh3>0) then | |
| !st delnh3 = nh3g(i,k) - xnh3(i,k) | |
| !st delnh4 = - delnh3 | |
| !st endif |
| !st dmsadt_gasuptk_tomsa = dmsadt_gasuptk | ||
| !st if (ntot_msa_c == 0) then | ||
| !st dmsadt_gasuptk_tomsa = 0.0_r8 | ||
| !st dmsadt_gasuptk_toso4 = dmsadt_gasuptk | ||
| !st end if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| !st dmsadt_gasuptk_tomsa = dmsadt_gasuptk | |
| !st if (ntot_msa_c == 0) then | |
| !st dmsadt_gasuptk_tomsa = 0.0_r8 | |
| !st dmsadt_gasuptk_toso4 = dmsadt_gasuptk | |
| !st end if |
| !H2SO4 not updated in Pengfei's model | ||
| !st TEST with H2SO4 uptake | ||
| qin(i,k,id_h2so4) = qin(i,k,id_h2so4) - dso4dt_gasuptk * dtime * cldfrc(i,k) | ||
| !qin(i,k,id_h2so4) = MAX( qin(i,k,id_h2so4), small_value ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| !qin(i,k,id_h2so4) = MAX( qin(i,k,id_h2so4), small_value ) |
| !st if (id_msa > 0) qin(i,k,id_msa) = qin(i,k,id_msa) - dmsadt_gasuptk * dtime * cldfrc(i,k) | ||
|
|
||
| ! so2 -- the first order loss rate for so2 is frso2_c*clwlrat(i,k) | ||
| ! fwetrem = max( 0.0_r8, (1.0_r8-exp(-min(100._r8,dtime*frso2_c*clwlrat(i,k)))) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ! fwetrem = max( 0.0_r8, (1.0_r8-exp(-min(100._r8,dtime*frso2_c*clwlrat(i,k)))) ) |
| qin(i,k,id_so2) = MAX( qin(i,k,id_so2), small_value ) | ||
|
|
||
| ! h2o2 -- the first order loss rate for h2o2 is frh2o2_c*clwlrat(i,k) | ||
| ! fwetrem = max( 0.0_r8, (1.0_r8-exp(-min(100._r8,dtime*frh2o2_c*clwlrat(i,k)))) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ! fwetrem = max( 0.0_r8, (1.0_r8-exp(-min(100._r8,dtime*frh2o2_c*clwlrat(i,k)))) ) |
| !st if (id_nh3>0) then | ||
| !st dqdt_aq = delnh3/dtime*cldfrc(i,k) | ||
| !st dqdt = dqdt_aq | ||
| !st qin(i,k,id_nh3) = qin(i,k,id_nh3) + dqdt * dtime | ||
| !st endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| !st if (id_nh3>0) then | |
| !st dqdt_aq = delnh3/dtime*cldfrc(i,k) | |
| !st dqdt = dqdt_aq | |
| !st qin(i,k,id_nh3) = qin(i,k,id_nh3) + dqdt * dtime | |
| !st endif |
| integer :: id_so4, id_h2so4 | ||
|
|
||
| logical :: has_sox = .true. | ||
| logical :: inv_so2, inv_nh3, inv_hno3, inv_h2o2, inv_ox, inv_nh4no3, inv_ho2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does inv_* stand for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Francis and Simone, inv_* stands for invariant. So, it sounds like in certain compsets people holds these tracers (SO2, NH3, H2O2, etc.) constant. In most cases nowadays I don't think we use invariant tracers, so the code mostly uses id_so2 instead of inv_so2, for instance. But, it's used for some compsets.
Francis is the one to answer this question.
| if (masterproc) then | ||
| write(iulog,*) 'sox_inti: has_sox = ',has_sox |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does masterproc mean? (There is a typo: sox_inti -> sox_init.)
It doesn't appear to provide useful information, and it also duplicates the following logs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
masterproc comes from utils/spmd_utils.F90 and is a flag called when scientists want to write() something in a log file.
Yes, that's a typo and can be changed to sox_init.
| ! = ( fact1_hno3 )/(1 + fact2_hno3 *(1 + fact3_hno3/hplus) | ||
| ! [hno3-] = ehno3/hplus | ||
| xk = 2.1e5_r8 *EXP( 8700._r8*work1(i) ) | ||
| xe = 15.4_r8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some variables (line435, line 492 and so on) that are constant should be defined outside the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this. Line 435 and line 458 are different, so the existing approach is to declare xe as real(r8) and update xe for different reactions. xe is a constant in line 435 but get updated in line 458 as a function of work1 (which is dependent on temperature tfld).
| else ! ???? bug ???? | ||
| xso2(i,k)=1.e-20_r8 | ||
| xh2o2(i,k)=xh2o2(i,k)-xso2(i,k) | ||
| endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we verify if this code is valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these lines mean that if you remove lines 821-824, lines 818-820 sometimes will not work. This is probably because xso2 was too small (smaller than 1.e-20_r8), but I'm not sure why that is the case. This is something that Mary should comment on.
BTW, I think line 822 can be
xso2(i,k)=small_value
| !----------------------------------------------------------------------- | ||
| !----------------------------------------------------------------------- | ||
| subroutine setsox( state, & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is large and difficult to test. I think it would be beneficial to break it down into smaller functions for each step, or a series of steps to make it more testable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I think since the code is being refactored it is up to the software engineers to design how the code looks like, as long as it looks good to Mary (this is her science after all).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a-okay with breaking the code down into smaller functions.
| call sox_cldaero_update( state, & | ||
| pbuf, ncol, lchnk, loffset, dtime, mbar, pdel, press, tfld, cldnum, cldfrc, cfact, cldconc%xlwc, & | ||
| xdelso4hp, xh2so4, xso4, xso4_init, nh3g, hno3g, xnh3, xhno3, xnh4c, xno3c, xmsa, xso2, xh2o2, qcw, qin, & | ||
| aqso4, aqh2so4, aqso4_h2o2, aqso4_o3, aqso4_h2o2_3d=aqso4_h2o2_3d, aqso4_o3_3d=aqso4_o3_3d ) | ||
|
|
||
| xphlwc(:,:) = 0._r8 | ||
| do k = 1, pver | ||
| do i = 1, ncol | ||
| if (cldfrc(i,k)>=1.e-5_r8 .and. lwc(i,k)>=1.e-8_r8) then | ||
| xphlwc(i,k) = -1._r8*log10(xph(i,k)) * lwc(i,k) | ||
| endif | ||
| end do | ||
| end do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding of this function is that it sets variables to update cldaero by calling sox_cldaero_update(). There are also variables with intent(out) (eg. xphlwc in line 880) that aren't used for updating cldaero. What is the purpose of those variables, and how are they used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are two questions here:
-
sox_cldaero_update() is a function that calculates and outputs the production rates of sulfate (so4) with cloud chemistry through several pathways (e.g., so4 formed due to o3 oxidation, due to h2o2 oxidation, etc). So, looking at sox_cldaero_update() under carmo_aero/carma_cloud.F90, the only intent(out) variables are aqso4, aqh2so4, aqso4_h2o2, ... which are sulfate production rates (kg/m2/s). sox_cldaero_update() is called here in aerosol/cloud_aqueous_chemistry.F90, so setsox() gets these arrays as intent(out) too (see line 215). And, when setsox() is called in the aerosol interface, we will see that they are outputted by setsox() just to be set as history variables, as follows:
call outfld( 'AQSO4_H2O2', aqso4_h2o2(:ncol), ncol, lchnk) call outfld( 'AQSO4_O3', aqso4_o3(:ncol), ncol, lchnk) call outfld( 'XPH_LWC', xphlwc(:ncol,:), ncol, lchnk ) -
I think lines 875-878 and lines 880-887 are two different things. xphlwc is a separate intent(out) variable that setsox() wants to output when setsox() is called. It is also a history variable in the aerosol interface, as follow:
call outfld( 'XPH_LWC', xphlwc(:ncol,:), ncol, lchnk )
=====
I copied the above code for outfld() from the CESM2.2 version. In the older CESM2.2, modal_aero/aero_model.F90 calls setsox(), setsox() calculates xphlwc and calls sox_cldaero_update() that calculates aqso4 etc, and aero_model.F90 gets them and do outfld(), so scientists get the history fields for plotting and analyses. I'm not sure where setsox() is called in this new CAM tag, and Francis and Simone will know better where the aerosol interface is. You can also grep it in this new CAM code.
But basically in one sentence, the purpose of sox_cldaero_update() in CESM2.2 is to output sulfate formation rates to aero_model.F90 so scientists get the history fields.
| fwetrem = 0.0_r8 ! don't include h2o2 wet removal here | ||
|
|
||
| dqdt_wr = -fwetrem*xh2o2(i,k)/dtime*cldfrc(i,k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If fwetrem is zero, then dqdt_wr should also be zero, which seems to be unnecessary logic. Could you confirm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I'm not sure why h2o2 and so2 wet removals were decided to set as zero. I think Mary should make a decision on whether fwetrem should be non-zero (i.e., using line 424 instead of line 425).
But yes, if we just keep the code as is, I would say this can be deleted or commented out (preferred).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe fwetrem for h2o2 and so2 is set to zero because wet removal (or wet scavenging) is computed elsewhere in CAM-chem (the Neu & Prather scheme, mo_neu_wetdep.F90). Let's confirm this with Francis and Simone. If it's correct, then I suggest removing these lines of code.
* draft cloud test * fix dependencies * create snapshot of cloud chemistry * update cloud chemistry test * update snapshot * draft cloud chemistry regression test * fix output of cloud chem snapshot data * move test data * finish cloud chem test against snapshot * add test against original cloud module * clean up * remove PFunit
|
Hi all,
Water dissociates: H2O <--> H+ + OH-
And Kw is its dissociation equilibrium constant:
Kw = [H+] [OH-] = 1.e-14 M^2 (M = Molar = mol/L)
So, xkw is the H2O dissociation constant.
Reference: Seinfeld and Pandis textbook
Some side notes --
Because of this weak dissociation, it allows the pH to be defined: pH =
-log10 [H+]
where pH = 7.0 for pure water at 298K.
If you look at the list of parameter statements, there is a pattern:
[Gas] <--> [Aq] where KH = Henry's Law equilibrium constant.
[Aq] <--> [H+] + [Aq-] where K1 = first dissociation equilibrium constant
[Aq-] <--> [H+] + [Aq=] where K2 = second dissociation equilibrium
constant
…-- Mary
^--^--^--^--^--^--^--^--^--^--^--^--^--^--^-^--^--^--^-^--^
Mary Barth
Senior Scientist
phone: 303-497-8186 email: ***@***.***
NSF - National Center for Atmospheric Research
P.O. Box 3000
Boulder, CO 80307
Staff web page <https://staff.ucar.edu/users/barthm>
SIMA Web Site <http://sima.ucar.edu>
MUSICA Web Site
<http://www2.acom.ucar.edu/sections/multi-scale-infrastructure-chemistry-modeling-musica>
DC3 Web Site <http://www2.acom.ucar.edu/dc3/>
^--^--^--^--^--^--^--^--^--^--^--^--^--^--^-^--^--^--^-^--^
On Fri, Feb 21, 2025 at 2:35 PM Danny M. Leung ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/chemistry/aerosol/cloud_aqueous_chemistry.F90
<#5 (comment)>:
> + real(r8), parameter :: const0 = 1.e3_r8/6.023e23_r8
+ real(r8), parameter :: xa0 = 11._r8
+ real(r8), parameter :: xb0 = -.1_r8
+ real(r8), parameter :: xa1 = 1.053_r8
+ real(r8), parameter :: xb1 = -4.368_r8
+ real(r8), parameter :: xa2 = 1.016_r8
+ real(r8), parameter :: xb2 = -2.54_r8
+ real(r8), parameter :: xa3 = .816e-32_r8
+ real(r8), parameter :: xb3 = .259_r8
+
+ real(r8), parameter :: kh0 = 9.e3_r8 ! HO2(g) -> Ho2(a)
+ real(r8), parameter :: kh1 = 2.05e-5_r8 ! HO2(a) -> H+ + O2-
+ real(r8), parameter :: kh2 = 8.6e5_r8 ! HO2(a) + ho2(a) -> h2o2(a) + o2
+ real(r8), parameter :: kh3 = 1.e8_r8 ! HO2(a) + o2- -> h2o2(a) + o2
+ real(r8), parameter :: Ra = 8314._r8/101325._r8 ! universal constant (atm)/(M-K)
+ real(r8), parameter :: xkw = 1.e-14_r8 ! water acidity
Yes, that looks like [H+] when ph=14 and that looks like a scaling factor
to me
—
Reply to this email directly, view it on GitHub
<#5 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALB5EDQFEY25NV5FDAYIAMT2Q6L3ZAVCNFSM6AAAAABSRA4PC6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDMMZUGI4TSNRTGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
* rename, remove boilerplate * rename function args * update constants * renaming * remove unused variables * remove unused dependencies * renaming * more clean-up * address review comments * remove duplicate log info * fix units in description * address review comments
| !----------------------------------------------------------------- | ||
| ! ... co2 effects | ||
| !----------------------------------------------------------------- | ||
| co2g = 330.e-6_r8 !330 ppm = 330.e-6 atm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to use the CO2 concentration from the model state? (also, this value seems like it might be low for the current atmosphere, unless I'm misinterpreting this) @dmleung - what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think so! I think in older model treatments CO2 is always fixed, but there is no reason we need to stick with it now given we have active CO2 chemistry in the chem_mech.in. We can follow the treatment of so2g and h2o2g, which are also from the model state.
|
Matt,
If the model state provides CO2, then please use it!
Yes, 330 ppmv is low. It's more representative of 1970 (or earlier) values.
However, I did a calculation once that showed me that the CO2 value didn't
have a big influence on the pH estimate. That's because sulfate and nitrate
dominate the pH calculation.
- Mary
^--^--^--^--^--^--^--^--^--^--^--^--^--^--^-^--^--^--^-^--^
Mary Barth
Senior Scientist
phone: 303-497-8186 email: ***@***.***
NSF - National Center for Atmospheric Research
P.O. Box 3000
Boulder, CO 80307
Staff web page <https://staff.ucar.edu/users/barthm>
SIMA Web Site <http://sima.ucar.edu>
MUSICA Web Site
<http://www2.acom.ucar.edu/sections/multi-scale-infrastructure-chemistry-modeling-musica>
DC3 Web Site <http://www2.acom.ucar.edu/dc3/>
^--^--^--^--^--^--^--^--^--^--^--^--^--^--^-^--^--^--^-^--^
…On Thu, Feb 27, 2025 at 10:55 AM Matt Dawson ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/chemistry/aerosol/cloud_aqueous_chemistry.F90
<#5 (comment)>:
> + xk = 58._r8 *EXP( 4085._r8*work1(i) )
+ xe = 1.7e-5_r8*EXP( -4325._r8*work1(i) )
+
+ fact1_nh3 = (xk*xe*patm/water_dissociation_constant)*(xnh3(i,k)+xnh4(i,k))
+ fact2_nh3 = xk*GAS_CONSTANT_L_ATM_MOL_K*temperature(i,k)*xl
+ fact3_nh3 = xe/water_dissociation_constant
+
+ !-----------------------------------------------------------------
+ ! ... h2o effects
+ !-----------------------------------------------------------------
+ Eh2o = water_dissociation_constant
+
+ !-----------------------------------------------------------------
+ ! ... co2 effects
+ !-----------------------------------------------------------------
+ co2g = 330.e-6_r8 !330 ppm = 330.e-6 atm
Would it be better to use the CO2 concentration from the model state?
(also, this value seems like it might be low for the current atmosphere,
unless I'm misinterpreting this) @dmleung <https://github.com/dmleung> -
what do you think?
—
Reply to this email directly, view it on GitHub
<#5 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALB5EDWTUCGC5ICRZ24SGKL2R5GQZAVCNFSM6AAAAABSRA4PC6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDMNBYGYZDCMBYGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
* add snapshot files for CARMA and BAM cloud chemistry * update CARMA and BAM test data * add missing CARMA fields * add missing fields to CARMA snapshot * add missing fields for CARMA snapshot * add bam and carma tests
|
|
||
| conc_obj => cldaero_allocate() | ||
|
|
||
| conc_obj%xlwc(:ncol,:) = lwc(:ncol,:)*cfact(:ncol,:) ! cloud water L(water)/L(air) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mattldawson By the end of our Tue meeting we touched upon this a bit -- and I am still a little baffled by the unit for conc_obj%xlwc. It looks like [lwc] has a unit of kg water / kg air, and [cfact] is also constructed to be kg air / L air (I checked cfact's calculation and that unit looks right to me). If so, then it looks like xlwc should have a unit of kg water / L air, which is different from the comment here.
Not sure how important this is, but just trying to make sure things are right. What do you think? Let me know if I was wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I struggled with this too. I think they might have just been doing an implicit conversion with the (approximate) density of water (1kg/L). That's all I could come up with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That actually makes sense, thanks for that. Maybe we can add a bit onto the comment here?
| conc_obj%xlwc(:ncol,:) = lwc(:ncol,:)*cfact(:ncol,:) ! cloud water L(water)/L(air) | |
| conc_obj%xlwc(:ncol,:) = lwc(:ncol,:)*cfact(:ncol,:) ! cloud water in L(water)/L(air), assuming water has a density of ~ 1 kg (water) / L (water). |
| ! volume mixing ratios for cloud chemistry species | ||
| real(r8), dimension(ncol,pver) :: xhno3, xh2o2, xso2, xso4, xno3, & | ||
| xnh3, xnh4, xo3, xph, xho2, xh2so4, xmsa, xso4_init | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @mattldawson and @dmleung, are those vmr variables for gas species, aerosols or a mix of both? NH3, O3 look gas, but SO4, NH4 seem aerosols. Doesn't aerosol use mass mixing ratio?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these variables come from species_vmr. See the code below, which is later of this module:
call so4%mixing_ratio( species_vmr, fixed_concentrations, air_number_density, xso4 )
And, yes, species_vmr stores both gas-phase and aerosol-phase species in volume mixing ratio (here). Simone said aerosol species could be stored as mass mixing ratio elsewhere but i don't know where. Aerosols are definitely outputted as mmr in the history files, but here they are vmr.
Reimplements four cloud chemistry modules with new file and module names so that the code can be reviewed.
closes #1
From issue #1, things to consider in review: