From 353c2e612b3bb4307979f17b7d0caeab038597fa Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Wed, 10 Jul 2024 17:10:27 -0600 Subject: [PATCH 1/8] generalized aerosol fluxes to surface with bulk dust rebin new file: src/chemistry/aerosol/aero_deposition_cam.F90 modified: src/chemistry/aerosol/aero_deposition_cam.F90 modified: src/chemistry/aerosol/aerosol_properties_mod.F90 modified: src/chemistry/aerosol/modal_aerosol_properties_mod.F90 modified: src/chemistry/modal_aero/aero_model.F90 --- src/chemistry/aerosol/aero_deposition_cam.F90 | 324 ++++++++++++++++++ .../aerosol/aerosol_properties_mod.F90 | 28 +- .../aerosol/modal_aerosol_properties_mod.F90 | 100 +++++- src/chemistry/modal_aero/aero_model.F90 | 12 +- 4 files changed, 456 insertions(+), 8 deletions(-) create mode 100644 src/chemistry/aerosol/aero_deposition_cam.F90 diff --git a/src/chemistry/aerosol/aero_deposition_cam.F90 b/src/chemistry/aerosol/aero_deposition_cam.F90 new file mode 100644 index 0000000000..b4f31f263e --- /dev/null +++ b/src/chemistry/aerosol/aero_deposition_cam.F90 @@ -0,0 +1,324 @@ +module aero_deposition_cam +!------------------------------------------------------------------------------ +! Purpose: +! +! Partition the contributions from modal components of wet and dry +! deposition at the surface into the fields passed to the coupler. +!------------------------------------------------------------------------------ + + use shr_kind_mod, only: r8 => shr_kind_r8 + use constituents, only: cnst_get_ind, pcnst + use camsrfexch, only: cam_out_t + use aerosol_properties_mod, only: aero_name_len + use aerosol_properties_mod, only: aerosol_properties + use modal_aerosol_properties_mod, only: modal_aerosol_properties + + implicit none + + private + +! Public interfaces + + public :: aero_deposition_cam_init + public :: aero_deposition_cam_setwet + public :: aero_deposition_cam_setdry + +! Private module data + + integer :: bcphi_ndx( pcnst ) = -1 + integer :: bcphi_cnt = 0 + integer :: bcpho_ndx( pcnst ) = -1 + integer :: bcpho_cnt = 0 + integer :: ocphi_ndx( pcnst ) = -1 + integer :: ocphi_cnt = 0 + integer :: ocpho_ndx( pcnst ) = -1 + integer :: ocpho_cnt = 0 + + class(aerosol_properties), pointer :: aero_props=>null() + integer :: nele_tot=0 ! total number of aerosol elements + + ! bulk dust bins (meters) + + integer, parameter :: n_bulk_dst_bins = 4 + real(r8), parameter :: bulk_dst_edges(n_bulk_dst_bins+1) = & + (/1.0e-15_r8, 0.5e-6_r8, 1.25e-6_r8, 2.5e-6_r8, 1.0e-2_r8/) ! meters +! (/0.05e-6_r8, 0.5e-6_r8, 1.25e-6_r8, 2.5e-6_r8, 5.0e-6_r8/) ! meters +! (/1.e-15_r8, 1.25e-6_r8, 2.5e-6_r8, 5.0e-6_r8, 1.0e-2_r8/) ! meters (Flanner's) + +! in mo_setaer.F90 : +! dust is treated as 4 size distributions +! 0.05 - 0.5; 0.5 - 1.25; 1.25 - 2.5; 2.5 - 5.0 microns + +! in components/cice/src/icepack/columnphysics/icepack_zbgc_shared.F90 + ! Aerosol order and type should be consistent with order/type + ! specified in delta Eddington: 1) hydrophobic black carbon; + ! 2) hydrophilic black carbon; 3) dust (0.05-0.5 micron); + ! 4) dust (0.5-1.25 micron); 5) dust (1.25-2.5 micron); + ! 6) dust (2.5-5 micron) + +contains + + !============================================================================ + subroutine aero_deposition_cam_init() + + integer :: pcnt, scnt + character(len=*), parameter :: subrname = 'aero_deposition_cam_init' + + ! construct the aerosol properties object + aero_props => modal_aerosol_properties() + + ! set the cam constituent indices and determine the counts + ! for the specified aerosol types + + ! black carbons + call get_indices( type='black-c', hydrophilic=.true., indices=bcphi_ndx, count=bcphi_cnt ) + call get_indices( type='black-c', hydrophilic=.false., indices=bcpho_ndx, count=bcpho_cnt ) + + ! primary and secondary organics + call get_indices( type='p-organic',hydrophilic=.true., indices=ocphi_ndx, count=pcnt ) + call get_indices( type='s-organic',hydrophilic=.true., indices=ocphi_ndx(pcnt+1:), count=scnt ) + ocphi_cnt = pcnt+scnt + + call get_indices( type='p-organic',hydrophilic=.false., indices=ocpho_ndx, count=pcnt ) + call get_indices( type='s-organic',hydrophilic=.false., indices=ocpho_ndx(pcnt+1:), count=scnt ) + ocpho_cnt = pcnt+scnt + + ! total number of aerosol elements + nele_tot = aero_props%ncnst_tot() + + contains + + !========================================================================== + ! returns CAM constituent indices of the aerosol tracers (and count) + !========================================================================== + subroutine get_indices( type, hydrophilic, indices, count) + + character(len=*), intent(in) :: type + logical, intent(in ) :: hydrophilic + integer, intent(out) :: indices(:) + integer, intent(out) :: count + + integer :: ibin,ispc, ndx, nspec + character(len=aero_name_len) :: spec_type, spec_name + + count = 0 + indices(:) = -1 + + ! loop through aerosol bins / modes + do ibin = 1, aero_props%nbins() + + ! check if the bin/mode is hydrophilic + if ( aero_props%hydrophilic(ibin) .eqv. hydrophilic ) then + do ispc = 1, aero_props%nspecies(ibin) + + call aero_props%get(ibin,ispc, spectype=spec_type, specname=spec_name) + + if (spec_type==type) then + + ! get CAM constituent index + call cnst_get_ind(spec_name, ndx, abort=.false.) + if (ndx>0) then + count = count+1 + indices(count) = ndx + endif + + endif + + enddo + endif + + enddo + + end subroutine get_indices + + end subroutine aero_deposition_cam_init + + !============================================================================ + ! Set surface wet deposition fluxes passed to coupler. + !============================================================================ + subroutine aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) + + ! Arguments: + real(r8), intent(in) :: aerdepwetis(:,:) ! aerosol wet deposition (interstitial) + real(r8), intent(in) :: aerdepwetcw(:,:) ! aerosol wet deposition (cloud water) + type(cam_out_t), intent(inout) :: cam_out ! cam export state + + ! Local variables: + integer :: i, ispec, ibin, mm, ndx + integer :: ncol ! number of columns + + real(r8) :: dep_fluxes(nele_tot) + real(r8) :: dst_fluxes(n_bulk_dst_bins) + character(len=aero_name_len) :: specname, name_c + + ncol = cam_out%ncol + + cam_out%bcphiwet(:) = 0._r8 + cam_out%ocphiwet(:) = 0._r8 + cam_out%dstwet1(:) = 0._r8 + cam_out%dstwet2(:) = 0._r8 + cam_out%dstwet3(:) = 0._r8 + cam_out%dstwet4(:) = 0._r8 + + ! derive cam_out variables from deposition fluxes + ! note: wet deposition fluxes are negative into surface, + ! dry deposition fluxes are positive into surface. + ! srf models want positive definite fluxes. + do i = 1, ncol + + ! black carbon fluxes + do ispec=1,bcphi_cnt + cam_out%bcphiwet(i) = cam_out%bcphiwet(i) & + - (aerdepwetis(i,bcphi_ndx(ispec))+aerdepwetcw(i,bcphi_ndx(ispec))) + enddo + do ispec=1,bcpho_cnt + cam_out%bcphiwet(i) = cam_out%bcphiwet(i) & + - (aerdepwetis(i,bcpho_ndx(ispec))+aerdepwetcw(i,bcpho_ndx(ispec))) + enddo + + ! organic carbon fluxes + do ispec=1,ocphi_cnt + cam_out%ocphiwet(i) = cam_out%ocphiwet(i) & + - (aerdepwetis(i,ocphi_ndx(ispec))+aerdepwetcw(i,ocphi_ndx(ispec))) + enddo + do ispec=1,ocpho_cnt + cam_out%ocphiwet(i) = cam_out%ocphiwet(i) & + - (aerdepwetis(i,ocpho_ndx(ispec))+aerdepwetcw(i,ocpho_ndx(ispec))) + enddo + + ! dust fluxes + + dep_fluxes = 0._r8 + dst_fluxes = 0._r8 + + do ibin = 1,aero_props%nbins() + do ispec = 0,aero_props%nspecies(ibin) + if (ispec==0) then + call aero_props%num_names(ibin, specname, name_c) + else + call aero_props%get(ibin,ispec, specname=specname) + end if + call cnst_get_ind(specname, ndx, abort=.false.) + if (ndx>0) then + mm = aero_props%indexer(ibin,ispec) + dep_fluxes(mm) = - (aerdepwetis(i,ndx)+aerdepwetcw(i,ndx)) + end if + end do + end do + + ! rebin dust fluxes to bulk dust bins + call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes) + cam_out%dstwet1(i) = cam_out%dstwet1(i) + dst_fluxes(1) + cam_out%dstwet2(i) = cam_out%dstwet2(i) + dst_fluxes(2) + cam_out%dstwet3(i) = cam_out%dstwet3(i) + dst_fluxes(3) + cam_out%dstwet4(i) = cam_out%dstwet4(i) + dst_fluxes(4) + + ! in rare cases, integrated deposition tendency is upward + if (cam_out%bcphiwet(i) .lt. 0._r8) cam_out%bcphiwet(i) = 0._r8 + if (cam_out%ocphiwet(i) .lt. 0._r8) cam_out%ocphiwet(i) = 0._r8 + if (cam_out%dstwet1(i) .lt. 0._r8) cam_out%dstwet1(i) = 0._r8 + if (cam_out%dstwet2(i) .lt. 0._r8) cam_out%dstwet2(i) = 0._r8 + if (cam_out%dstwet3(i) .lt. 0._r8) cam_out%dstwet3(i) = 0._r8 + if (cam_out%dstwet4(i) .lt. 0._r8) cam_out%dstwet4(i) = 0._r8 + + enddo + + end subroutine aero_deposition_cam_setwet + + !============================================================================ + ! Set surface dry deposition fluxes passed to coupler. + !============================================================================ + subroutine aero_deposition_cam_setdry(aerdepdryis, aerdepdrycw, cam_out) + + ! Arguments: + real(r8), intent(in) :: aerdepdryis(:,:) ! aerosol dry deposition (interstitial) + real(r8), intent(in) :: aerdepdrycw(:,:) ! aerosol dry deposition (cloud water) + type(cam_out_t), intent(inout) :: cam_out ! cam export state + + ! Local variables: + integer :: i, ispec, ibin, mm, ndx + integer :: ncol ! number of columns + + real(r8) :: dep_fluxes(nele_tot) + real(r8) :: dst_fluxes(n_bulk_dst_bins) + character(len=aero_name_len) :: specname, name_c + + ncol = cam_out%ncol + + cam_out%bcphidry(:) = 0._r8 + cam_out%ocphidry(:) = 0._r8 + cam_out%bcphodry(:) = 0._r8 + cam_out%ocphodry(:) = 0._r8 + cam_out%dstdry1(:) = 0._r8 + cam_out%dstdry2(:) = 0._r8 + cam_out%dstdry3(:) = 0._r8 + cam_out%dstdry4(:) = 0._r8 + + ! derive cam_out variables from deposition fluxes + ! note: wet deposition fluxes are negative into surface, + ! dry deposition fluxes are positive into surface. + ! srf models want positive definite fluxes. + do i = 1, ncol + + ! black carbon fluxes + do ispec=1,bcphi_cnt + cam_out%bcphidry(i) = cam_out%bcphidry(i) & + + (aerdepdryis(i,bcphi_ndx(ispec))+aerdepdrycw(i,bcphi_ndx(ispec))) + enddo + do ispec=1,bcpho_cnt + cam_out%bcphodry(i) = cam_out%bcphodry(i) & + + (aerdepdryis(i,bcpho_ndx(ispec))+aerdepdrycw(i,bcpho_ndx(ispec))) + enddo + + ! organic carbon fluxes + do ispec=1,ocphi_cnt + cam_out%ocphidry(i) = cam_out%ocphidry(i) & + + (aerdepdryis(i,ocphi_ndx(ispec))+aerdepdrycw(i,ocphi_ndx(ispec))) + enddo + do ispec=1,ocpho_cnt + cam_out%ocphodry(i) = cam_out%ocphodry(i) & + + (aerdepdryis(i,ocpho_ndx(ispec))+aerdepdrycw(i,ocpho_ndx(ispec))) + enddo + + ! dust fluxes + + dep_fluxes = 0._r8 + dst_fluxes = 0._r8 + + do ibin = 1,aero_props%nbins() + do ispec = 0,aero_props%nspecies(ibin) + if (ispec==0) then + call aero_props%num_names(ibin, specname, name_c) + else + call aero_props%get(ibin,ispec, specname=specname) + end if + call cnst_get_ind(specname, ndx, abort=.false.) + if (ndx>0) then + mm = aero_props%indexer(ibin,ispec) + dep_fluxes(mm) = aerdepdryis(i,ndx)+aerdepdrycw(i,ndx) + end if + end do + end do + + ! rebin dust fluxes to bulk dust bins + call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes) + cam_out%dstdry1(i) = cam_out%dstdry1(i) + dst_fluxes(1) + cam_out%dstdry2(i) = cam_out%dstdry2(i) + dst_fluxes(2) + cam_out%dstdry3(i) = cam_out%dstdry3(i) + dst_fluxes(3) + cam_out%dstdry4(i) = cam_out%dstdry4(i) + dst_fluxes(4) + + ! in rare cases, integrated deposition tendency is upward + if (cam_out%bcphidry(i) .lt. 0._r8) cam_out%bcphidry(i) = 0._r8 + if (cam_out%ocphidry(i) .lt. 0._r8) cam_out%ocphidry(i) = 0._r8 + if (cam_out%bcphodry(i) .lt. 0._r8) cam_out%bcphodry(i) = 0._r8 + if (cam_out%ocphodry(i) .lt. 0._r8) cam_out%ocphodry(i) = 0._r8 + if (cam_out%dstdry1(i) .lt. 0._r8) cam_out%dstdry1(i) = 0._r8 + if (cam_out%dstdry2(i) .lt. 0._r8) cam_out%dstdry2(i) = 0._r8 + if (cam_out%dstdry3(i) .lt. 0._r8) cam_out%dstdry3(i) = 0._r8 + if (cam_out%dstdry4(i) .lt. 0._r8) cam_out%dstdry4(i) = 0._r8 + + enddo + + end subroutine aero_deposition_cam_setdry + +end module aero_deposition_cam diff --git a/src/chemistry/aerosol/aerosol_properties_mod.F90 b/src/chemistry/aerosol/aerosol_properties_mod.F90 index aadd56f87d..cc67354bc7 100644 --- a/src/chemistry/aerosol/aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/aerosol_properties_mod.F90 @@ -70,6 +70,8 @@ module aerosol_properties_mod procedure(aero_min_mass_mean_rad), deferred :: min_mass_mean_rad procedure(aero_optics_params), deferred :: optics_params procedure(aero_bin_name), deferred :: bin_name + procedure(aero_rebin_bulk_fluxes), deferred :: rebin_bulk_fluxes + procedure(aero_hydrophilic), deferred :: hydrophilic procedure :: final=>aero_props_final end type aerosol_properties @@ -91,12 +93,13 @@ end function aero_number_transported ! density ! hygroscopicity ! species type + ! species name ! short wave species refractive indices ! long wave species refractive indices ! species morphology !------------------------------------------------------------------------ subroutine aero_props_get(self, bin_ndx, species_ndx, list_ndx, density, hygro, & - spectype, specmorph, refindex_sw, refindex_lw) + spectype, specname, specmorph, refindex_sw, refindex_lw) import :: aerosol_properties, r8 class(aerosol_properties), intent(in) :: self integer, intent(in) :: bin_ndx ! bin index @@ -105,6 +108,7 @@ subroutine aero_props_get(self, bin_ndx, species_ndx, list_ndx, density, hygro, real(r8), optional, intent(out) :: density ! density (kg/m3) real(r8), optional, intent(out) :: hygro ! hygroscopicity character(len=*), optional, intent(out) :: spectype ! species type + character(len=*), optional, intent(out) :: specname ! species name character(len=*), optional, intent(out) :: specmorph ! species morphology complex(r8), pointer, optional, intent(out) :: refindex_sw(:) ! short wave species refractive indices complex(r8), pointer, optional, intent(out) :: refindex_lw(:) ! long wave species refractive indices @@ -378,6 +382,28 @@ function aero_bin_name(self, list_ndx, bin_ndx) result(name) end function aero_bin_name + !------------------------------------------------------------------------------ + ! returns dust deposition fluxes rebinned to specified diameter limits + !------------------------------------------------------------------------------ + subroutine aero_rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes) + import :: aerosol_properties, r8 + class(aerosol_properties), intent(in) :: self + character(len=*),intent(in) :: bulk_type ! aerosol type to rebin + real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 + real(r8), intent(in) :: diam_edges(:) ! meters + real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + + end subroutine aero_rebin_bulk_fluxes + + !------------------------------------------------------------------------------ + ! Returns TRUE if bin is hydrophilic, otherwise FALSE + !------------------------------------------------------------------------------ + logical function aero_hydrophilic(self, bin_ndx) + import :: aerosol_properties + class(aerosol_properties), intent(in) :: self + integer, intent(in) :: bin_ndx ! bin number + end function aero_hydrophilic + end interface contains diff --git a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 index 66cee40480..3739bdfcc8 100644 --- a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 @@ -36,6 +36,8 @@ module modal_aerosol_properties_mod procedure :: soluble procedure :: min_mass_mean_rad procedure :: bin_name + procedure :: rebin_bulk_fluxes + procedure :: hydrophilic final :: destructor end type modal_aerosol_properties @@ -182,12 +184,13 @@ end function number_transported ! density ! hygroscopicity ! species type + ! species name ! short wave species refractive indices ! long wave species refractive indices ! species morphology !------------------------------------------------------------------------ subroutine get(self, bin_ndx, species_ndx, list_ndx, density, hygro, & - spectype, specmorph, refindex_sw, refindex_lw) + spectype, specname, specmorph, refindex_sw, refindex_lw) class(modal_aerosol_properties), intent(in) :: self integer, intent(in) :: bin_ndx ! bin index @@ -196,6 +199,7 @@ subroutine get(self, bin_ndx, species_ndx, list_ndx, density, hygro, & real(r8), optional, intent(out) :: density ! density (kg/m3) real(r8), optional, intent(out) :: hygro ! hygroscopicity character(len=*), optional, intent(out) :: spectype ! species type + character(len=*), optional, intent(out) :: specname ! species name character(len=*), optional, intent(out) :: specmorph ! species morphology complex(r8), pointer, optional, intent(out) :: refindex_sw(:) ! short wave species refractive indices complex(r8), pointer, optional, intent(out) :: refindex_lw(:) ! long wave species refractive indices @@ -212,6 +216,10 @@ subroutine get(self, bin_ndx, species_ndx, list_ndx, density, hygro, & density_aer=density, hygro_aer=hygro, spectype=spectype, & refindex_aer_sw=refindex_sw, refindex_aer_lw=refindex_lw) + if (present(specname)) then + call rad_cnst_get_info(ilist, bin_ndx, species_ndx, spec_name=specname) + end if + if (present(specmorph)) then specmorph = 'UNKNOWN' end if @@ -665,4 +673,94 @@ function bin_name(self, list_ndx, bin_ndx) result(name) end function bin_name + !------------------------------------------------------------------------------ + ! returns dust deposition fluxes rebinned to specified diameter limits + !------------------------------------------------------------------------------ + subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes) + + class(modal_aerosol_properties), intent(in) :: self + character(len=*),intent(in) :: bulk_type ! aerosol type to rebin + real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 + real(r8), intent(in) :: diam_edges(:) ! meters + real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + + real(r8) :: dns_dst ! kg/m3 + real(r8) :: sigma_g, vmd, tmp, massfrac_bin(size(bulk_fluxes)) + real(r8) :: Ndust, Mdust, Mtotal, Ntot + integer :: k,l,m,mm, nbulk + logical :: has_dust + character(len=aero_name_len) :: spectype + character(len=aero_name_len) :: modetype + + real(r8), parameter :: sqrtwo =sqrt(2._r8) + + nbulk = size(bulk_fluxes) + + bulk_fluxes(:) = 0.0_r8 + + do m = 1,self%nbins() + Mdust = 0._r8 + Mtotal = 0._r8 + mm = self%indexer(m,0) + Ntot = dep_fluxes(mm) ! #/m2 + + has_dust = .false. + + do l = 1,self%nspecies(m) + mm = self%indexer(m,l) + call self%get(m,l, spectype=spectype, density=dns_dst) ! kg/m3 + if (spectype==bulk_type) then + Mdust = dep_fluxes(mm) ! kg/m2 + has_dust = .true. + end if + Mtotal = Mtotal + dep_fluxes(mm) ! kg/m2 + end do + mode_has_dust: if (has_dust) then + call rad_cnst_get_info(0, m, mode_type=modetype) + if (Mdust>0._r8) then + + call rad_cnst_get_mode_props(0, m, sigmag=sigma_g) + tmp = sqrtwo*log(sigma_g) + + ! 1. dust number concentration in coarse mode (wetdep) + Ndust = Ntot * Mdust/Mtotal ! #/m2 + + ! 2. dust volume median diameter (wetdep): meters + vmd = (6._r8*Mdust/(pi*Ndust*dns_dst))**(1._r8/3._r8) * exp(1.5_r8*(log(sigma_g))**2) + + massfrac_bin = 0._r8 + + do k = 1,nbulk + massfrac_bin(k) = 0.5_r8*( erf((log(diam_edges(k+1)/vmd))/tmp) & + - erf((log(diam_edges(k )/vmd))/tmp) ) + bulk_fluxes(k) = bulk_fluxes(k) + massfrac_bin(k) * Mdust + end do + + if (abs(1._r8-sum(massfrac_bin)) > 1.e-6_r8) then + write(*,*) 'bulk_dust_fluxes WARNING mode-num, massfrac_bin, sum(massfrac_bin) = ', & + m, massfrac_bin, sum(massfrac_bin) + end if + + end if + end if mode_has_dust + end do + + end subroutine rebin_bulk_fluxes + + !------------------------------------------------------------------------------ + ! Returns TRUE if bin is hydrophilic, otherwise FALSE + !------------------------------------------------------------------------------ + logical function hydrophilic(self, bin_ndx) + class(modal_aerosol_properties), intent(in) :: self + integer, intent(in) :: bin_ndx ! bin number + + character(len=aero_name_len) :: modetype + + call rad_cnst_get_info(0, bin_ndx, mode_type=modetype) + + hydrophilic = (trim(modetype) == 'accum') + !soluble = trim(mode_name)/='primary_carbon' ??? + + end function hydrophilic + end module modal_aerosol_properties_mod diff --git a/src/chemistry/modal_aero/aero_model.F90 b/src/chemistry/modal_aero/aero_model.F90 index 43ef5caa33..2beb9eb7ee 100644 --- a/src/chemistry/modal_aero/aero_model.F90 +++ b/src/chemistry/modal_aero/aero_model.F90 @@ -193,7 +193,7 @@ subroutine aero_model_init( pbuf2d ) use modal_aero_calcsize, only: modal_aero_calcsize_init use modal_aero_coag, only: modal_aero_coag_init - use modal_aero_deposition, only: modal_aero_deposition_init + use aero_deposition_cam, only: aero_deposition_cam_init use modal_aero_gasaerexch, only: modal_aero_gasaerexch_init use modal_aero_newnuc, only: modal_aero_newnuc_init use modal_aero_rename, only: modal_aero_rename_init @@ -255,7 +255,7 @@ subroutine aero_model_init( pbuf2d ) ! call modal_aero_deposition_init only if the user has not specified ! prescribed aerosol deposition fluxes if (.not.aerodep_flx_prescribed()) then - call modal_aero_deposition_init + call aero_deposition_cam_init() endif if (convproc_do_aer) then @@ -680,7 +680,7 @@ subroutine aero_model_drydep ( state, pbuf, obklen, ustar, cam_in, dt, cam_out, use modal_aero_data, only: numptrcw_amode use modal_aero_data, only: lmassptr_amode use modal_aero_data, only: lmassptrcw_amode - use modal_aero_deposition, only: set_srf_drydep + use aero_deposition_cam,only: aero_deposition_cam_setdry ! args type(physics_state), intent(in) :: state ! Physics state variables @@ -958,7 +958,7 @@ subroutine aero_model_drydep ( state, pbuf, obklen, ustar, cam_in, dt, cam_out, ! if the user has specified prescribed aerosol dep fluxes then ! do not set cam_out dep fluxes according to the prognostic aerosols if (.not.aerodep_flx_prescribed()) then - call set_srf_drydep(aerdepdryis, aerdepdrycw, cam_out) + call aero_deposition_cam_setdry(aerdepdryis, aerdepdrycw, cam_out) endif endsubroutine aero_model_drydep @@ -967,12 +967,12 @@ subroutine aero_model_drydep ( state, pbuf, obklen, ustar, cam_in, dt, cam_out, !============================================================================= subroutine aero_model_wetdep( state, dt, dlf, cam_out, ptend, pbuf) - use modal_aero_deposition, only: set_srf_wetdep use wetdep, only: wetdepa_v2, wetdep_inputs_set, wetdep_inputs_t use modal_aero_data use modal_aero_calcsize, only: modal_aero_calcsize_sub use modal_aero_wateruptake,only: modal_aero_wateruptake_dr use modal_aero_convproc, only: deepconv_wetdep_history, ma_convproc_intr, convproc_do_evaprain_atonce + use aero_deposition_cam, only: aero_deposition_cam_setwet ! args @@ -1650,7 +1650,7 @@ subroutine aero_model_wetdep( state, dt, dlf, cam_out, ptend, pbuf) ! if the user has specified prescribed aerosol dep fluxes then ! do not set cam_out dep fluxes according to the prognostic aerosols if (.not. aerodep_flx_prescribed()) then - call set_srf_wetdep(aerdepwetis, aerdepwetcw, cam_out) + call aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) endif endsubroutine aero_model_wetdep From 4b879d0b38d8dd002cf74e32768d9fe20eff5a39 Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Thu, 18 Jul 2024 10:22:34 -0600 Subject: [PATCH 2/8] Use CAM4 BAM dust sizes; pass in aero_props from aero_model; misc cleanup modified: src/chemistry/aerosol/aero_deposition_cam.F90 modified: src/chemistry/aerosol/modal_aerosol_properties_mod.F90 modified: src/chemistry/modal_aero/aero_model.F90 --- src/chemistry/aerosol/aero_deposition_cam.F90 | 28 ++++++------------- .../aerosol/modal_aerosol_properties_mod.F90 | 13 +++++---- src/chemistry/modal_aero/aero_model.F90 | 6 +++- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/chemistry/aerosol/aero_deposition_cam.F90 b/src/chemistry/aerosol/aero_deposition_cam.F90 index b4f31f263e..0707fb4522 100644 --- a/src/chemistry/aerosol/aero_deposition_cam.F90 +++ b/src/chemistry/aerosol/aero_deposition_cam.F90 @@ -2,7 +2,7 @@ module aero_deposition_cam !------------------------------------------------------------------------------ ! Purpose: ! -! Partition the contributions from modal components of wet and dry +! Partition the contributions from aerosols of wet and dry ! deposition at the surface into the fields passed to the coupler. !------------------------------------------------------------------------------ @@ -11,7 +11,6 @@ module aero_deposition_cam use camsrfexch, only: cam_out_t use aerosol_properties_mod, only: aero_name_len use aerosol_properties_mod, only: aerosol_properties - use modal_aerosol_properties_mod, only: modal_aerosol_properties implicit none @@ -40,32 +39,23 @@ module aero_deposition_cam ! bulk dust bins (meters) integer, parameter :: n_bulk_dst_bins = 4 - real(r8), parameter :: bulk_dst_edges(n_bulk_dst_bins+1) = & - (/1.0e-15_r8, 0.5e-6_r8, 1.25e-6_r8, 2.5e-6_r8, 1.0e-2_r8/) ! meters -! (/0.05e-6_r8, 0.5e-6_r8, 1.25e-6_r8, 2.5e-6_r8, 5.0e-6_r8/) ! meters -! (/1.e-15_r8, 1.25e-6_r8, 2.5e-6_r8, 5.0e-6_r8, 1.0e-2_r8/) ! meters (Flanner's) - -! in mo_setaer.F90 : -! dust is treated as 4 size distributions -! 0.05 - 0.5; 0.5 - 1.25; 1.25 - 2.5; 2.5 - 5.0 microns -! in components/cice/src/icepack/columnphysics/icepack_zbgc_shared.F90 - ! Aerosol order and type should be consistent with order/type - ! specified in delta Eddington: 1) hydrophobic black carbon; - ! 2) hydrophilic black carbon; 3) dust (0.05-0.5 micron); - ! 4) dust (0.5-1.25 micron); 5) dust (1.25-2.5 micron); - ! 6) dust (2.5-5 micron) + ! CAM4 bulk dust bin sizes (https://doi.org/10.1002/2013MS000279) + real(r8), parameter :: bulk_dst_edges(n_bulk_dst_bins+1) = & + (/0.1e-6_r8, 1.0e-6_r8, 2.5e-6_r8, 5.0e-6_r8, 10.e-6_r8/) contains !============================================================================ - subroutine aero_deposition_cam_init() + subroutine aero_deposition_cam_init(aero_props_in) + + class(aerosol_properties),target, intent(in) :: aero_props_in integer :: pcnt, scnt character(len=*), parameter :: subrname = 'aero_deposition_cam_init' ! construct the aerosol properties object - aero_props => modal_aerosol_properties() + aero_props => aero_props_in ! set the cam constituent indices and determine the counts ! for the specified aerosol types @@ -192,7 +182,7 @@ subroutine aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) dst_fluxes = 0._r8 do ibin = 1,aero_props%nbins() - do ispec = 0,aero_props%nspecies(ibin) + do ispec = 0,aero_props%nmasses(ibin) if (ispec==0) then call aero_props%num_names(ibin, specname, name_c) else diff --git a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 index 3739bdfcc8..19c78aaaf6 100644 --- a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 @@ -46,6 +46,8 @@ module modal_aerosol_properties_mod procedure :: constructor end interface modal_aerosol_properties + logical, parameter :: debug = .false. + contains !------------------------------------------------------------------------------ @@ -717,7 +719,7 @@ subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxe end do mode_has_dust: if (has_dust) then call rad_cnst_get_info(0, m, mode_type=modetype) - if (Mdust>0._r8) then + if (Ntot>0._r8 .and. Mdust>0._r8 .and. Mtotal>0._r8) then call rad_cnst_get_mode_props(0, m, sigmag=sigma_g) tmp = sqrtwo*log(sigma_g) @@ -736,9 +738,11 @@ subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxe bulk_fluxes(k) = bulk_fluxes(k) + massfrac_bin(k) * Mdust end do - if (abs(1._r8-sum(massfrac_bin)) > 1.e-6_r8) then - write(*,*) 'bulk_dust_fluxes WARNING mode-num, massfrac_bin, sum(massfrac_bin) = ', & - m, massfrac_bin, sum(massfrac_bin) + if (debug) then + if (abs(1._r8-sum(massfrac_bin)) > 1.e-6_r8) then + write(*,*) 'bulk_dust_fluxes WARNING mode-num, massfrac_bin, sum(massfrac_bin) = ', & + m, massfrac_bin, sum(massfrac_bin) + end if end if end if @@ -759,7 +763,6 @@ logical function hydrophilic(self, bin_ndx) call rad_cnst_get_info(0, bin_ndx, mode_type=modetype) hydrophilic = (trim(modetype) == 'accum') - !soluble = trim(mode_name)/='primary_carbon' ??? end function hydrophilic diff --git a/src/chemistry/modal_aero/aero_model.F90 b/src/chemistry/modal_aero/aero_model.F90 index 2beb9eb7ee..ab7f2280ad 100644 --- a/src/chemistry/modal_aero/aero_model.F90 +++ b/src/chemistry/modal_aero/aero_model.F90 @@ -29,6 +29,7 @@ module aero_model use modal_aero_wateruptake, only: modal_strat_sulfate use mo_setsox, only: setsox, has_sox + use modal_aerosol_properties_mod, only: modal_aerosol_properties implicit none private @@ -106,6 +107,8 @@ module aero_model logical :: convproc_do_aer + class(modal_aerosol_properties), pointer :: aero_props=>null() + contains !============================================================================= @@ -255,7 +258,8 @@ subroutine aero_model_init( pbuf2d ) ! call modal_aero_deposition_init only if the user has not specified ! prescribed aerosol deposition fluxes if (.not.aerodep_flx_prescribed()) then - call aero_deposition_cam_init() + aero_props => modal_aerosol_properties() + call aero_deposition_cam_init(aero_props) endif if (convproc_do_aer) then From fbca9ea514749b38800c88e4e3b8dd701a9fc74b Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Thu, 18 Jul 2024 16:15:09 -0600 Subject: [PATCH 3/8] improve checks on number and mass fluxes to avoid divide by zero modified: src/chemistry/aerosol/modal_aerosol_properties_mod.F90 --- src/chemistry/aerosol/modal_aerosol_properties_mod.F90 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 index 19c78aaaf6..8057a321c2 100644 --- a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 @@ -694,7 +694,8 @@ subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxe character(len=aero_name_len) :: spectype character(len=aero_name_len) :: modetype - real(r8), parameter :: sqrtwo =sqrt(2._r8) + real(r8), parameter :: sqrtwo = sqrt(2._r8) + real(r8), parameter :: onethrd = 1._r8/3._r8 nbulk = size(bulk_fluxes) @@ -719,7 +720,7 @@ subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxe end do mode_has_dust: if (has_dust) then call rad_cnst_get_info(0, m, mode_type=modetype) - if (Ntot>0._r8 .and. Mdust>0._r8 .and. Mtotal>0._r8) then + if (Ntot>1.e-40_r8 .and. Mdust>1.e-40_r8 .and. Mtotal>1.e-40_r8) then call rad_cnst_get_mode_props(0, m, sigmag=sigma_g) tmp = sqrtwo*log(sigma_g) @@ -728,7 +729,7 @@ subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxe Ndust = Ntot * Mdust/Mtotal ! #/m2 ! 2. dust volume median diameter (wetdep): meters - vmd = (6._r8*Mdust/(pi*Ndust*dns_dst))**(1._r8/3._r8) * exp(1.5_r8*(log(sigma_g))**2) + vmd = (6._r8*Mdust/(pi*Ndust*dns_dst))**onethrd * exp(1.5_r8*(log(sigma_g))**2) massfrac_bin = 0._r8 From bbfc5761da235b0e7d70c20ab0779252dfdd2108 Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Thu, 8 Aug 2024 10:26:08 -0600 Subject: [PATCH 4/8] tweak a comment modified: src/chemistry/modal_aero/aero_model.F90 --- src/chemistry/modal_aero/aero_model.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chemistry/modal_aero/aero_model.F90 b/src/chemistry/modal_aero/aero_model.F90 index 7503669511..86236a0650 100644 --- a/src/chemistry/modal_aero/aero_model.F90 +++ b/src/chemistry/modal_aero/aero_model.F90 @@ -256,7 +256,7 @@ subroutine aero_model_init( pbuf2d ) call modal_aero_coag_init call modal_aero_newnuc_init - ! call modal_aero_deposition_init only if the user has not specified + ! call aero_deposition_cam_init only if the user has not specified ! prescribed aerosol deposition fluxes if (.not.aerodep_flx_prescribed()) then aero_props => modal_aerosol_properties() From 536e7cbf70d0cc61e8f21304f92bfef8609dae8e Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Wed, 28 Aug 2024 09:19:51 -0600 Subject: [PATCH 5/8] add error checking and comments modified: src/chemistry/aerosol/aero_deposition_cam.F90 modified: src/chemistry/aerosol/aerosol_properties_mod.F90 modified: src/chemistry/aerosol/modal_aerosol_properties_mod.F90 --- src/chemistry/aerosol/aero_deposition_cam.F90 | 62 +++++++++++++------ .../aerosol/aerosol_properties_mod.F90 | 16 +++-- .../aerosol/modal_aerosol_properties_mod.F90 | 62 ++++++++++++------- 3 files changed, 92 insertions(+), 48 deletions(-) diff --git a/src/chemistry/aerosol/aero_deposition_cam.F90 b/src/chemistry/aerosol/aero_deposition_cam.F90 index 0707fb4522..d22119c6b4 100644 --- a/src/chemistry/aerosol/aero_deposition_cam.F90 +++ b/src/chemistry/aerosol/aero_deposition_cam.F90 @@ -7,8 +7,10 @@ module aero_deposition_cam !------------------------------------------------------------------------------ use shr_kind_mod, only: r8 => shr_kind_r8 + use shr_kind_mod, only: cl => shr_kind_cl use constituents, only: cnst_get_ind, pcnst use camsrfexch, only: cam_out_t + use cam_abortutils,only: endrun use aerosol_properties_mod, only: aero_name_len use aerosol_properties_mod, only: aerosol_properties @@ -140,6 +142,8 @@ subroutine aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) real(r8) :: dep_fluxes(nele_tot) real(r8) :: dst_fluxes(n_bulk_dst_bins) character(len=aero_name_len) :: specname, name_c + integer :: errstat + character(len=cl) :: errstr ncol = cam_out%ncol @@ -156,21 +160,25 @@ subroutine aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) ! srf models want positive definite fluxes. do i = 1, ncol - ! black carbon fluxes + ! hydrophilic black carbon fluxes do ispec=1,bcphi_cnt cam_out%bcphiwet(i) = cam_out%bcphiwet(i) & - (aerdepwetis(i,bcphi_ndx(ispec))+aerdepwetcw(i,bcphi_ndx(ispec))) enddo + + ! hydrophobic black carbon fluxes do ispec=1,bcpho_cnt cam_out%bcphiwet(i) = cam_out%bcphiwet(i) & - (aerdepwetis(i,bcpho_ndx(ispec))+aerdepwetcw(i,bcpho_ndx(ispec))) enddo - ! organic carbon fluxes + ! hydrophilic organic carbon fluxes do ispec=1,ocphi_cnt cam_out%ocphiwet(i) = cam_out%ocphiwet(i) & - (aerdepwetis(i,ocphi_ndx(ispec))+aerdepwetcw(i,ocphi_ndx(ispec))) enddo + + ! hydrophobic organic carbon fluxes do ispec=1,ocpho_cnt cam_out%ocphiwet(i) = cam_out%ocphiwet(i) & - (aerdepwetis(i,ocpho_ndx(ispec))+aerdepwetcw(i,ocpho_ndx(ispec))) @@ -197,19 +205,23 @@ subroutine aero_deposition_cam_setwet(aerdepwetis, aerdepwetcw, cam_out) end do ! rebin dust fluxes to bulk dust bins - call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes) + call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes, errstat, errstr) + if (errstat/=0) then + call endrun('aero_deposition_cam_setwet: '//trim(errstr)) + end if + cam_out%dstwet1(i) = cam_out%dstwet1(i) + dst_fluxes(1) cam_out%dstwet2(i) = cam_out%dstwet2(i) + dst_fluxes(2) cam_out%dstwet3(i) = cam_out%dstwet3(i) + dst_fluxes(3) cam_out%dstwet4(i) = cam_out%dstwet4(i) + dst_fluxes(4) ! in rare cases, integrated deposition tendency is upward - if (cam_out%bcphiwet(i) .lt. 0._r8) cam_out%bcphiwet(i) = 0._r8 - if (cam_out%ocphiwet(i) .lt. 0._r8) cam_out%ocphiwet(i) = 0._r8 - if (cam_out%dstwet1(i) .lt. 0._r8) cam_out%dstwet1(i) = 0._r8 - if (cam_out%dstwet2(i) .lt. 0._r8) cam_out%dstwet2(i) = 0._r8 - if (cam_out%dstwet3(i) .lt. 0._r8) cam_out%dstwet3(i) = 0._r8 - if (cam_out%dstwet4(i) .lt. 0._r8) cam_out%dstwet4(i) = 0._r8 + if (cam_out%bcphiwet(i) < 0._r8) cam_out%bcphiwet(i) = 0._r8 + if (cam_out%ocphiwet(i) < 0._r8) cam_out%ocphiwet(i) = 0._r8 + if (cam_out%dstwet1(i) < 0._r8) cam_out%dstwet1(i) = 0._r8 + if (cam_out%dstwet2(i) < 0._r8) cam_out%dstwet2(i) = 0._r8 + if (cam_out%dstwet3(i) < 0._r8) cam_out%dstwet3(i) = 0._r8 + if (cam_out%dstwet4(i) < 0._r8) cam_out%dstwet4(i) = 0._r8 enddo @@ -232,6 +244,8 @@ subroutine aero_deposition_cam_setdry(aerdepdryis, aerdepdrycw, cam_out) real(r8) :: dep_fluxes(nele_tot) real(r8) :: dst_fluxes(n_bulk_dst_bins) character(len=aero_name_len) :: specname, name_c + integer :: errstat + character(len=cl) :: errstr ncol = cam_out%ncol @@ -250,21 +264,25 @@ subroutine aero_deposition_cam_setdry(aerdepdryis, aerdepdrycw, cam_out) ! srf models want positive definite fluxes. do i = 1, ncol - ! black carbon fluxes + ! hydrophilic black carbon fluxes do ispec=1,bcphi_cnt cam_out%bcphidry(i) = cam_out%bcphidry(i) & + (aerdepdryis(i,bcphi_ndx(ispec))+aerdepdrycw(i,bcphi_ndx(ispec))) enddo + + ! hydrophobic black carbon fluxes do ispec=1,bcpho_cnt cam_out%bcphodry(i) = cam_out%bcphodry(i) & + (aerdepdryis(i,bcpho_ndx(ispec))+aerdepdrycw(i,bcpho_ndx(ispec))) enddo - ! organic carbon fluxes + ! hydrophilic organic carbon fluxes do ispec=1,ocphi_cnt cam_out%ocphidry(i) = cam_out%ocphidry(i) & + (aerdepdryis(i,ocphi_ndx(ispec))+aerdepdrycw(i,ocphi_ndx(ispec))) enddo + + ! hydrophobic organic carbon fluxes do ispec=1,ocpho_cnt cam_out%ocphodry(i) = cam_out%ocphodry(i) & + (aerdepdryis(i,ocpho_ndx(ispec))+aerdepdrycw(i,ocpho_ndx(ispec))) @@ -291,21 +309,25 @@ subroutine aero_deposition_cam_setdry(aerdepdryis, aerdepdrycw, cam_out) end do ! rebin dust fluxes to bulk dust bins - call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes) + call aero_props%rebin_bulk_fluxes('dust', dep_fluxes, bulk_dst_edges, dst_fluxes, errstat, errstr) + if (errstat/=0) then + call endrun('aero_deposition_cam_setdry: '//trim(errstr)) + end if + cam_out%dstdry1(i) = cam_out%dstdry1(i) + dst_fluxes(1) cam_out%dstdry2(i) = cam_out%dstdry2(i) + dst_fluxes(2) cam_out%dstdry3(i) = cam_out%dstdry3(i) + dst_fluxes(3) cam_out%dstdry4(i) = cam_out%dstdry4(i) + dst_fluxes(4) ! in rare cases, integrated deposition tendency is upward - if (cam_out%bcphidry(i) .lt. 0._r8) cam_out%bcphidry(i) = 0._r8 - if (cam_out%ocphidry(i) .lt. 0._r8) cam_out%ocphidry(i) = 0._r8 - if (cam_out%bcphodry(i) .lt. 0._r8) cam_out%bcphodry(i) = 0._r8 - if (cam_out%ocphodry(i) .lt. 0._r8) cam_out%ocphodry(i) = 0._r8 - if (cam_out%dstdry1(i) .lt. 0._r8) cam_out%dstdry1(i) = 0._r8 - if (cam_out%dstdry2(i) .lt. 0._r8) cam_out%dstdry2(i) = 0._r8 - if (cam_out%dstdry3(i) .lt. 0._r8) cam_out%dstdry3(i) = 0._r8 - if (cam_out%dstdry4(i) .lt. 0._r8) cam_out%dstdry4(i) = 0._r8 + if (cam_out%bcphidry(i) < 0._r8) cam_out%bcphidry(i) = 0._r8 + if (cam_out%ocphidry(i) < 0._r8) cam_out%ocphidry(i) = 0._r8 + if (cam_out%bcphodry(i) < 0._r8) cam_out%bcphodry(i) = 0._r8 + if (cam_out%ocphodry(i) < 0._r8) cam_out%ocphodry(i) = 0._r8 + if (cam_out%dstdry1(i) < 0._r8) cam_out%dstdry1(i) = 0._r8 + if (cam_out%dstdry2(i) < 0._r8) cam_out%dstdry2(i) = 0._r8 + if (cam_out%dstdry3(i) < 0._r8) cam_out%dstdry3(i) = 0._r8 + if (cam_out%dstdry4(i) < 0._r8) cam_out%dstdry4(i) = 0._r8 enddo diff --git a/src/chemistry/aerosol/aerosol_properties_mod.F90 b/src/chemistry/aerosol/aerosol_properties_mod.F90 index cc67354bc7..c94f277637 100644 --- a/src/chemistry/aerosol/aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/aerosol_properties_mod.F90 @@ -383,15 +383,19 @@ function aero_bin_name(self, list_ndx, bin_ndx) result(name) end function aero_bin_name !------------------------------------------------------------------------------ - ! returns dust deposition fluxes rebinned to specified diameter limits + ! returns bulk deposition fluxes of the specified species type + ! rebinned to specified diameter limits !------------------------------------------------------------------------------ - subroutine aero_rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes) + subroutine aero_rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes, & + error_code, error_string) import :: aerosol_properties, r8 class(aerosol_properties), intent(in) :: self - character(len=*),intent(in) :: bulk_type ! aerosol type to rebin - real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 - real(r8), intent(in) :: diam_edges(:) ! meters - real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + character(len=*),intent(in) :: bulk_type ! aerosol type to rebin + real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 + real(r8), intent(in) :: diam_edges(:) ! meters + real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + integer, intent(out) :: error_code ! error code (0 if no error) + character(len=*), intent(out) :: error_string ! error string end subroutine aero_rebin_bulk_fluxes diff --git a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 index 8057a321c2..54f64fa759 100644 --- a/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 +++ b/src/chemistry/aerosol/modal_aerosol_properties_mod.F90 @@ -676,80 +676,98 @@ function bin_name(self, list_ndx, bin_ndx) result(name) end function bin_name !------------------------------------------------------------------------------ - ! returns dust deposition fluxes rebinned to specified diameter limits + ! returns bulk deposition fluxes of the specified species type + ! rebinned to specified diameter limits !------------------------------------------------------------------------------ - subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes) + subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes, & + error_code, error_string) + use infnan, only: nan, assignment(=) class(modal_aerosol_properties), intent(in) :: self - character(len=*),intent(in) :: bulk_type ! aerosol type to rebin - real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 - real(r8), intent(in) :: diam_edges(:) ! meters - real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + character(len=*),intent(in) :: bulk_type ! aerosol type to rebin + real(r8), intent(in) :: dep_fluxes(:) ! kg/m2 + real(r8), intent(in) :: diam_edges(:) ! meters + real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2 + integer, intent(out) :: error_code ! error code (0 if no error) + character(len=*), intent(out) :: error_string ! error string real(r8) :: dns_dst ! kg/m3 real(r8) :: sigma_g, vmd, tmp, massfrac_bin(size(bulk_fluxes)) - real(r8) :: Ndust, Mdust, Mtotal, Ntot + real(r8) :: Ntype, Mtype, Mtotal, Ntot integer :: k,l,m,mm, nbulk - logical :: has_dust + logical :: has_type, type_not_found + character(len=aero_name_len) :: spectype character(len=aero_name_len) :: modetype real(r8), parameter :: sqrtwo = sqrt(2._r8) real(r8), parameter :: onethrd = 1._r8/3._r8 + error_code = 0 + error_string = ' ' + + type_not_found = .true. + nbulk = size(bulk_fluxes) bulk_fluxes(:) = 0.0_r8 do m = 1,self%nbins() - Mdust = 0._r8 + Mtype = 0._r8 Mtotal = 0._r8 mm = self%indexer(m,0) Ntot = dep_fluxes(mm) ! #/m2 - has_dust = .false. + has_type = .false. do l = 1,self%nspecies(m) mm = self%indexer(m,l) call self%get(m,l, spectype=spectype, density=dns_dst) ! kg/m3 if (spectype==bulk_type) then - Mdust = dep_fluxes(mm) ! kg/m2 - has_dust = .true. + Mtype = dep_fluxes(mm) ! kg/m2 + has_type = .true. + type_not_found = .false. end if Mtotal = Mtotal + dep_fluxes(mm) ! kg/m2 end do - mode_has_dust: if (has_dust) then + mode_has_type: if (has_type) then call rad_cnst_get_info(0, m, mode_type=modetype) - if (Ntot>1.e-40_r8 .and. Mdust>1.e-40_r8 .and. Mtotal>1.e-40_r8) then + if (Ntot>1.e-40_r8 .and. Mtype>1.e-40_r8 .and. Mtotal>1.e-40_r8) then call rad_cnst_get_mode_props(0, m, sigmag=sigma_g) tmp = sqrtwo*log(sigma_g) - ! 1. dust number concentration in coarse mode (wetdep) - Ndust = Ntot * Mdust/Mtotal ! #/m2 + ! type number concentration + Ntype = Ntot * Mtype/Mtotal ! #/m2 - ! 2. dust volume median diameter (wetdep): meters - vmd = (6._r8*Mdust/(pi*Ndust*dns_dst))**onethrd * exp(1.5_r8*(log(sigma_g))**2) + ! volume median diameter (meters) + vmd = (6._r8*Mtype/(pi*Ntype*dns_dst))**onethrd * exp(1.5_r8*(log(sigma_g))**2) massfrac_bin = 0._r8 do k = 1,nbulk massfrac_bin(k) = 0.5_r8*( erf((log(diam_edges(k+1)/vmd))/tmp) & - - erf((log(diam_edges(k )/vmd))/tmp) ) - bulk_fluxes(k) = bulk_fluxes(k) + massfrac_bin(k) * Mdust + - erf((log(diam_edges(k )/vmd))/tmp) ) + bulk_fluxes(k) = bulk_fluxes(k) + massfrac_bin(k) * Mtype end do if (debug) then if (abs(1._r8-sum(massfrac_bin)) > 1.e-6_r8) then - write(*,*) 'bulk_dust_fluxes WARNING mode-num, massfrac_bin, sum(massfrac_bin) = ', & + write(*,*) 'rebin_bulk_fluxes WARNING mode-num, massfrac_bin, sum(massfrac_bin) = ', & m, massfrac_bin, sum(massfrac_bin) end if end if end if - end if mode_has_dust + end if mode_has_type end do + if (type_not_found) then + bulk_fluxes(:) = nan + error_code = 1 + write(error_string,*) 'aerosol_properties::rebin_bulk_fluxes ERROR : ',trim(bulk_type),' not found' + end if + end subroutine rebin_bulk_fluxes !------------------------------------------------------------------------------ From e7f1ea1e90c2d98bf232ab5a27739e89b7473ed2 Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Wed, 28 Aug 2024 10:54:01 -0600 Subject: [PATCH 6/8] ChangeLog draft --- components/cdeps | 2 +- components/cice | 2 +- doc/ChangeLog | 68 ++++++++++++++++++++++++++++++++++++++++++++++-- src/dynamics/fv3 | 2 +- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/components/cdeps b/components/cdeps index 46c10740ce..7b0b3a8272 160000 --- a/components/cdeps +++ b/components/cdeps @@ -1 +1 @@ -Subproject commit 46c10740ce83a154edfc876093f72e7f041c3659 +Subproject commit 7b0b3a827241c53d296ec877cb1f59966bf5e5bf diff --git a/components/cice b/components/cice index bdf6ea04d6..f14ec8339b 160000 --- a/components/cice +++ b/components/cice @@ -1 +1 @@ -Subproject commit bdf6ea04d6133434fcaa4de5336de106f01290d0 +Subproject commit f14ec8339bc5bc4a7a0664da5e247b5cfda531a1 diff --git a/doc/ChangeLog b/doc/ChangeLog index 188b2f027d..47d944b09b 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,69 @@ =============================================================== +Tag name: cam6_4_025 +Originator(s): fvitt, tilmes +Date: 28 Aug 2024 +One-line Summary: Repartition dust deposition fluxes to surface models +Github PR URL: https://github.com/ESCOMP/CAM/pull/1096 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Repartition the modal dust deposition fluxes into 4 bulk bins for passing to the surface + models. The aerosol fluxes code was refactored in a generalized way which can easily be + expanded for other aerosol representations, such as CARMA, and aerosol species types. + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: cacraigucar + +List all files eliminated: N/A + +List all files added and what they do: +A src/chemistry/aerosol/aero_deposition_cam.F90 + - aerosol model independent module that uses aerosol abstract interface + to prepare deposition fluxes passed to surface models + +List all existing files that have been modified, and describe the changes: +M src/chemistry/aerosol/aerosol_properties_mod.F90 +M src/chemistry/aerosol/modal_aerosol_properties_mod.F90 + - add interface for calculating generalized bulk fluxes + +M src/chemistry/modal_aero/aero_model.F90 + - replace use of modal_aero_deposition with generalized aero_deposition_cam + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + +derecho/nvhpc/aux_cam: + +izumi/nag/aux_cam: + +izumi/gnu/aux_cam: + +Summarize any changes to answers: + larger than roundoff but same climate + +URL for AMWG diagnostics output used to validate new climate: + +https://acomstaff.acom.ucar.edu/tilmes/amwg/cam7/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004_vs_f.e23_beta02.FLTHIST_ne30.001_1995_2004/website/index.html + +The land diagnostics are here: + +https://webext.cgd.ucar.edu/FLTHIST/f.e23_beta02.FLTHIST_ne30.surf_flux/lnd/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004-f.e23_beta02.FLTHIST_ne30.001_1995_2004/setsIndex.html + +=============================================================== +=============================================================== + Tag name: cam6_4_024 Originator(s): eaton Date: 27 Aug 2024 @@ -48,9 +112,9 @@ List all existing files that have been modified, and describe the changes: bld/build-namelist . if simple model or aquaplanet remove the settings of - stream_ndep_data_filename and stream_ndep_mesh_filename + stream_ndep_data_filename and stream_ndep_mesh_filename . modify logic so the add_default call for drydep_srf_file is not made for - simple models or aquaplanet + simple models or aquaplanet bld/namelist_files/namelist_definition.xml . remove the variables in the ndep_stream_nml group. Not used. diff --git a/src/dynamics/fv3 b/src/dynamics/fv3 index df3550b0f6..66227690a9 160000 --- a/src/dynamics/fv3 +++ b/src/dynamics/fv3 @@ -1 +1 @@ -Subproject commit df3550b0f6a835778f32ccc8c6291942e0413f62 +Subproject commit 66227690a9fb43a64492de32de14562a25ede717 From c9d17f164aa2ad5bc72f519b472644c545c260b1 Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Wed, 28 Aug 2024 14:23:40 -0600 Subject: [PATCH 7/8] ChangeLog update --- doc/ChangeLog | 58 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 47d944b09b..58ec09cc9a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -3,7 +3,7 @@ Tag name: cam6_4_025 Originator(s): fvitt, tilmes Date: 28 Aug 2024 -One-line Summary: Repartition dust deposition fluxes to surface models +One-line Summary: Repartition dust deposition fluxes passed to surface models Github PR URL: https://github.com/ESCOMP/CAM/pull/1096 Purpose of changes (include the issue number and title text for each relevant GitHub issue): @@ -43,23 +43,71 @@ then copy the lines from the td.*.status files for the failed tests to the appropriate machine below. All failed tests must be justified. derecho/intel/aux_cam: + PEND ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + + PEND SMS_D_Ln9_P1280x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.derecho_intel.cam-outfrq9s + PEND SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s + - pre-existing pend/failures -- need fix in CLM external + + DIFF ERP_D_Ln9.ne30pg3_ne30pg3_mg17.FLTHIST.derecho_intel.cam-outfrq9s + DIFF ERP_D_Ln9.ne30pg3_ne30pg3_mg17.FLTHIST.derecho_intel.cam-outfrq9s_rrtmgp + DIFF ERP_Ld3.f09_f09_mg17.FWHIST.derecho_intel.cam-reduced_hist1d + DIFF ERP_Ln9.C96_C96_mg17.F2000climo.derecho_intel.cam-outfrq9s_mg3 + DIFF ERP_Ln9.f09_f09_mg17.F1850.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.f09_f09_mg17.F2000climo.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.f09_f09_mg17.F2010climo.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.f09_f09_mg17.FHIST_BDRD.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.f19_f19_mg17.FWsc1850.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.ne30pg3_ne30pg3_mg17.FCnudged.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s + DIFF ERS_Ld3.f10_f10_mg37.F1850.derecho_intel.cam-outfrq1d_14dec_ghg_cam7 + DIFF ERS_Ln9.f09_f09_mg17.FX2000.derecho_intel.cam-outfrq9s + DIFF ERS_Ln9.f19_f19_mg17.FXSD.derecho_intel.cam-outfrq9s + DIFF ERS_Ln9_P288x1.mpasa120_mpasa120.F2000climo.derecho_intel.cam-outfrq9s_mpasa120 + DIFF ERS_Ln9_P36x1.mpasa480_mpasa480.F2000climo.derecho_intel.cam-outfrq9s_mpasa480 + DIFF SMS_D_Ln9.f09_f09_mg17.FCts2nudged.derecho_intel.cam-outfrq9s_leapday + DIFF SMS_D_Ln9.f09_f09_mg17.FCvbsxHIST.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f09_f09_mg17.FSD.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s_waccm_ma_mam4 + DIFF SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie + DIFF SMS_D_Ln9.ne16pg3_ne16pg3_mg17.FX2000.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.ne30pg3_ne30pg3_mg17.FCts4MTHIST.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.ne30pg3_ne30pg3_mg17.FMTHIST.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9_P1280x1.ne30pg3_ne30pg3_mg17.FCLTHIST.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.T42_T42.FSCAMARM97.derecho_intel.cam-outfrq9s + DIFF SMS_Ld1.f09_f09_mg17.FCHIST_GC.derecho_intel.cam-outfrq1d + DIFF SMS_Ld1.f09_f09_mg17.FW2000climo.derecho_intel.cam-outfrq1d + DIFF SMS_Ld1.ne30pg3_ne30pg3_mg17.FC2010climo.derecho_intel.cam-outfrq1d + DIFF SMS_Lh12.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq3h + DIFF SMS_Lm13.f10_f10_mg37.F2000climo.derecho_intel.cam-outfrq1m + DIFF SMS_Ln9.f09_f09_mg17.F2010climo.derecho_intel.cam-nudging + DIFF SMS_Ln9.f09_f09_mg17.FW1850.derecho_intel.cam-reduced_hist3s + DIFF SMS_Ln9.f19_f19.F2000climo.derecho_intel.cam-silhs + DIFF SMS_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s_rrtmgp + - expected baseline failures due to changes in dust deposition fluxes to surface models derecho/nvhpc/aux_cam: + DIFF ERS_Ln9_G4-a100-openacc.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_mg3_default + - expected baseline failure due to changes in dust deposition fluxes to surface models izumi/nag/aux_cam: + FAIL DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae + - pre-existing failure - issue #670 -izumi/gnu/aux_cam: +izumi/gnu/aux_cam: All PASS Summarize any changes to answers: larger than roundoff but same climate URL for AMWG diagnostics output used to validate new climate: -https://acomstaff.acom.ucar.edu/tilmes/amwg/cam7/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004_vs_f.e23_beta02.FLTHIST_ne30.001_1995_2004/website/index.html + https://acomstaff.acom.ucar.edu/tilmes/amwg/cam7/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004_vs_f.e23_beta02.FLTHIST_ne30.001_1995_2004/website/index.html -The land diagnostics are here: + The land diagnostics are here: -https://webext.cgd.ucar.edu/FLTHIST/f.e23_beta02.FLTHIST_ne30.surf_flux/lnd/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004-f.e23_beta02.FLTHIST_ne30.001_1995_2004/setsIndex.html + https://webext.cgd.ucar.edu/FLTHIST/f.e23_beta02.FLTHIST_ne30.surf_flux/lnd/f.e23_beta02.FLTHIST_ne30.surf_flux_1995_2004-f.e23_beta02.FLTHIST_ne30.001_1995_2004/setsIndex.html =============================================================== =============================================================== From 1fad54910dacf2705612de63b1d9bad1cde1faa5 Mon Sep 17 00:00:00 2001 From: Francis Vitt Date: Wed, 28 Aug 2024 16:37:40 -0600 Subject: [PATCH 8/8] ChangeLog update --- doc/ChangeLog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 58ec09cc9a..85a19b87ea 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -8,8 +8,8 @@ Github PR URL: https://github.com/ESCOMP/CAM/pull/1096 Purpose of changes (include the issue number and title text for each relevant GitHub issue): - Repartition the modal dust deposition fluxes into 4 bulk bins for passing to the surface - models. The aerosol fluxes code was refactored in a generalized way which can easily be + Repartition the modal dust deposition fluxes into 4 bulk bins for passing to the surface + models. The aerosol fluxes code was refactored in a generalized way which can easily be expanded for other aerosol representations, such as CARMA, and aerosol species types. Describe any changes made to build system: N/A @@ -46,9 +46,9 @@ derecho/intel/aux_cam: PEND ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 - PEND SMS_D_Ln9_P1280x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.derecho_intel.cam-outfrq9s - PEND SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s - - pre-existing pend/failures -- need fix in CLM external + FAIL SMS_D_Ln9_P1280x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.derecho_intel.cam-outfrq9s + FAIL SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s + - pre-existing failures -- need fix in CLM external DIFF ERP_D_Ln9.ne30pg3_ne30pg3_mg17.FLTHIST.derecho_intel.cam-outfrq9s DIFF ERP_D_Ln9.ne30pg3_ne30pg3_mg17.FLTHIST.derecho_intel.cam-outfrq9s_rrtmgp