-
Notifications
You must be signed in to change notification settings - Fork 33
CCPPize prescribed volcanic aerosol (prescribe_volcaero) #372
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
Open
jimmielin
wants to merge
12
commits into
ESCOMP:main
Choose a base branch
from
jimmielin:hplin/volcrad_aero_prescribe
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
f98c63f
Implement prescribed_volcanic_aerosol (CAM4, CAM5); add to tracer_dat…
jimmielin 37afbef
Update UNSET (since paramgen does not like empty values); GLC
jimmielin 7c4a0c7
Fix boltz physconst units.
jimmielin df29ac0
cherry-picked from trunk 175ea9ebb6e40f5a17f082f1df47b71597121791
jimmielin 9b8852d
Add sima_state_diagnostics to test SDF to get volc_mmr constituent diag
jimmielin 5799c5c
Merge branch 'main' into hplin/volcrad_aero_prescribe
jimmielin e812a6b
Address review comments
jimmielin 4e2f9ef
Merge branch 'main' into hplin/volcrad_aero_prescribe
jimmielin 1649409
Remove extraneous const_props
jimmielin 68a09ed
Address review comments
jimmielin 962296b
Update remaining filename_for_ to filename_of_ to match ESMStandardNa…
jimmielin aaf079d
Merge branch 'main' into hplin/volcrad_aero_prescribe
jimmielin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,349 @@ | ||
| ! Manages reading and interpolation of prescribed volcanic aerosol concentrations. | ||
| ! | ||
| ! This module uses CCPP constituents (non-advected) to store prescribed volcanic aero | ||
| ! fields: | ||
| ! 1) volcanic aerosol mass mixing ratio (from prescribed dataset) | ||
| ! 2) geometric-mean wet aerosol radius (derived from mass) | ||
| ! | ||
| ! Based on original CAM version from: Francis Vitt | ||
| module prescribed_volcanic_aerosol | ||
| use ccpp_kinds, only: kind_phys | ||
|
|
||
| ! CAM-SIMA host model dependency to read aerosol data | ||
| use tracer_data, only: trfile ! data information and file read state | ||
| use tracer_data, only: trfld ! tracer data container | ||
|
|
||
| implicit none | ||
| private | ||
|
|
||
| ! public CCPP-compliant subroutines | ||
| public :: prescribed_volcanic_aerosol_register | ||
| public :: prescribed_volcanic_aerosol_init | ||
| public :: prescribed_volcanic_aerosol_run | ||
|
|
||
| ! fields to store tracer_data state and information | ||
| type(trfld), pointer :: tracer_data_fields(:) | ||
| type(trfile) :: tracer_data_file | ||
|
|
||
| ! module state variables | ||
| logical :: has_prescribed_volcaero = .false. | ||
|
|
||
| ! Constituent names | ||
| character(len=*), parameter :: volcaero_const_name = 'VOLC_MMR' | ||
| character(len=*), parameter :: volcrad_const_name = 'VOLC_RAD_GEOM' | ||
|
|
||
| ! Molecular weight of volcanic aerosol species (sulfate) [g mol-1] | ||
| real(kind_phys), parameter :: molmass_volcaero = 47.9981995_kind_phys | ||
|
|
||
| ! WACCM-derived empirical coefficient relating mass concentration | ||
| ! to wet aerosol geometric-mean radius [m (kg m-3)^(-1/3)] | ||
| real(kind_phys), parameter :: radius_conversion = 1.9e-4_kind_phys | ||
|
|
||
| ! TODO: infrastructure for writing (and reading) tracer_data restart information. | ||
| ! see CAM/prescribed_volcrad_aero::{init,read,write}_prescribed_volcaero_restart | ||
| ! !!! Restarts will not be bit-for-bit without this !!! | ||
| ! TODO when SIMA implements restarts. | ||
|
|
||
| contains | ||
|
|
||
| ! Register prescribed volcanic aerosol constituents. | ||
| !> \section arg_table_prescribed_volcanic_aerosol_register Argument Table | ||
| !! \htmlinclude prescribed_volcanic_aerosol_register.html | ||
| subroutine prescribed_volcanic_aerosol_register( & | ||
| amIRoot, iulog, & | ||
| prescribed_volcaero_file, & | ||
| volcaero_constituents, & | ||
| errmsg, errflg) | ||
|
|
||
| use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t | ||
|
|
||
| ! Input arguments: | ||
| logical, intent(in) :: amIRoot | ||
| integer, intent(in) :: iulog | ||
| character(len=*), intent(in) :: prescribed_volcaero_file ! input filename from namelist | ||
|
|
||
| ! Output arguments: | ||
| type(ccpp_constituent_properties_t), allocatable, intent(out) :: volcaero_constituents(:) | ||
| character(len=*), intent(out) :: errmsg | ||
| integer, intent(out) :: errflg | ||
|
|
||
| character(len=*), parameter :: subname = 'prescribed_volcanic_aerosol_register' | ||
|
|
||
| errmsg = '' | ||
| errflg = 0 | ||
|
|
||
| ! Check if prescribed volcanic aerosols are enabled | ||
| if (prescribed_volcaero_file == 'UNSET' .or. & | ||
| len_trim(prescribed_volcaero_file) == 0) then | ||
| if (amIRoot) then | ||
| write(iulog,*) subname//': No prescribed volcanic aerosols specified' | ||
| end if | ||
| return | ||
| end if | ||
|
|
||
| has_prescribed_volcaero = .true. | ||
|
|
||
| ! Register two constituents: aerosol MMR and geometric-mean radius | ||
| allocate(volcaero_constituents(2), stat=errflg, errmsg=errmsg) | ||
| if (errflg /= 0) then | ||
| errmsg = subname // ": " // trim(errmsg) | ||
| return | ||
| end if | ||
|
|
||
| ! (1) Volcanic aerosol dry mass mixing ratio | ||
| call volcaero_constituents(1)%instantiate( & | ||
| std_name = volcaero_const_name, & | ||
|
cacraigucar marked this conversation as resolved.
|
||
| diag_name = volcaero_const_name, & | ||
| long_name = 'prescribed volcanic aerosol dry mass mixing ratio', & | ||
| units = 'kg kg-1', & | ||
| vertical_dim = 'vertical_layer_dimension', & | ||
| min_value = 0.0_kind_phys, & | ||
| advected = .false., & | ||
| water_species = .false., & | ||
| mixing_ratio_type = 'dry', & | ||
| errcode = errflg, & | ||
| errmsg = errmsg) | ||
| if (errflg /= 0) return | ||
|
|
||
| ! (2) Volcanic aerosol geometric-mean radius (derived quantity) | ||
| call volcaero_constituents(2)%instantiate( & | ||
|
nusbaume marked this conversation as resolved.
|
||
| std_name = volcrad_const_name, & | ||
| diag_name = volcrad_const_name, & | ||
| long_name = 'prescribed volcanic aerosol geometric-mean radius derived from mass', & | ||
| units = 'm', & | ||
| vertical_dim = 'vertical_layer_dimension', & | ||
| min_value = 0.0_kind_phys, & | ||
| advected = .false., & | ||
| water_species = .false., & | ||
| mixing_ratio_type = 'dry', & | ||
| errcode = errflg, & | ||
| errmsg = errmsg) | ||
| if (errflg /= 0) return | ||
|
|
||
| if (amIRoot) then | ||
| write(iulog,*) trim(subname)//& | ||
| ': Registered 2 prescribed volcanic aerosol constituents: '//& | ||
| volcaero_const_name//', '//volcrad_const_name | ||
| end if | ||
|
|
||
| end subroutine prescribed_volcanic_aerosol_register | ||
|
|
||
| ! Initialize prescribed volcanic aerosol reading via tracer_data. | ||
| !> \section arg_table_prescribed_volcanic_aerosol_init Argument Table | ||
| !! \htmlinclude prescribed_volcanic_aerosol_init.html | ||
| subroutine prescribed_volcanic_aerosol_init( & | ||
| amIRoot, iulog, & | ||
| prescribed_volcaero_name, & | ||
| prescribed_volcaero_file, & | ||
| prescribed_volcaero_filelist, & | ||
| prescribed_volcaero_datapath, & | ||
| prescribed_volcaero_type, & | ||
| prescribed_volcaero_cycle_yr, & | ||
| prescribed_volcaero_fixed_ymd, & | ||
| prescribed_volcaero_fixed_tod, & | ||
| errmsg, errflg) | ||
|
|
||
| ! host model dependency for tracer_data read utility | ||
| use tracer_data, only: trcdata_init | ||
|
|
||
| ! host model dependency for history output | ||
| use cam_history, only: history_add_field | ||
| use cam_history_support, only: horiz_only | ||
|
|
||
| ! Input arguments: | ||
| logical, intent(in) :: amIRoot | ||
| integer, intent(in) :: iulog | ||
| character(len=*), intent(in) :: prescribed_volcaero_name ! netCDF field name for volcanic aerosol | ||
| character(len=*), intent(in) :: prescribed_volcaero_file ! input filename from namelist | ||
| character(len=*), intent(in) :: prescribed_volcaero_filelist ! input filelist from namelist | ||
| character(len=*), intent(in) :: prescribed_volcaero_datapath ! input datapath from namelist | ||
| character(len=*), intent(in) :: prescribed_volcaero_type ! data type from namelist | ||
| integer, intent(in) :: prescribed_volcaero_cycle_yr ! cycle year from namelist [1] | ||
| integer, intent(in) :: prescribed_volcaero_fixed_ymd ! fixed year-month-day from namelist (YYYYMMDD) [1] | ||
| integer, intent(in) :: prescribed_volcaero_fixed_tod ! fixed time of day from namelist [s] | ||
|
|
||
| ! Output arguments: | ||
| character(len=*), intent(out) :: errmsg | ||
| integer, intent(out) :: errflg | ||
|
|
||
| ! Local variables: | ||
| character(len=64) :: specifier(1) | ||
|
|
||
| character(len=*), parameter :: subname = 'prescribed_volcanic_aerosol_init' | ||
|
|
||
| errmsg = '' | ||
| errflg = 0 | ||
|
|
||
| if (.not. has_prescribed_volcaero) return | ||
|
|
||
| if (amIRoot) then | ||
| write(iulog,*) trim(subname)//': volcanic aerosol is prescribed in: '// & | ||
| trim(prescribed_volcaero_file) | ||
| end if | ||
|
|
||
| ! Build specifier: constituent_name:ncdf_field_name | ||
| specifier(1) = trim(volcaero_const_name) // ':' // trim(prescribed_volcaero_name) | ||
|
|
||
| ! Initialize tracer_data module with file and field information | ||
| call trcdata_init( & | ||
| specifier = specifier, & | ||
| filename = prescribed_volcaero_file, & | ||
| filelist = prescribed_volcaero_filelist, & | ||
| datapath = prescribed_volcaero_datapath, & | ||
| flds = tracer_data_fields, & | ||
| file = tracer_data_file, & | ||
| data_cycle_yr = prescribed_volcaero_cycle_yr, & | ||
| data_fixed_ymd = prescribed_volcaero_fixed_ymd, & | ||
| data_fixed_tod = prescribed_volcaero_fixed_tod, & | ||
| data_type = prescribed_volcaero_type) | ||
|
|
||
| ! Verify tracer_data is correctly initialized | ||
| if (.not. associated(tracer_data_fields)) then | ||
| errflg = 1 | ||
| errmsg = subname//': tracer_data_fields not associated after trcdata_init' | ||
| return | ||
| end if | ||
|
|
||
| ! Register history fields. | ||
| call history_add_field('VOLC_MASS', & | ||
| 'volcanic aerosol vertical mass path in layer', & | ||
| 'lev', 'inst', 'kg m-2') | ||
| call history_add_field('VOLC_MASS_C', & | ||
| 'volcanic aerosol column mass', & | ||
| horiz_only, 'inst', 'kg m-2') | ||
|
|
||
| if (amIRoot) then | ||
| write(iulog,*) trim(subname)//': Initialized volcanic aerosol field from tracer_data' | ||
| end if | ||
|
|
||
| end subroutine prescribed_volcanic_aerosol_init | ||
|
|
||
| ! Advance prescribed volcanic aerosol data, convert units, apply tropopause | ||
| ! masking, and compute geometric-mean radius. | ||
| !> \section arg_table_prescribed_volcanic_aerosol_run Argument Table | ||
| !! \htmlinclude prescribed_volcanic_aerosol_run.html | ||
| subroutine prescribed_volcanic_aerosol_run( & | ||
| ncol, pver, pcnst, & | ||
| mwdry, boltz, gravit, & | ||
| T, pmiddry, pdel, zm, & | ||
| pmid, pint, phis, zi, & | ||
| tropLev, & | ||
| constituents, & | ||
| errmsg, errflg) | ||
|
|
||
| ! host model dependency for tracer_data | ||
| use tracer_data, only: advance_trcdata | ||
|
|
||
| ! host model dependency for history output | ||
| use cam_history, only: history_out_field | ||
|
|
||
| ! framework dependency to get constituent index | ||
| use ccpp_scheme_utils, only: ccpp_constituent_index | ||
|
|
||
| ! dependency for unit string handling | ||
| use string_utils, only: to_lower, get_last_significant_char | ||
|
|
||
| integer, intent(in) :: ncol | ||
| integer, intent(in) :: pver | ||
| integer, intent(in) :: pcnst | ||
| real(kind_phys), intent(in) :: mwdry ! molecular weight of dry air [g mol-1] | ||
| real(kind_phys), intent(in) :: boltz ! Boltzmann constant [J K-1] | ||
| real(kind_phys), intent(in) :: gravit ! gravitational acceleration [m s-2] | ||
| real(kind_phys), intent(in) :: T(:,:) ! air temperature [K] (layer centers) | ||
| real(kind_phys), intent(in) :: pmiddry(:,:) ! dry air pressure [Pa] (layer centers) | ||
| real(kind_phys), intent(in) :: pdel(:,:) ! air pressure thickness [Pa] (layer centers) | ||
| real(kind_phys), intent(in) :: zm(:,:) ! geopotential height wrt surface [m] (layer centers) | ||
| real(kind_phys), intent(in) :: pmid(:,:) ! air pressure [Pa] (layer centers) | ||
| real(kind_phys), intent(in) :: pint(:,:) ! air pressure at interfaces [Pa] | ||
| real(kind_phys), intent(in) :: phis(:) ! surface geopotential [m2 s-2] | ||
| real(kind_phys), intent(in) :: zi(:,:) ! geopotential height wrt surface at interfaces [m] | ||
| integer, intent(in) :: tropLev(:) ! tropopause vertical layer index [index] | ||
|
|
||
| real(kind_phys), intent(inout) :: constituents(:,:,:) | ||
|
|
||
| character(len=*), intent(out) :: errmsg | ||
| integer, intent(out) :: errflg | ||
|
|
||
| ! Local variables | ||
| integer :: i, k | ||
| integer :: mmr_idx, rad_idx | ||
| real(kind_phys) :: to_mmr(ncol, pver) ! unit conversion factor to MMR [1] | ||
| real(kind_phys) :: mmrvolc ! volcanic aerosol MMR [kg kg-1] | ||
| real(kind_phys) :: concvolc ! mass concentration of volcanic aerosol [kg m-3] | ||
| real(kind_phys) :: volcmass(ncol, pver) ! volcanic aerosol mass path in layer [kg m-2] | ||
| real(kind_phys) :: columnmass(ncol) ! volcanic aerosol column mass [kg m-2] | ||
|
|
||
| character(len=*), parameter :: subname = 'prescribed_volcanic_aerosol_run' | ||
|
|
||
| errmsg = '' | ||
| errflg = 0 | ||
|
|
||
| if (.not. has_prescribed_volcaero) return | ||
|
|
||
| ! Advance tracer_data to current time | ||
| call advance_trcdata(tracer_data_fields, tracer_data_file, & | ||
| pmid, pint, phis, zi) | ||
|
|
||
| ! Get constituent indices for MMR and radius | ||
| call ccpp_constituent_index(volcaero_const_name, & | ||
| mmr_idx, errmsg=errmsg, errcode=errflg) | ||
| if (errflg /= 0) return | ||
|
|
||
| call ccpp_constituent_index(volcrad_const_name, & | ||
| rad_idx, errmsg=errmsg, errcode=errflg) | ||
| if (errflg /= 0) return | ||
|
|
||
| ! Determine unit conversion factor based on units in the input file | ||
| select case ( to_lower(trim(tracer_data_fields(1)%units(:get_last_significant_char(tracer_data_fields(1)%units)))) ) | ||
| case ("molec/cm3", "/cm3", "molecules/cm3", "cm^-3", "cm**-3") | ||
| ! Number density [molecules cm-3] -> MMR [kg kg-1] | ||
| ! mmr = (M * 1e6 * k_B * T) / (M_air * p_dry) | ||
| to_mmr(:ncol,:) = (molmass_volcaero * 1.0e6_kind_phys * boltz * T(:ncol,:)) & | ||
| / (mwdry * pmiddry(:ncol,:)) | ||
| case ('kg/kg', 'mmr', 'kg kg-1') | ||
| to_mmr(:ncol,:) = 1.0_kind_phys | ||
| case ('mol/mol', 'mole/mole', 'vmr', 'fraction') | ||
| to_mmr(:ncol,:) = molmass_volcaero / mwdry | ||
| case default | ||
| errflg = 1 | ||
| errmsg = subname//': unrecognized units: '//trim(tracer_data_fields(1)%units) | ||
| return | ||
| end select | ||
|
|
||
| ! Convert tracer_data field to MMR and store in constituent array. | ||
| ! Apply tropopause masking: zero below tropopause. | ||
| ! Compute geometric-mean radius where MMR > 0 above tropopause. | ||
| constituents(:ncol, :pver, rad_idx) = 0.0_kind_phys | ||
|
|
||
| do k = 1, pver | ||
| do i = 1, ncol | ||
| ! Apply unit conversion | ||
| mmrvolc = to_mmr(i, k) * tracer_data_fields(1)%data(i, k) | ||
|
|
||
| ! Zero below tropopause | ||
| if (k >= tropLev(i)) then | ||
| mmrvolc = 0.0_kind_phys | ||
| end if | ||
|
|
||
| constituents(i, k, mmr_idx) = mmrvolc | ||
|
|
||
| ! Compute geometric-mean wet aerosol radius from mass concentration | ||
| if (mmrvolc > 0.0_kind_phys) then | ||
| ! concvolc [kg m-3] = mmr [kg kg-1] * pdel [Pa] / (g [m s-2] * zm [m]) | ||
| concvolc = (mmrvolc * pdel(i, k)) / (gravit * zm(i, k)) | ||
| constituents(i, k, rad_idx) = radius_conversion * (concvolc ** (1.0_kind_phys / 3.0_kind_phys)) | ||
| end if | ||
| end do | ||
| end do | ||
|
|
||
| ! Compute volcanic aerosol mass path in each layer [kg m-2] | ||
| volcmass(:ncol, :pver) = constituents(:ncol, :pver, mmr_idx) * pdel(:ncol, :pver) / gravit | ||
| columnmass(:ncol) = sum(volcmass(:ncol, :pver), 2) | ||
|
|
||
| ! History output | ||
| call history_out_field('VOLC_MASS', volcmass(:, :)) | ||
| call history_out_field('VOLC_MASS_C', columnmass(:)) | ||
|
|
||
| end subroutine prescribed_volcanic_aerosol_run | ||
|
|
||
| end module prescribed_volcanic_aerosol | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.